Java Reflection: Создание реализующего класса

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

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

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

Комментарии к вопросу (2)

Легко, Ява.яз.отразить.Доверенности на помощь!

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

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");
    }
}
Комментарии (2)
Решение

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

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

Если это делается в тестовых целях, то вам следует обратить внимание на такие мокинг-фреймворки, как jMock и EasyMock.

Комментарии (1)

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

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

Комментарии (0)

На самом деле, вы должны использовать имя класса в методе 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";
    }

}
Комментарии (2)