2010-02-06 5 views
8

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

public class HelloClass { 

    private class MyClass 
    { 
     public MyClass() 
     { 
      System.out.println ("Oh heck this is me!"); 
     } 
    } 

    public Object newInstance (Object o) 
    { 
     try { 
      // java.lang.InstantiationException here 
      return o.getClass().newInstance();   
     } catch (Exception e) { 
      e.printStackTrace(System.out); 
      return null; 
     } 
    } 

    public void run() 
    { 
     MyClass m = new MyClass(); 
     Object o = newInstance(m); 
    } 

    public static void main(String[] args) 
    { 
     HelloClass hd = new HelloClass(); 
     hd.run(); 
    } 
} 

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

UPD: Вот исключение я получаю:

java.lang.InstantiationException: HelloClass$MyClass 
    at java.lang.Class.newInstance0(Class.java:340) 
    at java.lang.Class.newInstance(Class.java:308) 
    at HelloClass.newInstance(HelloClass.java:14) 
    at HelloClass.run(HelloClass.java:24) 
    at HelloClass.main(HelloClass.java:30) 
+0

Какой класс вы пытаетесь создать экземпляр? Если это абстрактный класс или интерфейс, то это не сработает, и вы получите исключение InstantiationException. Может быть, в том числе и трассировка стека исключения поможет. – JasCav

+0

Я пытаюсь создать экземпляр MyClass, подумал, что это совершенно очевидно, поскольку я вызываю newInstance (m), где m является экземпляром MyClass;). Добавлено исключение из исходного сообщения. – azerole

+0

Почему упоминание дженериков в названии? Что они должны делать с этой проблемой? – skaffman

ответ

6

Конструкторы для внутренних классов имеют скрытый первый аргумент, который необходимо предоставить, когда вы используете отражение. Передайте экземпляр внешнего класса.

Вместо

return o.getClass().newInstance(); 

использования:

return o.getClass().getConstructor(getClass()).newInstance(this); 
+0

И поскольку указание конкретного конструктора по положению не очень надежное, я думаю, теперь понимаю, почему FindBugs жалуется в таких случаях, что класс должен быть * статическим * внутренним классом. Интересно! –

+0

Большое спасибо. Теперь я вижу. – azerole

+0

О да, вроде бы это неплохо. –

1

Проблема, кажется, что это не статический класс член, как это работает и, если вы объявите MyClass как статические, и если вы сделаете это класс высшего уровня. Не совсем понятно, почему.

1

Очень хороший вопрос!

Это потому, что внутренний класс имеет неявный аргумент в каждом конструкторе - его внешний класс. Следовательно, он не имеет конструктора по умолчанию.

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

+0

Это то, что я тоже думал, но, похоже, что 'newInstance()' не имеет версии, которая принимает закрытый объект, вам нужно использовать объекты Constructor. – skaffman

+0

вот что я только что видел :) исправил. – Bozho

+0

Предполагая, что вы имели в виду 'HelloClass.class', это не работает для меня, но выдает' IllegalArgumentException': * неправильное количество аргументов *. –

0

Метод newInstance в объекте Class работает только для конкретного класса с конструктором no-arg.

Если вы измените MyClass на статичный, он будет квалифицироваться и код будет работать. Как бы то ни было, он имеет неявный конструктор с внешним объектом в качестве параметра и не имеет конструктора no-arg.

Вы можете сделать свой собственный newInstance метод работы с использованием метода newInstance конструктора:

public Object newInstance (Object o) 
{ 
    try { 
     final Constructor<? extends Object> constructor = 
        o.getClass().getConstructor(this.getClass()); 
     return constructor.newInstance(this); 
    } catch (Exception e) { 
     e.printStackTrace(System.out); 
     return null; 
    } 
} 
+0

Только после публикации этого обновления я обновляюсь и вижу, что другие дали практически тот же ответ. Я все равно оставлю, но чувствую себя немного глупо! –

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