资讯专栏INFORMATION COLUMN

JAVA泛型笔记

n7then / 3070人阅读

摘要:泛型类泛型类和普通类的区别就是类定义时,在类名后加上泛型声明。泛型类的内部成员方法就可以使用声明的参数类型。

泛型是JDK 1.5的一项新特性,它的本质是参数化类型(Parameterized Type),即所操作的数据类型在定义时被指定为一个参数。当我们使用的时候给这个参数指定不同的对象类型,就可以处理不同的对象。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口和泛型方法。

一、泛型实现方式

泛型声明方式:<占位符>
占位符有两大类:

普通占位符,E, T, K, V一般是单字母大写,表示接收特定的类型。

通用占位符,也叫通配符,占位符中包含“?”问号,表示接任意数据类型或者指定范围数据类型。

泛型类

泛型类和普通类的区别就是类定义时,在类名后加上泛型声明。泛型类的内部成员、方法就可以使用声明的参数类型。泛型类最常见的用途就是作为容纳不同数据类型的容器类,比如Java集合容器类。

class GenericClass{
    private T value;

    public T getValue() {
        return value;
    }

    public void setValue(T value) {
        this.value = value;
    }
}
泛型接口

和泛型类一样,泛型接口在接口名后添加泛型声明,接口方法就可以直接使用声明的参数类型。
实现类在实现泛型接口时需要指明具体的参数类型,不然默认类型是 Object,这就失去了泛型接口的意义。

interface genericInterface {
    K getKey();
    V getValue();
}

未指明类型的实现类,默认是 Object 类型:

class GenericClass implements genericInterface{
    @Override
    public Object getKey() {
        return null;
    }

    @Override
    public Object getValue() {
        return null;
    }
}

指明了类型的实现:

class GenericClass implements genericInterface {
    @Override
    public String getKey() {
        return null;
    }

    @Override
    public Object getValue() {
        return null;
    }
}
泛型方法

泛型方法指的是使用泛型的方法。如果这个方法所在的类是个泛型类,直接使用类声明的参数类型。

如果这个方法所在的类不是泛型类或者他想要处理不同于泛型类所声明的参数类型,这时候我们就需要使用泛型方法。即在方法前加入泛型声明,方法就可以直接使用声明的参数类型。

class GenericClass {

    private Object value;

    public  T getValue(){
        return (T)value;
    }

    public void setValue(Object value){
        this.value = value;
    }
}

方法getValue()就是泛型方法,调用代码如下:

GenericClass genericClass = new GenericClass();
genericClass.setValue(123);

Integer value = genericClass.getValue();
二、泛型的优点 数据类型安全

泛型的主要目的通过参数类型检查,提高JAVA程序数据类型的安全,提早发现错误,避免ClassCastException 异常发生。

List list = new ArrayList();
list.add("test generic");
list.add(123);// 注:123会转换成Integer对象
list.add(null);

当不实用泛型的时候,上面代码的使用是被允许的,我们可以放入任何对象,当我们按照某种对象类型去取数据就会出现ClassCastException 异常。

//List list = new ArrayList();
List list = new ArrayList();
list.add("test generic");
//list.add(123);
list.add(null);

List是泛型接口,当我们这样使用的时候,“123”这个元素是不被允许使用的。

消除类型转换

当我们不使用泛型时,每次取出集合中的元素都需要我们强制转换成我们需要的元素。(Object->Class Type)。

List list = new ArrayList();
list.add("test generic");
String s = (String) list.get(0);

“test generic”存入list是一个Object的对象,取出来是我们需要转换成我们要的字符串String类型。

List list = new ArrayList();
list.add("test generic");
String s = list.get(0);

使用泛型后list.get(0)中取出来的数据类型,就是我们存入时的String类型。

简码,提高效率

通过泛型的应用,做到了简码,而且JVM中类文件也相应的减少。JVM几乎没有做任何的更改,所有的类型校验,类型转换都是在编译器阶段完成。

三、通配符 无限制通配符

定义时不关心或者不确定实际要操作的数据是什么类型,可以使用无限制通配符(尖括号里一个问号,即 ),表示可以持有任何类型。

class GenericClass {
    private T data;
    public T getData() {
        return data;
    }
    public void setData(T data) {
        this.data = data;
    }
    @Override
    public String toString() {
        return "GenericClass{" +
                "data=" + data +
                "}";
    }
}

泛型类定义

public static void print(GenericClass context){
     System.out.println(context);
}

通配符定义的方法参数类型

GenericClass integerGenericClass = new GenericClass<>();
integerGenericClass.setData(123);
GenericClass stringGenericClass = new GenericClass<>();
stringGenericClass.setData("123");
print(integerGenericClass);
print(stringGenericClass);

使用时?是一个万能的类型,T只能是具体的类型

上界通配符

在类型参数中使用extends表示这个泛型中的参数必须是 E 或者 E 的子类,这样有两个好处:

如果传入的类型不是E或者E的子类,编辑不成功

泛型中可以使用E的方法,要不然还得强转成E才能使用

List list = new ArrayList(){{add(new Integer(456));add(new Long(456L)); }};
list.add(null);
//list.add(new Integer(123));
//list.add(new Long(123L));
System.out.println(list.size());
Number number = list.get(0);

当使用上边界通配符时,是不允许往里存数据的,不确定具体元素类型。

下界通配符 < ? super E>

在类型参数中使用super表示这个泛型中的参数必须是E或者E的父类。

用于灵活写入或比较,使得对象可以写入父类型的容器,使得父类型的比较方法可以应用于子类对象。

List list = new ArrayList(){{add(new B()); add(new C());}};
list.add(null);
list.add(new C());
list.add(new B());
//list.add(new A());
Object object = list.get(0);

C是B的子类,B是A的子类。当使用下界通配符时,是允许存放E和E的子对象数据的,因为子类对象的引用可以赋值给父类对象的引用(顶级父类是Object),所以取出来的数据类型是Object.

四、总结

在实例化的时候,就必须声明泛型具体是一个什么类型。

使用泛型、通配符提高了代码的复用性。

把一个对象分为声明、使用两部分的话。泛型侧重于类型的声明上代码复用,通配符则侧重于使用上的代码复用。泛型用于定义内部数据类型的不确定性,通配符则用于定义使用的对象类型不确定性。

如果类型参数在方法声明中只出现一次,可以用通配符代替它。

不能同时声明泛型通配符上界和下界。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/70631.html

相关文章

  • JAVA笔记 - 收藏集 - 掘金

    摘要:动态代理个经纪人如何代理个明星掘金在代理模式女朋友这么漂亮,你缺经纪人吗中我们用宝强的例子介绍了静态代理模式的概念。掘金使用从头创建一个,这种方法比较简单。 动态代理:1 个经纪人如何代理 N 个明星 - Android - 掘金在 代理模式:女朋友这么漂亮,你缺经纪人吗? 中我们用宝强的例子介绍了静态代理模式的概念。 本来我的目的是通过大家耳熟能详的例子来加深理解,但是有些网友指责...

    kamushin233 评论0 收藏0
  • Java8实战》-第三章读书笔记(Lambda表达式-01)

    摘要:之前,使用匿名类给苹果排序的代码是的,这段代码看上去并不是那么的清晰明了,使用表达式改进后或者是不得不承认,代码看起来跟清晰了。这是由泛型接口内部实现方式造成的。 # Lambda表达式在《Java8实战》中第三章主要讲的是Lambda表达式,在上一章节的笔记中我们利用了行为参数化来因对不断变化的需求,最后我们也使用到了Lambda,通过表达式为我们简化了很多代码从而极大地提高了我们的...

    longshengwang 评论0 收藏0
  • java 8 实战》读书笔记 -第三章 Lambda表达式

    摘要:利用前面所述的方法,这个例子可以用方法引用改写成下面的样子构造函数引用对于一个现有构造函数,你可以利用它的名称和关键字来创建它的一个引用。 第三章 Lambda表达式 函数式接口 函数式接口就是只定义一个抽象方法的接口,哪怕有很多默认方法,只要接口只定义了一个抽象方法,它就仍然是一个函数式接口。 常用函数式接口 showImg(https://segmentfault.com/img...

    whinc 评论0 收藏0
  • Java笔记-Java反射(二)

    摘要:构造器创建实例构造器和方法的反射类不同点在于,可以创建实例,代码如下所示。 上一篇文章介绍了反射的基本概念以及获取类相关信息的反射API,这一章节主要记录如何对类的成员进行操作的相关反射API。 操作类成员的类 反射API中提供了如下接口,用于对类的成员进行操作。 java.lang.reflect.Member 该接口主要有以下三个实现类,用于对类成员中的字段,方法和构造器进行操作...

    luckyw 评论0 收藏0

发表评论

0条评论

n7then

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<