Java泛型与C ++模板有何不同? 为什么不能将int用作参数?

我正在尝试创建

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

在Java中,但这不起作用。

有人可以解释为什么int作为类型参数不起作用吗?
Integer类用于int基本工程,但是有人可以解释为什么不接受int吗?

Java 1.6版

yesraaj asked 2020-01-22T12:21:14Z
7个解决方案
66 votes

Java泛型与C ++模板有很大不同,因此我不会在这里列出差异。 (有关更多详细信息,请参见C ++和Java中“通用”类型之间的区别是什么。)

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

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

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

这样可以减轻一些痛苦。 但是,这肯定会损害运行时效率。

Michael Myers answered 2020-01-22T12:21:48Z
25 votes

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

关于您的实际问题,C ++模板与Java泛型有何不同,答案是……确实有很大的不同。 实际上,这是两种完全不同的方法来实现相似的最终效果。

Java倾向于关注泛型的定义。 也就是说,仅通过考虑泛型中的代码来检查泛型定义的有效性。 如果参数未正确约束,则无法对其执行某些操作。 最终使用它的实际类型不予考虑。

C ++相反。 仅对模板本身进行最少的验证。 实际上,只有解析它才被认为是有效的。 定义的实际正确性是在使用模板的位置完成的。

JaredPar answered 2020-01-22T12:22:22Z
9 votes

它们是非常不同的概念,可用于执行某些但不是全部相同的任务。 正如在其他答复中所说的那样,要花很多时间才能解决所有差异,但这就是我所看到的大招。

泛型允许通过单个实例化泛型容器来实现运行时多态容器。 在Java中,所有(非原始)对象都是引用,并且所有引用的大小均相同(并且具有某些相同的接口),因此可以由字节码处理。 但是,仅具有字节码实例化的必要含义是类型擦除器。 您无法确定实例化该容器的类。 由于根本不同的对象模型(对象并不总是引用),因此这在c ++中不起作用。

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

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

Todd Gardner answered 2020-01-22T12:22:58Z
8 votes

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

模板的行为类似于模板。 因此,如果您写:

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

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

另一方面,仅检查泛型,然后删除所有类型信息。 因此,如果您写:

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,因此泛型的通用性较差
kravemir answered 2020-01-22T12:23:54Z
3 votes

您不能在Java中将基元用作类型参数。 Java的泛型值得通过类型擦除来实现,这意味着编译器会在定义类型时检查您是否正在使用类型,但是在编译时,所有内容都被视为对象。 由于int和其他原语不是对象,因此无法使用它们。 而是使用Integer。

Pesto answered 2020-01-22T12:24:14Z
3 votes

那是因为int是原始的,这是一个已知问题。

如果确实需要,您可以继承/编写自己的集合来做到这一点。

z - answered 2020-01-22T12:24:38Z
1 votes

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

Peter Lawrey answered 2020-01-22T12:24:59Z
translate from https://stackoverflow.com:/questions/996135/how-are-java-generics-different-from-c-templates-why-cant-i-use-int-as-a-par