2015-05-13 2 views
2

Я пытаюсь использовать Class.cast(), чтобы преобразовать коробочная Double к примитиву двойной:Java не может отливать из коробочного типа примитивного типа

Object d = 1.0d; 
Class<?> clazz = double.class; 
//the bellow line throws java.lang.ClassCastException: 
//Cannot cast java.lang.Double to double 
clazz.cast(d); 

Я делаю это потому, что в какой-то части моего кода , объект значения и класс задаются динамически, и у меня есть гарантия того, что объект значения имеет совместимый тип. Но это исключение действительно смущает меня. Каков контракт с использованием cast()?

UPDATE Я побежал в это, потому что у нас есть такой код:

interface Provider <T> { 
    T get(); 
    Class<T> getClazz(); 
} 

//a special handling for double primitive 
class DoubleProvider implements Provider<Double> { 

    public double getDouble(){ 
     return 1.0d; 
    } 

    @Override 
    public Double get() { 
    return getDouble(); 
    } 

    @Override 
    public Class<Double> getClazz() { 
    //why this actually compiles? 
    return double.class; 
    } 
} 

Если двойной и двойной настолько различны, что они не считаются назначаемые в ни способов, почему Java позволяет метод getClazz() в DoubleProvider для компиляции? Какова связь между double.class и Double.class?

+1

Вы не можете отнести класс-оболочку к примитиву таким образом. Автобоксинг и кастинг [не то же самое] (http://stackoverflow.com/questions/501653/java-whats-the-difference-between-autoboxing-and-casting). – azurefrog

ответ

6

Вы не можете бросить в Double к double (или наоборот), так как ни является подтипом другого. Используйте (double), который автоматически отменяет значение.

Зачем нужен cast()?

javadoc для API - это договор по методу. В этом случае javadoc says:

Отдает объект классу или интерфейсу, представленным этим объектом класса.

[...]

Броски: ClassCastException - если объект не является недействительным и не может быть назначен на тип T.

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

if (clazz == double.class) 
    handleDouble((double) o); 
if (clazz == int.class) 
    handleInt((int) o); 
... 

Относительно вашего редактирования: Это потому, что double.class имеет тип Class<Double>. JLS states:

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

+0

Утверждение JLS имеет смысл, но Double.class.equals (double.class) возвращает false? – Xinchao

+0

Да. Ты прав. Я был слишком быстр, когда формулировал свой ответ. Перефразировано. Благодарю. – aioobe

3

Авто [un] бокс - это, по сути, трюк компилятора. Его явная цель состоит в том, чтобы скрыть тот факт, что примитивы не, назначаемые или литые к соответствующему типу класса обертки, и наоборот.Всякий раз, когда вы думаете, назначая double переменной типа Double (скажем), вы на самом деле первым Autoboxing в double в Double, а затем назначая, что, как если бы вы написали что-то вроде этого:

Double wrapper = Double.valueOf(1.0d); 

В тот же день мы должны были сделать это вручную.

Я делаю это потому, что в какой-то части моего кода, объект значения и класса приведены динамически

Если вы действительно получать значение объект, то проблема не возникает. Примитивы не являются объектами, и Java не предоставляет возможности обрабатывать примитив bona fide, который должен позволять вам путать его с объектом. Если у вас есть метод, который принимает ссылку Object или если у вас есть переменная, содержащая ее, то вы можете быть на 100% увереннее, что ссылочный объект не является double или любым другим примитивом, хотя это может быть Double или экземпляр одного из других классов-оболочек.

Update: Если ваша система должна обрабатывать значения примитивных типов, а также типов оболочек, сохраняя различия между ними, то вы, вероятно, необходимо предоставить специальный случай для примитивов. Вы можете идентифицировать классы, представляющие примитивы, через Class.isPrimitive(). Их ровно девять, включая Void.TYPE.

Update2: В ответ на добавленную вопрос, тип Double.TYPE (оригинал, остается в силе, написание double.class) является Class<Double>. Поэтому это допустимое возвращаемое значение для метода, имеющего этот тип возврата. "Зачем?" вопросы всегда немного щекотливы, но я считаю справедливым вывод, что по крайней мере одна причина, по которой Double.TYPE имеет этот специфический параметр класса, заключается в том, что лучшей альтернативы нет. Аргументами типа должны быть имена ссылки типов. double не является ссылочным типом, поэтому тип double.class не может быть Class<double>. Class<Double> - следующая лучшая альтернатива.

Примечание хорошо: хотя Double.class и double.class оба имеют типаjava.lang.Class<java.lang.Double>, они разные классы.

+0

Справа. На самом деле мой случай обратный: у меня есть объект Double value и объект класса double.class. Поэтому я стараюсь double.class.cast (Double), что по сути является одной и той же проблемой. – Xinchao

+0

@ Xinchao, я обновил свой ответ с общим предложением для вашего дела. –

+0

спасибо! Я обновил свой вопрос и включил еще одну путаницу :) – Xinchao

Смежные вопросы