Java 允许泛型中的原始类型

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18670576/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 10:02:10  来源:igfitidea点击:

Java permits primitive types in generics

javagenerics

提问by S E

I know that java is not supposed support generic arguments which are primitive types, and sure enough something like:

我知道 java 不应该支持原始类型的泛型参数,并且肯定是这样的:

Vector<byte> test;

will fail to compile.

将无法编译。

however with a little slight-of-hand that I accidentally performed in a program, I found that it is actually possible to create a generic object with a primitive type (technique shown below)

然而,由于我在程序中不小心执行了一些轻微的操作,我发现实际上可以创建具有原始类型的通用对象(技术如下所示)

Furthermore, java falsely allows this instance to be assigned to a variable of type Vector<Byte>when as the print statements show, byte.class and Byte.class are two separate beasts. Because of this, attempts to do calls on the object result in unexpected and strange behaviors/errors.

此外,Vector<Byte>当如打印语句所示,byte.class 和 Byte.class 是两个独立的野兽时,java 错误地允许将此实例分配给类型的变量。因此,尝试对对象进行调用会导致意外和奇怪的行为/错误。

Is this a java bug? or is there some rhyme or reason to this madness? It seems like even if java allowed the unexpected behavior of creating primitive-typed generics, they should not be assignable to a generic of the wrapper type which is of a distinct class from the primitive.

这是一个java错误吗?或者这种疯狂有什么韵律或理由吗?似乎即使 java 允许创建原始类型泛型的意外行为,它们也不应该分配给与原始类型不同的包装类型的泛型。

import java.util.Vector;

public class Test
{
    //the trick here is that I am basing the return type of
    //the vector off of the type that was given as the generic
    //argument for the instance of the reflections type Class,
    //however the the class given by byte.class yields a non-class
    //type in the generic, and hence a Vector is created with a
    //primitive type
    public static <Type> Vector<Type> createTypedVector(Class<Type> type)
    {
        return new Vector<Type>(0,1);
    }

    public static void main(String ... args)
    {
        //these lines are to demonstrate that 'byte' and 'Byte'
        //are 2 different class types
        System.out.println(byte.class);
        System.out.println(Byte.class);

        //this is where I create an instance of type Vector<byte>
        //and assign it to a variable of type Vector<Byte>
        Vector<Byte> primitiveTypedGenericObject = createTypedVector(byte.class);

        //this line causes unexpected exceptions to be thrown
        //because primitiveTypedGenericObject is not actually type
        //Vector<Byte>, but rather Vector<byte>
        primitiveTypedGenericObject.set(0,(byte)0xFF);

    }

}

采纳答案by Hyman

Both Byte.classand Byte.TYPEare Class<Byte>objects. The latter are just used to distinguish between primitive type and object type.

这两个Byte.classByte.TYPEClass<Byte>对象。后者只是用来区分原始类型和对象类型。

Actually Byte.TYPE is defined as:

实际上 Byte.TYPE 定义为:

public static final Class<Byte> TYPE = (Class<Byte>) Class.getPrimitiveClass("byte");

and getPrimitiveClassis an opaque method which retrieves the type from the VM so we can't investigate it further.

andgetPrimitiveClass是一种从 VM 中检索类型的不透明方法,因此我们无法进一步研究它。

So, even if you think that you are passing a primitive data type Class, since they don't exist (why should they, since they refer to something that is typable according to the Java typing system for objects, which doesn't include primitive types until they are boxed into wrapper classes), you are creating a Vector<Byte>.

因此,即使您认为您正在传递原始数据类型类,因为它们不存在(为什么要它们,因为它们指的是根据对象的 Java 类型系统可类型化的东西,其中不包括原始数据类型)类型,直到它们被装箱到包装类中),您正在创建一个Vector<Byte>.

But in the end this doesn't matter much, upon reaching run-time execution type annotations are erased and the generic type doesn't mean anything. Whenever you'll add a byteit will be autoboxed to a Byteobject and that's it.

但最终这并不重要,到达运行时执行类型注释被删除,泛型类型没有任何意义。每当您添加 a 时,byte它都会自动装箱到一个Byte对象中,仅此而已。

I have no way to test your code at the moment, which exceptions are thrown at runtime when adding items to the Vector?

我目前无法测试您的代码,将项目添加到Vector?

回答by Andromeda

No! It is not bug. It is called Autoboxing. When you pass byteto a generic method that expects Byte, the compiler automatically Autoboxes it to Byte which is an instance of Object. The antithesis of that operation is called Auto Unboxingand that is why operations like the one shown below are legal.

不!这不是错误。它被称为自动装箱。当您将byte传递给需要Byte的泛型方法时,编译器会自动将其自动装箱为 Byte ,它是 Object 的一个实例。该操作的对立面称为自动拆箱,这就是为什么如下所示的操作是合法的。

int a = new Integer(5);
Integer b = 5;

回答by jdphenix

You've stumbled upon autoboxing and unboxing. See http://docs.oracle.com/javase/tutorial/java/data/autoboxing.html

您偶然发现了自动装箱和拆箱。请参阅http://docs.oracle.com/javase/tutorial/java/data/autoboxing.html

The nutshell version

简而言之

List<Integer> list = new List<Integer>(); 
list.add(1); // works

byte.class, int.class, etc. resolve to Byte, Integer, etc. See the Java Language Specification, 15.8.2:

byte.classint.class等解析为ByteInteger等。请参阅Java Language Specification, 15.8.2

15.8.2. Class Literals

......

The type of p.class, where p is the name of a primitive type (§4.2), is Class<B>, where B is the type of an expression of type p after boxing conversion (§5.1.7).

The type of void.class(§8.4.5) is Class<Void>.

15.8.2. 类文字

......

的类型p.class,其中 p 是原始类型的名称(第4.2 节),是Class<B>,其中 B 是装箱转换后的 p 类型表达式的类型(第5.1.7 节)。

void.class(第8.4.5 节)的类型是Class<Void>