泛型教程(一)---基础知识

泛型(generic types)

泛型就是被参数化了类型的一个类或者接口。下面的Box类作为一个例子去理解这个概念

一个简单的Box类

先从一个非泛化的类Box开始,这个类作用于一个任何类型的对象。这里只需要两个方法,set 和 get

public class Box{
private Object object;
public void set(Object object){this.object = object;}
public Object get(){return this.object;}
}

你可以接受和返回除了原始类型(primitive type)以外的任何类型的对象。在运行期间无法验证类如何被使用。某一部分的代码可能放了一个Integer在Box里,且期望得到输出Integer,但是另外一部分代码可能错误的传入了一个String,结果在运行时产生错误。


Box类的泛型

一个泛化类(generic class)定义成如下形式:

class name {/* ... */}
类型参数(type parameter)部分被尖括号包围且在类名之后。详细点,就是 T1,T2,..,Tn。 这些叫做类型参数(type parameter)或者类型变量(type variables)

为了使用泛化来更新一下Box类,你可以创建一个泛型申明通过更改代码“public class Box”为"public class Box"。这里就使用了类型变量(type variables),可以用在类里的任何地方。

/**
* Generic version of the Box class.
* @param the type of the value being boxed
*/
public class Box {
// T stands for "Type"
private T t;

public void set(T t) { this.t = t; }
public T get() { return t; }
}


可以看到,所有的object都替换成了T。类型变量可以时任何非原始类型(non-primitive type),比如任何的class type,interface type,array type甚至其他的type variable


类型参数命名转换(Type parameter naming Conventions)

类型参数的名字都是单个字母,大写。
经常使用的类型参数的名字如下:
  1. E-Element(used extensively by the java collections framework)
  2. k-Key
  3. N-Number
  4. T-Type
  5. V-Value
  6. S,U,V etc, 2nd,3rd,4th types

调用和实例化泛型(invoking and Instantiating a Generic Type)

在你的代码里想要引用Box泛化类,你需要调用泛型,也就是把T替换成一个具体的值,比如Integer

Box integerBox;

你可以把调用泛型接近当成是普通方法的调用,但是你不需要传入一个argument,而是传入一个type argument给Box类。


Type Parameter 和 Type Argument 的区别
Type parameter 和 Type Argument是不同的,编码的时候传入一个type argument是为了创建一个参数化类型(parameterized type). 所以 Foo中的T是一个类型参数(type parameter), Foo中里的String是一个type argument。
(所以 Foo就是一个parameterized type)


就像其他的变量声明一样,这里实际上并没有创建一个Box对象,而只是声明了说,integerBox会引用一个Integer的Box。
去实例化这个类,使用new关键字。但是需要把放在类名和括号之间。

Box integerBox = new Box();
Java 7之后,可以直接写成

Box integerBox = new Box<>();
编译器会自动从context中推断需要的type argument。new Box<>()里的<>被称为diamond.

多个类型参数(multiple Type Parameters)
一个泛化类可以有多个类型参数,比如OrderedPair泛化类,实现了Pair泛化接口

public interface Pair{
public K getKey();
public V getValue();
}

public class OrderedPair implements Pair{
private K key;
private V value;
public OrderedPair(K Key, V value){
this.key = key;
this.value = value
}

public K getKey() {return key;}
public V getValue() {return value;}
}

下面的两句代码实例化了两个 OrderedPair 类:

Pair p1 = new OrderedPair("Even",8);
Pair p2 = new OrderedPair("Hello","world");

代码中,new OrderedPair把K实例化成String,把V 实例化成Integer。所以,OrderedPair的构造函数的参数类型就是String和Integer。由于自动打包,可以传入一个String和一个int。

刚刚提到了diamond,因为java编译器能够从OrderedPair推断出K 和V 的类型,所以使用diamond可以把代码缩写成:

Pair p1 = new OrderedPair<>("Even",8);
Pair p2 = new OrderedPair<>("Hello","world");

创建一个泛化接口和泛化类一样。

参数化类型(Parameterized Type)
你也可以使用一个参数化类型(parameterized)来替换类型参数(type parameter)。比如用List替换K

OrderedPair> p = new OrderedPair<>("primes", new Box(...));

你可能感兴趣的:(java)