简单理解Java泛型

声明一个泛型类并实例化

Box是一个泛型类,这里的T是参数传递给泛型类的泛型,它可以是任何对象。而t则是T的一个实例。个人理解泛型,就是泛化类型,将具体的类型用统一的类指代。add和get是定义的两个方法。

public class Box<T>{
	private T t;
	public void add(T t){
		this.t = t;
	}
	public void get(T t){
		return t;
	}
}

在main方法中,泛型类这样使用。其中intbox和strbox都是泛型类的对象,可以调用泛型类中已定义的方法。

Box<Integer> intbox = new Box<Integer>();
Box<String> strbox = new Box<String>();
intbox.add(new Integer(1));
System.out.println(intbox.get());
//调用了泛型类中的方法,打印数字1

泛型类可以有多个类型参数,这就使得泛型可以当C++中的结构体来使用。当然,凭我现有的知识,结构体与类并无本质的差异。同时,可以用参数化类型来代替,比如传的不只是一个类,而是某个框架,如下例。

public static void main(String[] args){
	Box<Integer,String> box = new Box<Integer,String>();
	box.add(Integer.valueOf(100),"hello world");

	Box2<Integer,List<String>> box2 = new Box2<Integer,List<String>>();
	List<String> m = new ArrayList<String>();
	m.add("Hello");m.add("world");
	box2.add(Integer.valueOf(10),m);//此时的m是一个列表
}
class Box<T,S>{
	private T t;
	private S s;
	public void add(T t,S s){
		this.t = t;
		this.s = s;
	}
}

参数命名约定 也就是尖括号里的字母,这是一般的约定并无强制要求

字符 意义
E 由Java集合框架使用(list等)
K 表示映射中的键值(key)
V 表示映射中的值(value)
N 表示数字
T 第一类通用参数
S 第二类通用参数
U 第三类通用参数
V 第四类通用参数

有界类型参数

什么是泛型有界类型参数?就是限制允许传递给类型参数的类型。简单来说就是给泛型一定的条件,比如只允许接受Char类或者它的子类实例。要声明它,只需要后跟extend关键字和边界上限即可。如果需要多重边界,则用&连接。

public static <T extends Number & Comparable<T>> T maximum(T x,T y,T z){
	T max = x;
	if(y.compareTo(max)>0){
		max = y;
	}
	if(z.compareTo(max)>0){
		max = z;
	}
	return max;
}
public static void main(String[] args){
	System.out.println(maximum(10,20,30));
	System.out.println(maximum(22.1,33.2,44.3));
}

Java在List、Set、Map中都提供了泛型的支持,语法如下

List<T> list = new ArrayList<T>();
Set<T> set = new HashSet<T>();
Map<T> map = new HashMap<T>();

通配类型符

首先要知道,为什么需要通配类型?《Java语言程序设计》中有一个例子。

public static void main(String[] args){
	GenericStack<Integer> intstack = new GenericStack<Integer>();
	intstack.push(1);intstack.push(2);
	System.out.println(max(intstack));
}
public static double max(GenericStack<Number> stack){
	double max = stack.pop().doubleValue();
	while(!stack.empty()){
		double value = stack.pop().doubleValue();
		if(value>max)max=value;
	}
	return max;
}

这段程序会出现编译错误,原因是虽然Integer是Number的子类,但GenericStack<Integer>不是GenericStack<Number>的子类。因此需要通配符规避这种错误。
?表示非受限通配符
?extend T 表示T或T的一个未知子类
?super T 表示T或T的一个父类

public static double max(GeericStack<? extends Number> stack)就可以改正上面的错误。


泛型类型擦除

泛型是使用一种称为类型消除的方法来实现的。编译器使用泛型类型信息来编译代码,但是随后会消除它。因此,泛型信息在运行时是不可用的。这种方法可以使泛型代码向后兼容使用原始类型的遗留代码。
泛型在编译的时候一旦确认其是安全的,就会将它转换为原始类型。不管实际的具体类型是什么,泛型类是被它所有实例共享的。


限制

不能使用E object = new E();,因为运行时泛型类型E是不可用的。同理不能创建数组。
异常类不能是泛型。
静态环境下不允许类的参数是泛型类型。
除非由无界通配符进行参数化,否则不允许转换为参数化类型。如下段代码。

private static void add(Box<?> box){
	Box<Integer> intbox = (Box<Integer>) box;
}

无法用instanceof验证。

发布了14 篇原创文章 · 获赞 11 · 访问量 2527

猜你喜欢

转载自blog.csdn.net/qq_43425914/article/details/104183880
今日推荐