繁体   English   中英

Java泛型 - 不允许子类

[英]Java generics - Don't allow subclasses

我有一个关于泛型的问题。 所以假设我有3个类“Foo”,“Bar”(它是Foo的子类),类“Factory”和接口“TestInterface”。 我想编写一个泛型方法,它只允许“直接”实现接口的对象,因此没有子类。 这对我来说很难,因为Java8似乎比Java7“更聪明”。

这是一个例子:

public interface TestInterface<T extends TestInterface<T>> {

}

public class Foo implements TestInterface<Foo>{

}

public class Bar extends Foo {

}

public class Factory {

   public static <T extends TestInterface<T>> T doSth(T arg) {
       return arg;
   }
}

好的,这些是我的课程。 现在在doSth(T arg)方法中我想在这种情况下允许Foo对象,因为它是唯一“直接”实现接口的类。

显然这样现在不会编译:

Bar b = Factory.doSth(new Bar());

因为Bar没有实现TestInterface<Bar>

好吧,我现在的问题是,这行将编译没有任何问题:

Foo f = Factory.doSth(new Bar());

即使通用参数是T和T应该用它自己的类实现接口(对不起,真的不知道怎么说,希望你知道我的意思),编译器接受“Bar”作为参数。

所以编译器必须表现得像“好吧Bar不适合,但也许超级类适合”。 然后它“看到”它与超级“Foo”一起工作。 然后酒吧将被视为一个Foo,因为每个酒吧都是某种Foo或某样的? 至少那是我的想象。

好吧,如果我尝试使用Java7编译该行,它就会失败。 所以看起来Java8在类型擦除方面有点聪明?!

Java8中是否有任何方法不允许子类,因此这不会编译?:

Foo f = Factory.doSth(new Bar());

希望你能理解我的问题,我很少用英文写作。

电贺

之所以Foo f = Factory.doSth(new Bar()); 在Java 8而不是Java 7中工作是因为Java 8具有更好的类型推断。 在Java 7中,类型被推断为:

Foo f = Factory.<Bar>doSth(new Bar());

Bar没有实现TestInterface<Bar> ,但它通过继承实现了TestInterface<Foo> Java 8的类型推断得到了提升,类型将被推断为:

Foo f = Factory.<Foo>doSth(new Bar());

请注意, Factory.<Foo>doSth()期望将Foo作为参数,因此new Bar()被隐式转换为Foo ,它可以正常工作。

我担心没有办法解决这个问题。 您将始终能够将对象转发到其超类。 你可以让Foo final ,但这完全不允许Foo子类化。

我同意这种情况确实存在; Bar在概念上是Foo的子类,但我们不想让它们共享同一个方法doSth() 它不完全相同,但类似的是,在许多情况下应避免在超子类之间共享equals()方法,以保持等价关系的对称性和传递性。 (详情见JB的Effective Java 2nd ed。的第8项)

到目前为止,我没有找到一个通用参数描述的好解决方案。 (Java的类型系统,就像其他典型的OO语言一样),似乎基本上假设每对超类和子类都应默认共享超类的方法。)相反,我发现在这种情况下丢弃继承将是一种可能的解决方案。 , 如下,

public class Bar  { // using composition, instead of inheritance
  Foo Bar(Foo f) {
     this.f = f;
  }
  // here, definitions of delegated methods for each of f's methods
  // see details in Item 16 of Effective Java 2nd ed. by J.B.

  Foo asFoo(){ 
     return f;
  }
}

通过对Bar这种修改,我们可以在这里得到编译时错误,

Foo b = Factory.doSth(new Bar(new Foo())); // a compile time error occurs

即使我们在JDK7中使用<Foo>

Foo b = Factory.<Foo>doSth(new Bar(new Foo())); // a compile time error occurs

另一方面,如果有必要,我们可以使用asFoo()来避免这个错误。

Foo b = Factory.<Foo>doSth(new Bar(new Foo()).asFoo()); // no compile time error

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM