【发布时间】:2009-06-15 13:32:13
【问题描述】:
我正在尝试创建
ArrayList<int> myList = new ArrayList<int>();
在 Java 中,但这不起作用。
有人可以解释为什么int 作为类型参数不起作用吗?
将Integer 类用于int 原始作品,但有人可以解释为什么int 不被接受吗?
Java 1.6 版
【问题讨论】:
我正在尝试创建
ArrayList<int> myList = new ArrayList<int>();
在 Java 中,但这不起作用。
有人可以解释为什么int 作为类型参数不起作用吗?
将Integer 类用于int 原始作品,但有人可以解释为什么int 不被接受吗?
Java 1.6 版
【问题讨论】:
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)
这样可以消除一些痛苦。不过,这肯定会损害运行时效率。
【讨论】:
int 不起作用的原因是您不能将原始类型用作 Java 中的泛型参数。
至于您的实际问题,C++ 模板与 Java 泛型有何不同,答案是它们真的非常不同。这些语言本质上应用完全不同的方法来实现相似最终效果。
Java 倾向于关注泛型的定义。即,仅通过考虑泛型中的代码来检查泛型定义的有效性。如果参数没有得到适当的约束,就不能对它们执行某些操作。不考虑最终调用它的实际类型。
C++ 正好相反。仅对模板本身进行最少的验证。它实际上只需要可解析即可被认为是有效的。定义的实际正确性是在使用模板的地方完成的。
【讨论】:
它们是非常不同的概念,可以用来执行一些但不是所有相同的任务。正如其他回复中所说,要了解所有差异需要相当多的时间,但这是我认为的粗略。
泛型允许通过泛型容器的单个实例化来实现运行时多态容器。在 Java 中,所有(非原始)对象都是引用,并且所有引用的大小相同(并且具有一些相同的接口),因此可以由字节码处理。然而,只有字节码实例化的必要含义是类型擦除器;您无法分辨容器是用哪个类实例化的。这在 C++ 中不起作用,因为对象模型根本不同,其中对象并不总是被引用。
模板允许通过多个实例化编译时多态容器(以及通过在 c++ 类型系统上提供(当前弱类型)语言的模板元编程。)。这允许对给定类型进行专门化,缺点是可能需要多个编译实例化而导致“代码膨胀”。
模板比泛型更强大;前者实际上是嵌入在 C++ 中的另一种语言,而据我所知,后者仅在容器中有用
【讨论】:
主要区别在于它们的实现方式,但它们的名称准确地描述了它们的实现。
模板的行为类似于模板。所以,如果你写:
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();
...
最后:
Object,所以泛型的通用性较差【讨论】:
您不能在 Java 中使用原语作为类型参数。 Java 的泛型值得通过类型擦除,这意味着编译器会检查您是否使用了定义它们的类型,但是在编译时,所有内容都被视为对象。由于 int 和其他原语不是对象,因此不能使用它们。相反,请使用整数。
【讨论】:
那是因为 int 是一个原语,它是一个known issue。
如果你真的想要,你可以继承/编写你自己的集合来做到这一点。
【讨论】:
This bug is not available
您可以尝试来自 GNU Trove 的 TIntArraList,它的作用类似于 int 值的 ArrayList。
【讨论】:
对于您的问题,Java 对象在某种程度上等同于 C++ 中的指针。
Java 会进行垃圾收集,因为这些动态对象在某些时候会“看不见”(不再被指向),然后需要进行空间清理。
int 被识别为原始类型,因此无法返回 null,这就是 Java 泛型不能接受原始类型的原因。为了表明元素没有以Map、Set、List 的形式存储在Java 容器中,方法将返回null。那如果不能回null,你还回什么?
对于std::array,静态和动态数组,C++ 强制您定义默认构造函数,这是因为 C++ 数组是类型数组,而不是 Java 中的指针数组。您必须指出哪个默认值(Java 中的null 值)将采用这种结构中的对象。
想一想,在 Java 中,数组中的任何对象默认为 null,在 C++ 中,除非您声明一个指针数组并将所有指针设置为 0x0 或(最好)为 nullptr .
【讨论】: