Java 泛型与 C++ 模板有何不同?为什么我不能使用 int 作为参数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/996135/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How are Java generics different from C++ templates? Why can't I use int as a parameter?
提问by yesraaj
I am trying to create
我正在尝试创建
ArrayList<int> myList = new ArrayList<int>();
in Java but that does not work.
在 Java 中,但这不起作用。
Can someone explain why int
as type parameter does not work?
Using Integer
class for int
primitive works, but can someone explain why int
is not accepted?
有人可以解释为什么int
类型参数不起作用吗?
将Integer
类用于int
原始作品,但有人可以解释为什么int
不被接受吗?
Java version 1.6
Java 1.6 版
采纳答案by Michael Myers
Java generics are so different from C++ templates that I am not going to try to list the differences here. (See What are the differences between “generic” types in C++ and Java?for more details.)
Java 泛型与 C++ 模板如此不同,我不打算在这里列出差异。(有关更多详细信息,请参阅C++ 和 Java 中“通用”类型之间的区别是什么?)
In this particular case, the problem is that you cannot use primitives as generic type parameters (see JLS §4.5.1: "Type arguments may be either reference types or wildcards.").
在这种特殊情况下,问题是您不能将原语用作泛型类型参数(请参阅JLS §4.5.1:“类型参数可以是引用类型或通配符。”)。
However, due to autoboxing, you can do things like:
但是,由于自动装箱,您可以执行以下操作:
List<Integer> ints = new ArrayList<Integer>();
ints.add(3); // 3 is autoboxed into Integer.valueOf(3)
So that removes some of the pain. It definitely hurts runtime efficiency, though.
这样就消除了一些痛苦。不过,它肯定会损害运行时效率。
回答by Pesto
You can't use primitives as type parameters in Java. Java's generics worth through type erasure, meaning that the compiler checks that you're using the types as you've defined them, but upon compilation, everything is treated as an Object. Since int and other primitives aren't Objects, they can't be used. Instead, use Integer.
在 Java 中不能使用原语作为类型参数。Java 的泛型值得通过类型擦除,这意味着编译器会检查您是否在使用您定义的类型,但在编译时,一切都被视为对象。由于 int 和其他原语不是对象,因此不能使用它们。相反,使用整数。
回答by z -
that's because int is a primitive, it is a known issue.
那是因为 int 是一个原始类型,这是一个已知问题。
If you really wanted to, you can subclass/write your own collection that can do that.
如果你真的想要,你可以子类化/编写你自己的集合来做到这一点。
回答by JaredPar
The reason that int
doesn't work, is that you cannot use primitive types as generic parameters in Java.
int
不起作用的原因是您不能在 Java 中使用原始类型作为泛型参数。
As to your actual question, how C++ templates are different from Java generics, the answer is that they're really, really different. The languages essentially apply completely different approaches to implementing a similarend effect.
至于您的实际问题,C++ 模板与 Java 泛型有何不同,答案是它们确实非常不同。这些语言本质上应用完全不同的方法来实现类似的最终效果。
Java tends to focus on the definition of the generic. That is, the validity of the generic definition is checked by only considering the code in the generic. If parameters are not properly constrained, certain actions cannot be performed on them. The actual type it's eventually invoked with, is not considered.
Java 倾向于关注泛型的定义。即,仅通过考虑泛型中的代码来检查泛型定义的有效性。如果参数没有正确约束,则无法对它们执行某些操作。不考虑它最终调用的实际类型。
C++ is the opposite. Only minimal verification is done on the template itself. It really only needs to be parsable to be considered valid. The actual correctness of the definition is done at the place in which the template is used.
C++则相反。仅对模板本身进行最少的验证。它真的只需要可解析就可以被认为是有效的。定义的实际正确性是在使用模板的地方完成的。
回答by Todd Gardner
They are very different concepts, which can be used to perform some, but not all of the same tasks. As said in the other responses, it would take a quite a bit to go over all the differences, but here's what I see as the broad strokes.
它们是非常不同的概念,可用于执行某些但并非所有相同的任务。正如在其他回复中所说,要了解所有差异需要花费很多时间,但这是我所看到的粗略之处。
Generics allow for runtime polymorphic containers through a single instantiation of a generic container. In Java, all the (non-primitive) objects are references, and all references are the same size (and have some of the same interface), and so can be handled by the bytecode. However, a necessary implication of having only instantiation of byte code is type eraser; you can't tell which class the container was instantiated with. This wouldn't work in c++ because of a fundamentally different object model, where objects aren't always references.
泛型允许通过泛型容器的单个实例化运行时多态容器。在 Java 中,所有(非原始)对象都是引用,并且所有引用的大小都相同(并且具有一些相同的接口),因此可以由字节码处理。然而,只有字节码实例化的必要含义是类型擦除器;您无法分辨容器是用哪个类实例化的。由于完全不同的对象模型,这在 c++ 中不起作用,其中对象并不总是引用。
Templates allow for compile time polymorphic containers through multiple instantiations (as well as template metaprogramming by providing a (currently weakly typed) language over the c++ type system.). This allows for specializations for given types, the downside being potential "code bloat" from needing more than one compiled instantiation.
模板允许通过多个实例化编译时多态容器(以及通过在 c++ 类型系统上提供(当前弱类型)语言的模板元编程。)。这允许对给定类型进行专门化,缺点是需要多个编译实例化可能导致“代码膨胀”。
Templates are more powerful than generics; the former is effectively another language embedded within c++, while to the best of my knowledge, the latter is useful only in containers
模板比泛型更强大;前者实际上是嵌入在 c++ 中的另一种语言,而据我所知,后者仅在容器中有用
回答by Peter Lawrey
You could try TIntArraList from GNU Trove which will act like an ArrayList of int values.
您可以尝试来自 GNU Trove 的 TIntArraList,它的作用类似于 int 值的 ArrayList。
回答by kravemir
The main difference is in way they are implemented, but their names accurately describe their implementation.
主要区别在于它们的实现方式,但它们的名称准确地描述了它们的实现。
Templates behave like templates. So, if you write:
模板的行为类似于模板。所以,如果你写:
template<typename T>
void f(T s)
{
std::cout << s << '\n';
}
...
int x = 0;
f(x);
...
Compiler applies the template, so in the end compiler treats the code like:
编译器应用模板,因此最终编译器将代码视为:
void f_generated_with_int(int s)
{
std::cout << s << '\n';
}
...
int x = 0;
f_generated_with_int(x);
...
So, for each type which is used to call f
a new code is "generated".
因此,对于用于调用f
新代码的每种类型都是“生成”的。
On the other hand, generics is only typechecked, but then all type information is erased. So, if you write:
另一方面,泛型只进行类型检查,然后所有类型信息都被删除。所以,如果你写:
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 compiles it like:
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();
...
In the end:
到底:
- templates require instantiation of each call to templated function (in compilation of each .cpp file), so templates are slower to compile
- with generics you can't use primitives, because they are not
Object
, so generics is less versatile
- 模板需要实例化对模板化函数的每次调用(在每个 .cpp 文件的编译中),因此模板编译速度较慢
- 使用泛型你不能使用原语,因为它们不是
Object
,所以泛型不太通用