一、为什么用泛型
早期的Object类型可以接收任意的对象类型,实际使用中存在类型转换问题,所以Java提供了泛型来解决这个安全问题。
二、什么是泛型
即“参数化类型”,就是将类型由原来的具体的类型参数化,类似于方法中的
变量参数,此时类型也定义成参数形式,然后在使用/调用时传入具体的
类型
泛型提供了编 译时类型安全检测机制
好处:在编译的时候能够检查类型安 全
三、泛型类
泛型类型用于类的定义中,被称为泛型类
通过泛型可以完成对一组类的操作对外开 放相同的接口
泛型的类型参数只能是类类型
.泛型的类型参数可以有多个
如果没有定义具体类型,默认为Object
import java.util.ArrayList;
import java.util.Date;
public class Demo {
public static void main(String[] args) {
/*
ArrayList<E> E -->参数 -->泛型
泛型--> 参数化类型
java中所有的集合类,都支持泛型,支持向类中,传入一个类型,
建议集合中只存储一种类型 , 就不需要进行向下转型
*/
/*
//不使用泛型
ArrayList list = new ArrayList();
list.add(10);
list.add("a");
list.add(new Date());
for(Object object : list){
if(object instanceof String){
String s = (String) object;
System.out.println(object);
}
if(object instanceof Date){
String s = (String)object;
System.out.println(object);
}
}
*/
//使用泛型
ArrayList<String> list = new ArrayList();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
for(String s :list){
System.out.println(s);
}
}
}
四、从泛型类派生子类
子类也是泛型类,子类和父类的泛型类型要一致
class A extends Demo
//如果一个子类继承(实现)父级类(接口)是有泛型的,
//那么子类也可以定义为一个泛型类
public class Person<T> implements Comparable<T> {
public int compareTo(T o){
return 0;
}
public static void main(String[] args) {
Person<String> p =new Person<>();
}
}
子类不是泛型类,父类要明确泛型的数据类型
class A extends Demo
//如果一个子类继承(实现)父级类(接口)是有泛型的,
//那么子类也可以不定义为泛型类,那么父类(接口)类型必须要明确才行
public class Person implements Comparable<Person>{
public int compareTo(Person o){
return 0;
}
public static void main(String[] args) {
Person p = new Person();
}
}
五、泛型接口
泛型接口与泛型类的定义及使用基本相同
子类也是泛型类,子类和父类的泛型类型要一致
子类不是泛型类,父类要明确泛型的数据类型
六、通配符,上边界,下边界
类型通配符一般是使用"?"代替具体的类型实参
public class Demo1<E> {
/*
方法中的参数的泛型实际可以为什么.
test(Demo<?> d) ? 类型通配符,指的是实际传入参数的类型, ?表示可以是任何类型
*/
public void test(Demo1<E> d){
}
public void test1(Demo1<? extends E> d1){
// ? extends E 泛型上限
// 际传入参数的泛型,上限是E 以及E的子类
}
public void test2(Demo1<? super E> d2){
// super E 泛型下限
// 实际传入参数的泛型,下限是E 以及T的父类
}
public static void main(String[] args) {
Demo1 d0 = new Demo1<>();
Demo1<Integer> d1 = new Demo1<>();
Demo1<String> d2 = new Demo1<>();
d0.test(d1);
d0.test(d2);
/*
Demo1<Number> d0 = new Demo1<>();
Demo1<Integer> d1 = new Demo1<>();
Demo1<Number> d2 = new Demo1<>();
d0.test1(d1);
d0.test1(d2);*/
/*
Demo1<Number> d0 = new Demo1<>();
Demo1<Object> d1 = new Demo1<>();
Demo1<Number> d2 = new Demo1<>();
d0.test2(d1);
d0.test2(d2);*/
}
}
七、类型擦除
泛型代码能够很
好地和之前版本的代码兼容。那是因为,泛到信息只存在于代码编译阶段,在进入JVM之 前,与泛型相关的信息会被擦除掉,我们称之为一类型擦除。
泛型类被类型擦除后,相应的类型就被替换成 Object 类型或者上限类型
验证Ep:
import java.lang.reflect.Field;
import java.util.ArrayList;
public class Demo2<T> {
public T name;
public static void main(String[] args) throws NoSuchFieldException, SecurityException {
// transient Object[] elementData;
ArrayList<String> list = new ArrayList();
//泛型只是在编译期间来对类型进行限制,底层还是Object类型.
//这就是泛型类型擦除
list.add("");
Demo2<String> d2 = new Demo2<>();
d2.name = "aaa";
// d2.name = 1111;
//同过反射机制,获取运行时的属性,结果发现,运行时,底层是Object类型
Class c = d2.getClass();
Field f = c.getField("name");
System.out.println(f.getName()+":::"+f.getType());
}
}