也许我忽略了这一点,但是来自C#背景,我看不出有任何理由使用Java的泛型......
在C#中,我有一个方法,它接受一个字符串并将其反序列化为一个对象......
public static Deserialize<T>(string source) {
// Use reflection to examine T and determine
// which properties I should be reading from
// the string. Create an instance of T,
// populate the properties and return it
}
我可以打电话如下:x.Deserialize<AnyClass>("String representation of AnyClass");
类型擦除似乎使Java无法实现这一点?
我对泛型的下一个最常见的用法是存储事物列表,但由于我不能List<int>
并且必须使用List<Integer>
,所以当我发现它似乎毫无意义的顶部装箱/拆箱可以使用int[]
。
所以...是泛型的唯一真正用途,比如
List<MyClass> MyClassList = new List<MyClass>
并获得一些类型的编译时类型检查?如果是这样,由于变量名称清楚地表明类型应该是什么(至少只要我使用合理的命名约定),它似乎是多余的。
我无法帮助,但我觉得我错过了一些东西......
答案 0 :(得分:9)
好吧,如果你不使用泛型,你每次都可以投。你必须:
// if raw List
MyClass c = (MyClass) myClassList.get(0);
// if List<MyClass>
MyClass c = myClassList.get(0);
例如。
是的,泛型在运行时被删除,是的,它们只是在编译时强制执行类型安全;但是在使用边界时仍然存在运行时类型擦除。例如:
public <E extends RuntimeException> E get(final Class<E> c,
final Throwable t)
{
try {
return (E) getHandle(c).invokeExact(t);
} catch (Error | RuntimeException e) {
throw e;
} catch (Throwable oops) {
final RuntimeException exception = new IllegalStateException(oops);
exception.addSuppressed(t);
throw exception;
}
}
E
这里有一个运行时类型擦除;它extends RuntimeException
。因此,演员阵容为RuntimeException
,而不是Object
。
有关运行时类型擦除的另一个有趣示例,请参阅javadoc of Collections.max()
(提示:为什么定义T extends Object & Comparable<? super T>
而不是T extends Comparable<? super T>
?)
答案 1 :(得分:2)
来自Java Docs:
简而言之,泛型使类型(类和接口)在定义类,接口和方法时成为参数。与方法声明中使用的更熟悉的形式参数非常相似,类型参数提供了一种使用不同输入重用相同代码的方法。不同之处在于形式参数的输入是值,而类型参数的输入是类型。
使用泛型的代码比非泛型代码有许多好处:
在编译时进行更强大的类型检查。 Java编译器将强类型检查应用于通用代码,并在代码违反类型安全性时发出错误。修复编译时错误比修复运行时错误更容易,这很难找到。
消除演员阵容。 以下没有泛型的代码片段需要强制转换:
List list = new ArrayList();
list.add("hello");
String s = (String) list.get(0);
当重写使用泛型时,代码不需要转换:
List<String> list = new ArrayList<String>();
list.add("hello");
String s = list.get(0); // no cast
使程序员能够实现通用算法。 通过使用泛型,程序员可以实现通用算法,这些算法可以处理不同类型的集合,可以自定义,并且类型安全且易于阅读。
答案 2 :(得分:1)
通用类型仅在编译时检查,但它可以帮助避免错误。
答案 3 :(得分:1)
List<MyClass> MyClassList = new ArrayList<MyClass>();
不等同于:
List MyClassList = new ArrayList();
第二个将在Object类型上工作,你将被允许做一些像MyClassList.add这样的蠢事(new Integer(0));
这是泛型或C ++模板的主要优势之一。编译时间检查,验证您的应用程序不会执行任何未定义的行为 - 如上例所示。
答案 4 :(得分:1)
您的Deserialize
方法在Java中并非不可能。您只需显式传递Class
对象,因为无法在运行时从类型参数T
确定它。
public static <T> T deserialize(Class<T> clazz, String source) {
// Use reflection to examine clazz and determine
// which properties I should be reading from
// the String. Create an instance of T
// (which you can do using clazz.newInstance()),
// populate the properties and return it
}
可以使用deserialize(AnyClass.class, "String representation of AnyClass")
调用它。
答案 5 :(得分:0)
List list = new ArrayList();
list.add("car");
list.add("cycle");
list.add(12);
列表可以包含任何对象,可以是String,Integer或double,Employee等
可能会导致类型安全问题并在编译时停止运行时错误。
List<String> list = new ArrayList<String>();
在这里,只能添加字符串值