一般地覆盖Java中的方法 [英] Override a method in Java generically

查看:175
本文介绍了一般地覆盖Java中的方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我有这样的基类,我不能改变:

  public abstract class A {
public abstract Object get(int i);
}

我尝试用类B扩展它:

  public class B extends A {
@Override
public String get(int i){
/ / impl
returnSomeString;
}
}

一切正常。但我试图让它使用更通用的失败,如果我尝试:

  public class C extends A {
@Override
public< T extends Object> T get(int i){
// impl
return(T)someObj;
}
}

我想不出任何理由,为什么应该是不允许的。在我的理解中,泛型类型 T 被绑定到一个对象 - 这是请求的返回类型 A 。如果我可以把 String 作为返回类型放在 B ,为什么我不允许把< T extends Object>在我的 C 类中



另一个奇怪的行为在我的观点是一个额外的方法是这样的:

  public class D extends A {

@Override
public Object get(int i){
// impl
}

public< T extends Object> T get(int i){
// impl
}
}

也不允许使用 DuplicateMethod 的提示。这个,至少让我感到困惑,我想java应该做出决定:它是返回类型,为什么不允许覆盖,如果不是,我应该能够添加这个方法。

解决方案

JLS#8.4.2。方法签名


方法m1的签名是方法m2的签名的子签名,如果:




  • m2具有与m1相同的签名,或


  • m1的签名与m2的
    签名的擦除(§4.6)相同。



根据上述规则,由于您的父母没有擦除,您的孩子有一个,因此不是有效的覆写。



JLS# 8.4.8.3。覆盖和隐藏的要求



示例8.4.8.3-4。擦除影响覆盖



类不能有两个成员方法具有相同的名称和类型擦除:

  class C< T> {
T id(T x){...}
}
class D extends C< String> {
Object id(Object x){...}
}

这是非法的,因为D.id(Object)是D的成员,C.id(String)在D的超类型中声明,并且:




  • 两种方法具有相同的名称,id

  • C.id(String)可访问D

  • 这两种方法具有相同的擦除


< >

类的两个不同方法不能覆盖具有相同擦除的方法:

  C类{
T id(T x){...}
}
接口I< T> {
T id(T x);
}
class D extends C< String>实现I< Integer> {
public String id(String x){...}
public Integer id(Integer x){...}
}

这也是非法的,因为D.id(String)是D的成员,D.id(Integer)在D中声明, p>


  • 这两种方法具有相同的名称,id

  • D.id(Integer)

  • 这两种方法有不同的签名(也不是另一个的
    子签名)

  • D.id(String) .id(String)和D.id(Integer)
    覆盖了I.id(Integer),但两个覆盖的方法具有相同的
    擦除



此外,它提供了一个允许从超级到子级的示例


子标志的概念被设计为表示签名不相同但在其中可以覆盖另一个的两个方法之间的关系。具体来说,它允许一个方法,其签名不使用通用类型来覆盖该方法的任何已生成的版本。这是重要的,所以库设计者可以自由地生成独立于客户定义子类或子接口的库的方法。


  class CollectionConverter {
List toList(Collection c){...}
}
类Overrider extends CollectionConverter {
List toList(Collection c){...}

}



现在,假设此代码是在引入泛型之前编写的,现在类CollectionConverter的作者决定生成代码,因此:

  class CollectionConverter {
< T>列表< T> toList(Collection< T> c){...}
}

没有特殊的配置,Overrider.toList将不再覆盖CollectionConverter.toList。 这将显着抑制泛型的使用,因为库编写者会犹豫迁移现有代码。


If I have a base class like this I couldn't change:

public abstract class A {
    public abstract Object get(int i);
}

and I try to extend it with a Class B like this:

public class B extends A{
    @Override
    public String get(int i){
        //impl
        return "SomeString";
    }
}

everything is ok. But my attempt to make it use more generic fails if I try:

public class C extends A{
    @Override
    public <T extends Object> T get(int i){
        //impl
        return (T)someObj;
    }
}

I can't think of any reason, why this should be dissallowed. In my understanding the generic type T is bound to an Object - which is the requested return type of A. If I can put String or AnyObject as return type inside B, why I'm not allowed to put <T extends Object> T inside my C class?

Another Strange behavior in my point of View is that an additional Method like this:

public class D extends A{

    @Override
    public Object get(int i){
        //impl
    }

    public <T extends Object> T get(int i){
        //impl
    }
}

Is also not allowed with the hint of a DuplicateMethod. This one, at least confuses me, and I think java should make a decision: Is it the SAME return Type, why not allow overriding, and if it is not, I should be able to add this Method. To tell me its the same, but I cannot take it to Override is very weired in common sense

解决方案

JLS # 8.4.2. Method Signature

The signature of a method m1 is a subsignature of the signature of a method m2 if either:

  • m2 has the same signature as m1, or

  • the signature of m1 is the same as the erasure (§4.6) of the signature of m2.

As per above rule as your parent do not have an erasure and your child has one so it is not a valid overriding.

JLS#8.4.8.3. Requirements in Overriding and Hiding

Example 8.4.8.3-4. Erasure Affects Overriding

A class cannot have two member methods with the same name and type erasure:

class C<T> {
    T id (T x) {...}
}
class D extends C<String> {
    Object id(Object x) {...}
}

This is illegal since D.id(Object) is a member of D, C.id(String) is declared in a supertype of D, and:

  • The two methods have the same name, id
  • C.id(String) is accessible to D
  • The signature of D.id(Object) is not a subsignature of that of C.id(String)
  • The two methods have the same erasure

Two different methods of a class may not override methods with the same erasure:

 class C<T> {
     T id(T x) {...}
 }
 interface I<T> {
     T id(T x);
 }
 class D extends C<String> implements I<Integer> {
    public String  id(String x)  {...}
    public Integer id(Integer x) {...}
 }

This is also illegal, since D.id(String) is a member of D, D.id(Integer) is declared in D, and:

  • The two methods have the same name, id
  • D.id(Integer) is accessible to D
  • The two methods have different signatures (and neither is a subsignature of the other)
  • D.id(String) overrides C.id(String) and D.id(Integer) overrides I.id(Integer) yet the two overridden methods have the same erasure

Also It gives example of a case where it is allowed from super to child

The notion of subsignature is designed to express a relationship between two methods whose signatures are not identical, but in which one may override the other. Specifically, it allows a method whose signature does not use generic types to override any generified version of that method. This is important so that library designers may freely generify methods independently of clients that define subclasses or subinterfaces of the library.

Consider the example:

class CollectionConverter {
List toList(Collection c) {...}
}
class Overrider extends CollectionConverter {
 List toList(Collection c) {...}

}

Now, assume this code was written before the introduction of generics, and now the author of class CollectionConverter decides to generify the code, thus:

 class CollectionConverter {
   <T> List<T> toList(Collection<T> c) {...}
 }

Without special dispensation, Overrider.toList would no longer override CollectionConverter.toList. Instead, the code would be illegal. This would significantly inhibit the use of generics, since library writers would hesitate to migrate existing code.

这篇关于一般地覆盖Java中的方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆