引言
前面我们说到了集合,但是集合有个缺点——把一个对象“丢进”集合里后,集合就会“忘记”这个对象的数据类型,当再次取出该对象时,该对象的编译类型就变成了Object类型。但这样会带来如下两个问题:
集合对元素类型没有任何限制,可能把不同元素对象放进去,将会引发异常。
取元素后要进行强制类型转换,可能引发ClassCastException异常。
什么是java泛型?
泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,主要目的是建立具有类型的安全的集合框架。
泛型的定义与使用
泛型类
(此处用一个完整例子来展示)
//在实例化泛型类时,必须指定T的具体类型
public class Person<T> {
//成员变量类型T均由外部指定
private T name;
private T age;
private T sex;
public Person(T name, T age, T sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
@Override
public String toString() {
return "Person{" +
"name=" + name +
", age=" + age +
", sex=" + sex +
'}';
}
public static void main(String args[]) {
//若不传入泛型参数类型,参数可以为任意类型,此时name为String,age为int,sex为String
Person p = new Person("张三", 20, "男");
//此时name为String,age为double,sex为boolean
Person p2 = new Person("李四", 21.5, false);
//指定T类型为String后,此时若传入参数为("王五", 22, "男")将发生编译错误,age也必须为String类型
Person<String> p3 = new Person<>("王五", "22", "男");
System.out.println(p);
System.out.println(p2);
System.out.println(p3);
}
}
运行结果,注意看参数类型:
泛型接口
以下为JDK5.0集合框架中Map接口定义的一部分:
publicinterface Map<K, V> {
publicvoid put(K key, V value);
public Vget(K key);
}
后文将以Map接口的实现类来进行讲述
集合泛型类
注意:当声明或实例化一个泛型对象时,必须指定类型参数的值
如:Map<String, String> map = newHashMap<String, String>();
参数类型可以是:基本数据类型的装箱类、引用类型
对于常见的泛型模式,推荐的名称是:
K ——键,比如映射的键。
V ——值,比如 List 和 Set 的内容,或者 Map 中的值。
E ——异常类。
T ——泛型。
示例如下:(学生类是个基本的JavaBean,有name.age.sex属性以及构造方法,代码省略)
@Test
public void genericTest(){
Map<String,Student> student=new HashMap<>();
Student stu1=new Student("赵一",23,"男");
Student stu2=new Student("小芳",21,"女");
student.put("坏学生",stu1);
student.put("好学生",stu2);
Iterator it=student.entrySet().iterator();
while(it.hasNext()){
Map.Entry entry= (Map.Entry) it.next();
Object key=entry.getKey();
Student s= (Student) entry.getValue();
System.out.println(key+"----"+s.getName()+"----他/她的年纪是:"+s.getAge());
}
}
运行结果:
泛型通配符
首先做个小测试:
List<String> slist=new ArrayList<>();
List<Integer> ilist=new ArrayList<>();
System.out.println(slist.getClass()+"?="+ilist.getClass());
结果:
由此我们可以知道List<String>和List<Integer>的类型相同,即泛型类型在逻辑上可以看做是多个不同的类型,实际上都是相同的基本类型。
因此,形如Generic<Animal>和Generic<Dog>不是具有父子关系的泛型类型,所以我们需要一个逻辑上可以表示同时是Generic<Animal>和Generic<Dog>父类的引用类型,通配符由此而来。
类型通配符一般是用?代替具体的类型实参。当具体类型不确定时,可用?通配符来表示位置类型,如:
Class<?> classType=Class.forName(“java.lang.String”);
通配符上下边界
List<? extends Number>list;表示通配符的上边界,即?只能被赋值为Number或其子类型。
List<? super Integer>list;表示通配符的下边界,即?只能被赋值为Integer或其父类型。
关于<T>和<?>
Class<T>在实例化的时候,T要替换成具体类。
Class<?>时个通配泛型,?可以带便任何类型,主要用于声明时的限制情况。
我觉得<T>和<?>还有更多值得思考的地方,比如我之前一直在想的一个问题,T泛型其实本来就可以代表任意类型(任意基本数据类型的包装类)了,只是在实例化的时候替换成具体类,那么?通配符与之相比就作用来说又有什么区别呢?
由于编者水平有限…待更加深入学习后再做解释。
本文参考: java泛型详解、 java泛型详解-最详细
原文出自:https://my.youkuaiyun.com/qq_37094660(如需转载请注明出处)