当前位置: 首页 > 知识库问答 >
问题:

返回泛型超类

华锦
2023-03-14

对于一堆带有泛型的包装类,我的继承结构遇到了一些麻烦。这基本上是结构:

public abstract class SuperWrapper<E extends Super>{
    private E wrappedObject;
    public E getWrappedObject(){
        return wrappedObject;
    }
}

public abstract class MiddleWrapper<E extends Middle> extends SuperWrapper<E>{}

public class SubAWrapper extends MiddleWrapper<SubA>{}

public class SubBWrapper extends MiddleWrapper<SubB>{}
public class Super{}

public class Middle extends Super{}

public class SubA extends Middle{}

public class SubB extends Middle{}
public static MiddleWrapper<?> findMiddle(String id){
    SubAWrapper a = new SubAWrapper();
    SubBWrapper b = new SubBWrapper();
    if(returnSubA){
        return a;
    } else{
        return b;
    }
}
public static <E extends Middle> MiddleWrapper<E> findMiddle(String id){
    SubAWrapper a = new SubAWrapper();
    SubBWrapper b = new SubBWrapper ();
    if(returnSubA){
        return (MiddleWrapper<E>) a;
    } else{
        return (MiddleWrapper<E>) b;
    }
}

这将与当前代码一起编译和工作,但是,这似乎很危险。如果调用方像这样使用这个方法:middlewrapper middle=findMiddle(“1”); ,它将很好地编译,但是如果findMiddle尝试返回SubBWrapper,则在运行时会有一个ClassCastException。我以为行得通却行不通的是:

public static MiddleWrapper<Middle> findMiddle(String id){
    SubAWrapper a = new SubAWrapper ();
    SubBWrapper b = new SubBWrapper ();
    if(returnSubA){
        return (MiddleWrapper<Middle>) a; //Compile error here
    } else{
        return (MiddleWrapper<Middle>) b; //and here
    }
}

所以我的问题基本上是,有没有正确的方法来编写编译、运行并遵循最佳实践的方法findMiddle?

对于额外的学分,有没有一种方法可以编写一个方法,使它返回一个列表,同时包含SubA和subb。如下所示,但不使用通配符:

public static List<MiddleWrapper<?>> getAllMiddle(){
    List<MiddleWrapper<?>> ret = Lists.newArrayList();
    ret.add(new SubAWrapper());
    ret.add(new SubBWrapper());
    return ret;
}

共有1个答案

韦衡
2023-03-14

MiddleWrapper是用Middle类参数化的泛型类:

public abstract class MiddleWrapper<E extends Middle> extends SuperWrapper<E>{}

如果要提供一个方法,该方法返回middlewrapper列表,该middlewrapper至少具有两个不同的泛型类型,则您没有很多选择。

如果您不需要对middle子类设置任何可能返回的约束。
您显示的方法很好:

public static List<MiddleWrapper<?>> getAllMiddle() {
  List<MiddleWrapper<?>> ret = Lists.newArrayList();
  ret.add(new SubAWrapper());
  ret.add(new SubBWrapper());
  return ret;
}

你说:

这会编译并起作用,但SonarQube警告在返回类型中使用通配符,从我的谷歌搜索来看,这不是应该忽略的警告之一。

为什么在middlewrapper<?>中使用会是一个不好的做法?
middlewrapper是泛型的,在您的方法中,您可以返回用作泛型的任何类型的middle
这是此用例的方法。

public class ValidMiddle extends Middle {...}

public class SubA extends ValidMiddle{...}

public class SubB extends ValidMiddle{...}

而方法应该是:

public static List<MiddleWrapper<? extends ValidMiddle>> getAllMiddleWithMoreSpecificType() {
  List<MiddleWrapper<? extends ValidMiddle>> ret = Lists.newArrayList();
  ret.add(new SubAWrapper());
  ret.add(new SubBWrapper());
  return ret;
}

请注意,对于应该操作此声明类型的客户端来说,这种方式稍微冗长一些:

 List<MiddleWrapper<? extends ValidMiddle>> listOfWrappers = getAllMiddle();
 类似资料:
  • 我想让一个函数返回一个保证实现两个接口的对象。编译时不一定知道确切的对象。我的代码看起来像: 在尝试编译时,我遇到以下错误: 你好世界java:13:错误:不兼容的类型:C无法转换为T 返回新的C() ^ 其中T是一个类型变量: T扩展了方法f(布尔值) HelloWorld中声明的a,B。java:14:错误:不兼容的类型:D无法转换为T 返回新的D() ^ 其中T是一个类型变量: T扩展了方法

  • 我在我的Java程序中写了这个函数: 这就是我所说的: 它是有效的,但我觉得我应该能够省略第一个参数,并从返回类型(结果被分配到的类型)推断出它。这可能吗?如果是,语法是什么?

  • 我有一个返回泛型的函数: 所以,当我试图匹配一个函数结果时,我的问题是: 我得到一个警告:“类型模式数组[CustomerInfo到[CustomerApplication到]]中的非变量类型参数CustomerApplication-DDTO未选中,因为它已被擦除消除。” 这是否意味着在Array[]中可以得到任何类型的数组?所以我已经阅读了关于ClassTag和TypeTag的文章,但是误解了

  • 问题内容: 我有一个旧类,该类本身不是泛型,但其方法返回类型之一使用泛型: 使用泛型返回字符串的集合。因此,我可以进行遍历,而无需将元素强制转换为: 但是,如果我将自己更改为通用名称,但其他所有内容均保持不变: 然后继续使用对的非泛型引用,不再返回,而是返回非类型。因此,客户端代码无法编译: 为什么是这样?有哪些解决方法? 我的猜测是,通过使用对泛型类的非泛型引用,Java将关闭整个类的所有泛型。

  • 问题内容: 背景 我曾经写过这种方法: 应该这样称呼它: 这很好用(尽管我在研究当前容易出错的问题时在这里的答案中已经看到)。 目前的情况 无论如何,现在我正在编写以下代码(在扩展javax.servlet.jsp.tagext.TagSupport的类中): 目的是可以这样称呼: 我的评估方法中的代码显然不起作用。的第二个参数应该是Class对象。这导致我: 我的问题 如何获得通用(返回)类型的