为什么需要范型?
1.适用于多种数据类型,执行相同的代码。
2.使用范型后,在编码的时候可以直接指定数据类型,插入错误的数据类型,在编译期间直接不通过。
范型类
public class NormalGeneric<T> {
private T data;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public NormalGeneric(T data) {
this.data = data;
}
public NormalGeneric() {
}
public static void main(String[] args) {
NormalGeneric<String> normalGeneric=new NormalGeneric<>();
normalGeneric.setData("hello");
NormalGeneric<Integer> normalGeneric1=new NormalGeneric<>(1);
}
}
范型接口
public interface IGeneric<T> {
T next();
}
public class ImplGeneric<T> implements IGeneric<T> {
@Override
public T next() {
return null;
}
}
public class Impl2Generic implements IGeneric<String> {
@Override
public String next() {
return null;
}
}
范型方法
public class GenericMethod {
public <T> T print(T... a) {
return a[a.length / 2];
}
public static void main(String[] args) {
GenericMethod genericMethod=new GenericMethod();
genericMethod.print("a","b");
}
}
类型变量的限定-方法上
public static <T extends Comparable> T min(T a, T b) {
if (a.compareTo(b) > 0) {
return a;
} else {
return b;
}
}
//单继承多实现
public static <T extends ArrayList & Comparable & Runnable> T min2(T a, T b) {
if (a.compareTo(b) > 0) {
return a;
} else {
return b;
}
}
范型的局限性
public class NormalGeneric<T> {
private T data;
public NormalGeneric(){
//此处会发生错误,不能实例化类型变量
this.data=new T();
}
//此处会发生错误,静态域或者方法里不能引用类型变量
//虚拟机在创建对象时,先执行的静态后执行的构造
private static T instance;
public static void get(T t){}
//正常编译,静态方法本身就是范方法
public static <T> void print(T t){}
}
public class Restrict<T> {
private T data;
public static void main(String[] args) {
Restrict<Double> d1 = new Restrict<>();
Restrict<Double> d2 = new Restrict<>();
//泛型不允许用instanceof
//if(d1 instanceof Restrict<Double>){
//}
//可以这样使用
if (d1 instanceof Restrict) {
System.out.println(">>>>>");
}
//false
System.out.println(d1 == d2);
//true
System.out.println(d1.getClass() == d2.getClass());
//com.hello.android.Restrict
System.out.println(d2.getClass());
Restrict<Double>[] d1Array;
//编译异常
//Restrict<Double>[] d2Array=new Restrict<Double>[10];
//编译正常
Restrict<Double>[] d3Array = new Restrict[10];
d3Array[0] = d1;
d3Array[1] = d2;
System.out.println(d3Array);
//泛型类不能extends Exception\Throwable
}
//不能捕获泛型类对象
// public <T extends Throwable> void test(T t) {
// try {
//
// } catch (T t2) {
//
// }
// }
//这样允许捕获泛型类对象
public <T extends Throwable> void test2(T t) throws T {
try {
} catch (Throwable x) {
throw t;
}
}
}
范型类的继承规则
package com.hello.android;
public class Pair<T> {
private T one;
private T two;
public static void main(String[] args) {
//Employee与 Worker存在继承关系,但employeePair完全与workerPair不存在继承关系
Pair<Employee> employeePair = new Pair<>();
Pair<Worker> workerPair = new Pair<>();
//泛型类是可以继承
Pair<Employee> employeePair1 = new ExtPair<>();
}
public static class ExtPair<T> extends Pair<T> {
}
}
通配符
package com.hello.android;
public class Pair<T> {
private T one;
private T two;
public void setOne(T one) {
this.one = one;
}
public static void main(String[] args) {
//Worker extends Employee存在继承关系,但employeePair完全与workerPair不存在继承关系
Pair<Employee> employeePair = new Pair<>();
Pair<Worker> workerPair = new Pair<>();
//正常编译
set(employeePair);
//编译出错
//set(workerPair);
//正常编译
set2(employeePair);
//采用通配符方式正常编译
set2(workerPair);
//正常编译
set3(employeePair);
//正常编译,super代表的下边界不能低于Worker
set3(workerPair);
//Worker extends Employee、 Employee extends Skill存在继承关系,
//与在方法里使用的通配符理解不一样
//此处理解为Employee和Employee的子类可以set操作,可以安全的进行类型转型,而Skill不行
Pair<? super Employee> pair = new Pair<>();
pair.setOne(new Worker());
pair.setOne(new Employee());
//编译出错
//pair.setOne(new Skill());
}
public static void set(Pair<Employee> e) {
}
//通配符用在方法上 extends代表上边界不能超过Employee,Employee、Employee的子类
public static void set2(Pair<? extends Employee> e) {
}
//通配符用在方法上 super代表下边界不能低于Worker,Worker、Worker的基类
public static void set3(Pair<? super Worker> e) {
}
}
虚拟机如何实现泛型
类型擦除
//编译器不通过,方法重载,但编译器对泛型进行类型擦除后,属于同一个类型,导致编译不通过
public static void method(List<String> params){
}
public static void method(List<Integer> params){
}