Можете ли вы требовать несколько типов одновременно? - PullRequest
3 голосов
/ 13 января 2009

В основном я хочу сделать это:

public interface A {
    void a();
}
public interface B {
    void b();
}
public class SomeClass {
    public SomeClass(<A&B> e) { // Note the type here
        e.a();
        e.b();
    }
}

То, что я сделал в комментариях, явно незаконно. Я знаю, что могу просто требовать, чтобы переданный объект реализовывал интерфейс A или интерфейс B, но есть ли способ сделать и то и другое?

Я предполагаю, что есть обходные пути (например, требование, чтобы параметр был типа A, а затем проверил, является ли он также экземпляром B), но в этом случае компилятор не получает помощи. Вы знаете какой-нибудь способ сделать это? Или, возможно, более разумный обходной путь ...

Ответы [ 5 ]

16 голосов
/ 13 января 2009

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

  public <T extends CharSequence & Appendable> void someMethod(T param) {
    ...
  }
3 голосов
/ 13 января 2009

Ну, есть нотация <T extends A & B> f(T ab), но вы должны отдавать предпочтение композиции, а не наследованию. Вам не нужно ничего расширять. Просто создайте тип, который является совместным объединением (продукт) обоих типов A и B, следующим образом:

public abstract class P2<A, B> {
  public A _1();
  public B _2();
}

Иногда называется продуктом-2 или типом "пара". Вы можете создать удобный конструктор для них:

public final class P {
  private P() {}
  public static <A, B> P2 p(final A a, final B b) {
    return new P2<A, B>() {
      public A _1() {
        return a;
      }
      public B _2() {
        return b;
      }
    }
  }
}

Обратите внимание, что вы можете использовать один и тот же объект для обоих аргументов, если A и B являются интерфейсами и ваш объект реализует оба из них:

P2<A, B> both = P.p(o, o);

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

Вы найдете этот тип, а также продукты до 8 типов, включенные в библиотеку Functional Java . Также существует тип с именем Either<A, B>, представляющий собой несвязное объединение (сумма) двух типов, так что он содержит значение, имеющее тип A или B (или оба).

3 голосов
/ 13 января 2009

В зависимости от дизайна вы можете выполнить одно из следующих действий:

  1. Сделать A: B или B: A.
  2. Сделать интерфейс C: A, B.

В любом случае вы захотите заключить контракт, включающий как a (), так и b ().

1 голос
/ 13 января 2009

Просто стрельба в темноте, я не знаю, правильный ли это синтаксис, т. Е. Если вам нужно переопределить методы в C, но как насчет этого:

public interface A {
    void a();
}
public interface B {
    void b();
}

public interface C extends A, B{}

public class SomeClass{
    public SomeClass(C e) { // Note the type here
      e.a();
      e.b();
    }

}
0 голосов
/ 13 января 2009

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

public void foo(A a, B b) {
    ....
}

Это не так сложно, поверь мне.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...