简体   繁体   English

Java允许泛型中的原始类型

[英]Java permits primitive types in generics

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. 此外,java错误地允许将此实例分配给Vector<Byte>类型的变量,而当print语句显示时,byte.class和Byte.class是两个独立的野兽。 Because of this, attempts to do calls on the object result in unexpected and strange behaviors/errors. 因此,尝试对对象进行调用会导致意外和奇怪的行为/错误。

Is this a java bug? 这是一个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允许创建基本类型泛型的意外行为,它们也不应该被赋予包装类型的泛型,该类型与原语具有不同的类。

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

    }

}

Both Byte.class and Byte.TYPE are Class<Byte> objects. Byte.classByte.TYPE都是Class<Byte>对象。 The latter are just used to distinguish between primitive type and object type. 后者仅用于区分原始类型和对象类型。

Actually Byte.TYPE is defined as: 实际上,Byte.TYPE定义为:

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

and getPrimitiveClass is an opaque method which retrieves the type from the VM so we can't investigate it further. getPrimitiveClass是一个不透明的方法,它从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> . 因此,即使您认为您正在传递原始数据类型Class,因为它们不存在(为什么它们应该是,因为它们引用的是根据对象的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 byte it will be autoboxed to a Byte object and that's it. 每当你添加一个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添加项目时会在运行时抛出哪些异常?

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语言规范,15.8.2

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 ). p.class的类型,其中p是基本类型的名称(第4.2节 ),是Class<B> ,其中B是在装箱转换(第5.1.7节 )之后类型p的表达式的类型。

The type of void.class ( §8.4.5 ) is Class<Void> . void.class§8.4.5 )的类型是Class<Void>

No! 没有! It is not bug. 这不是错误。 It is called Autoboxing . 它被称为Autoboxing When you pass byte to a generic method that expects Byte , the compiler automatically Autoboxes it to Byte which is an instance of Object. 当您将byte传递给期望Byte的泛型方法时,编译器会自动将其Autoboxes为Byte,这是Object的一个实例。 The antithesis of that operation is called Auto Unboxing and that is why operations like the one shown below are legal. 该操作的对立面称为自动取消装箱 ,这就是为什么像下面所示的操作是合法的。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM