Принудительный необязательный звонок - PullRequest
2 голосов
/ 24 марта 2010

Иногда при использовании отражения 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 ]

1 голос
/ 01 октября 2012

Вы уже знаете, что проблема типа 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);
}
1 голос
/ 27 марта 2010

В какое вуду вы попали :)? Из вопроса и комментариев я предположил, что вы уверены, что у вас есть объекты, которые расширяют абстрактный класс 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);

Если вы не хотите изменять текущую иерархию объектов, вы можете обмануть компилятор, используя другой уровень косвенности с шаблоном адаптера *1012*.

«Все проблемы в информатике могут быть решен другим уровнем косвенность. "- Дэвид Уилер

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)

0 голосов
/ 25 марта 2010

Вы указываете вторую границу для V, чтобы расширить SomeOtherClass. Но я предполагаю, что SomeClass не реализует SomeOtherClass (если бы он это сделал, вам не понадобилось бы несколько границ). Таким образом, someData не соответствует этой границе, и, следовательно, ошибка компилятора. Переменная someData должна принадлежать классу, который расширяет SomeClass и реализует SomeOtherClass.

0 голосов
/ 25 марта 2010

Попробуйте указать это явно:

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