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

来源:互联网 发布:cet照片采集软件 编辑:程序博客网 时间:2024/06/03 18:49
泛型(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<T1,T2,....Tn> {/* ... */}
类型参数(type parameter)部分被尖括号包围且在类名之后。详细点,就是 T1,T2,..,Tn。 这些叫做类型参数(type parameter)或者类型变量(type variables)

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

/**
* Generic version of the Box class.
* @param <T> the type of the value being boxed
*/
public class Box<T> {
// 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<Integer> integerBox;

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


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


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

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

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

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

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

public class OrderedPair<K,V> implements Pair<K,V>{
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<String,Integer> p1 = new OrderedPair<String,Integer>("Even",8);
Pair<String,String> p2 = new OrderedPair<String,String>("Hello","world");

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

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

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

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

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

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

0 0
原创粉丝点击