3

据我所知,泛型仅在编译时有用。

因此可以声明:

private Set set = new HashSet<String>();

然后,在这个字符串哈希集中,将狗或任何东西添加到该集合中,没有任何问题,因为在运行时没有像数组 (ArrayStoreException...) 那样的任何检查(但是当你使用它时,你可能会遇到类转换之类的问题放...

所以我想说的是,我们通常这样实例化泛型集合:

Set<String> set = new HashSet<String>();

我的问题是,为什么我们要放置 HashSet 的类型,因为只有变量引用的类型才是真正重要的(我认为)。

我的意思是,我们可以简单地写:

Set<String> set = new HashSet();

它的工作原理完全相同吗?那么为什么我们通常在实例化的时候写类型呢?(这不是强制性的)


编辑

我知道用于类型推断的“钻石运算符”,但为什么我们甚至需要它!!!因为类型推断已经开始工作了!

以下代码:

            Set<String> set = new HashSet();
            set.add("Test add a string 1");
            set.add("Test add a string 2");
            for ( String s : set ) {
                    System.out.println(s);
            }

产生输出:

测试添加字符串 1 测试添加字符串 2

自己测试 http://ideone.com/vuiCE

因此,现在您将类型推断作为 Java7 的一项功能进行讨论,但它已经对我有用了……

使用 java7 我将不得不更换我的

            Set<String> set = new HashSet();

经过

            Set<String> set = new HashSet<>();

做完全相同的事情仍然需要 2 个额外的字符,不是吗?(除非泛型不仅是 Java7 的编译时间?我不知道)

4

5 回答 5

4

它的工作原理完全相同吗?

在运行时:的。

在编译时:

您的代码会将包含任意对象的集合分配给存储包含错误字符串的集合的变量,并且类型检查器将不赞成。

当您编写时,new HashSet()您使用的是原始类型。我指的是这个问题关于它的含义,以及为什么应该避免它:


一般来说,你可以这样争论:

Set<String> set = new HashSet();

不远

HashSet tmp = new HashSet();
...
Set<String> set = tmp;

反过来又不远

HashSet tmp = new HashSet();
tmp.add(7);
...
Set<String> set = tmp;

仍然可以编译,但是出于一千个原因是不好的:)


Java 7 允许您编写

Set<String> set = new HashSet<>();

但是,它告诉编译器推断<...之间的类型>

关于“钻石运算符”的文档:

于 2011-11-04T14:06:42.597 回答
3

您最后的建议是类型推断,并且已通过所谓的菱形运算符在 Java 7 中引入:

Set<String> set = new HashSet<>();

所以是的,那可能从一开始就存在。但这是 Java,通常需要几十年才能获得批准的新语言功能(<--有点夸张)

于 2011-11-04T14:05:59.460 回答
1

尽管 Java 当前删除了泛型类型信息,但他们在设计语言和库时非常小心,以便将来可以添加回完整的泛型类型信息(所谓的具体化)。任何正确编写的通用代码(即没有任何 javac 警告)都将在这种语言更改后继续存在。在您的示例中,钻石版本是面向未来的;原始版本不是 - 当然它仍然必须编译,但它会在运行时抛出类型转换异常。

然而,这种未来的兼容性完全是一种幻想。擦除将永远与我们同在。如果引入完全具体化,可以肯定地说几乎所有非平凡的泛型代码都会中断,因为每个人都在编写不正确的泛型代码。

这不是我们的错。Java 迫使我们这样做。它给了我们胡说八道的擦除,我们别无选择,只能绕过它来实现一些东西。我们的代码完全依赖于擦除的详细知识。

JDK是最有罪的。JDK API 是经过精心设计的,可以经受住具体化;但是实现取决于擦除。如果 Java 增加了具体化,这些 JDK 代码必须重写。如果 Java 团队责怪我们编写了错误的代码,而他们必须自己做同样的事情,那他们将是极其虚伪的。

鉴于没有重写就无法在具体化中生存的代码量,我们可以肯定地说 Java 永远不会添加具体化,只要它保持对向后兼容性的承诺。

在那种情况下,是的,无论如何。没什么可怕的Set<String> set = new HashSet()。就我个人而言,我总是添加<>以避免警告。(实际上,只要有可能,我都会尝试使我的代码能够证明,正如我所说,这是一种妄想行为)

在您的示例中,推理是微不足道的。可能有更复杂的情况,<>推理不是那么微不足道,它的类型检查可能会有所帮助,而原始版本则缺乏。

class Foo<T>
{
    Foo(Class<T> clazz){}
}

Foo<String> foo1 = new Foo(Integer.class);    // compiles (wrongly) 

Foo<String> foo2 = new Foo<>(Integer.class);  // does not compile
于 2011-11-05T03:12:09.813 回答
0

Java 7 解决了为类实例创建表达式添加有限类型推断的问题。如果需要为构造函数显式声明参数化类型,并且该构造函数的完整参数化类型 < T1 , T2 , ...Tn > 从上下文中显而易见,则可以将构造函数的参数化类型替换为空类型参数集:<>。<> 构造在构造对象并将其分配给变量或将其作为参数传递时是合法的。

详情:点击这里

于 2011-11-04T14:11:52.313 回答
0

实际上它不是必需的。如果你输入

Set<String> s = new HashSet();

代码编译,我们得到一个警告,我们可以用 Xlint 检查。

Note: filetest.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

然后,如果我们尝试添加一个整数值,例如,我们会得到一个编译错误。

于 2011-11-04T14:13:45.557 回答