2011-02-07 3 views
2

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

public interface I_Test 
{ 
    public String get(String key, Enum type); 
} 

и реализовать это следующим образом:

public class Test_1 implements I_Test 
{ 
    public String get(String key, Enum type) 
    { 
     Enum_1 t1 = (Enum_1)type; 

     switch(t1) 
     { 
      case NAME: 
       return "Garry"; 
      case DOB: 
       return "1966"; 
      default: 
       throw new IllegalArgumentException("Unkown type [" + type + "]"); 
     } 
    } 
} 

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

Я надеялся, что дженерик могут решить эту проблему, так что я сделал это:

public interface I_Test<T extends Enum> 
{ 
    public String get(String key, T type); 
} 

и это:

public class Test_1 implements I_Test<Enum_1> 
{ 
    public String get(String key, Enum_1 type) 
    { 
     switch(type) 
     { 
      case NAME: 
       return "Garry"; 
      case DOB: 
       return "1966"; 
      default: 
       throw new IllegalArgumentException("Unkown type [" + type + "]"); 
     } 
    } 
} 

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

I_Test<Enum_1> t1 = new Test_1(); 

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

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

+0

Я не совсем понимаю, что делает ваш интерфейс (что означает «обрабатывать различные типы запросов», в каком контексте?), Но это похоже на неправильное использование интерфейса - в основном из-за вашей реализации использует «переключатель» вместо полиморфизма. Похож на то, что ваша логика выше могла быть сделана гораздо проще с помощью «Карта » – davin

+0

Мне пришлось удалить конфиденциальные данные, должно было сделать лучше, - извините за путаницу. Я могу сказать, что get принимает данные и тип запроса. Тип запросов зависит от реализации: в настоящее время существует 4 поддерживаемых реализации и более 30 различных типов запросов, разбросанных по ним, где я работаю. – BigMac66

ответ

4

Точка дженериков заключается в том, чтобы ваш код был более надежным (в отношении безопасности типа). С помощью дженериков вы можете узнать о несовместимости типов во время компиляции, а не во время выполнения. Когда вы определили свой интерфейс как I_Test<T extends Enum>, вы в основном говорите, что вам нужен do, чтобы интерфейс был обобщен в соответствии с определенным типом. Вот почему Java дает вам предупреждение.

Вы получите такое же предупреждение, если вы сделали что-то подобное Map myMap = new HashMap<string>();.

В Java вы фактически указываете типы, и они не выводятся из того, что находится на RHS (если вы не делаете что-то вроде Integer i = 1, но это автобоксинг). Поскольку вы обобщили свой интерфейс, когда вы объявляете что-то с помощью этого интерфейса, вам нужно указать тип для использования (для обобщения).

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

So I_Test<Enum_1> фактически переведен на необработанный тип I_Test во время компиляции. Использование необработанного типа обычно считается плохой практикой (следовательно, «раздражающим предупреждением»). Компилятор говорит вам, что у него недостаточно информации для проверки типов, и поэтому он не может обеспечить безопасность типа (поскольку вы использовали необработанный тип).

Чтобы узнать больше о дженериков, посмотрите на следующее:

+0

Спасибо за ваш комментарий. Я действительно знаком с большей частью того, что вы сказали. Я пытаюсь найти разумный способ избежать предупреждения, не подавляющего его - как правило, я думаю, что предупреждения служат правильной цели и не любят подавлять их. Похоже, это может быть исключение из этого правила ... :) – BigMac66

+0

Если ваш интерфейс/класс использует дженерики, невозможно предотвратить это предупреждение. Вы * получите *, если используете сырой тип :). Единственный раз, когда вы должны игнорировать предупреждение, можно, если вы можете * гарантировать *, что тип * - это тип, который вы ожидаете. То есть, если это невозможно, для него может быть любой другой тип. –

+0

Ах, это моя проблема и почему я обратился к дженерикам. Я старший разработчик, и некоторые из менее опытных разработчиков смешивают вещи, которые не следует смешивать. Я понимаю, что они пытаются повторно использовать код, но они не проявляют осторожности. Хотя это не является верным решением для решения этой проблемы, я думаю, что это поможет в достаточном количестве случаев, чтобы стоить того, чтобы принять обобщения ... Еще раз спасибо за вашу помощь. – BigMac66

1

Дженерики является о компиляции предупреждений времени. Если вы не хотите их, не используйте их.

Сказав, что вы можете создавать различные, нетипичных подынтерфейсы, например:

public interface Enum_1_Test extends I_Test<Enum_1> { 
    ... 
} 

А потом объявить класс как

public class Test_1 implements Enum_1_Test 

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

1

Необработанный I_Test поддерживает любой тип перечисления в качестве аргумента, а реализация Test_1 поддерживает только ограниченное подмножество (Enum_1), это связано с тем, что Test_1 указан как реализация I_Test только для одного типа перечисления.

Вот пример, почему компилятор выдает предупреждение, следующий код компилируется, поскольку исходный тип I_Test принимает любое перечисление, однако, поскольку Test_1 поддерживает только Enum_1, он будет генерировать исключение класса.

enum MyEnum{A} 
I_Test t1 = new Test_1();//warning here 
t1.get("",MyEnum.A);//Exception at runtime, but compiles fine 

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

enum MyEnum{A} 
I_Test<Enum_1> t1 = new Test_1(); 
t1.get("",MyEnum.A);//Does not compile