泛型
-
oracle原文地址:https://docs.oracle.com/javase/tutorial/java/generics/erasure.html
在Java中,泛型的引入是为了在编译时提供强类型检查和支持泛型编程。为了实现泛型,Java编译器应用类型擦除实现:
1、 用类型参数(type parameters)的限定(如果没有就用Object)替换泛型类型中的所有类型参数。
2、 需要保持类型安全的时候插入类型转换(隐含插入)
3、 在extened 泛型类型中生成桥方法来保证多态性
类型擦除确保不会为已参数化了的类型(paramterized types)产生新类,这样泛型能保证没有运行时的负载。 -
泛型的好处是在编译的时候检查类型安全,减少运行时的问题;避免强制转换的麻烦;
特性
只在编译阶段有效。在编译过程中,正确检验泛型结果后,会将泛型的相关信息擦除
如:
public class MyClass {
private static List<String> list1 = new ArrayList<>();
private static List<Integer> list2 = new ArrayList<>();
public static void main(String args[]){
list1.add("aaaa");
list2.add(11);
System.out.println("----list1------>" + list1.getClass());
System.out.println("----list2------>" + list2.getClass());
System.out.println("泛型类型是否相同-->" + list2.getClass().equals(list1.getClass()));
}
}
输出结果:
----list1------>class java.util.ArrayList
----list2------>class java.util.ArrayList
泛型类型是否相同-->true
在编译之后程序会采取去泛型化的措施。也就是说Java中的泛型,只在编译阶段有效。在编译过程中,正确检验泛型结果后,会将泛型的相关信息擦出,并且在对象进入和离开方法的边界处添加类型检查和类型转换的方法。也就是说,泛型信息不会进入到运行时阶段。
对此总结成一句话:泛型类型在逻辑上看以看成是多个不同的类型,实际上都是相同的基本类型。
擦除规则
JVM并不知道泛型的存在,因为泛型在编译阶段就已经被处理成普通的类和方法;
处理机制是通过类型擦除,擦除规则:
若泛型类型没有指定具体类型,用Object作为原始类型;
若有限定类型< T exnteds XClass >,使用XClass作为原始类型;
若有多个限定< T exnteds XClass1 & XClass2 >,使用第一个边界类型XClass1 XClass2作为原始类型
如下例:
测试目录结构
├── MyClass.java //测试类
├── parent
│ ├── IOne.java //接口1
│ ├── ITwo.java //接口2
│ └── ParentOne.java //父类
├── sun
│ ├── Sun.java
│ └── SunOne.java
├── Test.java
├── TestOne.java
└── TestTwo.java
定义测试类
package com.example.test;
import com.example.test.sun.Sun;
import com.example.test.sun.SunOne;
public class MyClass {
public static void main(String args[]){
//无限定
Test test = new Test();
test.setT("test");
//< T exnteds XClass > 限定
TestOne testOne = new TestOne();
testOne.setT(new SunOne());
//多个限定< T exnteds XClass1 & XClass2 >
TestTwo testTwo = new TestTwo();
testTwo.setT(new Sun());
System.out.println("----test------>" + test.getClass());
System.out.println("----testOne------>" + testOne.getClass());
System.out.println("----testTwo------>" + testTwo.getClass());
}
}
无限定
package com.example.test;
/**
* T 无限定
* @param <T>
*/
public class Test<T> {
/**
* T 最终等同于
* private Object t;
*/
private T t;
public void setT(T t) {
this.t = t;
}
}
单个限定
package com.example.test;
import com.example.test.parent.ParentOne;
/**
* T 传入的类型必须继承于ParentOne
* @param <T>
*/
public class TestOne<T extends ParentOne> {
private T t;
public void setT(T t) {
this.t = t;
}
}
package com.example.test.sun;
import com.example.test.parent.ParentOne;
public class SunOne extends ParentOne {
}
package com.example.test.parent;
public class ParentOne {
}
多个限定 类实现两个接口
package com.example.test;
import com.example.test.parent.IOne;
import com.example.test.parent.ITwo;
/**
* T 类型 必须继承IOne ITwo 接口
* @param <T>
*/
public class TestTwo<T extends IOne & ITwo> {
private T t;
public void setT(T t) {
this.t = t;
}
}
package com.example.test.sun;
import com.example.test.parent.IOne;
import com.example.test.parent.ITwo;
public class Sun implements IOne,ITwo {
}
package com.example.test.parent;
public interface ITwo {
}
package com.example.test.parent;
public interface IOne {
}
泛型中占位符T和?区别
“<T>"和"<?>",首先要区分开两种不同的场景:
- 第一,声明一个泛型类或泛型方法。
- 第二,使用泛型类或泛型方法。
- 类型参数“<T>”主要用于第一种,声明泛型类或泛型方法。
- 无界通配符“<?>”主要用于第二种,使用泛型类或泛型方法
泛型的限定:
? extends E:接收E类型或者E的子类型。
?super E:接收E类型或者E的父类型。
简单例子
package com.example.test;
import java.util.ArrayList;
import java.util.List;
public class MyClass {
private static List list1 = new ArrayList();
private static List<String> list2 = new ArrayList();
public static void main(String args[]){
list1.add("aaa");
list1.add(33);
list2.add("bbbb");
list2.add("cccc");
for (int i =0 ;i<list1.size();i++){
System.out.println("---------->" + list1.get(i));
}
System.out.println("-----#############-----");
for (int i =0 ;i<list2.size();i++){
System.out.println("---------->" + list2.get(i));
}
}
}
输出
---------->aaa
---------->33
-----#############-----
---------->bbbb
---------->cccc
一个限定类型,只能add String
另一个,可添加多种类型的数据
//使用通配符?
SuperClass<?> sup = new SuperClass<String>("例子");
sup = new SuperClass<Student>(new Student());
sup = new SuperClass<Teacher>(new Teacher());
//不使用通配符
SuperClass<String> sup1 = new SuperClass<String>("lisi");
SuperClass<Student> sup2 = new SuperClass<Student>(new Student());
SuperClass<Teacher> sup3 = new SuperClass<Teacher>(new Teacher());
网友评论