Java 有界类型参数与普通基类

Java 有界类型参数与普通基类,java,generics,type-erasure,Java,Generics,Type Erasure,在编译时,javac使用泛型有界类型,并用上界替换它 例如,编译器将转换 <T extends Base> void foo(T p) {} 在这种特殊情况下,我认为泛型肯定比其他选项更受欢迎。但是我想知道具体的优点。请参考 但简而言之,有两件事需要注意: 泛型方法是引入自己类型参数的方法。这类似于声明泛型类型,但类型参数的作用域仅限于声明它的方法。允许使用静态和非静态泛型方法以及泛型类构造函数 -https://docs.oracle.com/javase/tutorial/ja

在编译时,javac使用泛型有界类型,并用上界替换它

例如,编译器将转换

<T extends Base> void foo(T p) {}
在这种特殊情况下,我认为泛型肯定比其他选项更受欢迎。但是我想知道具体的优点。

请参考

但简而言之,有两件事需要注意:

泛型方法是引入自己类型参数的方法。这类似于声明泛型类型,但类型参数的作用域仅限于声明它的方法。允许使用静态和非静态泛型方法以及泛型类构造函数

-https://docs.oracle.com/javase/tutorial/java/generics/methods.html

类型推断是Java编译器查看每个方法调用和相应声明的能力,以确定使调用适用的一个或多个类型参数。推理算法确定参数的类型以及(如果可用)分配或返回结果的类型。最后,推理算法试图找到适用于所有参数的最具体类型


-https://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html

让我通过一个例子正确地解释有界类型的需要

假设您正在编写一个库或框架,供其他人使用。比如说,在某些类方法中,你需要执行一些中性加法、减法、乘法等。那么,你需要什么类型的数据呢?当然是中性类型。所以,您所做的就是创建一个类号。但是,有各种类型的数字,如浮点、整数等。因此,您创建了整数、浮点子类等。现在,您还创建了一个类NumberUtil,它为用户提供了一些功能,如查找平均值、查找数字频率等。当然,一句话:NumberUtil非常棒,每个人都想使用它。现在,让我们谈谈NumberTil类中的平均方法让我们编写一些代码:

class NumberUtil<T extends Number> {
  T[] nums;
  public NumberUtil(T[] nums) {
    this.nums = nums;
  }
  public Double average() {
    Double sum = 0.0;
    for(int i=0; i<nums.length; i++) {
      sum = sum + nums[i].doubleValue(); // note, you've ensured T must be a number
      // so, T must able to convert it's value to double value
    }
    return sum / nums.length;
  }
}

现在,让我们假设,其他一些人正在使用您的库,特别是NumberTill,因为它非常棒,但是他们正在使用自己的名为SomeNumberType的类型。但有可能,这个SomeNumberType并没有将Number子类化,或者,它没有实现Number接口,如果您已经将Number声明为接口的话。因此,您不能保证SomeNumberType将提供双值方法。但是,通过编写T extends Number,您已经在编译时确保了SomeNumberType必须是Number的子类,并且一切都将正常工作。至少,它将具有Number类的peropite,这意味着,它还将具有doubleValue方法。

它是不等价的。只有在编译之后。但是在编译过程中,编译器可以确保使用实际的T而不仅仅是Base的类型安全性。所以,仅仅因为泛型在运行时被擦除,并不意味着它们是无用的。编译器可以确保完全的泛型类型安全。因此,在系统已经被证实是正确和安全的之后,让泛型继续存在并没有多大意义,尽管这并不完全正确。@Zabuzard伟大的解释!所以问题是,我应该从更广泛的角度来看待它,因为它的好处确实存在于编译之前发生的事情中。对不起,先生。我是新手,正在学习如何在平台上发布答案。谢谢你重新安排答案,非常感谢,先生。非常感谢你接受反馈
class NumberUtil<T extends Number> {
  T[] nums;
  public NumberUtil(T[] nums) {
    this.nums = nums;
  }
  public Double average() {
    Double sum = 0.0;
    for(int i=0; i<nums.length; i++) {
      sum = sum + nums[i].doubleValue(); // note, you've ensured T must be a number
      // so, T must able to convert it's value to double value
    }
    return sum / nums.length;
  }
}