2013-09-07 4 views
2

Я пытаюсь выяснить, как динамически вызывать метод. У меня есть строка, которая описывает имя метода, но я не уверен, как это сделать. Я думал, что это можно сделать с отражением, но не получило никакого успеха. Примерjava динамически вызывать методы

set.add(vehicleConfiguration.getVehicleYear.getName()); 

set.add(vehicleConfiguration.getVehicleMake().getName()); 

set.add(vehicleConfiguration.getVehicleModel().getName()); 

Вы заметите, все вызовы методов такие же, за исключением getVehicleYear и т.д.

У меня есть строка, которая описывает имена методов, просто не знаю, как его использовать.

Я дошел до этого с отражением, но не смог.

set.add(Class.forName("VehicleConfiguration").getMethod("vehicleMake", null).getName()); 

Заранее спасибо.

+1

Каких типов возвращаемых 'getVehicleModel()', 'getVehicleMake()' и 'getVehicleYear()'? Если у всех их есть метод getName() ', похоже, что дженерики будут намного лучшим решением вашей проблемы, чем отражением. Или даже просто блок 'if' /' else'. Отражение переполняется в 99% случаев. – MrLore

+0

@MrLore, я открыт для идей, пожалуйста, покажите пример ниже, используя общий. Я предпочел бы держаться подальше от if/else, если это возможно. Спасибо –

ответ

0

Это закончилось тем, что мое окончательное решение который представляет собой комбинацию растворов MrLore и Sotirios Delimanolis. Это решение полностью динамично, без каких-либо условий.

Этот класс выполняет поиск имени путем передачи имени свойства;

String propertyName = "vehicleYear"; 

vehicleConfiguration.getInfo(propertyName).getName() 

propertyName = "vehicleMake"; 

vehicleConfiguration.getInfo(propertyName).getName() 

Этот класс представляет VehicleConfiguration

@Entity 
public class VehicleConfiguration extends StatefulEntity { 

    @ManyToOne 
    @JoinColumn(name = "year_id") 
    private VehicleYear vehicleYear; 

    @ManyToOne 
    @JoinColumn(name = "make_id") 
    private VehicleMake vehicleMake; 

    public LookupBaseEntity getInfo(final String fieldName) { 
     try { 
      String methodName = WordUtils.capitalize(fieldName); 
      Method method = VehicleConfiguration.class.getMethod("get" + methodName); 
      return (LookupBaseEntity) method.invoke(this); 
     } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { 
      Logger.getLogger(VehicleConfiguration.class.getName()).log(Level.SEVERE, null, ex); 
     } 
     return null; 
} 

Этот класс представляет VehicleYear

@Entity 
public class VehicleYear extends LookupBaseEntity { 

} 

Этот класс представляет VehicleMake

@Entity 
public class VehicleMake extends LookupBaseEntity { 

} 

которые оба EXTE й LookupBaseEntity

public class LookupBaseEntity extends StatefulEntity { 

    private String name; 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

} 
2

Вы должны использовать фактическое имя метода: getVehicleMake, а не vehicleMake.

Кроме того, если вы используете это как что-либо иное, кроме упражнения, не сворачивайте свои собственные. Используйте Commons BeanUtils или Spring's BeanWrapper.

+0

спасибо chrylis, я пропустил этот. Два других небольших вопроса, что происходит с нулем, и когда я перехожу к вызову getName(), действительно ли он вызывает метод getName() моего метода или вызывает getName() из getMethod()? –

+1

Изменение имени метода недостаточно. Вызов 'getName()' неуместен. –

+0

@George «null» сообщает системе отражения, что вы хотите использовать метод getVehicleMake, который не принимает никаких параметров, и, как отметил Sotirios, вы будете называть 'getName()' на 'Method', а не результат, который вы хотите (вы не' invoke() '' Method'). – chrylis

4

Класс, который вы ищете, является Method. Пожалуйста, внимательно прочитайте соответствующий javadoc.

Вы можете получить метод с, например

// assumign `getVehicleMake` is the name of the method and it accepts no parameters 
Method method = VehicleConfiguration.class.getMethod("getVehicleMake"); 
// VehicleConfiguration.class can be replaced by 
// Class.forName("VehicleConfiguration") 
// if VehicleConfiguration is the fully qualified, ie. with packages, name of the class 
// other you need Class.forName("com.yourpackage.VehicleConfiguration") 

Затем нужно invoke() этот метод на примере вашего класса.

VehicleConfiguration instance = new VehicleConfiguration(); 

Object returnObject = method.invoke(instance); // assuming no parameters 

Чтобы затем вызвать getName(), вам нужно бросить возвращаемый объект к типу, который имеет метод. Предполагая, что getMake() является метод типа VehicleMake, назовем его как этот

((VehicleMake)returnObject).getMake(); 
+0

Когда вы переходите на листинг объекта returnObject, это может быть динамическое или нет? –

+0

@George Не совсем, вам нужно знать тип, чтобы код компилировался. Есть некоторые обходные пути, как использование отражения для этого тоже. Вы не можете вызвать метод типа, которого вы не знаете. –

1

Расширение на мой комментарий, как и все методы, которые вы показали, есть метод getName(), давайте создадим простой класс, который определяет это:

class Nameable 
{ 
    private String name; 

    public Nameable(final String name) 
    { 
     this.name = name; 
    } 

    public String getName() 
    { 
     return this.name; 
    } 
} 

Теперь при создании объекта для Марка, модель и год, все они могут использовать этот класс, чтобы они могли быть использованы как взаимозаменяемые, а затем могут быть объединены в Car:

class Car 
{ 
    public final Nameable make; 
    public final Nameable model; 
    public final Nameable year; 

    public Car(Nameable make, Nameable model, Nameable year) 
    { 
     this.make = make; 
     this.model = model; 
     this.year = year; 
    } 

    public Nameable getInfo(final String info) 
    { 
     switch(info) 
     { 
      case "make": return this.make; 
      case "model": return this.model; 
      case "year": return this.year; 
     } 
     return null; 
    } 
} 

Тогда простая реализация будет:

class PaganiZonda2006 extends Car 
{ 
    public PaganiZonda2006() 
    { 
     super(new Nameable("Pagani"), new Nameable("Zonda"), new Nameable("2006")); 
    } 
} 

И, наконец, если вы хотите получить информацию, вы можете прочитать его следующим образом:

public static void main(String[] args) 
{ 
    Car car = new PaganiZonda2006(); 
    System.out.println(car.getInfo("make").getName()); //Pagani 
    System.out.println(car.getInfo("model").getName()); //Zonda 
    System.out.println(car.getInfo("year").getName()); //2006 
} 
+0

спасибо, я закончил использовать ваше решение. Это не совсем динамично, как я бы надеялся сделать это с помощью оператора switch, но мне это нравится намного лучше, чем другие представленные решения. –

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