ฉันจะเรียกใช้วิธีการ Java ได้อย่างไรเมื่อกำหนดชื่อวิธีเป็นสตริง?


684

ถ้าฉันมีตัวแปรสองตัว:

Object obj;
String methodName = "getName";

objฉันจะเรียกวิธีการที่ระบุโดยmethodNameบนคลาสได้อย่างไร?

วิธีการที่ถูกเรียกไม่มีพารามิเตอร์และStringค่าตอบแทน มันทะเยอทะยานสำหรับถั่วจาวา


3
อาจใช้API การสะท้อนกลับหรือใช้Groovy
Peter Kelley

คำตอบ:


972

การเข้ารหัสจากสะโพกมันจะเป็นสิ่งที่ชอบ:

java.lang.reflect.Method method;
try {
  method = obj.getClass().getMethod(methodName, param1.class, param2.class, ..);
} catch (SecurityException e) { ... }
  catch (NoSuchMethodException e) { ... }

พารามิเตอร์จะระบุวิธีการเฉพาะที่คุณต้องการ (หากมีการใช้งานมากเกินไปหลายตัวหากวิธีนั้นไม่มีข้อโต้แย้งให้เท่านั้น methodName )

จากนั้นคุณเรียกใช้วิธีการนั้นโดยการโทร

try {
  method.invoke(obj, arg1, arg2,...);
} catch (IllegalArgumentException e) { ... }
  catch (IllegalAccessException e) { ... }
  catch (InvocationTargetException e) { ... }

.invokeถ้าคุณยังไม่มีข้อโต้แย้งใด ๆ แต่ใช่ อ่านเกี่ยวกับJava Reflection


2
อารมณ์เสียเล็กน้อยจากความจริงที่ว่า Java ใช้การลบแบบพิมพ์ แต่การรู้ว่าอย่างน้อยก็มี Reflection ส่งเสียงเชียร์ฉันอีกครั้ง: D และตอนนี้ด้วย lambdas ใน Java 8 ภาษากำลังเพิ่มขึ้นอย่างรวดเร็วด้วยการพัฒนาที่ทันสมัย สิ่งเดียวที่ขาดหายไปในขณะนี้คือการสนับสนุนแบบดั้งเดิมสำหรับตัวรับและผู้ตั้งค่าหรือคุณสมบัติตามที่รู้จักใน C #
7hi4g0

120
ไม่ยุติธรรม -1 เฮนริกอาจไม่สนับสนุนข้อยกเว้นการบีบและไม่ได้เขียนอะไรให้พวกเขาเพราะเขาแค่พยายามสะท้อนความคิด
ดึง

70
บวกหนึ่งสำหรับแสดงข้อยกเว้นที่อาจเกิดขึ้น ถ้าฉันเขียนสิ่งนี้มันจะเป็น ... catch (Exception e) {...
mikbanUtah

1
ผมได้ "ตัวแปรอาจจะไม่ได้รับการเริ่มต้น" สำหรับในmethod method.invoke(obj, arg1, arg2,...);การmethod = null;แก้ปัญหา แต่การกล่าวถึงในคำตอบนั้นไม่ใช่ความคิดที่ไม่ดี
อามิน

2
@ DeaMon1 วิธีการ Java ไม่ได้ใช้ "exit codes" แต่ถ้าเมธอดคืนค่าอะไรinvokeก็จะคืนค่าที่คืนกลับมา InvocationTargetExceptionหากเกิดข้อยกเว้นการเรียกใช้วิธีการยกเว้นจะถูกห่อใน
ThePyroEagle

194

ใช้วิธีการภาวนาจากการสะท้อน:

Class<?> c = Class.forName("class name");
Method method = c.getDeclaredMethod("method name", parameterTypes);
method.invoke(objectToInvokeOn, params);

ที่ไหน:

  • "class name" เป็นชื่อของคลาส
  • objectToInvokeOn เป็นประเภทวัตถุและเป็นวัตถุที่คุณต้องการเรียกใช้วิธีการ
  • "method name" เป็นชื่อของวิธีการที่คุณต้องการโทร
  • parameterTypesเป็นชนิดClass[]และประกาศพารามิเตอร์ที่วิธีการใช้
  • paramsเป็นประเภทObject[]และประกาศพารามิเตอร์ที่จะส่งผ่านไปยังวิธีการ

เจ๋งฉันคิดว่าคุณพูดถูกกับ getDeclaredMethod () มันน่าจะปลอดภัยกว่า getMethod () ..
brasskazoo

22
ไม่ถูกต้อง. ใช่ getDeclaredMethod ทำงานกับวิธีการส่วนตัวและได้รับการป้องกัน แต่มันไม่ทำงานกับวิธีการที่กำหนดไว้ใน superclasses (วิธีการสืบทอด) ดังนั้นมันขึ้นอยู่กับว่าคุณต้องการทำอะไร ในหลายกรณีคุณต้องการให้มันทำงานโดยไม่คำนึงถึงระดับที่แน่นอนซึ่งวิธีการที่กำหนดไว้
jrudolph

และฉันควรใส่ไฟล์ "คลาส" ที่ไหน? ควรอธิบายสำหรับ Eclipse IDE
Dr.jacky

@ Mr.Hyde บนเส้นทางการเรียน
Stijn de Witt

ฉันควรใส่อะไรข้างในและ method.invoke () ถ้าวิธีที่ฉันโทรไม่ยอมรับพารามิเตอร์ใด ๆ เลย? ดูเหมือนว่าฉันยังต้องระบุพารามิเตอร์ที่สองควรเป็นอาเรย์ของวัตถุที่ว่างเปล่าหรือไม่
อิกอร์

101

สำหรับผู้ที่ต้องการตัวอย่างรหัสตรงไปตรงมาใน Java 7:

Dog ระดับ:

package com.mypackage.bean;

public class Dog {
    private String name;
    private int age;

    public Dog() {
        // empty constructor
    }

    public Dog(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void printDog(String name, int age) {
        System.out.println(name + " is " + age + " year(s) old.");
    }
}

ReflectionDemo ระดับ:

package com.mypackage.demo;

import java.lang.reflect.*;

public class ReflectionDemo {

    public static void main(String[] args) throws Exception {
        String dogClassName = "com.mypackage.bean.Dog";
        Class<?> dogClass = Class.forName(dogClassName); // convert string classname to class
        Object dog = dogClass.newInstance(); // invoke empty constructor

        String methodName = "";

        // with single parameter, return void
        methodName = "setName";
        Method setNameMethod = dog.getClass().getMethod(methodName, String.class);
        setNameMethod.invoke(dog, "Mishka"); // pass arg

        // without parameters, return string
        methodName = "getName";
        Method getNameMethod = dog.getClass().getMethod(methodName);
        String name = (String) getNameMethod.invoke(dog); // explicit cast

        // with multiple parameters
        methodName = "printDog";
        Class<?>[] paramTypes = {String.class, int.class};
        Method printDogMethod = dog.getClass().getMethod(methodName, paramTypes);
        printDogMethod.invoke(dog, name, 3); // pass args
    }
}

เอาท์พุท: Mishka is 3 year(s) old.


คุณสามารถเรียกใช้ตัวสร้างด้วยพารามิเตอร์ด้วยวิธีนี้:

Constructor<?> dogConstructor = dogClass.getConstructor(String.class, int.class);
Object dog = dogConstructor.newInstance("Hachiko", 10);

หรือคุณสามารถลบ

String dogClassName = "com.mypackage.bean.Dog";
Class<?> dogClass = Class.forName(dogClassName);
Object dog = dogClass.newInstance();

และทำ

Dog dog = new Dog();

Method method = Dog.class.getMethod(methodName, ...);
method.invoke(dog, ...);

การอ่านที่แนะนำ: การสร้างอินสแตนซ์ของคลาสใหม่


1
คำตอบที่ดีที่สุดที่นี่ เสร็จสมบูรณ์และรัดกุม
รูเบน JaMes Aveño Gruta

1
แก้ไขคำตอบที่ดีที่สุด
Dhara Patel

คุณจะได้Methodสิ่งของที่ไหน
parlad

จากการสะท้อน pkg
เงิน

55

วิธีนี้สามารถเรียกใช้เช่นนี้ได้ นอกจากนี้ยังมีความเป็นไปได้อีกมาก (ตรวจสอบการสะท้อนกลับ API) แต่นี่เป็นวิธีที่ง่ายที่สุด:

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.junit.Assert;
import org.junit.Test;

public class ReflectionTest {

    private String methodName = "length";
    private String valueObject = "Some object";

    @Test
    public void testGetMethod() throws SecurityException, NoSuchMethodException, IllegalArgumentException,
            IllegalAccessException, InvocationTargetException {
        Method m = valueObject.getClass().getMethod(methodName, new Class[] {});
        Object ret = m.invoke(valueObject, new Object[] {});
        Assert.assertEquals(11, ret);
    }



}

7
+1 สำหรับคำตอบเดียวที่ยอมรับว่า OP ระบุ "ไม่มีพารามิเตอร์" ในคำถามของเขา (และเนื่องจากเป็นสิ่งที่ฉันกำลังมองหาด้วย)
John Fitzpatrick

16

ก่อนอื่นเลย หลีกเลี่ยงรหัสประเภทนี้ มันมีแนวโน้มที่จะเป็นรหัสที่ไม่ดีและไม่ปลอดภัยเช่นกัน (ดูหมวดที่ 6 ของแนวทางการเข้ารหัสอย่างปลอดภัยสำหรับภาษาการเขียนโปรแกรม Java รุ่น 2.0 )

หากคุณต้องทำเช่นนั้นให้เลือก java.beans เพื่อสะท้อน ถั่วห่อหุ้มการสะท้อนช่วยให้การเข้าถึงที่ค่อนข้างปลอดภัยและธรรมดา


11
ฉันไม่เห็นด้วย. มันง่ายมากที่จะเขียนโค้ดดังกล่าวเพื่อความปลอดภัยและฉันได้ทำในหลายภาษา ตัวอย่างเช่นหนึ่งสามารถสร้างชุดของวิธีการที่อนุญาตและอนุญาตให้ใช้วิธีการที่จะเรียกถ้าชื่อของมันอยู่ในชุด ปลอดภัยยิ่งขึ้น (แต่ยังคงเป็นกระดูกหัวง่าย) จะ จำกัด แต่ละวิธีที่อนุญาตให้อยู่ในสถานะที่ระบุและไม่อนุญาตให้เรียกใช้วิธีการยกเว้นว่าเธรด / อินเตอร์เฟส / ผู้ใช้ / สิ่งที่ตรงกับเกณฑ์ดังกล่าว
JSON

ไม่มีหมวดหมู่ทั้งหมดเกี่ยวกับปัญหาดังกล่าว ตอนนี้ฉันกำลังสร้างโปรแกรมอย่างง่ายเพื่อให้ผู้ใช้สามารถกำหนดงานโดยพลการบนออบเจ็กต์โดยใช้เว็บอินเตอร์เฟส ฉันรู้ว่ามันเป็นจริงไม่ปลอดภัย แต่การทดสอบที่เหมาะสมจะดำเนินการเมื่อได้รับการกำหนดค่าและจะช่วยให้ผู้ที่ไม่ใช่โปรแกรมเมอร์สามารถกำหนดค่างานได้ง่ายและยังช่วยให้โปรแกรมสามารถเชื่อมโยงคลาสที่กำหนดเองเข้ากับรหัสทั่วไปได้ ส่วนที่ฉันใช้การสะท้อนเพื่อให้พวกเขากำหนดค่าวิธีการที่จะใช้ผ่านทางเว็บอินเตอร์เฟส) โดยไม่ต้องอัปเดต GUI
DGoiko

14

เพื่อให้คำตอบของเพื่อนร่วมงานของคุณสมบูรณ์คุณอาจต้องใส่ใจกับ:

  • การโทรแบบสแตติกหรืออินสแตนซ์ (ในกรณีหนึ่งคุณไม่จำเป็นต้องใช้อินสแตนซ์ของคลาสในอีกกรณีหนึ่งคุณอาจจำเป็นต้องพึ่งพาคอนสตรัคเตอร์เริ่มต้นที่มีอยู่ซึ่งอาจจะใช่หรือไม่ใช่ก็ได้)
  • การเรียกใช้เมธอด public หรือ non-public (สำหรับวิธีหลังคุณต้องเรียก setAccessible บนเมธอดภายใน doPrivileged block , findbugsอื่น ๆจะไม่พอใจ )
  • encapsulating เป็นอีกหนึ่งข้อยกเว้นการสมัครได้ถ้าคุณต้องการที่จะโยนข้อยกเว้นระบบจาวามากมาย (ดังนั้น CCException ในรหัสด้านล่าง)

นี่คือโค้ด java1.4 เก่าซึ่งคำนึงถึงคะแนนเหล่านั้น:

/**
 * Allow for instance call, avoiding certain class circular dependencies. <br />
 * Calls even private method if java Security allows it.
 * @param aninstance instance on which method is invoked (if null, static call)
 * @param classname name of the class containing the method 
 * (can be null - ignored, actually - if instance if provided, must be provided if static call)
 * @param amethodname name of the method to invoke
 * @param parameterTypes array of Classes
 * @param parameters array of Object
 * @return resulting Object
 * @throws CCException if any problem
 */
public static Object reflectionCall(final Object aninstance, final String classname, final String amethodname, final Class[] parameterTypes, final Object[] parameters) throws CCException
{
    Object res;// = null;
    try {
        Class aclass;// = null;
        if(aninstance == null)
        {
            aclass = Class.forName(classname);
        }
        else
        {
            aclass = aninstance.getClass();
        }
        //Class[] parameterTypes = new Class[]{String[].class};
    final Method amethod = aclass.getDeclaredMethod(amethodname, parameterTypes);
        AccessController.doPrivileged(new PrivilegedAction() {
    public Object run() {
                amethod.setAccessible(true);
                return null; // nothing to return
            }
        });
        res = amethod.invoke(aninstance, parameters);
    } catch (final ClassNotFoundException e) {
        throw new CCException.Error(PROBLEM_TO_ACCESS+classname+CLASS, e);
    } catch (final SecurityException e) {
        throw new CCException.Error(PROBLEM_TO_ACCESS+classname+GenericConstants.HASH_DIESE+ amethodname + METHOD_SECURITY_ISSUE, e);
    } catch (final NoSuchMethodException e) {
        throw new CCException.Error(PROBLEM_TO_ACCESS+classname+GenericConstants.HASH_DIESE+ amethodname + METHOD_NOT_FOUND, e);
    } catch (final IllegalArgumentException e) {
        throw new CCException.Error(PROBLEM_TO_ACCESS+classname+GenericConstants.HASH_DIESE+ amethodname + METHOD_ILLEGAL_ARGUMENTS+String.valueOf(parameters)+GenericConstants.CLOSING_ROUND_BRACKET, e);
    } catch (final IllegalAccessException e) {
        throw new CCException.Error(PROBLEM_TO_ACCESS+classname+GenericConstants.HASH_DIESE+ amethodname + METHOD_ACCESS_RESTRICTION, e);
    } catch (final InvocationTargetException e) {
    throw new CCException.Error(PROBLEM_TO_ACCESS+classname+GenericConstants.HASH_DIESE+ amethodname + METHOD_INVOCATION_ISSUE, e);
    } 
    return res;
}

12
Object obj;

Method method = obj.getClass().getMethod("methodName", null);

method.invoke(obj, null);

วัตถุควรมีค่า / ค่าอย่างน้อยที่สุด
Lova Chittumuri

สิ่งนี้ใช้ได้ดีกับสิ่งที่ฉันต้องการ ฉันมีคลาสที่อินสแตนซ์แล้วและต้องการเพียงวิธีการออกจากมัน การเพิ่มการจับสำหรับข้อยกเว้นเป็นความคิดที่ดีที่นี่ แต่อย่างอื่นมันใช้ได้ดีสำหรับฉัน ฉันคิดว่าวิธีหลีกเลี่ยงข้อยกเว้นว่าง ๆ คือใช้ nullables แต่ฉันใช้ชื่อเมธอดที่ จำกัด มาก ๆ (ตามตัวอักษรเพียงแค่ตัวนับจาก 1 ถึง 4)
Jain Waldrip

12
//Step1 - Using string funClass to convert to class
String funClass = "package.myclass";
Class c = Class.forName(funClass);

//Step2 - instantiate an object of the class abov
Object o = c.newInstance();
//Prepare array of the arguments that your function accepts, lets say only one string here
Class[] paramTypes = new Class[1];
paramTypes[0]=String.class;
String methodName = "mymethod";
//Instantiate an object of type method that returns you method name
 Method m = c.getDeclaredMethod(methodName, paramTypes);
//invoke method with actual params
m.invoke(o, "testparam");

8

หากคุณโทรหลายครั้งคุณสามารถใช้วิธีการจัดการใหม่ที่แนะนำใน Java 7 ที่นี่เราไปสำหรับวิธีการของคุณกลับสตริง:

Object obj = new Point( 100, 200 );
String methodName = "toString";  
Class<String> resultType = String.class;

MethodType mt = MethodType.methodType( resultType );
MethodHandle methodHandle = MethodHandles.lookup().findVirtual( obj.getClass(), methodName, mt );
String result = resultType.cast( methodHandle.invoke( obj ) );

System.out.println( result );  // java.awt.Point[x=100,y=200]

1
เพื่อผู้อ่านในอนาคต; หากคุณใส่ใจเรื่องประสิทธิภาพคุณจะต้องใช้invokeExactทุกครั้งที่ทำได้ สำหรับสิ่งนั้นลายเซ็นไซต์การโทรต้องตรงกับประเภทการจัดการวิธี โดยปกติจะใช้เวลาเล็กน้อยในการทำงาน ในกรณีนี้คุณจะต้องใช้พารามิเตอร์ตัวแรกด้วย: methodHandle = methodHandle.asType(methodHandle.type().changeParameterType(0, Object.class));แล้วจึงเรียกใช้เช่นString result = (String) methodHandle.invokeExact(obj);
Jorn Vernee

7

ดูเหมือนจะเป็นสิ่งที่สามารถทำได้ด้วยแพ็คเกจ Java Reflection

http://java.sun.com/developer/technicalArticles/ALT/Reflection/index.html

โดยเฉพาะอย่างยิ่งภายใต้วิธีการเรียกใช้ตามชื่อ:

นำเข้า java.lang.reflect. *;

public class method2 {
  public int add(int a, int b)
  {
     return a + b;
  }

  public static void main(String args[])
  {
     try {
       Class cls = Class.forName("method2");
       Class partypes[] = new Class[2];
        partypes[0] = Integer.TYPE;
        partypes[1] = Integer.TYPE;
        Method meth = cls.getMethod(
          "add", partypes);
        method2 methobj = new method2();
        Object arglist[] = new Object[2];
        arglist[0] = new Integer(37);
        arglist[1] = new Integer(47);
        Object retobj 
          = meth.invoke(methobj, arglist);
        Integer retval = (Integer)retobj;
        System.out.println(retval.intValue());
     }
     catch (Throwable e) {
        System.err.println(e);
     }
  }
}

6

การจัดทำดัชนี (เร็วกว่า)

คุณสามารถใช้FunctionalInterfaceเพื่อบันทึกวิธีการในภาชนะเพื่อจัดทำดัชนีพวกเขา คุณสามารถใช้คอนเทนเนอร์อาเรย์เพื่อเรียกใช้โดยใช้ตัวเลขหรือ hashmap เพื่อเรียกใช้โดยใช้สตริง โดยเคล็ดลับนี้คุณสามารถดัชนีวิธีการของคุณที่จะเรียกพวกเขาแบบไดนามิกได้เร็วขึ้น

@FunctionalInterface
public interface Method {
    double execute(int number);
}

public class ShapeArea {
    private final static double PI = 3.14;

    private Method[] methods = {
        this::square,
        this::circle
    };

    private double square(int number) {
        return number * number;
    }

    private double circle(int number) {
        return PI * number * number;
    }

    public double run(int methodIndex, int number) {
        return methods[methodIndex].execute(aNumber);
    }
}

ไวยากรณ์ของแลมบ์ดา

คุณสามารถใช้แลมบ์ดาไวยากรณ์ได้:

public class ShapeArea {
    private final static double PI = 3.14;

    private Method[] methods = {
        number -> {
            return number * number;
        },
        number -> {
            return PI * number * number;
        },
    };

    public double run(int methodIndex, int number) {
        return methods[methodIndex].execute(aNumber);
    }
}

1
เทคนิคนี้ดูเหมือนจะดีกว่าการสะท้อน
John O

มันดีกว่านี้จริงเหรอ?
Dimitri Kopriwa

@DimitriKopriwa การจัดทำดัชนีเป็นวิธีที่คุณใช้ ram แทนการคำนวณ CPU O(1)สำหรับการทำดัชนีจำนวนเต็มความยากลำบากของขั้นตอนวิธีคือ
Amir Fo

5
Method method = someVariable.class.getMethod(SomeClass);
String status = (String) method.invoke(method);

SomeClassเป็นคลาสและsomeVariableเป็นตัวแปร


ถ้า someVariable เป็นวัตถุจริงๆให้โทร someVariable.getClass () นอกจากนี้คุณไม่สามารถเรียก getMethod () ที่มีคลาสเป็นอาร์กิวเมนต์เท่านั้น ไม่เรียกใช้เมธอดด้วยเมธอด ถูกต้อง: someVariable.getClass (). getMethod ("coolMethod", parameterClasses) .invoke (อาร์กิวเมนต์);
Orangle

5

ฉันทำสิ่งนี้:

try {
    YourClass yourClass = new YourClass();
    Method method = YourClass.class.getMethod("yourMethodName", ParameterOfThisMethod.class);
    method.invoke(yourClass, parameter);
} catch (Exception e) {
    e.printStackTrace();
}

5

โปรดอ้างอิงรหัสต่อไปนี้อาจช่วยคุณได้

public static Method method[];
public static MethodClass obj;
public static String testMethod="A";

public static void main(String args[]) 
{
    obj=new MethodClass();
    method=obj.getClass().getMethods();
    try
    {
        for(int i=0;i<method.length;i++)
        {
            String name=method[i].getName();
            if(name==testMethod)
            {   
                method[i].invoke(name,"Test Parameters of A");
            }
        }
    }
    catch(Exception ex)
    {
        System.out.println(ex.getMessage());
    }
}

ขอบคุณ ....


นี่ไม่ใช่วิธีเปรียบเทียบสตริงใน Java คุณต้องใช้วิธีการ. equals มิฉะนั้นคุณเพียงแค่เปรียบเทียบว่าพวกเขาคือการอ้างอิงวัตถุเดียวกันและคุณไม่สนใจจริง ๆ เกี่ยวกับการอ้างอิงวัตถุ - เพียงแค่เนื้อหาสตริงการแข่งขัน นอกจากนี้คุณยังสามารถรับวิธีการตามชื่อผ่านการสะท้อนดังนั้นไม่แน่ใจว่าทำไมคุณจะม้วนของคุณเอง?
Lo-Tan

5

นี่คือความพร้อมในการใช้วิธีการ:

ในการเรียกใช้เมธอดโดยไม่มีอาร์กิวเมนต์:

public static void callMethodByName(Object object, String methodName) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
    object.getClass().getDeclaredMethod(methodName).invoke(object);
}

ในการเรียกใช้เมธอดด้วยอาร์กิวเมนต์:

    public static void callMethodByName(Object object, String methodName, int i, String s) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        object.getClass().getDeclaredMethod(methodName, int.class, String.class).invoke(object, i, s);
    }

ใช้วิธีการด้านบนดังต่อไปนี้:

package practice;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;

public class MethodInvoke {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException {
        String methodName1 = "methodA";
        String methodName2 = "methodB";
        MethodInvoke object = new MethodInvoke();
        callMethodByName(object, methodName1);
        callMethodByName(object, methodName2, 1, "Test");
    }

    public static void callMethodByName(Object object, String methodName) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        object.getClass().getDeclaredMethod(methodName).invoke(object);
    }

    public static void callMethodByName(Object object, String methodName, int i, String s) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        object.getClass().getDeclaredMethod(methodName, int.class, String.class).invoke(object, i, s);
    }

    void methodA() {
        System.out.println("Method A");
    }

    void methodB(int i, String s) {
        System.out.println("Method B: "+"\n\tParam1 - "+i+"\n\tParam 2 - "+s);
    }
}

เอาท์พุท:

วิธีการ  
วิธีการ B:  
	Param1 - 1  
	พารามิเตอร์ 2 - ทดสอบ

3

Student.java

class Student{
    int rollno;
    String name;

    void m1(int x,int y){
        System.out.println("add is" +(x+y));
    }

    private void m3(String name){
        this.name=name;
        System.out.println("danger yappa:"+name);
    }
    void m4(){
        System.out.println("This is m4");
    }
}

StudentTest.java

import java.lang.reflect.Method;
public class StudentTest{

     public static void main(String[] args){

        try{

            Class cls=Student.class;

            Student s=(Student)cls.newInstance();


            String x="kichha";
            Method mm3=cls.getDeclaredMethod("m3",String.class);
            mm3.setAccessible(true);
            mm3.invoke(s,x);

            Method mm1=cls.getDeclaredMethod("m1",int.class,int.class);
            mm1.invoke(s,10,20);

        }
        catch(Exception e){
            e.printStackTrace();
        }
     }
}

1

คุณควรใช้สะท้อน - init วัตถุชั้นแล้ววิธีการในชั้นนี้แล้วเรียกวิธีการนี้กับวัตถุที่มีตัวเลือกพารามิเตอร์ อย่าลืมห่อตัวอย่างต่อไปนี้ในบล็อคลองจับ

หวังว่ามันจะช่วย!

Class<?> aClass = Class.forName(FULLY_QUALIFIED_CLASS_NAME);
Method method = aClass.getMethod(methodName, YOUR_PARAM_1.class, YOUR_PARAM_2.class);
method.invoke(OBJECT_TO_RUN_METHOD_ON, YOUR_PARAM_1, YOUR_PARAM_2);

1

นี่ใช้ได้ดีสำหรับฉัน:

public class MethodInvokerClass {
    public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, ClassNotFoundException, InvocationTargetException, InstantiationException {
        Class c = Class.forName(MethodInvokerClass.class.getName());
        Object o = c.newInstance();
        Class[] paramTypes = new Class[1];
        paramTypes[0]=String.class;
        String methodName = "countWord";
         Method m = c.getDeclaredMethod(methodName, paramTypes);
         m.invoke(o, "testparam");
}
public void countWord(String input){
    System.out.println("My input "+input);
}

}

เอาท์พุท:

My input testparam

ฉันสามารถเรียกใช้เมธอดได้โดยส่งชื่อไปยังเมธอดอื่น (เช่น main)


1

การใช้ import java.lang.reflect.*;

public static Object launchProcess(String className, String methodName, Class<?>[] argsTypes, Object[] methodArgs)
        throws Exception {

    Class<?> processClass = Class.forName(className); // convert string classname to class
    Object process = processClass.newInstance(); // invoke empty constructor

    Method aMethod = process.getClass().getMethod(methodName,argsTypes);
    Object res = aMethod.invoke(process, methodArgs); // pass arg
    return(res);
}

และนี่คือวิธีที่คุณใช้:

String className = "com.example.helloworld";
String methodName = "print";
Class<?>[] argsTypes = {String.class,  String.class};
Object[] methArgs = { "hello", "world" };   
launchProcess(className, methodName, argsTypes, methArgs);

0

ด้วยjooRเป็นเพียง:

on(obj).call(methodName /*params*/).get()

นี่คือตัวอย่างที่ละเอียดมากขึ้น:

public class TestClass {

    public int add(int a, int b) { return a + b; }
    private int mul(int a, int b) { return a * b; }
    static int sub(int a, int b) { return a - b; }

}

import static org.joor.Reflect.*;

public class JoorTest {

    public static void main(String[] args) {
        int add = on(new TestClass()).call("add", 1, 2).get(); // public
        int mul = on(new TestClass()).call("mul", 3, 4).get(); // private
        int sub = on(TestClass.class).call("sub", 6, 5).get(); // static
        System.out.println(add + ", " + mul + ", " + sub);
    }
}

ภาพพิมพ์นี้:

3, 12, 1


-10

สำหรับฉันวิธีการพิสูจน์ที่ง่ายและโง่ก็คือการทำให้วิธีการเรียกวิธีเช่น:

public static object methodCaller(String methodName)
{
    if(methodName.equals("getName"))
        return className.getName();
}

จากนั้นเมื่อคุณต้องการเรียกใช้เมธอดเพียงแค่ใส่สิ่งนี้

//calling a toString method is unnessary here, but i use it to have my programs to both rigid and self-explanitory 
System.out.println(methodCaller(methodName).toString()); 

4
ถ้าเช่นเป็นที่รู้จักกันอยู่แล้วในช่วง compiletime ทำไมคุณไม่เพียงแค่ทำclassName.getName().toString()? คุณขาดจุดสะท้อนทั้งหมด
BalusC

อย่างที่ฉันบอกไปว่าไม่จำเป็นในกรณีนี้ แต่สมมติว่าคุณมักจะรู้ว่าอินสแตนซ์นั้นเป็นนิสัยการเขียนโปรแกรมที่ไม่ดี
SMayne

2
@SMayne: ฉันอยากจะแนะนำให้ลบโพสต์นี้
lpapp

การเขียนโปรแกรมที่ไม่ดีค่อนข้างจะเป็นการชมเชยในกรณีนี้
pdenti
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.