2013-12-13 3 views
0

У меня есть простой интерфейс:Статическая реализация общий интерфейс

interface Predicate<T> { 

boolean accepts(T in); 

} 

Теперь я хотел бы предоставить н формы:

interface Predicate<T> { 

public static Predicate<T> ALL = new Predicate<T>(){ ... } 

boolean accepts(T in); 

} 

Это не является законным в форме, представленной выше. Есть ли способ предоставить общую реализацию, которая будет набираться, то есть в нескольких контекстах, я мог бы сказать Predicate.ALL, немного как Collections.EMPTY_SET?

UPDATE: Я имел в виду интерфейс ...

+0

просто удалите фигурные скобки – Blub

+0

В заголовке нет необходимости добавлять основной тег. –

+0

SOrry guys, я имею в виду интерфейс ... – Bober02

ответ

3

Вы можете использовать определение типа так же, как Collections.emptySet() (обратите внимание, что Collections.EMPTY_SET не использует дженерики).

Collections От:

public static final Set EMPTY_SET = new EmptySet(); 

public static final <T> Set<T> emptySet() { 
    return (Set<T>) EMPTY_SET; 
} 

Вы могли бы имитировать это так:

public static Predicate ALL = new Predicate(){ ... } 

public static final <T> Predicate<T> all() { 
    return (Predicate<T>) ALL; 
} 
+0

+1 И вы можете избежать необработанных типов, выполняя 'Predicate ALL = new Predicate ()' и т. Д. Также обязательно используйте '@SuppressWarnings (" unchecked ")' с объяснением, например «безопасный контравариантный бросок». –

1

вам нужно только заменить <T> с чем-то значимым в декларации ALL. Или удалить вообще - примечание, Collections.EMPTY_SET имеет тип Set, а не Set<T>.

1

Для начала ваш простой класс недействителен, так как accepts не имеет реализации и не является абстрактным. Предположим, вы хотели сделать его абстрактным, так что фактические предикаты являются производными классами, которые переопределяют его. Тогда предикат ALL - это тот, который всегда возвращает true. Но вы не можете сделать это статическим полем, потому что статические поля не могут ссылаться на параметр типа.

public abstract class Predicate<T> { 
    public abstract boolean accepts(T in); 

    public static <T> Predicate<T> all() { 
    return new Predicate<T> { boolean accepts(T in) { return true; } }; 
    } 
} 
0

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

abstract class Predicate<T> { 

    abstract boolean accepts(T in); 

} 

Если после этого вы хотите, чтобы обеспечить Многоцелевой «принимать любые» предикат вы можете сделать это следующим образом:

public static Predicate ALL = new Predicate(){ 
    @Override 
    boolean accepts(Object in) { 
     return true; 
    } 
}; 

@SuppressWarnings("unchecked") 
static final <T> Predicate<T> all(){ return (Predicate<T>)ALL;} 

Это имитирует способ, которым Collections.EMPTY_SET и Collections.emptySet() работа ,

Обратите внимание, что Collections.EMPTY_SET (и Predicate.ALL) не являются безопасными по типу, но Collections.emptySet() (и Predicate.all()) выдает тип, которому они назначены.

1

Есть два способа реализации ALL предиката:

public interface Predicate<T> { 
    public static final Predicate<Object> ALL = new Predicate<Object> { 
     @Override public boolean accepts(Object in) { return true; } 
    } 
    boolean accepts(T in); 
} 

Вы объявляете поле конкретного класса (константа) здесь, так что вы должны использовать конкретную замену переменного типа T. Как вы не интересующийся типом, вы используете супертип всех объектов: java.lang.Object.

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

public class PredicateTester { 
    public static void main(String[] args) { 
     test1(Predicate.ALL, "some string"); // compiler error 
     test2(Predicate.ALL, "some string"); 
    } 
    public static void test1(Predicate<String> pred, String in) { 
     System.out.println(pred.accepts(in) ? "pass" : "fail"); 
    } 
    public static void test2(Predicate<? super String> pred, String in) { 
     System.out.println(pred.accepts(in) ? "pass" : "fail"); 
    } 
} 

Хотя test1 и test2 являются допустимыми методами (и компилировать штраф), вызов метода test1 не будет компилироваться. Проще говоря: A Predicate < Объект > не является предикатом <String>.

Вывод: вы должны помнить, что PECS (продюсер продлевает, потребительский супер) при разработке ваших методов, которые будут использовать предикат в качестве аргумента.

Другой вариант просто не обеспечивает тип вообще:

public interface Predicate<T> { 
    @SuppressWarnings("rawtypes") 
    public static final Predicate ALL = new Predicate { 
     @Override public boolean accepts(Object in) { return true; } 
    } 
    boolean accepts(T in); 
} 

С этой реализацией упомянутым выше класс PredicateTester компилирует просто отлично. Итак, это путь.

+0

«Итак, это путь». Я не согласен. Я предпочитаю первый путь. «Predicate» - это потребитель, который означает, что любой, кто использует этот тип, всегда должен использовать «Predicate . Нет причин для использования иначе. – newacct

Смежные вопросы