我想创建一个引用使用接口的服务类型的类。该服务可以有不同的实现。不同的实现将处理不同类型的请求。在过去,我会定义一个类似这样的界面:
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 :(得分:4)
泛型的要点是确保您的代码更可靠(就类型安全而言)。使用泛型,您可以在编译时而不是运行时找到类型不兼容性。当您将接口定义为I_Test<T extends Enum>
时,您基本上是说做需要根据特定类型对接口进行通用化。这就是Java给你一个警告的原因。
如果你做了类似Map myMap = new HashMap<string>();
的事情,你会得到同样的警告。
在Java中,您实际上指定了类型,并且它们不是从RHS上的内容推断出来的(除非您执行Integer i = 1
之类的操作,但这是自动装箱)。由于您对接口进行了通用化,因此在使用该接口声明某些内容时,需要指定要使用的类型(进行泛化)。
当您实例化泛型类型时,编译器将使用称为“类型擦除”的东西来转换这些类型。这里,编译器删除与类型参数和类型参数关联的所有信息。 Java这样做是为了保持与Java之前编写的旧代码的兼容性。
因此在编译期间I_Test<Enum_1>
实际上已转换为原始类型I_Test
。使用原始类型通常被认为是不好的做法(因此,“烦人的警告”)。编译器告诉你它没有足够的信息来执行类型检查,因此无法确保类型安全(因为你使用了原始类型)。
要了解有关泛型的更多信息,请查看以下内容:
答案 1 :(得分:1)
泛型 关于编译时警告。如果您不想要它们,请不要使用它们。
话虽如此,您可以创建不同的非通用子接口,例如:
public interface Enum_1_Test extends I_Test<Enum_1> {
...
}
然后将您的班级声明为
public class Test_1 implements Enum_1_Test
但我不相信这是非常有用的。根据经验,如果你有一个适用于许多输入类型的实现,并且如果你想为每个输入类型单独实现,那么你想使用泛型。
答案 2 :(得分: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