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

Использование отражения в Java для создания нового экземпляра с типом ссылочной переменной, установленным для нового имени класса экземпляра?

Все примеры, на которые я смотрю на размышления, показывают создание нового экземпляра неизвестной реализации и включение этой реализации в интерфейс. Проблема в том, что теперь вы не можете вызывать какие-либо новые методы (только переопределения) для класса реализации, так как ваша ссылочная переменная объекта имеет тип интерфейса. Вот что я имею:

Class c = null;
try {
    c = Class.forName("com.path.to.ImplementationType");
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}
InterfaceType interfaceType = null;
try {
    interfaceType = (InterfaceType)c.newInstance();
} catch (InstantiationException e) {
    e.printStackTrace();
} catch (IllegalAccessException e) {
    e.printStackTrace();
}

Если у меня есть только ссылка на "com.path.to.ImplementationType", и я не знаю, что это за тип (он поступает из файла конфигурации), то как я могу использовать имя класса для перечислить его в ImplementationType? Возможно ли это?

4b9b3361

Ответ 1

Эта строка, похоже, суммирует суть вашей проблемы:

Проблема заключается в том, что теперь вы не можете вызывать какие-либо новые методы (только переопределения) для класса реализации, так как ваша ссылочная переменная объекта имеет тип интерфейса.

Вы довольно застряли в своей текущей реализации, так как вам нужно не только выполнить бросок, но и вам нужно определить метод (ы), который вы хотите вызвать в этом подклассе. Я вижу два варианта:

1. Как указано в другом месте, вы не можете использовать строковое представление имени класса для приведения вашего отраженного экземпляра к известному типу. Тем не менее, вы можете использовать тест String equals(), чтобы определить, подходит ли ваш класс к типу, который вы хотите, а затем выполнить строковое кодирование:

try {
   String className = "com.path.to.ImplementationType";// really passed in from config
   Class c = Class.forName(className);
   InterfaceType interfaceType = (InterfaceType)c.newInstance();
   if (className.equals("com.path.to.ImplementationType") {
      ((ImplementationType)interfaceType).doSomethingOnlyICanDo();
   } 
} catch (Exception e) {
   e.printStackTrace();
}

Это выглядит довольно уродливо, и это разрушает хороший управляемый конфигурацией процесс. Я не предлагаю вам это сделать, это просто пример.

2. Другой вариант, который у вас есть, - это расширить свое отражение от создания Class/Object, включив в него отражение Method. Если вы можете создать Class из строки, переданной из файла конфигурации, вы также можете передать имя метода из этого файла конфигурации и через отражение получить экземпляр самого Method из вашего объекта Class, Затем вы можете вызвать invoke (http://java.sun.com/javase/6/docs/api/java/lang/reflect/Method.html#invoke(java.lang.Object, java.lang.Object...)) на Method, передав в экземпляр вашего класса, который вы создали. Я думаю, что это поможет вам получить то, что вам нужно.

Вот пример кода. Обратите внимание, что я взял на себя смелость жестко кодировать параметры для методов. Вы также можете указать их в конфиге, и им нужно будет отразить их имена классов, чтобы определить их Class obejcts и экземпляры.

public class Foo {

    public void printAMessage() {
    System.out.println(toString()+":a message");
    }
    public void printAnotherMessage(String theString) {
        System.out.println(toString()+":another message:" + theString);
    }

    public static void main(String[] args) {
        Class c = null;
        try {
            c = Class.forName("Foo");
            Method method1 = c.getDeclaredMethod("printAMessage", new Class[]{});
            Method method2 = c.getDeclaredMethod("printAnotherMessage", new Class[]{String.class});
            Object o = c.newInstance();
            System.out.println("this is my instance:" + o.toString());
            method1.invoke(o);
            method2.invoke(o, "this is my message, from a config file, of course");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException nsme){
            nsme.printStackTrace();
        } catch (IllegalAccessException iae) {
            iae.printStackTrace();
        } catch (InstantiationException ie) {
            ie.printStackTrace();
        } catch (InvocationTargetException ite) {
            ite.printStackTrace();
        }
    }
}

и мой вывод:

this is my instance:[email protected]
[email protected]:a message
[email protected]:another message:this is my message, from a config file, of course

Ответ 2

//====Single Class Reference used to retrieve object for fields and initial values. Performance enhancing only====          
Class<?>    reference           =   vector.get(0).getClass();
Object      obj                 =   reference.newInstance();
Field[]     objFields           =   obj.getClass().getFields(); 

Ответ 3

В качестве дополнения к ответу akf вы можете использовать проверки экземпляров вместо вызовов String equals():

String cname="com.some.vendor.Impl";
try {
  Class c=this.getClass().getClassLoader().loadClass(cname);
  Object o= c.newInstance();
  if(o instanceof Spam) {
    Spam spam=(Spam) o;
    process(spam);
  }
  else if(o instanceof Ham) {
    Ham ham = (Ham) o;
    process(ham);
  }
  /* etcetera */
}
catch(SecurityException se) {
  System.err.printf("Someone trying to game the system?%nOr a rename is in order because this JVM doesn't feel comfortable with: "%s"", cname);
  se.printStackTrace();
}
catch(LinkageError le) {
  System.err.printf("Seems like a bad class to this JVM: "%s".", cname);
  le.printStackTrace();
}
catch(RuntimeException re) { 
  // runtime exceptions I might have forgotten. Classloaders are wont to produce those.
  re.printStackTrace();
}
catch(Exception e) { 
  e.printStackTrace();
}

Обратите внимание на либеральное кодирование некоторых значений. В любом случае основные моменты:

  • Используйте instanceof, а не equals(). Во всяком случае, он будет лучше взаимодействовать при рефакторинге.
  • Обязательно поймайте эти ошибки во время выполнения и безопасности.

Ответ 4

Вы хотите иметь возможность пройти в классе и получить экземпляр класса такого класса? Попробуйте следующее:

public static void main(String [] args) throws Exception {
    String s = instanceOf(String.class);
}

public static <T> T instanceOf (Class<T> clazz) throws Exception {
    return clazz.newInstance();
}

Ответ 5

Я не совсем уверен, что правильно задал вопрос, но, похоже, вам нужно что-то вроде этого:

    Class c = null;
    try {
        c = Class.forName("com.path.to.ImplementationType");
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
    T interfaceType = null;
    try {
        interfaceType = (T) c.newInstance();
    } catch (InstantiationException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }

Где T может быть определено на уровне метода или уровне класса, то есть <T extends InterfaceType>

Ответ 6

Если вы знали Class of ImplementationType, вы могли бы создать его экземпляр. Так что вы пытаетесь сделать это невозможно.