Force an unchecked call
Sometimes, when using Java reflection or some special storing operation into Object, you end up with unchecked warnings. I got used to it and when I can't do anything about it, I document why one call is unchecked and why it should be considered as safe.
But, for the first time, I've got an error about a unchecked call. This function :
public <K,V extends SomeClass & SomeOtherClass<K>> void doSomethingWithSomeMap (Map<K,V> map, V data);
I thought that calling it this way :
Map someMap = ...;
SomeClass someData = ...;
doSomethingWithSomeMap(someMap, someData);
开发者_如何学编程
would give me an unchecked call warning. Jikes does a warning, but javac gives me an error :
Error: <K,V>doSomethingWithSomeMap(java.util.Map<K,V>,V) in SomeClass cannot be applied to (java.util.Map,SomeClass)
Any way to force it to compile with a warning?
Thanks.
You already know that the problem is the type of someData
. Unfortunately Java does not currently allow you to use the intersection type SomeClass & SomeOtherClass
as the type for declaring a variable, nor as a cat target.
But there is a not-so-perfect way to do just this, by introducing an spurious type variable X extends SomeClass & SomeOtherClass
and then declaring X someData
.
This should be done on the method that reflectively produces values to be assigned to someData
. An unchecked cast (X)
will be necessary which is provably safe.
Overall, something like this:
public <X extends SomeClass & SomeOtherClass>
void doReflectionMagic() {
Map someMap = ...;
X someData = (X) ...;
doSomethingWithSomeMap(someMap, someData);
}
In what voodoo have you got yourself into :) ? From the question and comments I assumed that you are sure that you have objects that extend abstract class SomeClass
and also implement interface SomeOtherClass
. If this is the case I suggest an intermediate abstract class in the hierarchy that share these properties.
public abstract class Foo<K> extends SomeClass implements SomeOtherClass<K> {
...
}
That way you could simplify the static method signature to:
public <K,V extends Foo<K>> void doSomethingWithSomeMap (Map<K,V> map, V data);
If you do not want to change your current object hierarchy you can fool the compiler using another level of indirection with the adapter pattern.
"All problems in computer science can be solved by another level of indirection." -- 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);
}
This would print:
MyClass.method1
MyClass.method2(12)
Try to specify it explicitely:
//Type2 is subclass of (or implements) SomeClass
Map<Type1, Type2> someMap = ...;
SomeClass someData = ...;
<Type1, Type2>doSomethingWithSomeMap(someMap, someData);
You specify the second bound for V to extend SomeOtherClass. But I assume SomeClass does not implement SomeOtherClass (if it did, you wouldn't need multiple bounds). So someData does not conform to this bound, and hence compiler error. The variable someData needs to belong to a class which both extends SomeClass and implements SomeOtherClass.
精彩评论