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

Отражение Java: создание класса реализации

Class someInterface = Class.fromName("some.package.SomeInterface");

Как мне создать новый класс, который реализует someInterface?

Мне нужно создать новый класс и передать его функции, которая нуждается в someInterface в качестве аргумента.

4b9b3361

Ответ 1

Создание чего-то, что притворяется реализацией интерфейса "на лету", на самом деле не слишком сложно. Вы можете использовать java.lang.reflect.Proxy после реализации InvocationHandler для обрабатывать любые вызовы методов.

Конечно, вы могли бы создать настоящий класс с библиотекой, например BCEL.

Если это для тестовых целей, вы должны посмотреть на насмешливые фреймворки, такие как jMock и EasyMock.

Ответ 2

Легко, java.lang.reflect.Proxy на помощь!

Полный рабочий пример:

interface IRobot {

    String Name();

    String Name(String title);

    void Talk();

    void Talk(String stuff);

    void Talk(int stuff);

    void Talk(String stuff, int more_stuff);

    void Talk(int stuff, int more_stuff);

    void Talk(int stuff, String more_stuff);
}

public class ProxyTest {
    public static void main(String args[]) {
        IRobot robot = (IRobot) java.lang.reflect.Proxy.newProxyInstance(
                IRobot.class.getClassLoader(),
                new java.lang.Class[] { IRobot.class },
                new java.lang.reflect.InvocationHandler() {

            @Override
            public Object invoke(Object proxy, java.lang.reflect.Method method, Object[] args) throws java.lang.Throwable {
                String method_name = method.getName();
                Class<?>[] classes = method.getParameterTypes();

                if (method_name.equals("Name")) {
                    if (args == null) {
                        return "Mr IRobot";
                    } else {
                        return args[0] + " IRobot";
                    }
                } else if (method_name.equals("Talk")) {
                    switch (classes.length) {
                        case 0:
                            System.out.println("Hello");
                            break;
                        case 1:
                            if (classes[0] == int.class) {
                                System.out.println("Hi. Int: " + args[0]);
                            } else {
                                System.out.println("Hi. String: " + args[0]);
                            }
                            break;
                        case 2:
                            if (classes[0] == String.class) {
                                System.out.println("Hi. String: " + args[0] + ". Int: " + args[1]);
                            } else {
                                if (classes[1] == String.class) {
                                    System.out.println("Hi. int: " + args[0] + ". String: " + args[1]);
                                } else {
                                    System.out.println("Hi. int: " + args[0] + ". Int: " + args[1]);
                                }
                            }
                            break;
                    }
                }
                return null;
            }
        });

        System.out.println(robot.Name());
        System.out.println(robot.Name("Dr"));
        robot.Talk();
        robot.Talk("stuff");
        robot.Talk(100);
        robot.Talk("stuff", 200);
        robot.Talk(300, 400);
        robot.Talk(500, "stuff");
    }
}

Ответ 3

Если вы хотите выйти за пределы интерфейсов, вы можете взглянуть на cglib и objenesis. Вместе они позволят вам сделать некоторые довольно мощные вещи, расширяя абстрактный класс и создавая его. (jMock использует их для этой цели, например.)

Если вы хотите придерживаться интерфейсов, сделайте то, что сказал Джон Скит:).

Ответ 4

На самом деле вам нужно использовать имя класса в методе Class.fromName() и применить к вашему типу интерфейса. Посмотрите, помогает ли приведенный ниже пример.

public class Main {

    public static void main(String[] args) throws Exception {
        Car ferrari = (Car) Class.forName("Mercedez").newInstance();
        System.out.println(ferrari.getName());
    }
}

interface Car {
    String getName();
}

class Mercedez implements Car {

    @Override
    public String getName() {
        return "Mercedez";
    }

}

class Ferrari implements Car {

    @Override
    public String getName() {
        return "Ferrari";
    }

}