Java_泛型

泛型是JDK1.5及以上才可以使用的特性/语法,本质是类型参数化(Parameterized by types)。

T是泛型参数,表示一种数据类型,具体是什么类型,需要将来使用的时候进行传参来确定;如果在使用的时候,没有给泛型参数T传值,那么T默认就表示为Object类型;T是泛型参数的名字,也就是相当于形参,名字随便起,但是一般用一个有意义的大写字母。

public interface Collection<E>{
	boolean add(E e);
}

Collection是一个泛型接口,泛型参数是E,在接口中,add方法的参数类型也使用了E。说明在使用Collection接口的时候,如果没有给泛型参数传值,那么这个E就默认表示为Object,add方法就可以接收任意类型的对象。
Map接口使用泛型:

public interface Map<K,V>{
	V put(K key, V value);
	Set<Map.Entry<K, V>> entrySet();
}

泛型的种类:泛型类、泛型接口、泛型方法。
泛型类,如果泛型参数定义在类上面,那么这个类就是一个泛型类:

public class Point<T>{...}
public static void main(String[] args){
	Point<String> p = new Point<>();
}

泛型接口,如果泛型参数定义在接口上面,那么这个接口就是一个泛型接口:

public interface Action<T>{...}
public static void main(String[] args){
	//创建匿名内部类
	Action<String> a = new Action<>(){
		//...
	};
}

泛型方法,如果泛型参数定义在方法上面,那么这个方法就是一个泛型方法:

public class Test{
	public <T> T test(T t){
		//...
	}
}
public static void main(String[] args){
	Test t = new Test();
	String str = t.test("狗子");
	Integer i = t.test(6);
	Double d = t.test(50.5D);
}
//调用test方法时候,传什么类型的参数,test方法的返回类型就是什么类型的。
//编译通过
//父类型的引用,指向子类对象
Object o = new Integer(1);
//编译通过
//Object[]类型兼容所有的【引用】类型数组
//arr可以指向任意 引用类型 数组对象
Object[] arr = new Integer[1];
//编译失败
//注意,这个编译报错,类型不兼容
//int[] 是基本类型数组
Object[] arr = new int[1];
//编译失败
//错误信息:ArrayList<Integer>无法转为ArrayList<Object>
//在编译期间,ArrayList<Integer>和ArrayList<Object>是俩个不同的类型,并且没有子父类型的关系
ArrayList<Object> list = new ArrayList<Integer>();

=号俩边的所指定的泛型类型,必须是要一样的。这里说的泛型类型,指的是<>中所指定的类型。

Integer是Object的子类型,但ArrayList和ArrayList之间没有子父类型的关系,它们就是俩个不同的类型:

Object o = new Integer(1); //编译通过
ArrayList<Object> list = new ArrayList<Integer>(); //编译报错

也就是说,两个类型,如果是当做泛型的指定类型的时候,就没有多态的特点。

–通配符(?):?–>传入任意的内容。

//上限:? extends String:String和它的子类
//下限:? super String:String和它的父类
public void test1(Collection<Integer> c){
}//test1方法只能接收泛型是Integer类型的集合对象。
public void test2(Collection<String> c){
}//test2方法只能接收泛型是String类型的集合对象。
public void test3(Collection<Object> c){
}//test3方法只能接收泛型是Object类型的集合对象。

泛型的类型之间没有多态,所以=号俩边的泛型类型必须一致。

在这种情况下,就可以使用通配符(?)来表示泛型的父类型:

public void test(Collection<?> c){
}

这时候test方法中的参数类型,使用了泛型,并且使用问号来表示这个泛型的类型,这个问号就是通配符,可以匹配所有的泛型类型。
test方法可以接收 泛型是任意类型的 Collection集合对象。

使用通配符(?)所带来的问题:

Collection<?> c;
c = new ArrayList<String>();
c.add("blood");
/*
*因为变量c所声明的类型是Collection,同时泛型类型是通配符(?);
*那么编译器也不知道这个?将来会是什么类型,因为这个?只是一个通配符;
*所以,编译器不允许使用变量c来向集合中添加新数据,编译报错。
*/
c.add(null);
//集合中一定存的是引用类型,null是所有引用类型共同的一个值,所以一定可以添加进去。
//虽然使用通配符(?)的集合,不能再往其中添加数据了,但是可以遍历集合取出数据。
public static void main(String[] args) {
	ArrayList<String> list = new ArrayList<>();
	list.add("there1");
	list.add("there2");
	list.add("there3");
	list.add("there4");
	Collection<?> c = list;
	//编译报错
	//c.add("hello5");
	for(Object obj : c){
		System.out.println(obj);
	}
}

–泛型边界:
泛型的类型是可以任意设置的,只要是引用类型就可以。
如果在泛型中使用extends和super关键字,就可以对泛型的类型进行限制。即:规定泛型的上限和下限。

  1. 泛型的上限:
List<? extends Number> list
//将来引用list就可以接收泛型是Number或Number子类型(Byte,Short,Integer,Long)的List集合对象。

使用extends限定泛型的上限的使用:
1)在声明泛型类或者泛型接口的时候可以使用;
2)在声明泛型方法的时候可以使用;
3)在声明变量的时候可以使用。

  1. 泛型的下限:
List<? super Number> list
//将来引用list就可以接收泛型是Number或Number父类型的List集合对象。

使用super限定泛型的下限的使用:
1)在声明泛型类或泛型接口的时候不能使用;
2)在声明泛型方法的时候不能使用;
3)在声明变量的使用可以使用。

  1. extends和super对比:
    1)使用extends可以定义泛型的(上限),这个就表示将来泛型所接收的类型(最大)是什么类型。可以是这个最大类型或者它的(子类型)。
    2)使用super可以定义泛型的(下限),这个就表示将来泛型所接收的类型(最小)是什么类型。可以是这个(最小类型)或者它的(父类型)。

–类型擦除:
泛型类型仅存在于编译期间,编译后的字节码和运行时不包含泛型信息,所有的泛型类型映射到同一份字节码。
由于泛型是JDK1.5才加入到Java语言特性的,Java让编译器擦除掉关于泛型类型的信息,这样使得Java可以向后兼容之前没有使用泛型的类库和代码,因为在字节码(class)层面是没有泛型概念的。

ArrayList<Integer> list = new ArrayList<Long>();
//ArrayList<Integer>和new ArrayList<Long>在编译期间是不同的类型;
//但是在编译完成后,都是ArrayList.class文件。泛型信息被擦除后,所有的泛型类型都会变成Object类型。

如何理解泛型擦除?
1.真泛型:泛型中的类型是真实存在的。
伪泛型:仅于编译时类型检查,在运行时擦除类型信息。
2.Java的泛型是伪泛型。为什么说Java的泛型是伪泛型呢?因为在编译期间,所有的泛型信息都会被擦除掉。正确理解泛型概念的首要前提是理解类型擦出(type erasure)。
3.Java中的泛型基本上都是在编译器这个层次来实现的。在生成的Java字节码中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数,会在编译器在编译的时候去掉。这个过程就称为类型擦除。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值