【问题标题】:T extends Comparable<T>T 扩展 Comparable<T>
【发布时间】:2011-10-25 00:04:18
【问题描述】:

我有以下课程。

class MyClass<T>

它使用以下构造函数。

MyClass(Comparator<T> comparator, Collection<? extends T> data)

它有一个在构造函数中设置的字段,如下所示:

this.data = Collections.unmodifiableCollection(data);

在 T 实现 Comparable 的特殊情况下,我不想要求传入比较器,因为我可以使用自然排序。所以我想我应该可以使用这个构造函数:

public <T extends Comparable<T>> MyClass(Collection<T> data)

但显然存在类型不匹配:无法从上述赋值语句中的Collection&lt;T&gt; to Collection&lt;? extends T&gt; 转换。我尝试了各种各样的事情:添加更多的通用参数等等,但都没有奏效。我似乎无法指定一个界限:如果你有一个实现 Comparable 的类型 T,那就直接做吧。

有什么想法吗?

谢谢。

【问题讨论】:

  • 我猜你想将它声明为第二个构造函数,对吧?那么将MyClass&lt;T&gt; 更改为MyClass&lt;T extends Comparable&lt;T&gt;&gt; 不是一种选择?
  • 我发现我可以使用静态工厂方法来做到这一点:static > MyClass getInstance(Collection extends V> data),但这有点不令人满意.
  • (注意最后一个代码示例创建了两个通用参数,都称为T - 一个在类上,一个在构造函数上(就像在方法上一样,很少有用)。

标签: java generics


【解决方案1】:

不幸的是,我认为 Java 类型系统不可能实现这种“如果 Comparable 执行此操作,则执行此操作”逻辑。

您可以将 Comparable 和 non-Comparable 案例拆分为单独的类并将它们隐藏在接口后面,如下所示:

interface Interface<T> {
    public void processData();
}

class MyClass<T> implements Interface<T> {
    private final Collection<? extends T> data;
    MyClass(Comparator<T> comparator, Collection<? extends T> data) {
        this.data = data;
    }
    public void processData() {
        // ...
    }
}

class MyCompClass<T extends Comparable<T>> implements Interface<T> {
    private final Collection<? extends T> data;
    MyCompClass(Collection<? extends T> data) {
        this.data = data;
    }
    public void processData() {
        // ...
    }
}

class Factory {
    static <T extends Comparable<T>> Interface<T> create(Collection<? extends T> data) {
        return new MyCompClass<T>(data);
    }
    static <T> Interface<T> create(Comparator<T> comparator, Collection<? extends T> data) {
        return new MyClass<T>(comparator, data);
    }
}

但这可能会导致大量重复代码。另一种选择是让 MyClass 在其构造函数中需要一个 Comparator,并在工厂中构建该比较器:

class MyClass<T> {
    private final Collection<? extends T> data;
    MyClass(Comparator<T> comparator, Collection<? extends T> data) {
        this.data = data;
    }
    public void processData() {
        // ...
    }
}

class Factory {
    static <T extends Comparable<T>> MyClass<T> create(Collection<? extends T> data) {
        return new MyClass<T>(new Comparator<T>() {
            public int compare(T o1, T o2) {
                return o1.compareTo(o2);
            }
        }, data);
    }
    static <T> MyClass<T> create(Comparator<T> comparator, Collection<? extends T> data) {
        return new MyClass<T>(comparator, data);
    }
}

【讨论】:

  • 您的第二个解决方案正是我最终所做的。感谢您澄清使用 Java 的类型系统确实无法实现我想要做的事情。
  • 您甚至可以将该工厂方法放入MyClass
【解决方案2】:

我同意这似乎是不可能的,因为直接的解决方案

class MyClass<T> {

    Collection<? extends T> data;

    public MyClass(Comparator<T> comparator, Collection<? extends T> data) {
        this.data = data;
    }

    public <E extends T & Comparable<T>> MyClass(Collection<E> data) {
        this.data = data;
    }

}

被编译器拒绝

当第一个绑定是类型参数时,不能指定任何额外的绑定Comparable&lt;T&gt;

另请参阅Why can't I use a type argument in a type parameter with multiple bounds?(特别是 Chris Povirk 的回答)。

至于解决方案,我同意 Chris B。

【讨论】:

    【解决方案3】:

    第一种情况可以使用常规构造函数,第二种情况可以使用工厂方法:

    class MyClass<T> {
    
        Collection<? extends T> data;
        Comparator<? super T> comparator;
    
        public MyClass(Comparator<? super T> comparator, Collection<? extends T> data) {
            this.data = data;
            this.comparator = comparator;
        }
    
        public static <T extends Comparable<? super T>> MyClass<T> fromComparable(Collection<T> data) {
            return new MyClass<T>(Collections.reverseOrder(Collections.reverseOrder()), data);
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-15
      • 1970-01-01
      • 2012-01-22
      • 1970-01-01
      相关资源
      最近更新 更多