泛型

作者: 壹元伍角叁分 | 来源:发表于2021-05-27 21:53 被阅读0次

一、泛型类、泛型接口和泛型方法
1、泛型接口的定义:

interface FangXingJieKou<T> {
    public T useMethod();
}
interface FangXingJieKou<T,K> {
    public T useMethod();
}

2、两种泛型类的定义:
(1)

class FangXingLei implements FangXingJieKou<String> {
    @Override
    public String useMethod() {
        return null;
    }
}

(2)

class FangXingLei<T> implements FangXingJieKou<T> {
    @Override
    public T useMethod() {
        return null;
    }
}

3、泛型方法的定义,可以定义在普通类中:

class Test {
    public  <T> T addFangxing(T... a) {
        return a[a.length / 2];
    }
}

也可以使用在泛型类中:

class Test <T>{
    public <T> T addFangxing(T... a) {//方法中定义的类型T和类定义的T可以一样,也可以不一样,相互不影响
        return a[a.length / 2];
    }
}

这不是一个泛型方法,只是使用了泛型类作为了形参

class Test {
    public void show(Test <Number> a) {
    }
}

4、泛型方法和泛型类、泛型接口的区别
泛型类是在创建对象的时候声明泛型的类型,而泛型方法是使用的时候传入使用的类型。

二、如何限定类型变量
extends,后面可以传入类也可以传入接口,可以传入一个,也可以传入多个。只能有一个类(java单继承),或多个接口

interface FangXingFangFa {
    public <T extends Fruit> void useMethod();
}

使用了extends,限定了只能传入Firut本身及其子类

如果是类和接口混用的话,类一定要写在前面,用&连接:

interface FangXingFangFa {
    public <T extends ArrayList&Comparable> void useMethod();
}

泛型类中也是一样使用。

三、泛型使用中的约束和局限性
1、不能实例化类型变量:

class FangXingFangLei<T> {
    private T t;
    
    public void use(){
        T t1= new T();//报错
    }
}

2、静态域或者静态方法中是不能引用类型变量:
在对象创建的时候才知道泛型的类型是什么,而虚拟机在创建对象的时候,先执行了static。

class FangXingFangLei<T> {
    private static T t;//报错
    public static void use(T t){//报错
    }
    public static <T> void use(T t){//可以运行,静态方法本身是泛型方法就可以
    }
}

3、不能使用基本类型,只能使用包装类

FangXingFangLei<double>//不可以
FangXingFangLei<Double>//可以

4、不支持instanceof关键字

public static <T> void use(T t) {
    FangXingFangLei<Double> doubleFangXingFangLei = null;
    if (doubleFangXingFangLei instanceof FangXingFangLei<Double>){//报错
    } 
    if (doubleFangXingFangLei instanceof FangXingFangLei<T>){//报错
    }
}
public static <T> void use(T t) {
    FangXingFangLei<Double> doubleFangXingFangLei = new FangXingFangLei<>();
    FangXingFangLei<String> stringFangXingFangLei = new FangXingFangLei<>();
    if (doubleFangXingFangLei.getClass() == stringFangXingFangLei.getClass()) {
            //是true,不管传入的是哪个类型参数,获得的都是原生类型,泛型类型擦除,
    }
}

5、不允许初始化数组

public static <T> void use2(T t) {
    FangXingFangLei<Double>[] doubleFangXingFangLeiArray;//定义数组可以,
    doubleFangXingFangLeiArray = new FangXingFangLei<Double>[];//但不允许初始化
}

6、泛型类不能extends Exception/Throwable

public class FangXingFangLei<T> extends Exception{//报错
}
 public static <T extends Throwable> void use3(T t) {
        try {

        } catch (T t) {//报错

        }
    }
    public static <T extends Throwable> void use4(T t) throws T {//可以运行
        try {

        } catch (Exception e) {
            throw t;
        }
    }

四、泛型类型的继承规则

public class Fruit {
    public static class Apple extends Fruit {
    }

    public class Test<T> {

    }

    public void use() {
        // Test<Apple> 和 Test<Fruit>没有任何继承关系
        Test<Apple> appleTest = new Test<>();
        Test<Fruit> fruitTest = new Test<>();

        Fruit fruit = new Apple();//在java中这个是可以的
        Test<Fruit> fruit2 = new Test<Apple>();//报错
    }
}

泛型类可以继承或者扩展其他泛型类,如list和arraylist

public class Test<T> extends TestParent<T>{
}

public class TestParent<T> {
 }

public void use() {
    TestParent<Apple> testParent = new Test();//完全没问题
}

五、泛型中的通配符类型
1、先定义一个泛型类

public class FangXingLei<T> {
    private T t;

    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }
}

2、再定义一个Food类

public class Food {
    public static class Fruit extends Food{
        public static class Apple extends Fruit{
            public static class HongFuShi extends Apple{
            }
        }

        public static class Orange {
        }
    }
}

3、使用类

public class UseTongPeiFu {
    public void printExtends(FangXingLei<? extends Food.Fruit> fangXingLei) {
    }
    public void printSuper(FangXingLei<? super Food.Fruit> fangXingLei) {
    }

    /**
     * 使用通配符方法
     */
    public void useTongPeiFuMethod() {
        //extends限定了上限,泛型可以传入Food.Fruit本身及其子类
        printExtends(new FangXingLei<Food>());//报错
        printExtends(new FangXingLei<Food.Fruit>());//可以运行
        printExtends(new FangXingLei<Food.Fruit.Apple>());//可以运行
        printExtends(new FangXingLei<Food.Fruit.Apple.HongFuShi>());//可以运行
        printExtends(new FangXingLei<Food.Fruit.Orange>());//报错

        //super限定了下限,泛型可以传入Food.Fruit本身及其父类
        printSuper(new FangXingLei<Food>());//可以运行,
        printSuper(new FangXingLei<Food.Fruit>());//可以运行,
        printSuper(new FangXingLei<Food.Fruit.Apple>());//报错,
        printSuper(new FangXingLei<Food.Fruit.Apple.HongFuShi>());//报错
        printSuper(new FangXingLei<Food.Fruit.Orange>());//报错。
    }

    /**
     * 使用通配符对象
     */
    public void useTongPeiFuBean(){
        //通配符<? extend T>,只能传入T或者T的子类
        FangXingLei<? extends Food.Fruit> fruitExtends = new FangXingLei<>();
        //不能使用set方法,可以理解为,不能确定fruitExtends泛型是Fruit还是它的子类
        fruitExtends.setT(new Food());//报错,
        fruitExtends.setT(new Food.Fruit());//报错,
        fruitExtends.setT(new Food.Fruit.Apple());//报错,
        fruitExtends.setT(new Food.Fruit.Apple.HongFuShi());//报错,
        fruitExtends.setT(new Food.Fruit.Orange());//报错
        //可以使用get方法,只能确定是到自己,不能确定是哪个子类或者自己
        Food.Fruit t = fruitExtends.getT();

        //通配符<? super T>,只能传入T或者T的父类
        FangXingLei<? super Food.Fruit> fruitSuper = new FangXingLei<>();
        //只能使用自己及子类对象(水果、苹果、红富士),因为自己及子类对象都是水果。
        fruitSuper.setT(new Food());//报错,
        fruitSuper.setT(new Food.Fruit());//可以运行,
        fruitSuper.setT(new Food.Fruit.Apple());//可以运行,
        fruitSuper.setT(new Food.Fruit.Apple.HongFuShi());//可以运行,
        fruitSuper.setT(new Food.Fruit.Orange());//报错,
        //使用get方法,只知道是自己或者父类对象,不能确定是哪个父类或者自己,所以就只能判断是object
        Object t1 = fruitSuper.getT();
    }
}

总结:
extend和super两者最大的区别是extend可以安全的访问(get)数据,super可以安全的写入数据。

六、虚拟机是如何实现泛型的
类型擦除,可以理解为把类型转换成object。如果有extends的话,将第一个作为其原生类型

相关文章

  • 泛型 & 注解 & Log4J日志组件

    掌握的知识 : 基本用法、泛型擦除、泛型类/泛型方法/泛型接口、泛型关键字、反射泛型(案例) 泛型 概述 : 泛型...

  • 【泛型】通配符与嵌套

    上一篇 【泛型】泛型的作用与定义 1 泛型分类 泛型可以分成泛型类、泛型方法和泛型接口 1.1 泛型类 一个泛型类...

  • 泛型的使用

    泛型有三种使用方式,分别为:泛型类、泛型接口、泛型方法 泛型类 泛型接口 泛型通配符 泛型方法 静态方法与...

  • Java 泛型

    泛型类 例如 泛型接口 例如 泛型通配符 泛型方法 类中的泛型方法 泛型方法与可变参数 静态方法与泛型 泛型上下边...

  • 探秘 Java 中的泛型(Generic)

    本文包括:JDK5之前集合对象使用问题泛型的出现泛型应用泛型典型应用自定义泛型——泛型方法自定义泛型——泛型类泛型...

  • Web笔记-基础加强

    泛型高级应用 自定义泛型方法 自定义泛型类 泛型通配符? 泛型的上下限 泛型的定义者和泛型的使用者 泛型的定义者:...

  • 重走安卓进阶路——泛型

    ps.原来的标题 为什么我们需要泛型? 泛型类、泛型接口和泛型方法(泛型类和泛型接口的定义与泛型方法辨析); 如何...

  • Kotlin泛型的高级特性(六)

    泛型的高级特性1、泛型实化2、泛型协变3、泛型逆变 泛型实化 在Java中(JDK1.5之后),泛型功能是通过泛型...

  • Java 19-5.1泛型

    泛型类定义泛型类可以规定传入对象 泛型类 和泛型方法 泛型接口 如果实现类也无法确定泛型 可以在继承类中确定泛型:

  • 【Swift】泛型常见使用

    1、Swift泛型4种 泛型函数泛型类型泛型协议泛型约束 2、泛型约束3种 继承约束:泛型类型 必须 是某个类的子...

网友评论

      本文标题:泛型

      本文链接:https://www.haomeiwen.com/subject/qaadsltx.html