Java高级特性-泛型类

Java高级特性-泛型类

Java重载的知识中,在一个类内方法可以重载,Java编译器根据调用方法时传入的参数类型,参数个数来确定调用的是哪个方法。

// java
int add(int a, int b) {
    return a + b;
}

float add(float a, float b) {
    return a + b;
}

假设上述add方法包含需要在设计时包含所有可相加的原始类型,那么就需要写多个功能相同的方法。那么是不是可以只写一个方法来涵盖所有的类型相加的功能呢?答案就是泛型。

泛型优点

泛型可以让类型(class/interface)在定义类时变成参数(parameter)。

泛型的优点:

  1. 编译期更强的类型检查。

    Java编译器在编译时会对代码进行类型检查,如果代码违反类型安全规则,编译器会发出错误警告。这可以避免在运行时出现 ClassCastException。在编译期修改错误比在运行后修改出现的错误付出的代价要小。

  2. 消除类型转换。

    由于泛型提供了编译时的类型检查,所以不需要在代码中进行显式的类型转换。

    下面代码是不使用泛型的情况。

    List list = new ArrayList();
    list.add("hello");
    String s = (String) list.get(0); // 不使用泛型是,获取列表中item后还需要进行类型转换
    

    在使用泛型之后。

    List<String> list = new ArrayList<String>();
    list.add("hello");
    String s = list.get(0);  // 使用泛型后,获取item后,不需要显示的转换
    
  3. 代码重用:可以用一个类或者接口来操作不同类型的对象,这大大提高了代码的重用性。

  4. 提高程序可读性和稳定性:使用泛型可以使代码更易读,更稳定,更易于维护。

    例如:

    List<String> list = new ArrayList<String>();
    

    这个通过泛型创建的String列表,再想添加其他类型,编译器就会报错。

文章开头的代码在使用泛型后可以修改成。

<T> T add(T a, T b) {  // 修改为泛型方法
    return a +b;
}

泛型类

泛型类型是在类型上参数化的泛型类或接口。

下面是一个非泛型的具体类Box

public class Box {
    private Object object;

    public void set(Object object) { this.object = object; }
    public Object get() { return object; }
}

Box类中只定义了setget方法,参数Object表示可以向set方法方中传入任意的引用类型。Java编译器在编译这段代码时不会进行类型检查,因为set方法方中传入任意的引用类型,在使用过程中也可能造成意外的错误。

泛型类定义

泛型类的定义方式格式:

public class ClassName<T1, T2, ..., Tn> { /* ... */ }

其中,T1, T2, …, Tn 是类型参数,它们在实例化类的时候会被具体的类型替换。

看下使用了泛型定义后的Box类。

public class Box<T> {
    private T t;

    public void set(T t) { this.t = t; }
    public T get() { return t; }
}

注意:类型参数T不能是原始数据类型。将原始类型传给类型参数,编译器会报错

// 在代码中创建Box实例,将int类型传入,代码编译时报错。
Box.java:15: error: unexpected type
    Box<int> box = new Box();
        ^
  required: reference
  found:    int
Note: Box.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
1 error

正确的创建使用方式。

Box<Integer> integerBox = new Box<Integer>();
integerBox.set(Integer.valueOf(13));
Integer someInteger = integerBox.get();

类型参数命名

泛型中类型参数的命名惯例一般是单个大写字母表示。

下面是最常用的类型参数名:

  • E - Element (最常用来表示集合中的元素类型)
  • K - Key
  • N - Number
  • T - Type
  • V - Value
  • S,U,V etc. - 2nd, 3rd, 4th types

使用泛型类创建实例时,需要指定类型参数的具体类型。

Box<Integer> integerBox = new Box<Integer>();

在JDK 7之后,创建泛型类实例,调用类的构造方式时,可以省去类型参数,直接写空的<>括号。

Box<Integer> integerBox = new Box<>();

类型参数的个数

上述的Box类中包含了单个的T类型参数。其实泛型类中的类型参数个数可以有多个,最典型的就是android中Pair类。

public class Pair<F, S> {
    public final F first;
    public final S second;

    public Pair(F first, S second) {
        this.first = first;
        this.second = second;
    }

    @Override
    public boolean equals(@Nullable Object o) {
        if (!(o instanceof Pair)) {
            return false;
        }
        Pair<?, ?> p = (Pair<?, ?>) o;
        return Objects.equals(p.first, first) && Objects.equals(p.second, second);
    }

    @Override
    public int hashCode() {
        return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode());
    }

    @Override
    public String toString() {
        return "Pair{" + String.valueOf(first) + " " + String.valueOf(second) + "}";
    }

    public static <A, B> Pair <A, B> create(A a, B b) {
        return new Pair<A, B>(a, b);
    }
}

使用时,将类型参数 F,S 替换为具体类型。

Pair<String, Integer> p1 = new Pair<>("Even", 8);
Pair<String, String>  p2 = new Pair<>("hello", "world");

类型参数传入参数化的类型

已经具体化的类型也可以作为类型传给类型参数。

List<Box<Integer>> list = new ArrayList<>();

这行代码中,Box是一个泛型类,创建的具体类型是Box,将这个参数化后的Box类作为类型放入到List的声明中。

原始类型

泛型类在用以创建实例时,类型参数位置可以不替换为任何类型,且<>括号也省去。

Box b = new Box();

这里的BoxBox的原始类型。之所以可以使用原始类型,因为泛型是在JDK 5之后引入的,为了后向兼容,保留了原始类型的使用。

以下两种程序,编译器会显示警告,但程序还是可以运行。

// 将泛型实例赋值给一个原始类型变量
Box<Integer> b = new Box<>(); 
Box b1 = b; // Box is a raw type. References to generic type Box<T> should be parameterized
// 将原始类型实例赋值给一个泛型实例变量
MyBox b2 = new MyBox();
MyBox<Integer> b3 = b2;

这个警告显示原始类型绕过了泛型类型检查,从而将捕获不安全代码的操作推迟到运行时。因此,您应该避免使用原始类型。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

VoidHope

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值