代码之家  ›  专栏  ›  技术社区  ›  Surya

Java泛型:警告需要一个未选中的强制转换以符合<FraseNeNe>

  •  5
  • Surya  · 技术社区  · 16 年前

    我有一个接口

    interface x {
        A getValue();
    }
    

    以及实施

    class y implements x {
        public B getValue() { return new B();}
    }
    

    B是A的一个子类。我想这是因为协变覆盖。

    但是如果我把接口重写为

    interface x{
        <T extends A> T getValue();
    }
    

    我在实现中得到一个警告

    警告需要未选中的强制转换为 符合a.GetValue()。

    接口的两个版本有什么区别?我以为他们是一样的。

    4 回复  |  直到 16 年前
        1
  •  4
  •   waxwing    16 年前

    接口的第二个版本错误。它说 getValue 将返回您请求的任何子类-将根据左侧的表达式推断返回类型。

    因此,如果您获得 x (我们称之为 obj )可以合法地进行以下调用,而无需编译器警告:

    x obj = ...;
    B b = obj.getValue();
    

    这在您的示例中可能不正确,因为如果您添加另一个类 C 这也延伸了 A ,您也可以合法拨打电话:

    C c = obj.getValue();
    

    这是因为 T 不是属于接口的类型变量,只属于方法本身。

        2
  •  3
  •   Yishai    16 年前

    基本上当你做一个 <T extends A> 你是说你想要一个特定的A的子类,而不是任何A,因为这样你就可以:

     A getValue();
    

    编译器警告您,它不能确保返回的某个特定定义的子类仅返回一个自身。

    编辑:为了更好地解释这一点,b是a的子类,但不需要是a的唯一子类。考虑下面的层次结构。

    B扩展了 C延伸A而不是B

    现在我有了一个方法:

    public void someMethod(x value) {
        C c = x.getValue();
    }
    

    遵循泛型,它应该编译并保证没有运行时类强制转换异常(这里可能还有其他接口问题,但肯定有一些情况可以用来正确地演示这个问题——我和您的示例保持一致)。

    但是如果您将Y的一个实例传递给这个方法呢?

    好吧,现在我得到的是B而不是C。编译器警告你这可能发生。

        3
  •  1
  •   aperkins    16 年前

    编译器告诉您的是,无法解析泛型。除了输出,t没有被定义在任何地方-你说的是哪个t?如果接口被生成为T类型:

    interface x <T extends A> {
        T getValue()
    }
    

    然后这就可以了,或者如果该方法的值定义了您想要的返回类型:

    interface x {
        <T extends A> T getValue(T someArgument)
    }
    

    interface x {
        <T extends A> T getValue(Class<T> someArgument)
    }
    

    那就没有警告了。

    编辑:请参阅Waxwing的文章,了解为什么不应该为这个特定问题使用泛型的解释。我只是在展示仿制药是多么的合适。

        4
  •  0
  •   Brian Beckett    16 年前

    因此,要在阿尔伯托普和伊沙伊的两个答案的基础上,尝试以下方法:

    class y implements x {
        A getValue(){ return new B();}
    }
    

    B延伸了A,所以没关系。调用者不需要知道返回的子类是什么,只需要它扩展了a。所以我们开始了:)