Подтвердить что ты не робот

Java разрешает примитивные типы в дженериках

Я знаю, что java не предполагает поддержку общих аргументов, которые являются примитивными типами, и, конечно же, что-то вроде:

Vector<byte> test;

не скомпилируется.

однако с небольшим количеством рук, которые я случайно выполнил в программе, я обнаружил, что на самом деле можно создать общий объект с примитивным типом (метод, показанный ниже)

Кроме того, java ложно позволяет этому экземпляру присваиваться переменной типа Vector<Byte>, когда, как показывают операторы печати, byte.class и Byte.class являются двумя отдельными животными. Из-за этого попытки совершения вызовов по объекту приводят к неожиданным и странным поведениям/ошибкам.

Является ли это ошибкой 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);

    }

}
4b9b3361

Ответ 1

Оба Byte.class и Byte.TYPE являются объектами Class<Byte>. Последние просто используются для различения примитивного типа и типа объекта.

Фактически Byte.TYPE определяется как:

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

и getPrimitiveClass - непрозрачный метод, который извлекает тип из VM, поэтому мы не можем его исследовать дальше.

Итак, даже если вы считаете, что передаете примитивный тип данных Class, поскольку они не существуют (почему они должны, поскольку они ссылаются на то, что является типичным в соответствии с системой набора текста Java для объектов, t включают примитивные типы, пока они не будут помещены в классы-оболочки), вы создаете Vector<Byte>.

Но в конце концов это не имеет большого значения, по достижении времени выполнения аннотации типа стираются, а общий тип ничего не значит. Всякий раз, когда вы добавите byte, он будет автобоксирован объекту byte и что он.

У меня нет возможности проверить ваш код на данный момент, какие исключения вызывают во время выполнения при добавлении элементов в Vector?

Ответ 2

Вы наткнулись на autoboxing и unboxing. См. http://docs.oracle.com/javase/tutorial/java/data/autoboxing.html

Версия в ореховой скорлупе

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

byte.class, int.class и т.д. разрешить Byte, Integer и т.д. См. Спецификация языка Java, 15.8.2:

15.8.2. Литералы классов

......

Тип p.class, где p - имя примитивного типа (§4.2), Class<B>, где B является типом выражения типа p после преобразования бокса (§5.1.7).

Тип void.class (§8.4.5) Class<Void>.

Ответ 3

Нет! Это не ошибка. Он называется Автобоксинг. Когда вы передаете байт общий метод, ожидающий Байт, компилятор автоматически автоматически устанавливает его в байты, который является экземпляром объекта. Противопоставление этой операции называется Автоматическое разблокирование, и поэтому операции, подобные приведенным ниже, являются законными.

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