非泛型类中的泛型实例变量

2022-09-04 21:32:29

我正在尝试编写一个具有泛型成员变量但本身不是泛型的类。具体来说,我想说的是,我有一个“实现与自身相当的某种类型”的值列表,以便我可以在该列表中调用排序......我希望这是有道理的。

我尝试做的最终结果是创建一个类,这样我就可以创建一个具有(任何给定类型)数组的所述类的实例,并让它为该列表生成字符串表示形式。在实际代码中,我还传入了我正在传入的类型类:

String s = new MyClass(Integer.class, 1,2,3).asString();
assertEquals("1 or 2 or 3", s);
String s = new MyClass(String.class, "c", "b", "a").asString();
assertEquals("\"a\" or \"b\" or \"c\"", s);

最初我甚至不想传递类,我只想传入值并让代码检查结果数组以挑选值的类...但这也给我带来了麻烦。

以下是我拥有的代码,但我无法为变量类型提出正确的mojo。

public class MyClass {
    // This doesn't work as T isn't defined
    final List<T extends Comparable<? super T>> values;

    public <T extends Comparable<? super T>> MyClass (T... values) {
        this.values = new ArrayList<T>();
        for(T item : values) {
            this.values.add(item);
        }
    }

    public <T extends Comparable<? super T>> List<T> getSortedLst() {
        Collections.sort(this.values);
        return this.values;
    }
}

变量声明行上的错误:

Syntax error on token "extends", , expected

任何帮助将不胜感激。

编辑:更新了代码以使用List而不是数组,因为我不确定是否可以用数组完成。

@Mark:从我读到的一切来看,我真的想说“T是一种与自身相当的类型”,而不仅仅是“T是一种可比的类型”。话虽如此,以下代码也不起作用:

public class MyClass {
    // This doesn't work
    final List<? extends Comparable> values;

    public <T extends Comparable> MyClass (T... values) {
        this.values = new ArrayList<T>();
        for(T item : values) {
            this.values.add(item);
        }
    }

    public <T extends Comparable> List<T> getSortedLst() {
        Collections.sort(this.values);
        return this.values;
    }
}

添加行时出错:

The method add(capture#2-of ? extends Comparable) in the type List<capture#2-of ? extends Comparable> is not applicable for the arguments (T)

排序行上的错误:

Type mismatch: cannot convert from List<capture#4-of ? extends Comparable> to List<T>

结论:

归根结底,Java似乎无法完全处理我想做的事情。问题是因为我想说的是:

我想要一个与它们本身相当的项目列表,并且我从创建时传递的数据立即创建整个列表。

但是,Java看到我有那个列表,并且无法确定我的情况的所有信息在编译时都可用,因为我可以尝试稍后将内容添加到列表中,并且由于类型擦除,它不能保证安全性。如果不将泛型类型应用于类,就不可能将我的情况所涉及的条件传达给 Java。


答案 1

我认为简单的答案是你不能这样做。如果其中一个类属性的类型依赖于类型参数,则必须在类级别声明该参数。我不认为它以任何其他方式“有意义”。

如果示例中不是类的类型参数,那它是什么?它不能是方法的类型参数,因为该类型由方法的调用方式确定。(如果在 不同的静态上下文中调用该方法,并且具有不同的推断类型 ,则在属性声明的上下文中,名义类型是什么?TTT

因此,为了将此带回您在此处尝试执行的操作,将的实例包含某种类型的元素,并且您希望能够以静态类型安全的方式插入和删除元素。但与此同时,你不想说出那是什么类型。那么,编译器应该如何静态地区分保存(比如)对象的实例和保存对象的实例呢?MyClassMyClassIntegerString

我甚至不认为你可以用显式的动态类型检查来实现这一点。(我认为类型擦除意味着该方法的实现无法找出绑定到其返回类型的实际类型。getSortedList()

哈哈真正的解决方案是创建一个声明类型参数的泛型类;例如:MyClassT

public class MyClass <T extends Comparable<T>> {

并从两个方法中删除方法级类型参数的声明。T


答案 2

这其中有很多未经检查的警告,但原则上没有必要保留任何东西,除了包含您知道的东西之外的东西。您在构造函数中强制执行所需的规则,其他一切都应该没问题。像这样的东西怎么样:ListComparable

public class MyClass {

    final private List<Comparable> values;

    public <T extends Comparable<? super T>>MyClass(T... values){
        this.values = new ArrayList<Comparable>();
        for(T item : values) {
            this.values.add(item);
        }
    }

    public <T extends Comparable<? super T>> List<T> getSortedLst() {
        Collections.sort(this.values);
        return (List<T>)this.values;
    }

}

使用以下方法的快速测试表明,对于实现Compeable(如整数和字符串)的类,其行为符合预期,但对于未实现的类,将引发编译错误:MyClassComparable

    class Junk { }

    public static void main(String[] args){
        MyClass s = new MyClass(1,2,3);
        System.out.println(s.getSortedLst());

        MyClass a = new MyClass("c", "a", "b");
        System.out.println(a.getSortedLst());

        MyClass c = new MyClass(new Junk());
    }

推荐