【问题标题】:Java Generics - Specifying upper bound on a class implementing an interface which itself specifies an upper boundJava 泛型 - 在实现接口的类上指定上限,该接口本身指定上限
【发布时间】:2023-03-20 15:58:01
【问题描述】:

我有如下界面:

public interface ISort<T extends Comparable<T>> {
    public void sort(T[] array);
}

我对此的理解是&lt;T extends Comparable&lt;T&gt;&gt; 告诉编译器在这个类中,可能有一些泛型类型T,它们必须是Comparable&lt;T&gt; 或者是任何实现Comparable&lt;T&gt; 的类。

然后我有以下课程:

public class Sort<T extends Comparable<T>> implements ISort<T> {

    public void swap(T[] array, int i, int j) {
        T temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }

    public void sort(T[] array) {
        java.util.Arrays.sort(array);
    }

}

再次,我让&lt;T extends Comparable&lt;T&gt;&gt; 告诉编译器,在这个类中我将使用类型T,它必须与Comparable&lt;T&gt; 形成一个IS-A 关系。但是,为什么我只能输入implements ISort&lt;T&gt;,为什么我不需要写implements ISort&lt;T extends Comparable&lt;T&gt;&gt;?为了帮助我理解这一点,您能否解释一下这些泛型语句究竟向编译器推断了什么?

【问题讨论】:

    标签: java generics extends implements


    【解决方案1】:

    在类中指定T 和在extends 或implements 子句中使用T 是有区别的。

    当用类指定T 时,您声明类型参数T,但在extends 或implements 子句中,您使用类型参数已经声明了。

    public class Sort<T extends Comparable<T>>  // Declare T to be Comparable<T>
        implements ISort<T>                     // Use T
    

    在 extends 或 implements 子句中使用类型参数与在类主体中使用类型参数没有什么不同。

    【讨论】:

    • 这个解释对我来说最有意义。但是,我还有几个问题。如果我只是在implements ... 部分中使用T,这意味着我们已经确保T 的上限是Comparable&lt;T&gt;。如果是这样,那我为什么需要在接口文件中指定T extends Comparable&lt;T&gt;(我的第一个代码sn-p)?
    • 每个类/接口都可以定义自己的类型参数。 ISort 将自己的T 声明为Comparable&lt;T&gt;Sort 也将自己的T 声明为Comparable&lt;T&gt;Sort 上的 implements 子句表明 Sort 提供自己的 T 作为 ISort 的类型参数。
    【解决方案2】:

    在类声明中,您引入了一个具有上限的类型参数。当你使用T[] 作为sort 方法的第一个参数的类型时,你并没有声明任何东西(声明发生在文件的开头):你只是使用类型变量。请注意不同的措辞:

    • 在文件的开头,您声明了一个类型参数
    • 在排序的签名中,我们使用了一个类型变量

    类型参数的界限只允许在声明的地方,声明可以发生在三个地方:

    1. 类声明
    2. 构造函数定义
    3. 方法定义

    这里有一个快速表:

    // class
    public static class Foo<T> {
        // constructor
        public <A> Foo() {}
        // method
        public <B> void doSomething() {}
        // Not really allowed
        // public void doSomethingElse(List<T extends Number> bar) {}
        // here we have a wildcard, so you can do this
        public void doSomethingElse(List<? super T> bar) {}
    }
    

    【讨论】:

      【解决方案3】:

      泛型类型用法的语法是SomeType&lt;SomeTypeArgument&gt;

      你的情况

      class Sort<T extends Comparable<T>> implements ISort<T> {
              // ^ declares new type parameter             ^ uses it as a type argument 
              //                             
      

      您声明了一个新类型参数T,其边界与ISort 中声明的类型参数T 中的预期相匹配。因此,您可以使用Sort#T 作为ISort 的类型参数。

      这将类似于

      class Sort implements ISort<Integer> {
      

      唯一的区别是您不声明类型参数,而是使用现有类型。

      【讨论】:

        猜你喜欢
        • 2016-01-06
        • 1970-01-01
        • 2012-03-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-23
        • 2012-07-19
        • 1970-01-01
        相关资源
        最近更新 更多