泛型问题

时间:2013-03-08 12:23:33

标签: java generics

代码

  interface BaseIntr<T>{
      void saveSwiftMsg(Collection<String> headers) throws Exception;
  }

 class Impl implements BaseIntr{
       public void saveSwiftMsg(Collection<String> headers) throws Exception { }     
  }

已编辑版本的代码:

  interface BaseIntr<T>{
     T process(T t);
     void saveSwiftMsg(Collection<String> headers)      throws Exception;
  }

  class Impl implements BaseIntr{
     public void saveSwiftMsg(Collection<String> headers) throws Exception {    }
    @Override
    public Object process(Object t) {       return t;   }   
  }

工作环境

Java版本:1.7.0_04,供应商:Oracle Corporation

默认语言环境:en_IN,平台编码:Cp1252

操作系统名称:“windows 7”,版本:“6.1”,arch:“amd64”,系列:“windows”

java编译器抛出以下异常。但如果我删除&lt; T>从BaseIntr,它工作正常。

javac gen\GenericsTest.java
gen\GenericsTest.java:18: error: Impl is not abstract and does not override abstract     method saveSwiftMsg(Collection) in BaseIntr
 class Impl implements BaseIntr{
 ^
 gen\GenericsTest.java:20: error: name clash: saveSwiftMsg(Collection<String>) in Impl and saveSwiftMsg(Collection<String>) in BaseIntr have the same erasure, yet neither overrides the other
 public void saveSwiftMsg(Collection<String> headers) throws Exception {
                ^
2 errors

3 个答案:

答案 0 :(得分:3)

实现时,您的界面使用类型T进行参数化,您必须指定其类型:

class Impl implements BaseIntr<String>{
}

如果你想为String实现它。但是您可以将参数委托给实现类:

class Impl<T> implements BaseIntr<T>{
}

然后,您需要在实例化类时指定类型。

答案 1 :(得分:2)

如果使用泛型类型而未指定其类型参数(implements BaseIntr),则使用原始类型。这些是Java语言规范的defined,如下所示:

  

为了便于与非泛型遗留代码接口,可以使用参数化类型(第4.5节)的擦除(第4.6节)或者元素类型为的数组类型(第10.1节)的擦除作为类型。参数化类型。这种类型称为原始类型。

     

更准确地说,原始类型被定义为以下之一:

     
      
  • 通过获取泛型类型声明的名称而不带伴随类型参数列表而形成的引用类型。
  •   

  

未从其超类或超接口继承的原始类型C的构造函数(第8.8节),实例方法(第8.4节,第9.4节)或非静态字段(第8.3节)M的类型是原始的类型,对应于与C对应的泛型声明中其类型的擦除。

也就是说,继承的方法有签名

saveSwiftMsg(Collection headers) throws Exception 

要覆盖,覆盖方法必须与继承的方法具有相同的签名。它没有,导致编译错误。

我强烈建议只将原始类型用于其预期目的(与遗留代码接口),并启用(并修复)相应的编译器警告。

就此而言,规范也是如此:

  

原始类型的使用仅允许作为遗留代码兼容性的让步。在将泛型引入Java编程语言之后编写的代码中使用原始类型是非常不鼓励的。未来版本的Java编程语言可能会禁止使用原始类型。

     

为了确保始终标记可能违反键入规则的行为,对原始类型成员的某些访问将导致编译时未经检查的警告。访问原始类型的成员或构造函数时,编译时未经检查的警告的规则如下:

     
      
  • 在对字段的赋值中:如果左侧操作数的类型是原始类型,则如果擦除更改字段的类型,则会发生编译时未经检查的警告。

  •   
  • 在调用方法或构造函数时:如果要搜索的类或接口的类型(第15.12.1节)是原始类型,则如果擦除更改任何一个,则会发生编译时未经检查的警告方法或构造函数的形式参数类型。

  •   

您应该注意编译器警告,并指定您实现的接口的类型参数。

答案 2 :(得分:1)

你需要在子类中指定

class Impl implements BaseIntr<T>{
       public void saveSwiftMsg(Collection<String> headers) throws Exception { }     
  }

实际上你需要指定类型。这很好像

interface BaseIntr<String>{
      void saveSwiftMsg(Collection<String> headers) throws Exception;
  }

 class Impl implements BaseIntr<String>{
           public void saveSwiftMsg(Collection<String> headers) throws Exception { }     
      }