自Java5+;菱形运算符

自Java5+;菱形运算符,java,generics,jakarta-ee,collections,scjp,Java,Generics,Jakarta Ee,Collections,Scjp,据我所知,泛型只在编译时有用 因此,可以声明: private Set set = new HashSet<String>(); private Set=new HashSet(); 然后,在这个字符串hashset中,向该集合添加dogs或任何内容,没有任何问题,因为在运行时没有任何类似于数组的检查(ArrayStoreException…)(但在使用该集合时,可能会遇到类似类转换的问题 所以我想说的是,我们通常以这种方式实例化泛型集合: Set<String> s

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

因此,可以声明:

private Set set = new HashSet<String>();
private Set=new HashSet();
然后,在这个字符串hashset中,向该集合添加dogs或任何内容,没有任何问题,因为在运行时没有任何类似于数组的检查(ArrayStoreException…)(但在使用该集合时,可能会遇到类似类转换的问题

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

Set<String> set = new HashSet<String>();
Set Set=newhashset();
我的问题是,既然变量引用的类型才是真正重要的(我认为),为什么我们要设置HashSet的类型呢

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

Set<String> set = new HashSet();
Set Set=newhashset();
它也会起同样的作用,对吗? 那么为什么我们通常在实例化过程中编写类型呢?(这不是强制性的)


编辑

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

以下代码:

            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);
            }
Set Set=newhashset();
set.add(“测试添加字符串1”);
set.add(“测试添加字符串2”);
for(字符串s:set){
系统输出打印项次;
}
生成输出:

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

自己测试一下

所以现在您将类型推断作为Java7的一个特性来讨论,但它已经对我起作用了

有了java7,我将不得不替换我的

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

Set Set=newhashset();

做完全相同的事情还需要另外两个字符否?(除非泛型不仅仅是Java7的编译时?我不知道)

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

Set<String> set = new HashSet<>();
Set Set=newhashset();
是的,这可能从一开始就存在,但这是Java,通常需要几十年的时间才能获得新的语言特性的批准( 它的工作原理完全相同,对吗?

运行时:

编译时:

您的代码将把一个包含任意对象的集合分配给一个变量,该变量存储一个包含字符串的集合,这是错误的,类型检查器将不支持该集合

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


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

Set<String> set = new HashSet();
Set Set=newhashset();
不远

HashSet tmp = new HashSet();
...
Set<String> set = tmp;
HashSet tmp = new HashSet();
tmp.add(7);
...
Set<String> set = tmp;
HashSet tmp=newhashset();
...
Set=tmp;
这也离我们不远了

HashSet tmp = new HashSet();
...
Set<String> set = tmp;
HashSet tmp = new HashSet();
tmp.add(7);
...
Set<String> set = tmp;
HashSet tmp=newhashset();
tmp.add(7);
...
Set=tmp;
它仍然可以编译,但有一千个原因是不好的:)


Java7允许您编写

Set<String> set = new HashSet<>();
Set Set=newhashset();
但是,它告诉编译器推断
之间的类型

关于“菱形运算符”的文档:

  • (来自oracle.com)
  • (来自oracle.com)

Java 7解决了为 类实例创建表达式。在需要为 构造函数,以及的完全参数化类型 从上下文来看,该构造函数是显而易见的,然后参数化 构造函数的类型可以替换为类型的空集 参数:。构造时可以合法使用该构造 对象,并将其分配给变量,或作为 参数


有关详细信息:

实际上它不是必需的。 如果你打字

Set<String> s = new HashSet();

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

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

然而,这种未来的兼容性完全是一种错觉。擦除将永远伴随着我们。如果引入完全物化,可以肯定地说,几乎所有非平凡的通用代码都将崩溃,因为每个人都在编写错误的通用代码

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

JDK是罪魁祸首。JDK API是精心设计的,以在具体化过程中幸存下来;但是实现依赖于擦除。如果Java添加了具体化,这些JDK代码必须重写。如果Java团队指责我们编写了错误的代码,而他们自己却必须做同样的事情,那么他们将极其虚伪

考虑到大量代码在不重写的情况下无法通过具体化,我们可以有把握地说Java永远不会添加具体化,只要它保持向后兼容性的承诺

在这种情况下,是的,不管怎样。
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