Как я должен приводить для Java универсальный с несколькими границами? - PullRequest
17 голосов
/ 25 ноября 2008

Можно ли привести объект в Java к комбинированному универсальному типу?

У меня есть такой метод:

public static <T extends Foo & Bar> void doSomething(T object) {
    //do stuff
}

Вызов этого метода не проблема, если у меня есть класс, который реализует оба интерфейса (Foo & Bar).

Проблема в том, что когда мне нужно вызвать этот метод, объект, который мне нужно передать, принимается как java.lang.Object, и мне нужно привести его, чтобы сделать компилятор счастливым. Но я не могу понять, как сделать этот актерский состав.

редактирование:

Проблема заключается в такой функции:

public void problemFunction (Object o) {
  if ( o instanceof Foo && o instanceof Bar) {
      doSomething((Problematic cast) o);
  }
}

}

Ответы [ 5 ]

19 голосов
/ 10 октября 2015

Java 8 предоставляет возможность приведения с дополнительными границами . Вы можете разыграть Object как class с несколькими interfaces (или просто с несколькими interfaces).

Итак, это:

doSomething((Problematic cast) o);

просто превращается в это:

doSomething((Foo & Bar) o);
12 голосов
/ 25 ноября 2008

К сожалению, нет юридического актера, который вы можете сделать, чтобы удовлетворить эту ситуацию. Для реализации всех необходимых вам интерфейсов в качестве границ должен быть известен один тип, чтобы вы могли использовать его. Это может быть тип, который вы создаете для этой цели, или какой-то существующий тип.

interface Baz extends Foo, Bar { }

public void caller(Object w) {
  doSomething((Baz) w);
}

Если известны другие типы, такие как Baz, для определения границ, вы можете проверить эти типы и иметь в вызывающей стороне ветвь, которая вызывает doSomething с приведением к этим типам. Это не красиво.

Вы также можете использовать делегирование, создав собственный класс Baz, который соответствует границам, требуемым для doSomething. Затем оберните объект, который вам передан, в экземпляр вашего Baz класса и передайте эту оболочку doSomething.

private static class FooBarAdapter implements Foo, Bar {
  private final Object adaptee;
  FooBarAdapter(Object o) {
    adaptee = (Foo) (Bar) o;
  }
  public int flip() { return ((Foo) adaptee).flip(); }
  public void flop(int x) { ((Foo) adaptee).flop(x); }
  public void blort() { ((Bar) adaptee).blort(); }
}

public void problemFunction (Object o) {
  doSomething(new FooBarAdapter(o));
}
7 голосов
/ 25 ноября 2008
public static <T extends Foo & Bar> void doSomething(T object)

Похоже, это означает, что вы выполняете более одной операции с данным объектом.

Я бы сказал, что если требуемые операции, которые вы выполняете над объектом, достаточно различимы для разделения между интерфейсами, то они достаточно различимы, чтобы заслуживать своих собственных методов.

Вполне вероятно, что вы могли бы реструктурировать этот код для вызова отдельных методов для выполнения желаемой операции. Это может в конечном итоге сделать всю операцию более понятной с точки зрения клиента.

Вместо:

public void problemFunction (Object o) {
  if (o instanceof Foo && o instanceof Bar) {
      doSomething((Problematic cast) o);
  }
}

Становится:

public void problemFunction(Object o) {
  if (o instanceof Foo && o instanceof Bar) {
      fooifySomething((Foo) o);
      baratizeSomething((Bar) o);
  }
}
5 голосов
/ 02 декабря 2014

Можно "преобразовать" к типу объединения ужасными средствами кодирования типа объединения в параметр типа метода; для вашего примера вы можете написать

private <Q extends Foo & Bar> Q upcast(final Object in) {
    return (Q) in;
}

// ... elsewhere...

if (myObject instanceof Foo && myObject instanceof Bar) {
    doSomething(upcast(myObject));
}
0 голосов
/ 25 ноября 2008

В качестве обходного пути вы можете определить другой интерфейс FooBar, который расширяет Foo и Bar, и ваш класс реализует это. Он даже не должен быть интерфейсом верхнего уровня - вы можете объявить его закрытым, если не хотите загромождать или модифицировать оставшуюся часть кода:

private interface FooBar extends Foo, Bar {}
public void problemFunction (Object o) {
  if ( o instanceof Foo && o instanceof Bar) {
      doSomething((FooBar) o);
  }
}
...