栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

泛型的探究

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

泛型的探究

- 泛型的本质是类型参数化。

- 允许在定义类、接口、方法时使用类型形参,当使用时指定具体类型。

- 所有使用该泛型参数的地方都被统一化,保证类型一致。如果未指定具体类型,默认是object类型。集合体系中的所有类都增加了泛型,泛型也主要用在集合。

· 泛型定义在类上

在创建的时候指定对应的类型,使用的时候,就能使用对应的类型,而不用强转

public static void main(String[] args) {
    // 创建ObjectTool对象并指定元素类型为String
    ObjectTool stringTool = new ObjectTool<>();
    stringTool.setObj("muse");
    System.out.println(stringTool.getObj());
    // 创建ObjectTool对象并指定元素类型为Integer
    ObjectTool integerTool = new ObjectTool<>();
    // integerTool.setObj("aa"); // 编译报错
    integerTool.setObj(10);
    System.out.println(integerTool.getObj());
}


static class ObjectTool {
    private T obj;
    public T getObj() {
        return obj;
    }
    public void setObj(T obj) {
        this.obj = obj;
    }
}
·泛型定义在方法上

调用方法时指定对应的类型,传入什么类型的参数,就会被转换成什么类型。

public static void main(String[] args) {
    //创建对象
    ObjectTool tool = new ObjectTool();
    // 调用方法,传入的参数是什么类型,T就是什么类型
    tool.show("hello");
    tool.show(12);
    tool.show(12.5f);
}
static class ObjectTool {
    //定义泛型方法
    public  void show(T t) {
        System.out.println(t);
    }
}
·泛型定义在接口上

子类实现接口时,可以指定泛型,也可以不指定泛型,如下所示:

interface Inter {
    void show(T t);
}


class InterImpl1 implements Inter {
    @Override
    public void show(String s) {
        System.out.println(s);
    }
}


class InterImpl2 implements Inter {
    @Override
    public void show(T t) {
        System.out.println(t);
    }
}
·通配符之间的区别:object、T t、?

相同点:object T ?都可以指代任何类型,使用场景不同

不同点:

1.object使用的时候,如果要获取到原来的类型,需要进行强转。

2.T t :使用不需要强转,可以使用在集合中,object不可以使用在集合中,

        例: List传入List就会编译报错,传入List与List 就没问题

        一般使用最多的也是T进行通配

public  void test3(List list) {
    list.add(list.get(0));
    for (int i = 0; i < list.size(); i++) {
        System.out.print(list.get(i) + " ");
    }
    System.out.println();
}

3.?:定义了不能直接使用,会编译报错,T不会编译报错,可以直接使用,例:

public void test(List list) {
    // list.add(list.get(0)); // 编译错误
    for (int i = 0; i < list.size(); i++) {
        System.out.print(list.get(i) + " ");
    }
    System.out.println();
}
·泛型的上限和下限

上限:

        格式:类型名称 对象名称

        意义:只能接受该类型及其子类

下限:

        格式:类型名称 对象名称

        意义:只能接受该类型及其父类

·PECS(Producer Extends Consumer Super)

不允许存储,只能往外取

可以存储,但往外取只能使用object接收

extends知道存储类型肯定是T的子类,所以读取的时候,可以使用T或T的父类接收,但是为了保证类型的安全是禁止往里写入任何数据;

super知道存储类型肯定是T的父类,所以写入的时候,可以写入T及T的子类,但是读取的时候必须使用Object接收。

public static void testPECSextends() {
    List dogs = Lists.newArrayList(new Dog());
    List animals = dogs;
    
    // animals.add(new Cat()); // 编译失败
    // animals.add(new Animal()); // 编译失败
    // animals.add(new Dog()); // 编译失败
    
    Animal animal = animals.get(0);
    Object obj = animals.get(0);
    // Dog dog = animals.get(0); // 编译失败
}

public static void testPECSsuper() {
    List animals = Lists.newArrayList();
    List dogs = animals;
    
    dogs.add(new Dog());
    dogs.add(new WhiteDog());
    // dogs.add(new Animal()); // 编译失败
    // dogs.add(new Cat()); // 编译失败
    // dogs.add(new Object()); // 编译失败
    
    Object obj = dogs.get(0);
    // Dog dog = dogs.get(0); // 编译失败
    // Animal animal = dogs.get(0); // 编译失败
}
·类型擦除与桥接方法

在泛型出现之前,jdk编译器没有考虑过会出现泛型这种情况,那么为了兼容性,就需要向下兼容,使用的方法就是类型擦除与自动生成桥接方法。

泛型是提供给javac编译器使用的,它用于限定集合的输入类型,让编译器在源代码级别上,即挡住向集合中插入非法数据。但编译器编译完带有泛形的java程序后,生成的class文件中将不再带有泛型信息,以此使程序运行效率不受到影响,这个过程称之为“擦除”。

由于类型被擦除了,为了维持多态性,所以编译器就自动生成了桥接方法。

正常泛型使用:

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

//指定泛型类型为String
public class aaa extends AAA{
    @override
    public void setT(String s){
        this.t = s;
    }
}

向下兼容进行类型擦除和自动生成桥接方法之后:

//类型擦除即为在上面正常泛型的基础上将泛型全部抹去,同时将方法中的泛型T改成Object,如下所示
public class AAA{
    public T t;
    public void setT(Object t){
        this.t = data;
    }
}


//因为进行了类型擦除,所以aaa中的setT(String s)就不再override AAA中的setT(Object t)
//此时自动生成桥接方法,在桥接方法中将object强转成String后调用原来的setT(String s)
public class aaa extends AAA{
    public void setT(String s){
        this.t = s;
    }
    @override
    public void setT(Object t){
        setT((String)t);
    }
}

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号