2015-03-05 2 views
4

Если у меня есть интерфейс с универсальным методом, как следующее:Java Generics: переопределение общих методов, подстановочные знаки?

public interface Thing { 
    void <T extends Comparable<? super T>> doSomething(List<T> objects); 
} 

мне нужно что некрасиво общий typespec в некоторых местах, но большинство реализаций фактически не нужно:

public class ICareAboutSortingThing implements Thing { 
    @Override 
    public void <T extends Comparable<? super T>> doSomething(List<T> objects) { ... } 
} 

public class IDontCareAboutSortingThingx100 implements Thing { 
    @Override 
    public void <T extends Comparable<? super T>> doSomething(List<T> objects) { ... } 
} 

Что Я хотел бы написать что-то вроде:

public class IDontCareAboutSortingThingx100 implements Thing { 
    @Override 
    public void <?> doSomething(List<?> objects) { ... } 
} 

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

public class IDontCareAboutSortingThingx100 implements Thing { 
    @Override 
    public void <T> doSomething(List<T> objects) { ... } 
} 

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

ответ

1

По сути, вы просите контравариантен параметры метода, например, не-родовой пример выглядит следующим образом:

interface I { 
    void m(String s); 
} 

class C implements I { 
    @Override 
    public void m(Object o) {} 
} 

void(Object) является подсигнатурой void(String) потому что расширяющее преобразование всегда в порядке. Java не имеет этого.

Для дженериков, вы может переопределить общий метод быть не родовое:

class NotGeneric implements Thing { 
    @Override 
    public void doSomething(List rawList) {} 
} 

Но вы в принципе не должны это делать. Вы получите raw type warnings, и вы должны их послушать. Он доступен для обратной совместимости.

Если бы это был я, я бы просто повторил уродливую общую подпись, потому что я не думаю, что это все так уродливо.

Что еще вы могли бы сделать, как

interface NonGenericThing extends Thing { 
    @Override 
    default <T extends Comparable<? super T>> 
    void doSomething(List<T> list) { 
     doSomethingImpl(list); 
    } 
    void doSomethingImpl(List<?> list); 
} 

И тогда вы реализуете NonGenericThing вместо и переопределить doSomethingImpl. (До Java 8, NonGenericThing должен быть абстрактным классом.)

Конечно, это может быть невозможно, если Thing на самом деле большой интерфейс. Вы также можете объявить Thing таким образом, если это уместно.

+0

Спасибо, похоже на заключение и решение, к которому я пришел. К сожалению, я привязан к Java 7, но в итоге я заменил интерфейс для класса, который показал обе точки переопределения, причем один делегировал другому по умолчанию. Я мог бы поклясться, что Java поддерживает расширяющиеся типы аргументов при переопределении, но я предполагаю, что я фактически не пробовал в последнее время: стр. Немного постыдно; для неосновного случая я могу понять это как оптимизацию для поиска/привязки подписи метода, но тип erasure (kind) делает это несущественным. Полагаю, что это непротиворечиво: /. – user508633

+0

+1 на каких-либо сырых типах; Я могу понять, что использование кода private-scope в очень контролируемых обстоятельствах, если использование, как известно, безопасно, но иногда они появляются и в публичных интерфейсах, и это заставляет меня (и мою IDE) кричать. Еще хуже, но это 'public ThingProducingTs getThing (String)', что заставляет мои глаза ослеплять. – user508633

+0

Ну, общие типы должны быть объявлены каким-то образом. Java более точная, чем некоторые другие языки (* cough * C++). – Radiodef

4

Не совсем уверен, куда вы пытаетесь добраться, но не могли ли вы инкапсулировать ограничения в отдельном классе?

public class It<T extends Comparable<? super T>> { 

    public List<T> them; 
} 

public interface Thing { 

    void doSomething(It<String> them); 
} 
+0

Не уверен, что это отвечает на мой вопрос, но отвечает на соответствующий вопрос: как получить подстановочный шаблон, сопоставимый с самим собой (а именно 'It ').Я тоже использовал этот трюк, это очень полезно, несмотря на раздувание файлов лишних пустых интерфейсов. – user508633

0

Вы можете вставлять информацию о типе в классе:

public class IDontCareAboutSortingThingx100<T extends Comparable<? super T>> implements Thing<T> { 

    @Override 
    public void doSomething(List<T> objects) { 
    } 
} 
+1

Извините; на самом деле существует потребность в том, чтобы сам метод был общим, поскольку тот же экземпляр будет использоваться для нескольких разных параметров для 'T'. (На интерфейсе также есть и другие методы, о которых я не могу укоротить.) – user508633

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