2015-02-13 3 views
3

Я не уверен, почему Java требует от меня вернуть метод makeInstance в T? Что я делаю не так? Есть ли лучший способ сделать это?java generic type parameter с newInstance

public class Scratch { 

    public <T extends Base> T freshen(T instance) { 
     //why do I need to cast this to T 
     return makeInstance(instance.getClass()); 
    } 

    public <T extends Base> T makeInstance(Class<T> type) { 
     try { 
      return type.newInstance(); 
     } catch (InstantiationException ex) { 
      Logger.getLogger(Scratch.class.getName()).log(Level.SEVERE, null, ex); 
     } catch (IllegalAccessException ex) { 
      Logger.getLogger(Scratch.class.getName()).log(Level.SEVERE, null, ex); 
     } 
     return null; 
    } 

    public static final class Base { 

    } 

} 

ответ

2

Причина Java хочет, чтобы вы бросили результат в том, что T вернулся из makeInstance метод не гарантирует такой же, как T из freshen метода. Причиной этого является то, что getClass() не возвращает Class<T>. Вместо этого он возвращает Class<? extends X>, где X является стиранием статического типа instance, то есть Object. Вот где останавливается цепочка умозаключений компилятора: он не может вывести из этого вызова, что тип возврата будет T, требуя, чтобы вы сделали актерский состав.

Альтернативы отливки экземпляра будет литья класса, как это:

return makeInstance((Class<T>)instance.getClass()); 
+0

"' GetClass() '' возвращает класс '" 'GetClass()' 'фактически возвращает класс ', где' | X | 'является стиранием статического типа' instance', который в этом случае является 'Object'. – newacct

0

Вы можете решить эту проблему, используя следующее.

public class Scratch<T extends Base> { 

    public T freshen(T instance) { 
     // No need to cast this to T 
     return makeInstance(instance.getClass()); 
    } 

    public T makeInstance(Class<T> type) { 
     try { 
      return type.newInstance(); 
     } catch (InstantiationException ex) { 
      Logger.getLogger(Scratch.class.getName()).log(Level.SEVERE, null, ex); 
     } catch (IllegalAccessException ex) { 
      Logger.getLogger(Scratch.class.getName()).log(Level.SEVERE, null, ex); 
     } 
     return null; 
    } 

    public static final class Base { 

    } 

} 

Надеюсь, это поможет.

1

Основная причина для вашей проблемы является «тип стирания»: когда компилятор Java компилирует тело метода freshen() он по существу заменяет T тип с его верхней границей, а именно: Base.

Так вот рассуждения компилятор делает: - instance имеет тип Base (как я уже сказал, T был заменен Base) - .getClass() вызывается на переменную типа Base так что возвращаемое значение этого вызова является Class<? extends Base> - параметр, который передается makeInstance(), поэтому, с точки зрения компилятора, имеет тип Class<? extends Base>. Следовательно, внутри TmakeInstance() также Base => метод возвращает Base

+0

Очень хорошее объяснение. Я выбрал другого, потому что он дал мне хорошее решение. Спасибо – cyberoblivion

+0

@cyberoblivion, вы можете проголосовать за него, чтобы указать, что это ценно для будущих читателей вашего вопроса –