有没有理由在Java中使用泛型?

时间:2014-12-29 13:17:31

标签: java generics

也许我忽略了这一点,但是来自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>

并获得一些类型的编译时类型检查?如果是这样,由于变量名称清楚地表明类型应该是什么(至少只要我使用合理的命名约定),它似乎是多余的。

我无法帮助,但我觉得我错过了一些东西......

6 个答案:

答案 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>();

在这里,只能添加字符串值