Java泛型边界

上一篇文章 Java神秘的泛型擦除 中提到,泛型擦除会默认擦除到 Object 这个边界,因此可以在泛型对象上调用 Object 的任何方法,而不能实际泛型类型的方法。

泛型边界

然而,泛型是可以通过 extends 指定边界的。通过指定边界,我们就不必再局限于只能调用 Object 的方法,我们现在就可以根据指定的边界做更多有意义的事情。

interface IHello {
    void sayHello();
}

class Person<T extends IHello> {
    private final T item;

    public Person(T t) {
        item = t;
    }

    public void hello() {
        item.sayHello();
    }
}

泛型类Person的泛型参数通过 extends 指定了一个边界 IHello,那么泛型的类型就被限定为 IHello 接口或者它的实现类,因此在 Person 的 hello() 方法中可以调用泛型对象的 sayHello() 方法。

让我们用一段代码测试下

Person<IHello> p = new Person<>(() -> System.out.println("Hello!!!"));
p.hello(); // 输出为 Hello!!!

我们创建了一个 Person<IHello> 对象,在构造函数中,使用 lambda 表达式创建一个 IHello 接口的实现。可以看到输出结果正是 lambda 表达式的输出。

从这个例子可以发现,虽然 Java 泛型是用擦除实现的,但是可以通过指定泛型边界来弥补一点缺陷。


扩展泛型边界

通过 extends 关键字可以为泛型同时指定多个边界,这样就可以通过泛型对象使用多个边界的功能。下面的例子通过类的继承,扩展泛型的边界。

package com.example.lib;

interface IHello {
    void sayHello();
}

class Attribute {
    protected String name;
}

class Person<T extends IHello> {
    protected final T item;

    public Person(T t) {
        item = t;
    }

    public void hello() {
        item.sayHello();
    }
}

class HelloWithAttr extends Attribute implements IHello {
    public HelloWithAttr(String name) {
        this.name = name;
    }

    @Override
    public void sayHello() {
        System.out.println("Hello~");
    }
}

class NamedPerson<T extends Attribute & IHello> extends Person<T> {

    public NamedPerson(T t) {
        super(t);
    }


    public String getName() {
        return item.name;
    }
}

public class Test {
    public static void main(String[] args) {
        NamedPerson<HelloWithAttr> p = new NamedPerson<>(new HelloWithAttr("David"));
        p.hello();
        System.out.println(p.getName());
    }
}

Person 类的泛型通过 extends 关键字,限定边界为 IHello 接口,这样一来,泛型对象就可以使用 IHello 接口的 sayHello() 方法,这正是在 Hello 类的 hello() 方法中所做的。

NamedPerson 类继承 Person 类,再为泛型添加一个边界 Attribute 。如此一来,泛型对象不止可以使用 IHello 接口的方法,也可以使用 Attribute 的方法和属性。正如在 NamedPerson 类的 getName() 方法中所看到的,通过泛型对象 item ,可以获取 Attribute 类的 name 变量。

注意,通过 extends 扩展边界,如果边界有类和接口,类要放在接口的前面。

结束

与 C++ 比较,我们会觉得 Java 的泛型没那么简单易用,但是我们要掌握 Java 泛型能做什么,不能做什么,才能发挥 Java 泛型的真正力量。虽然说这个力量没有 C++ 那么强大,但是我们不得不面对这样一个现实。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值