强制进行未经检查的呼叫

时间:2010-03-24 20:28:09

标签: java generics javac

有时,当使用Java反射或对Object进行一些特殊的存储操作时,最终会出现未经检查的警告。我已经习惯了,当我无法做任何事情时,我会记录为什么一个电话未被检查以及为什么它应该被认为是安全的。

但是,这是第一次,我有一个关于未经检查的电话的错误。这个功能:

public <K,V extends SomeClass & SomeOtherClass<K>> void doSomethingWithSomeMap (Map<K,V> map, V data);

我以为这样称呼它:

Map someMap = ...;
SomeClass someData = ...;
doSomethingWithSomeMap(someMap, someData);

会给我一个未经检查的电话警告。 Jikes发出了警告,但是javac给了我一个错误:

Error: <K,V>doSomethingWithSomeMap(java.util.Map<K,V>,V) in SomeClass cannot be applied to (java.util.Map,SomeClass)

是否有任何方法强制它以警告编译?

感谢。

4 个答案:

答案 0 :(得分:1)

你有什么伏都教你自己进入:)? 从问题和评论中我假设您确定您拥有扩展抽象类SomeClass的对象并实现接口SomeOtherClass如果是这种情况,我建议使用中间体层次结构中共享这些属性的抽象类。

public abstract class Foo<K> extends SomeClass implements SomeOtherClass<K> {
  ...
}

这样你就可以将静态方法签名简化为:

public <K,V extends Foo<K>> void doSomethingWithSomeMap (Map<K,V> map, V data);

如果您不想更改当前的对象层次结构,可以使用adapter pattern的另一个间接层来欺骗编译器。

  

“计算机科学的所有问题都可以   另一个层次的解决方案   间接。“ - David Wheeler

public abstract class SomeClass {    
  public abstract void method1();
}

public interface SomeOtherClass<K> {
  void method2(K value);
}

public class MyClass extends SomeClass implements SomeOtherClass<Integer> {
  @Override
  public void method1() {
    System.out.println("MyClass.method1");
  }

  @Override
  public void method2(Integer value) {
    System.out.println("MyClass.method2(" + value + ")");
  }
}

public class Indirection<K> extends SomeClass implements SomeOtherClass<K> {
  private final Object objectValue;

  public Indirection(final Object value) {
    this.objectValue = value;
  }

  @Override
  public void method1() {
    ((SomeClass) objectValue).method1();
  }

  @Override
  public void method2(K value) {
    @SuppressWarnings("unchecked")
    SomeOtherClass<K> delegate = ((SomeOtherClass<K>) objectValue);

    delegate.method2(value);
  }
}

public static void main(String[] args) {
  Map someMap = new HashMap<Integer, MyClass>();
  SomeClass someData = new MyClass();
  Indirection a = new Indirection(someData);
  doSomethingWithSomeMap(someMap, a, 12);
}

public static <K,V extends SomeClass & SomeOtherClass<K>>
void doSomethingWithSomeMap (Map<K,V> map, V data, K value) {
  data.method1();
  data.method2(value);
}

这将打印:

  

MyClass.method1
  MyClass.method2(12)

答案 1 :(得分:1)

您已经知道问题是someData的类型。遗憾的是,Java目前不允许您使用交集类型SomeClass & SomeOtherClass作为声明变量的类型,也不能使用cat目标。

但是,通过引入虚假类型变量X extends SomeClass & SomeOtherClass然后声明X someData,有一种不那么完美的方法可以做到这一点。

这应该在反射生成要分配给someData的值的方法上完成。未经检查的演员(X)将是必要的,这是可证明安全的。

总的来说,这样的事情:

public <X extends SomeClass & SomeOtherClass>
void doReflectionMagic() {
    Map someMap = ...;
    X someData = (X) ...;
    doSomethingWithSomeMap(someMap, someData);
}

答案 2 :(得分:0)

尝试明确指定:

//Type2 is subclass of (or implements) SomeClass
Map<Type1, Type2> someMap = ...;
SomeClass someData = ...;
<Type1, Type2>doSomethingWithSomeMap(someMap, someData);

答案 3 :(得分:0)

指定V的第二个边界以扩展SomeOtherClass。但我假设SomeClass没有实现SomeOtherClass(如果确实如此,你不需要多个边界)。因此someData不符合此绑定,因此编译器错误。变量some​​Data需要属于一个类,它既扩展了SomeClass又实现了SomeOtherClass。