java 泛型

1.前言

使用

示例:

List<String> list = new ArrayList<String>();
//简写如下
List<String> list = new ArrayList<>();

2.深入泛型

定义泛型接口,类:
看Map类的源代码:

public interface Map<K,V>{	
	Set<K> keySet;
	void put(K key, V value);
}

定义了泛型以后,可以用普通类型的地方,基本也可以用泛型.把泛型看成一种数据类型。
这样做的好处:只定义了一个接口,可以实现定义了无数接口的功能。

自定义泛型类,除了第一行要加一个以外,其他地方和普通的类似:

public class Apple<E>{
	private E info;
	public Apple(){};
	public Apple(E info){
		this.info = info
	}
	//getset方法省略
	mian(){
		Apple<String> a1 = new Apple<>("苹果");
		Apple<Double> a2 = new Apple<>(123.123);
		print(a1.getInfo());
	}

子类继承泛型,或者实现接口:
类似于调用方法一样,子类不能还是泛型:

public class A extends Apple<String>{}

也可以不指定类型,去掉,这样默认为Object类型。

在带泛型的类或接口中,在静态方法,静态初始化块,静态变量的声明 和初始化中不允许使用泛型–类型形参。
错误示例:

sataic T info;
public static void bar(T msg){};

3.类型通配符

如果一个方法不能确定输入的时什么类型的变量,如何定义:
不加泛型也不好,会有警告
直接定义为Object类型不可以,因为List<Object>不是List<String>的父类,也不能包容,后者不能向上转型。

public void test(List<Object> c){}
test()

与之相对的是数组:Object[]String[]的父类,可以包容,如:

Integer t = new IntegerNumber n =t;//不会报错;

类型通配符:

<?>

public void test(List<?> c){
	for(Object o: c){
		print(o);
	}

}

这里的类型是Object,用起来还要转型。

设定类型通配符的上限:

public void draw(List<? extends shape> shapes){
	for(shape s : shapes){
		s.draw(this);
	}
}

类似的,对接口和类的类型形参上限设定:

public class Apple<T extends Number>{}

4.泛型方法

///普通类或接口下的方法才可以用static和泛型

定义泛型方法

需求:把一个数组所有元素添加到集合中

  1. 定义泛型为Object,只能针对Object对象
static void fromArrayToCollection(Object[] arr, Collection<Object> c){
	for(Object o: arr){
		c.add(o);
	}
}

  1. 使用泛型呢,也不可以,因为不允许添加类型的数据到集合
  2. 泛型方法:
    修饰符 <T, S> 返回类型 方法名(参数列表){}
static <T> void fromArrayToCollection(T[] arr, Collection<T> c){
	for(T o: arr){
 		 c.add(o);
 	}
}
//调用方法:直接调用
String[] as = new String[100];
Collection<Object> co = new ArrayList<>();
fromArrayToCollection(as,co);//T是Object,可以从下到上转型
//如果不是静态方法,通过对象调用,可以加上泛型,或者让编译器猜测
b.<String>fromArrayToCollection(as,co);//T是Object,可以从下到上转型
//保险起见,最好对T限制
static <T> void fromCollectionToCollection(Collection<? extends T> from, Collection<T> to){

泛型和通配符的区别

什么时候用泛型方法,什么时候用通配符?
大多时候可以用泛型代替类型通配符

boolean containsAll(Collection<?> c);
//等价于
<T>boolean containsAll(Collection<T> c);

//下面的T是指类或接口自带的泛型
boolean addAll(Collection< ? extends T> c);
//等价于
<E extends T>boolean addAll(Collection<E> c);

上面两个地方推荐通配符,因为泛型参数T只用了以一次。
泛型方法用来表示方法的一个或多个参数的依赖关系,或者返回值与参数之间的依赖关系,否则不用泛型方法。
总结:优先通配符

菱形语法和泛型构造器

class Foo{
	public <T> Foo(T t){
		print(t);
	}
}
class Foo2<E>{
 	public <T> Foo2(T t){
  		print(t);
	}
}
class Test{
	main(){
		new Foo(200);//Integer
		Foo2<String> f0 = new Foo2<>(500);//隐式
		Foo2<String> f1 = new <Integer> Foo2<String>(500);//显式,右边有Integer就要有String
	

设置通配符下限

<? super T>
比如上面的复制集合方法,复制Integer到Number,泛型是Number;
要在方法中返回最后一次复制的数,只能返回泛型Number,不是Integer。
返回Integer的改写如下

public static <T>  T copy(Collection<? super T> dest,  Collection<T> src) {
  	T last = null;
  	for(T o: src){
   		last = o;
    		dest.add(o);
   	}
  	return last;
 }

这个copy方法和上一种copy方法不能重载,不能同时定义。

5. 擦除与转换

当把一个泛型变量复制给不带泛型变量时,会擦除泛型信息

class Apple<T extends Number>{
}
class Test{
main{
Apple<Integer> a = new Apple<>(6);//a的T是Integer
Apple b = a;//b的T是Number了
(String)b.getSize();//运行时报错,把Number转为String

泛型与数组

看不懂,感觉不重要,略

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值