当覆盖泛型类的方法时,名称冲突 [英] Name clash when overriding method of generic class

查看:903
本文介绍了当覆盖泛型类的方法时,名称冲突的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  import java.util。* 

我试图理解名称冲突错误。 ;
import javax.swing。*;

class Foo< R扩展数字> {
public void doSomething(Number n,Map< String,JComponent> comps){
}
}

class Bar Foo {
public void { doSomething(Number n,Map< String,JComponent> comps){
}
}

错误消息:
$ b


error:name clash: doSomething(Number,Map< String,JComponent>) Bar
doSomething(Number,Map< String,JComponent>) > in Foo 具有相同的
擦除,但不会覆盖其他

我知道我可以通过从 Foo 中删除​​通用类型,或者通过更改 Bar 声明到 class Bar扩展Foo< Integer> ;我想知道的是为什么这个错误发生在特定情况下,但是如果我从每个方法中删除 comps 参数就会消失。我已经阅读了一些关于输入删除的内容,但在我看来,方法应该使用或不使用泛型相同的擦除,因此在任何情况下都是有效的覆盖。 (请注意,我甚至没有在任何地方使用泛型参数,这就是为什么我很惊讶。)



我知道我已经添加了泛型类型之前的父类,但只有警告的子类,而不是错误。任何人都可以解释这种情况?

解决方案

Luiggi正确的评论。这是原始类型


类的超类型可能是原始类型。对于
类的成员访问被视为正常,并且对于超类型的成员访问权被视为原始类型
。在类的构造函数中,对
super的调用被视为原始类型的方法调用。


这适用于调用一个超类型方法,而且在重写时也是如此。



以下面的例子为例:

  class Bar extends Foo {
public Bar(){
doSomething(1,new HashMap< Number,String>());






$ b你会注意到它会被编译, code> HashMap< Number,String>
不是可分配给 Map< String,JComponent> 的类型。
$ b


构造函数的类型(§8.8),实例方法(§8.4,§9.4)或
非静态从
超类或超接口继承的原始类型 C 的字段(第8.3节)是与
对应的原始类型,它的类型与 C


(注意 C 在我们的例子中是 Bar 。)



尝试覆盖方法时会发生同样的事情。当试图覆盖 Foo#doSomething(..)方法时,您的 Bar 类实际上将它声明为

  public void doSomething(Number n,Map comps){
}

换句话说,类型参数的每种用法都被清除。所以试图声明方法

  public void doSomething(Number n,Map< String,JComponent> comps){
在子类型 Bar 中的}

实际上是一个试图超载,而不是压倒一切。由于类型擦除,这失败了。可以用 @Override 验证的适当覆盖是

  public void doSomething(Number n,Map comps){
}

p>


I'm trying to understand the name clash error I get with the following code:

import java.util.*;
import javax.swing.*;

class Foo<R extends Number> {
    public void doSomething(Number n, Map<String, JComponent> comps) {
    }
}

class Bar extends Foo {
    public void doSomething(Number n, Map<String, JComponent> comps) {
    }
}

Error message:

error: name clash: doSomething(Number,Map<String,JComponent>) in Bar and doSomething(Number,Map<String,JComponent>) in Foo have the same erasure, yet neither overrides the other

I know I can fix it by either remove the generic type from Foo, or by changing the Bar declaration to class Bar extends Foo<Integer>; what I want to know is why this error occurs in the specific case, but goes away if I remove the comps parameter from each method. I've done some reading about type erasure, but it still appears to me that both methods should have the same erasure with or without generics, and therefore be a valid override in either case. (Note that I haven't even used the generic parameter anywhere yet, which is why I'm so surprised.)

I know that I've added generic types to parent classes before but only got warnings about the subclasses, not errors. Can anyone explain this scenario?

解决方案

Luiggi is right in the comments. This is a consequence of raw types.

The supertype of a class may be a raw type. Member accesses for the class are treated as normal, and member accesses for the supertype are treated as for raw types. In the constructor of the class, calls to super are treated as method calls on a raw type.

This applies when invoking a supertype method, but also when overriding one.

Take for example, the following

class Bar extends Foo {
    public Bar() {
        doSomething(1, new HashMap<Number, String>());
    }
}

You'll notice that it compiles, even though HashMap<Number, String> is not a type that is assignable to Map<String, JComponent>.

The type of a constructor (§8.8), instance method (§8.4, §9.4), or non-static field (§8.3) of a raw type C that is not inherited from its superclasses or superinterfaces is the raw type that corresponds to the erasure of its type in the generic declaration corresponding to C.

(Note that C in our case is Bar.)

And the same thing happens when trying to override a method. When trying to override the Foo#doSomething(..) method, your Bar class is actually seeing it declared as

public void doSomething(Number n, Map comps) {
}

In other words, every usage of type parameters is erased. So attempting to declare the method

public void doSomething(Number n, Map<String, JComponent> comps) {
}

in the subtype Bar is actually an attempt at overloading, not overriding. And this fails because of type erasure. The proper override, which you can verify with @Override, is

public void doSomething(Number n, Map comps) {
}

Further reading:

这篇关于当覆盖泛型类的方法时,名称冲突的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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