【问题标题】:How are Java generics different from C++ templates? Why can't I use int as a parameter?Java 泛型与 C++ 模板有何不同?为什么我不能使用 int 作为参数?
【发布时间】:2009-06-15 13:32:13
【问题描述】:

我正在尝试创建

ArrayList<int> myList = new ArrayList<int>();

在 Java 中,但这不起作用。

有人可以解释为什么int 作为类型参数不起作用吗?
Integer 类用于int 原始作品,但有人可以解释为什么int 不被接受吗?

Java 1.6 版

【问题讨论】:

标签: java c++ generics


【解决方案1】:

Java 泛型与 C++ 模板如此不同,因此我不打算在此处列出它们的区别。 (详情请参阅What are the differences between “generic” types in C++ and Java?。)

在这种特殊情况下,问题在于您不能将原语用作泛型类型参数(请参阅JLS §4.5.1:“类型参数可能是引用类型或通配符。”)。

但是,由于自动装箱,您可以执行以下操作:

List<Integer> ints = new ArrayList<Integer>();
ints.add(3); // 3 is autoboxed into Integer.valueOf(3)

这样可以消除一些痛苦。不过,这肯定会损害运行时效率。

【讨论】:

    【解决方案2】:

    int 不起作用的原因是您不能将原始类型用作 Java 中的泛型参数。

    至于您的实际问题,C++ 模板与 Java 泛型有何不同,答案是它们真的非常不同。这些语言本质上应用完全不同的方法来实现相似最终效果。

    Java 倾向于关注泛型的定义。即,仅通过考虑泛型中的代码来检查泛型定义的有效性。如果参数没有得到适当的约束,就不能对它们执行某些操作。不考虑最终调用它的实际类型。

    C++ 正好相反。仅对模板本身进行最少的验证。它实际上只需要可解析即可被认为是有效的。定义的实际正确性是在使用模板的地方完成的。

    【讨论】:

    • +1 勇敢地尝试解释差异 :-) (尽管我可能会对 C++ 模板的最小验证提出问题 - 任何不依赖于模板参数的代码都经过全面检查)
    • 另外,众所周知,C++ 社区已经付出了很多努力来解决对依赖模板代码的最小验证的担忧(尤其是当它导致神秘的错误消息时)。 C++0x 将具有可以受“概念”约束的模板,并且在首次遇到定义时将完全验证其定义(错误消息将更有意义)。当然,C++0x 也会有不受约束的模板(它们有自己的优势:)。
    • @Faisal:为了保持最新,我可能应该提一下,因为您的评论“概念”已从 C++0x(现在可能是 C++0B)中删除。容我们说,这不是一个普遍受欢迎的决定。
    • 为了让它再次保持最新状态,它们计划被包含在 C++17 中,但再次没有被接受。从版本 6 开始,它们作为编译器扩展包含在 GCC 中。
    【解决方案3】:

    它们是非常不同的概念,可以用来执行一些但不是所有相同的任务。正如其他回复中所说,要了解所有差异需要相当多的时间,但这是我认为的粗略。

    泛型允许通过泛型容器的单个实例化来实现运行时多态容器。在 Java 中,所有(非原始)对象都是引用,并且所有引用的大小相同(并且具有一些相同的接口),因此可以由字节码处理。然而,只有字节码实例化的必要含义是类型擦除器;您无法分辨容器是用哪个类实例化的。这在 C++ 中不起作用,因为对象模型根本不同,其中对象并不总是被引用。

    模板允许通过多个实例化编译时多态容器(以及通过在 c++ 类型系统上提供(当前弱类型)语言的模板元编程。)。这允许对给定类型进行专门化,缺点是可能需要多个编译实例化而导致“代码膨胀”。

    模板比泛型更强大;前者实际上是嵌入在 C++ 中的另一种语言,而据我所知,后者仅在容器中有用

    【讨论】:

    • Bolts Tasks 是泛型在容器之外有用的一个有趣例子。
    【解决方案4】:

    主要区别在于它们的实现方式,但它们的名称准确地描述了它们的实现。

    模板的行为类似于模板。所以,如果你写:

    template<typename T>
    void f(T s)
    {
        std::cout << s << '\n';
    }
    
    ...
    int x = 0;
    f(x);
    ...
    

    编译器应用模板,因此最终编译器将代码视为:

    void f_generated_with_int(int s)
    {
        std::cout << s << '\n';
    }
    
    ...
    int x = 0;
    f_generated_with_int(x);
    ...
    

    因此,对于用于调用f 的每种类型,都会“生成”一个新代码。

    另一方面,泛型只进行类型检查,但随后所有类型信息都将被删除。所以,如果你写:

    class X<T> {
        private T x;
    
        public T getX() { return x; }
        public void setX(T x) { this.x = x; }
    }
    
    ...
    Foo foo = new Foo();
    X<Foo> x = new X<>();
    x.setX(foo);
    foo = x.getX();
    ...
    

    Java 像这样编译它:

    class X {
        private Object x;
    
        public Object getX() { return x; }
        public void setX(Object x) { this.x = x; }
    }
    
    ...
    Foo foo = new Foo();
    X x = new X();
    x.setX(foo);
    foo = (Foo)x.getX();
    ...
    

    最后:

    • 模板需要对模板化函数的每次调用进行实例化(在每个 .cpp 文件的编译中),因此模板的编译速度较慢
    • 对于泛型,您不能使用原语,因为它们不是 Object,所以泛型的通用性较差

    【讨论】:

      【解决方案5】:

      您不能在 Java 中使用原语作为类型参数。 Java 的泛型值得通过类型擦除,这意味着编译器会检查您是否使用了定义它们的类型,但是在编译时,所有内容都被视为对象。由于 int 和其他原语不是对象,因此不能使用它们。相反,请使用整数。

      【讨论】:

        【解决方案6】:

        那是因为 int 是一个原语,它是一个known issue

        如果你真的想要,你可以继承/编写你自己的集合来做到这一点。

        【讨论】:

        • @z 链接说This bug is not available
        【解决方案7】:

        您可以尝试来自 GNU Trove 的 TIntArraList,它的作用类似于 int 值的 ArrayList。

        【讨论】:

          【解决方案8】:

          对于您的问题,Java 对象在某种程度上等同于 C++ 中的指针。

          Java 会进行垃圾收集,因为这些动态对象在某些时候会“看不见”(不再被指向),然后需要进行空间清理。

          int 被识别为原始类型,因此无法返回 null,这就是 Java 泛型不能接受原始类型的原因。为了表明元素没有以MapSetList 的形式存储在Java 容器中,方法将返回null。那如果不能回null,你还回什么?

          对于std::array,静态和动态数组,C++ 强制您定义默认构造函数,这是因为 C++ 数组是类型数组,而不是 Java 中的指针数组。您必须指出哪个默认值(Java 中的null 值)将采用这种结构中的对象。

          想一想,在 Java 中,数组中的任何对象默认为 null,在 C++ 中,除非您声明一个指针数组并将所有指针设置为 0x0 或(最好)为 nullptr .

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2020-07-01
            • 1970-01-01
            • 2020-01-26
            • 1970-01-01
            • 2023-03-24
            • 2011-06-14
            • 1970-01-01
            相关资源
            最近更新 更多