请阅读下面代码,理解泛型真正的意义
public class Demo1<H> {
// 不能在静态域或者方法上引用泛型
// public static H instance;
// // 这两种写法都是错误的,不被允许,因为静态的变量和方法所以类,
// public static H getInstance{
// return instance;
// }
public static void main(String[] args) {
// 限定泛型变量
Dog dog1 = new Dog();
dog1.age = 10;
Dog dog2 = new Dog();
dog2.age = 120;
Dog min = min(dog1, dog2);
System.out.println("最小的:" + min.age);
}
// 有时候,我们需要对类型变量加以约束,比如计算两个变量的最小,最大值。
// T extends Comparable中,T 表示应该绑定类型的子类,Comparable表示绑定类型
public static <T extends Comparable> T min(T a,T b){
if (a.compareTo(b) > 0){
return b;
}
return a;
}
}
public class Dog implements Comparable<Dog>{
int age;
@Override
public int compareTo(Dog dog) {
if (this.age > dog.age){
return 1;
}
return 0;
}
}
泛型高级用法以及泛型通配符的使用
编写一个水果连的列子
public class Food {
}
public class Fruit extends Food{
private String color;
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
public class Apple extends Fruit {
}
public class Orange extends Fruit {
}
public class HongFuShi extends Apple {
}
声明一个泛型类
public class GenericType<T> {
private T data;
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
public class Demo2 {
public static void main(String[] args) {
// 泛型通配符
GenericType<Fruit> genericType1 = new GenericType<>();
Apple apple = new Apple();
apple.setColor("红色");
genericType1.setData(apple);
print(genericType1);
GenericType<Orange> genericType2 = new GenericType<>();
Orange orange = new Orange();
orange.setColor("黄色");
genericType2.setData(orange);
// GenericType<Fruit> GenericType<Orange> 这两者之间没有任何关系,所以编译不过
// 为了解决这个问题,于是提出了一个泛型通配符
// print(genericType2);
// ? extends X 表示类型的上界是 X
// 调用下面这个方法完美的解决了上面的问题
print2(genericType2);
GenericType<? extends Fruit> genericType3 = genericType2;
// 这样是不被允许的,
// genericType3.setData(apple);
// genericType3.setData(orange);
// get方法则没问题,会返回一个Fruit类型的值。
Fruit fruit = genericType3.getData();
// 为什么会出现上面的问题,因为 ? extend Fruit 表示类型的上界,类型的上界是Fruit,所以编译器会
// 确切的知道 get 返回的类型,至于 set方法只知道传入的是Fruit的下界,但是至于具体是哪个子类编译器不知道
// 总结:主要用于安全的数据访问,
GenericType<? super Fruit> superType = new GenericType<>();
superType.setData(new Fruit());
superType.setData(new Orange());
superType.setData(new HongFuShi());
superType.setData(new Food());
Object data = superType.getData();
// ? super Fruit 表示类型的下界,类型参数是 Fruit的超类(包括Fruit本身),那么get方法返回的是
// fruit 的超类,那么到底是哪个超类?编译器不知道,但是 Object一定是它的超类,所以get方法返回的
// Object,编译器是可以确切知道的.对于set方法来说,编译器不知道它需要的确切类型,但是知道Fruit的
// 子类是可以安全的转型为Fruit
// 总结:主要用于安全的数据写入,可以写入Fruit 和 Fruit的子类
}
public static void userSuper(){
GenericType<Food> foodGenericType = new GenericType<>();
GenericType<Fruit> fruitGenericType = new GenericType<>();
GenericType<Apple> appleGenericType = new GenericType<>();
GenericType<Orange> orangeGenericType = new GenericType<>();
// ? super X
// 表示传递给方法的参数,必须是X的父类,或者本身
printSuper(foodGenericType);
printSuper(fruitGenericType);
// 下面这两个调用会有问题,编译不会通过
// printSuper(appleGenericType);
// printSuper(orangeGenericType);
}
public static void print(GenericType<Fruit> genericType){
System.out.println(genericType.getData().getColor());
}
public static void print2(GenericType<? extends Fruit> genericType){
System.out.println(genericType.getData().getColor());
}
public static void printSuper(GenericType<? super Fruit> genericType){
System.out.println(genericType.getData());
}
/*
* Java 语言中的泛型规则不一样,它只是存在于源码阶段,在编译后的字节码文件中,就已经替换成原生的类型
* (Raw Type, 也称为裸类型),并且在相应的地方插入了强制类型的转化
* 对于运行时的List<String> 和 List<Integer>就是同一个类型
* Java语言中的泛型实现方法在编译成Class文件之后,就会檫除,也就是一种伪泛型
* 所以导致下面 method这个方法编译不通过
* */
public static void method(List<String> msg){
System.out.println("msg");
}
public static void method(List<Integer> msg){
System.out.println("msg");
}