# Notes

# Generic Classes and Methods

Generics add stability and code efficiency to your code work.
泛型为编程工作增加了稳定性和编码效率。

A generic class or method is one whose definition uses a placeholder for one or more of the types it works with.
泛型类或方法是一种其定义使用占位符的类或方法。

The placeholder is really a type parameter.
占位符实际上是一个类型参数。

For a generic class, the actual type argument is specified when an object of the generic class is being instantiated.
对于泛型类,当实例化该泛型类的对象时,将指定实际的类型实参。

For a generic method, the compiler deduces the actual type argument from the type of data being passed to the method.
对于泛型方法,编译器从传递给方法的数据类型中推导实际的类型参数。

# Why Use Generics?

In a nutshell, generics enable types (classes and interfaces) to be parameters when defining classes, interfaces, and methods.
简而言之,泛型在定义类、接口和方法时,使类型(类和接口)成为参数。

Type parameters provide a way for you to reuse the same code with different inputs.
类型参数提供了一种在不同的输入中重用相同代码的方法。

Code that uses generics has many benefits over nongeneric code:
与非泛型代码相比,使用泛型的代码有很多好处:

  • Stronger type checks at compile time.
    在编译时进行更强大的类型检查。
    A Java compiler applies strong type checking to generic code and issues errors if the code violates type safety.
    Java 编译器对泛型代码进行强类型检查,如果代码违反类型安全,则会发出错误。
    Fixing compile-time errors is easier than fixing runtime errors, which can be difficult to find.
    修复编译时错误比修复运行时错误容易,后者可能很难找到。
  • Elimination of casts.
    消除强制转换。
    The following nongeneric code snippet requires casting:
    以下非泛型代码段需要强制转换:
    List list = new ArrayList();
    list.add("hello");
    String s = (String) list.get(0);
    When rewritten using generics, the code does not require casting:
    使用泛型重写时,代码不需要强制转换:
    List<String> list = new ArrayList<String>();
    list.add("hello");
    String s = list.get(0);   // no cast
  • The ability to implement generic algorithms.
    实现泛型算法的能力。
    By using generics, programmers can implement generic algorithms that work on collections of different types, can be customized, and are type safe and easier to read.
    通过使用泛型,程序员可以实现泛型算法,以处理不同类型的集合,可以对其进行自定义,并且类型安全,且易于阅读。

# Stacks 堆栈

A Stack is a Last In First Out (LIFO) data structure.
堆栈是后进先出(LIFO)数据结构。

It supports two basic operations called push and pop.
它支持两个基本操作,称为推入和弹出。

The push operation adds an element at the top of the stack, and the pop operation removes an element from the top of the stack.
推操作在堆栈顶部添加一个元素,而弹出操作从堆栈顶部移除一个元素。

Use cases: Consider a stack of books in inventory, stack of trays, etc.
用例:考虑一堆库存的书籍,一叠托盘等。

A stack is a linear collection which allows adding or removing elements from the same end (the top).
堆栈是线性集合,允许从同一端(顶部)添加或删除元素。

Stack elements are processed in a last in, first out (LIFO) manner.
堆栈元素以后进先出(LIFO)的方式处理。

In contrast, a queue is a collection where elements are processed in a first in, first out (FIFO) manner.
相反,队列是一个集合,其中以先进先出(FIFO)的方式处理元素。

Note that, stacks and queues have restrictions on how the elements can be accessed.
请注意,堆栈和队列对如何访问元素有限制。

# LIFO vs. FIFO?

Consider the following accounting example comparing LIFO and FIFO.
考虑下面的结算示例,比较 LIFO 和 FIFO。

Suppose we bought 5 identical computers at prices: $400, $400, $500, $500, $600; and then we sold 3 of them for $800 each.
假设我们以价格分别购买了 5 台相同的计算机:$400, $400, $500, $500, $600; 然后我们以每台 $800 的价格出售了其中的三台。

What is the profit?
利润是多少?
What is the value of the inventory?
库存的价值是多少?

The answer depends on which computers were sold.
答案取决于出售的计算机。

Although the computers are physically identical, their accounting values are different.
尽管这些计算机在物理上是相同的,但是其结算价值却不同。

The following are different calculations using FIFO and LIFO accounting.
以下是使用 FIFO 和 LIFO 结算的不同计算。

LIFOFIFO

Costs of Sold
销售成本

600 + 500 + 500 = 1600

400 + 400 + 500 = 1300

Profit
利润

2400 – 1600 = 800

2400 – 1300 = 1100

Inventory
库存

400 + 400 = 800

500 + 600 = 1100

Revenue+Inventory
收入 + 库存

2400 + 800 = 3200

2400 + 1100 = 3500

# demo

Stack.java
import java.util.Arrays;
public class Stack 
{
    private int count;
    private String[] data;
 
    public Stack()
    {
        data = new String[8];
        count = 0;
    }
 
    void expandCapacity()
    {
        data = Arrays.copyOf(data, data.length * 2);
    }
 
    void push(String e)
    {
        if (count == data.length)
            expandCapacity();
        data[count++] = e;
    }
 
    String pop() throws Exception
    {
        if (count <= 0)
        {
            throw new Exception("stack empty");
        }
        count--;
        return data[count];
    }
 
    boolean isEmpty()
    {
        return count == 0;
    }
 
    int size() 
    {
        return count;
    }
 
    public static void main(String[] args) throws Exception
    {
        Stack s = new Stack();
        s.push("Alice");
        s.push("Bob");
        s.push("Carl");
        s.push("Dave");
 
        while (!s.isEmpty())
            System.out.println(s.pop());
        
    }
}
Generic Stack.java
import java.util.Arrays;
public class StackGeneric <T>
{
    private int count;
    private T[] data;
 
    public StackGeneric()
    {
        data = (T[]) new Object[8];
        count = 0;
    }
 
    void expandCapacity()
    {
        data = Arrays.copyOf(data, data.length * 2);
    }
 
    void push(T e)
    {
        if (count == data.length)
            expandCapacity();
        data[count++] = e;
    }
 
    T pop() throws Exception
    {
        if (count <= 0)
        {
            throw new Exception("stack empty");
        }
        count--;
        return data[count];
    }
 
    boolean isEmpty()
    {
        return count == 0;
    }
 
    int size() 
    {
        return count;
    }
 
    public static void main(String[] args) throws Exception
    {
        StackGeneric<String> s = new StackGeneric<String>();
        s.push("Alice");
        s.push("Bob");
        s.push("Carl");
        s.push("Dave");
        StackGeneric<Integer> i = new StackGeneric<>();
        i.push(1);
        i.push(22);
 
        while (!s.isEmpty())
            System.out.println(s.pop());
    }
}