泛型

2019-12-21  本文已影响0人  leap_

泛型的作用

泛型的使用

public class NormalGeneric<T> {
    private T data;

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}


public static void main(String[] args) {
        NormalGeneric<String> normalGeneric = new NormalGeneric<>();
        normalGeneric.setData("12345");
        System.out.println(normalGeneric.getData());  // 输出12345
    }

声明了一个泛型类,泛型为T,T类似一个形参,在使用这个类的时候为这个T传入一个实参,类中所有用到的T都替换成实参String,实参必须是一个对象类型;

public interface People<T>{
        public T talk();
    }

定义了一个People接口,指定了一个泛型T,接口内部有一个talk抽象方法;

实现方式1:泛型类实现泛型接口
class Student<T> implements People<T>{
        @Override
        public T talk() {
            return null;
        }
    }
实现方式2:普通类实现泛型接口(直接指定泛型的实际类型)
class Teacher implements People<String>{
        @Override
        public String talk() {
            return null;
        }
    }
public  <T> T plus(){
        T result = null;
        //  todo
        return result;
    }

在使用这个方法的时候指定泛型的实际类型

normalGeneric.<Integer>plus(123);

也可以省去泛型的实际类型,编译器借助传入的参数会自动设置泛型的值

normalGeneric.plus("abc");

泛型变量的限定

public <T extends Comparable> T max(T a,T b){
        return a.compareTo(b)>0?a:b;
    }

class Man<T extends Comparable>{
        T man;
        public T getMan() {
            man.compareTo(man);  //  具有Compareable接口属性
            return man;
        }
    }

如果我们需要泛型变量具有特定接口的属性,可以给泛型T 继承一个接口,用来限定这个泛型的变量必须拥有这个接口的属性,传入的a和b必须实现Compareable接口;
T的extends后面,如果有类必须写在第一个,并且只能有一个类,可以有多个接口(单继承,多实现)

泛型的局限

泛型的通配符

类型之间的继承关系不能保证泛型之间的继承关系
下面举一个例子说明这句话的意思

首先声明了如下四个继承关系的类

public class Food {
}

public class Fruit extends Food {
}

public class Apple extends Fruit {
}

public class Orange extends Fruit {
}

再声明一个标准的泛型类

public class GenericType<T> {
    private T data;
    public void setData(T data) {
        this.data = data;
    }
    public T getData() {
        return data;
    }
}

我们声明了一个eat方法,传入的参数是泛型为Fruit的标准泛型类,创建了两个标准泛型类,一个泛型是Fruit,一个泛型是Apple,当调用eat方法时,只有fruit有效,apple却不行,可是apple明明继承了fruit,也是水果,为什么不能吃呢??

因为类型的继承不能保证泛型变量之间的继承关系,为了解决吃apple的问题,引入了通配符


我们将泛型的"实参"改成? extends Fruit,表示接收上界为Fruit的类型(Fruit和Fruit的子类)

下面再理解一句话:通配符用于安全的访问数据

为什么setdata()的时候不管传入fruit还是apple都是不行的,因为通配符? extends Fruit规定了可能是Fruit,可能是Apple,也可能是Orange,不确定传入的是哪个,所以set的时候都不可以,但是在取出的时候,有一点可以保证,那就是一定是Fruit,(因为Apple和Orange也是Fruit),所以通配符用于安全的访问数据

通配符只能用在泛型方法上,不可以用在泛型类上
? super Apple表示Apple 和 Apple 的父类:安全的写入数据

super通配符可以set当前类和其子类,get Object类
extends通配符不能set , 只能get当前类和其父类

泛型的原理

类型擦除:(在编译期完成)

在jdk中的泛型是伪泛型,泛型类型在编译的时候会被擦除,jvm看到的只有原始类型ArrayList<String> 和 ArrayList<Object> 在jvm看来是一样的

上一篇 下一篇

猜你喜欢

热点阅读