为什么 Java 泛型不支持原始类型?

发布于 2024-08-30 02:45:17 字数 230 浏览 6 评论 0原文

为什么 Java 中的泛型适用于类,但不适用于原始类型?

例如,这工作正常:

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

但这是不允许的:

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

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

For example, this works fine:

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

but this is not allowed:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

千纸鹤带着心事 2024-09-06 02:45:17

Java 中的泛型完全是编译时构造 - 编译器将所有泛型使用转换为正确类型的强制转换。这是为了保持与以前的 JVM 运行时的向后兼容性。

这:(

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

大致)变成:

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

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

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.

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.

魔法少女 2024-09-06 02:45:17

在 Java 中,泛型以它们的方式工作......至少部分......因为它们是在语言设计多年后添加到语言中的1。语言设计者在泛型选择上受到限制,因为必须提出与现有语言和 Java 类库向后兼容的设计。

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


1 - Java 1.0 中未包含泛型的原因是由于时间压力。他们认为必须尽快发布 Java 语言,以填补 Web 浏览器带来的新市场机会。詹姆斯·高斯林表示,如果他们有时间的话,他希望将仿制药纳入其中。如果发生这种情况,Java 语言会是什么样子谁也说不准。

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.

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.


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.

瘫痪情歌 2024-09-06 02:45:17

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

public class Container<T> {

    private T data;

    public T getData() {
        return data;
    }
}

在运行时将被视为

public class Container {

    private Object data;

    public Object getData() {
        return data;
    }
}

编译器负责提供正确的强制转换以确保类型安全。

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

将变成

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

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

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

由于所有基元都不是从“对象”继承的,所以我们不能使用它
作为泛型类型。

仅供参考:Project Valhalla 正在尝试解决上述问题。

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

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.

咿呀咿呀哟 2024-09-06 02:45:17

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

这应该出现在 Java 10 的 Project Valhalla 下。

Brian Goetz 论文中 专业化状态

有一个 关于原语不支持泛型的原因的精彩解释。并且,如何实施 Java 的未来版本。

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

选择了同构翻译策略,其中通用类型变量在合并到字节码中时被擦除到其边界。这意味着无论一个类是否为泛型,它仍然会编译为具有相同名称且成员签名相同的单个类。类型安全在编译时进行验证,运行时不受泛型类型系统的约束。反过来,这又限制了泛型只能在引用类型上工作,因为 Object 是最通用的可用类型,并且它不能扩展到原始类型。

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

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

In Brian Goetz paper on State of the Specialization

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'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.)

...

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.

难得心□动 2024-09-06 02:45:17

这些集合被定义为需要从java.lang.Object派生的类型。基本类型根本不这样做。

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文