为什么Java泛型不支持基本类型?

时间:2020-11-25 16:27:08

Why do generics in Java work with classes but not with primitive types?

为什么在Java中泛型会使用类而不是原始类型?

For example, this works fine:

例如,这样做很好:

List<Integer> foo = new ArrayList<Integer>();

but this is not allowed:

但这是不允许的:

List<int> bar = new ArrayList<int>();

5 个解决方案

#1


202  

Generics in Java are an entirely compile-time construct - the compiler turns all generic uses into casts to the right type. This is to maintain backwards compatibility with previous JVM runtimes.

Java中的泛型是一个完全编译时的构造——编译器将所有通用的应用程序转换为正确的类型。这是为了保持向后兼容以前的JVM运行时。

This:

这样的:

List<ClassA> list = new ArrayList<ClassA>();
list.add(new ClassA());
ClassA a = list.get(0);

gets turned into (roughly):

会变成(约):

List list = new ArrayList();
list.add(new ClassA());
ClassA a = (ClassA)list.get(0);

So, anything that is used as generics has to be convertable to Object (in this example get(0) returns an Object), and the primitive types aren't. So they can't be used in generics.

因此,任何用作泛型的东西都必须是可转换的对象(在本例中get(0)返回一个对象),而原始类型则不是。所以它们不能用于泛型。

#2


30  

In Java, generics work the way that they do ... at least in part ... because they were added to the language a number of years after the language was designed1. The language designers were constrained in their options for generics by having to come up with a design that was backwards compatible with the existing language and the Java class library.

在Java中,泛型的工作方式是…至少在某种程度上……因为在该语言被设计后的许多年里,它们被添加到语言中。语言设计人员必须设计出与现有语言和Java类库兼容的设计,从而限制了泛型的选择。

Other programming languages (e.g. C++, C#, Ada) do allow primitive types to be used as parameter types for generics. But the flip side of doing this is that such languages' implementations of generics (or template types) typically entail generation of a distinct copy of the generic type for each type parameterization.

其他编程语言(例如c++、c#、Ada)允许使用基本类型作为泛型的参数类型。但这样做的另一方面是,这种语言的泛型(或模板类型)的实现通常需要生成每个类型参数化的通用类型的不同副本。


1 - The reason generics were not included in Java 1.0 was because of time pressure. They felt that they had to get the Java language released quickly to fill the new market opportunity presented by web browsers. James Gosling has stated that he would have liked to include generics if they had had the time. What the Java language would have looked like if this had happened is anyone's guess.

1 - Java 1.0中不包含泛型的原因是时间压力。他们觉得必须尽快发布Java语言,以填补web浏览器带来的新市场机遇。詹姆斯·高斯林曾说过,如果他们有时间的话,他会喜欢把非专利药包括在内。如果发生这种情况,Java语言将会是什么样子,这是任何人的猜测。

#3


5  

The collections are defined to require a type which derives from java.lang.Object. The basetypes simply don't do that.

集合被定义为需要一个来自java.lang.Object的类型。基本类型不会这样做。

#4


2  

As per Java Documentation, generic type variables can only be instantiated with reference types, not primitive types.

根据Java文档,泛型类型变量只能用引用类型来实例化,而不是原始类型。

This is supposed to come in Java 10 under Project Valhalla.

这应该是在Valhalla项目下的Java 10。

In Brian Goetz paper on State of the Specialization

在Brian Goetz的论文中关于专业化的状态。

There is an excellent explanation about the reason for which generic were not supported for primitive. And, how it will be implemented in future releases of Java.

对于一般不支持原语的原因,有一个很好的解释。以及它将如何在Java的未来版本中实现。

Java's current erased implementation which produces one class for all reference instantiations and no support for primitive instantiations. (This is a homogeneous translation, and the restriction that Java's generics can only range over reference types comes from the limitations of homogeneous translation with respect to the bytecode set of the JVM, which uses different bytecodes for operations on reference types vs primitive types.) However, erased generics in Java provide both behavioral parametricity (generic methods) and data parametricity (raw and wildcard instantiations of generic types.)

Java当前被删除的实现,它为所有引用实例化生成一个类,并且不支持原始实例化。(这是一个同构的翻译,Java的泛型只能在引用类型上的限制来自于对JVM的字节码集的同构翻译的限制,它使用不同的字节码来操作引用类型和原始类型。)然而,在Java中被擦除的泛型提供了行为参数化(泛型方法)和数据参数化(泛型类型的原始和通配符实例化)。

...

a homogeneous translation strategy was chosen, where generic type variables are erased to their bounds as they are incorporated into bytecode. This means that whether a class is generic or not, it still compiles to a single class, with the same name, and whose member signatures are the same. Type safety is verified at compile time, and runtime is unfettered by the generic type system. In turn, this imposed the restriction that generics could only work over reference types, since Object is the most general type available, and it does not extend to primitive types.

选择了一个同质的翻译策略,当泛型类型变量被合并到字节码中时,它们会被删除。这意味着,不管类是否是通用的,它仍然会编译为一个类,具有相同的名称,其成员签名是相同的。类型安全在编译时验证,运行时不受泛型类型系统的约束。反过来,这限制了泛型只能工作于引用类型,因为对象是最通用的类型,而且它不扩展到基本类型。

#5


2  

In java generics are implemented by using "Type erasure" for backward compatibility. All generic types are converted to Object at runtime. for example,

在java泛型中,使用“类型擦除”来实现向后兼容性。所有泛型类型都在运行时转换为对象。例如,

public class Container<T> {

    private T data;

    public T getData() {
        return data;
    }
}

will be seen at runtime as,

将在运行时看到,

public class Container {

    private Object data;

    public Object getData() {
        return data;
    }
}

compiler is responsible to provide proper cast to ensure type safety.

编译器负责提供适当的浇注以确保类型安全。

Container<Integer> val = new Container<Integer>();
Integer data = val.getData()

will become

将成为

Container val = new Container();
Integer data = (Integer) val.getData()

Now the question is why "Object" is chose as type at runtime?

现在的问题是为什么在运行时选择“对象”作为类型?

Answer is Object is superclass of all objects and can represent any user defined object.

答案是对象是所有对象的超类,可以表示任何用户定义的对象。

Since all primitives doesn't inherit from "Object" so we can't use it as a generic type.

因为所有原语都不会从“对象”继承,所以我们不能将其用作泛型类型。

FYI : Project Valhalla is trying to address above issue.

FYI: Valhalla项目正在努力解决上述问题。

#1


202  

Generics in Java are an entirely compile-time construct - the compiler turns all generic uses into casts to the right type. This is to maintain backwards compatibility with previous JVM runtimes.

Java中的泛型是一个完全编译时的构造——编译器将所有通用的应用程序转换为正确的类型。这是为了保持向后兼容以前的JVM运行时。

This:

这样的:

List<ClassA> list = new ArrayList<ClassA>();
list.add(new ClassA());
ClassA a = list.get(0);

gets turned into (roughly):

会变成(约):

List list = new ArrayList();
list.add(new ClassA());
ClassA a = (ClassA)list.get(0);

So, anything that is used as generics has to be convertable to Object (in this example get(0) returns an Object), and the primitive types aren't. So they can't be used in generics.

因此,任何用作泛型的东西都必须是可转换的对象(在本例中get(0)返回一个对象),而原始类型则不是。所以它们不能用于泛型。

#2


30  

In Java, generics work the way that they do ... at least in part ... because they were added to the language a number of years after the language was designed1. The language designers were constrained in their options for generics by having to come up with a design that was backwards compatible with the existing language and the Java class library.

在Java中,泛型的工作方式是…至少在某种程度上……因为在该语言被设计后的许多年里,它们被添加到语言中。语言设计人员必须设计出与现有语言和Java类库兼容的设计,从而限制了泛型的选择。

Other programming languages (e.g. C++, C#, Ada) do allow primitive types to be used as parameter types for generics. But the flip side of doing this is that such languages' implementations of generics (or template types) typically entail generation of a distinct copy of the generic type for each type parameterization.

其他编程语言(例如c++、c#、Ada)允许使用基本类型作为泛型的参数类型。但这样做的另一方面是,这种语言的泛型(或模板类型)的实现通常需要生成每个类型参数化的通用类型的不同副本。


1 - The reason generics were not included in Java 1.0 was because of time pressure. They felt that they had to get the Java language released quickly to fill the new market opportunity presented by web browsers. James Gosling has stated that he would have liked to include generics if they had had the time. What the Java language would have looked like if this had happened is anyone's guess.

1 - Java 1.0中不包含泛型的原因是时间压力。他们觉得必须尽快发布Java语言,以填补web浏览器带来的新市场机遇。詹姆斯·高斯林曾说过,如果他们有时间的话,他会喜欢把非专利药包括在内。如果发生这种情况,Java语言将会是什么样子,这是任何人的猜测。

#3


5  

The collections are defined to require a type which derives from java.lang.Object. The basetypes simply don't do that.

集合被定义为需要一个来自java.lang.Object的类型。基本类型不会这样做。

#4


2  

As per Java Documentation, generic type variables can only be instantiated with reference types, not primitive types.

根据Java文档,泛型类型变量只能用引用类型来实例化,而不是原始类型。

This is supposed to come in Java 10 under Project Valhalla.

这应该是在Valhalla项目下的Java 10。

In Brian Goetz paper on State of the Specialization

在Brian Goetz的论文中关于专业化的状态。

There is an excellent explanation about the reason for which generic were not supported for primitive. And, how it will be implemented in future releases of Java.

对于一般不支持原语的原因,有一个很好的解释。以及它将如何在Java的未来版本中实现。

Java's current erased implementation which produces one class for all reference instantiations and no support for primitive instantiations. (This is a homogeneous translation, and the restriction that Java's generics can only range over reference types comes from the limitations of homogeneous translation with respect to the bytecode set of the JVM, which uses different bytecodes for operations on reference types vs primitive types.) However, erased generics in Java provide both behavioral parametricity (generic methods) and data parametricity (raw and wildcard instantiations of generic types.)

Java当前被删除的实现,它为所有引用实例化生成一个类,并且不支持原始实例化。(这是一个同构的翻译,Java的泛型只能在引用类型上的限制来自于对JVM的字节码集的同构翻译的限制,它使用不同的字节码来操作引用类型和原始类型。)然而,在Java中被擦除的泛型提供了行为参数化(泛型方法)和数据参数化(泛型类型的原始和通配符实例化)。

...

a homogeneous translation strategy was chosen, where generic type variables are erased to their bounds as they are incorporated into bytecode. This means that whether a class is generic or not, it still compiles to a single class, with the same name, and whose member signatures are the same. Type safety is verified at compile time, and runtime is unfettered by the generic type system. In turn, this imposed the restriction that generics could only work over reference types, since Object is the most general type available, and it does not extend to primitive types.

选择了一个同质的翻译策略,当泛型类型变量被合并到字节码中时,它们会被删除。这意味着,不管类是否是通用的,它仍然会编译为一个类,具有相同的名称,其成员签名是相同的。类型安全在编译时验证,运行时不受泛型类型系统的约束。反过来,这限制了泛型只能工作于引用类型,因为对象是最通用的类型,而且它不扩展到基本类型。

#5


2  

In java generics are implemented by using "Type erasure" for backward compatibility. All generic types are converted to Object at runtime. for example,

在java泛型中,使用“类型擦除”来实现向后兼容性。所有泛型类型都在运行时转换为对象。例如,

public class Container<T> {

    private T data;

    public T getData() {
        return data;
    }
}

will be seen at runtime as,

将在运行时看到,

public class Container {

    private Object data;

    public Object getData() {
        return data;
    }
}

compiler is responsible to provide proper cast to ensure type safety.

编译器负责提供适当的浇注以确保类型安全。

Container<Integer> val = new Container<Integer>();
Integer data = val.getData()

will become

将成为

Container val = new Container();
Integer data = (Integer) val.getData()

Now the question is why "Object" is chose as type at runtime?

现在的问题是为什么在运行时选择“对象”作为类型?

Answer is Object is superclass of all objects and can represent any user defined object.

答案是对象是所有对象的超类,可以表示任何用户定义的对象。

Since all primitives doesn't inherit from "Object" so we can't use it as a generic type.

因为所有原语都不会从“对象”继承,所以我们不能将其用作泛型类型。

FYI : Project Valhalla is trying to address above issue.

FYI: Valhalla项目正在努力解决上述问题。