简体   繁体   English

如何返回扩展某些东西的泛型类型 T 的列表

[英]How to return a list of generic type T that extends something

I have a problem with returning a list of a generic type T that extends something.我在返回一个扩展了某些东西的泛型类型 T 的列表时遇到了问题。

I have a base class, called A, and 2 subclasses, B and C.我有一个名为 A 的基础 class 和 2 个子类 B 和 C。 I want to return from a method either a list of B's or a list of C's depending on some context, but I cannot get the compiler to agree with it.我想根据某些上下文从方法返回 B 列表或 C 列表,但我无法让编译器同意它。

What I mean is:我的意思是:

import java.util.List;
import java.util.ArrayList;

public class Main {
    public static void main(String[] args) {
        List<B> ls1 = new Main().method1();
        List<C> ls2 = new Main().method2(); // Won't work,
                                            // have to cast to it
        // i.e. List<C> ls2 = (List<C>) new Main().method2();

        System.out.println(ls1);
        System.out.println(ls2);
    }

    <T extends A> List<T> method1() {
        List<B> ls = new ArrayList<>();
        ls.add(new B());
        return ls; // Doesn't work now, compiler error
                   // works if I explicitly cast to it, but says
                   // unsafe or unchecked operation
                   // return (List<T>) ls;
    }

    List<? extends A> method2() {
        List<C> ls = new ArrayList<>();
        ls.add(new C());
        return ls;
    }
}
class A {
}
class B extends A {
}
class C extends A {
}

As you can see, I tried both a wildcard and an actual type T, but neither of them gets rid of the compiler error: "incompatible types".如您所见,我尝试了通配符和实际类型 T,但它们都没有摆脱编译器错误:“不兼容的类型”。

Any help would be much appreciated, thank you.任何帮助将不胜感激,谢谢。

To fix compile error with修复编译错误

List<C> ls2 = new Main().method2();

You can just do你可以做

List<? extends A> ls2 = new Main().method2();

Note, that this cannot be List<C> , it is list of something that extends A .请注意,这不能是List<C> ,它是扩展 A 的东西的列表。 Using cast (List<C>) is wrong here, because there is no guarantee that method2 returns list of only C, it can be, for example, a mix of C and B objects.在这里使用 cast (List<C>)是错误的,因为不能保证method2返回的列表仅包含 C,例如,它可以是 C 和 B 对象的混合。

Upd: regarding method1 it is also wrong to do a cast to (List<T>) ls for s similar reason.更新:关于method1 ,出于类似的原因,对(List<T>) ls进行强制转换也是错误的。 Imagine you implement method1 like this想象一下你像这样实现method1

<T extends A> List<T> method1() {
    List<C> ls = new ArrayList<>();
    ls.add(new C());
    return (List<T> ) ls;
}

Then in your main method you can do following and compiler won't complain然后在您的main方法中,您可以执行以下操作,编译器不会抱怨

    List<B> ls1 = new Main().method1();
    B b = ls1.get(0);
   

But you'll get a runtime ClassCastException on the line B b = ls1.get(0);但是你会在B b = ls1.get(0);行上得到一个运行时ClassCastException

It is dangerous to say a list holds items of type B and allow an item of type C to exist inside of it.说一个列表包含B类型的项目并允许C类型的项目存在于其中是危险的。 It is safer to say that the list contains an interface or super-class instead.更安全地说,列表包含一个接口或超类。

Here is a dangerous example that throws a runtime exception.这是一个引发运行时异常的危险示例。

import java.util.*;

public class Main {
    public static class A {
        public String getA() { return "A"; }
        @Override public String toString() { return getA(); }
    };
    public static class B extends A {
        public String getB() { return "B"; }
        @Override public String toString() { return getB(); }
    }
    public static class C extends A {
        public String getC() { return "C"; }
        @Override public String toString() { return getC(); }
    }

    public static void main(String[] args) {
        List<B> ls1 = new Main().method3();
        List<C> ls2 = new Main().method3();

        // Will work, because toString() for each class is handled by each class.
        System.out.println(ls1);
        System.out.println(ls2);

        // Runtime errors!
        ls1.stream().map(B::getB).forEach(System.out::println);
        ls2.stream().map(C::getC).forEach(System.out::println);
    }

    public static <T extends A> List<T> method3() {
        return Arrays.asList((T) new A(), (T) new B(), (T) new C());
    }
}

The type of your list should be a common ancestor eg List<A> ls1 so that you can safely call common methods as you iterate through the list.您的列表的类型应该是一个共同的祖先,例如List<A> ls1以便您在遍历列表时可以安全地调用常用方法。

public static void main(String[] args) {
    List<A> ls3 = new Main().method3();

    ls3.stream().map(A::toString).forEach(System.out::println);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 在嵌套泛型类型(如CompletableFuture)上使用通配符 <List<? extends Something> &gt; - Use of wildcards on nested generic type like CompletableFuture<List<? extends Something>> Java如何返回扩展接口的泛型类型 - Java how to return a generic type that extends an interface 为什么泛型参数“扩展”派生 function 中不允许的东西,但泛型返回类型是? - Why is a generic argument that “extends” something not allowed in derived function, but generic return type is? 通用问题:T扩展接口类型。 无法调用方法返回扩展类型的对象? - Generic issues: T extends interface type. Cannot call method to return an object which extends the type? 如何返回一个通用数组<T extends Comparable<? super T> &gt; 在 Java 中? - How return a generic array of <T extends Comparable<? super T>> in Java? Java 通用类型:List 之间的区别<? extends Number>并列出<T extends Number> - Java Generic type : difference between List <? extends Number> and List <T extends Number> 怎么做 <T extends E> 泛型类型参数包容性? - How to make <T extends E> generic type argument inclusive? 带有泛型的mock方法,并以返回类型扩展 - mock method with generic and extends in return type 在类中实例化泛型类型:V扩展列表 - Instantiating Generic Type in class: V extends List 关键字扩展了Type参数 <T> 在通用Java中 - Keyword extends with Type Parameter<T> in Generic Java
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM