Java 泛型的理解

1. 引言

当我们使用 List 创建集合的时候,IDEA 会提示我们为这个集合写入泛型。泛型可以理解为这个集合的标签,标明了这个集合可以存储什么类型的数据。当然,我们也可以不写入泛型,这样创建出来的集合可以存储任意类型的数据,但都被当做 Object 类型处理。这样当我们取数据的时候,只能得到 Object 类型的数据,而不是我们存入时的数据类型。我们需要强制类型转换,才能得到我们想要的类型,这样处理不仅麻烦而且还会有安全性问题。

2. 什么是泛型

Java 泛型是 JDK5 引入的一个新特性,泛型提供了编译时类型安全检测机制,使得程序员能在编译期检测到非法的数据类型。

泛型的格式:<数据类型>

泛型的本质是参数化类型,就是给类型指定一个参数,使用的时候在指定参数具体的值。比如

// 创建一个String类型的list
List<String> list = new ArrayList<>();

// 创建一个Integer类型的list
List<Integer> list = new ArrayList<>();

泛型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。需要注意的是:

  • 泛型的数据类型只能填写引用数据类型,不可以使用基本数据类型;
  • 指定泛型的具体类型之后,可以传入该类类型或其子类类型的对象。

3. 为什么使用泛型

3.1 安全性

引言中我们提到,如果创建集合的时候不指定泛型,取数据的时候得到的是 Object 类型的数据,强制类型转换可能会报错。比如:

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

我们往一个没有写入泛型的 list 中写入了字符串和一个数字,取数据时我们想得到 String 类型的数据,需要进行强制类型转换:

for(int i = 0; i < list.size(); i++){
	String s = (String)list.get(i);
}

当 get 到 123 的时候,代码会报错,因为 Integer 类型不能转换成 String 类型。

所以我们创建容器时指定泛型,就避免了上述问题。

3.2 不需要类型转换

使用 List<String> list = new ArrayList<>() 创建一个 list,只能存储 String 类型的数据,并且取出的时候就是 String 类型,不需要转换。

4. 泛型的使用

泛型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。泛型标识可以理解为类型的形参,常用的泛型标识有 T 、 E 、 K 、 V:

  • T ----Type(Java类)
  • E ----Element(在集合中使用,因为集合中存放的是元素)
  • K ----Key(键)
  • V ----Value(值)

4.1 泛型类

创建一个泛型类的语法:

public class 类名<泛型标识> {
	private 泛型标识 变量名;
}

使用泛型类:

类名<具体的数据类型> 对象名 = new 类名 <具体的数据类型>();

Java1.7以后,= 后面的 <> 中的具体的数据类型可以省略不写。

类名<具体的数据类型> 对象名 = new 类名<>();

例:
创建一个泛型类:

public class GenericClass<T> {

    private T t;

    public T getT() {
        return t;
    }

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

使用该泛型类:

public class Test {

    public static void main(String[] args) {
        GenericClass<String> genericClass = new GenericClass<String>();

        genericClass.setT("zk");
        System.out.println(genericClass.getT());
    }

}

4.1.1 泛型类的继承

  • 子类也是泛型类,子类和父类的泛型要一致:
class Child<T> extends GenericClass<T> {

};
  • 子类不是泛型类,父类要明确泛型的数据类型:
class Child extends GenericClass<Integer> {

};

4.2 泛型接口

定义泛型接口的语法:

interface 接口名称<泛型标识> {
	泛型标识 方法名();
}

使用泛型接口:

  • 实现类也是泛型类,实现类和接口的泛型类型要一致;
  • 实现类不是泛型类,接口要明确数据类型。

例如:
泛型接口:

public interface GenericInterface<T> {
    T getValue();
}

实现类:

public class Test01<T> implements GenericInterface<T> {

    private T t;

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

    public T getValue() {
        return t;
    }

}

使用:

public class Test {

    public static void main(String[] args) {
        Test01<String> test01 = new Test01<>();
        test01.setT("hello");
        System.out.println(test01.getValue());
    }

}

4.3 泛型方法

创建泛型方法的语法:

修饰符 <泛型标识> 返回值类型 方法名(泛型标识 形参){
	方法体...
}

注:

  • 只有声明了 <T> 的方法才是泛型方法,<T> 表明该方法将使用泛型类型 T,此时才可以在方法中使用泛型类型 T。
public class GenericMethod {

    private <T> T print(T t){
        System.out.println(t);
        return t;
    }

    public static void main(String[] args) {
        GenericMethod genericMethod = new GenericMethod();
        System.out.println(genericMethod.print("hello"));
    }

}
  • 15
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值