Java:从作为参数传递的接口创建匿名 class

Java: Creating an anonymus class from a interface passed as an argument

这与Java8个接口有关。我有一个只有默认方法的接口。我可以创建此接口的匿名实例。

public interface Itest{
    default String get(){
            return "My name is ITest";
    }
}

public class A{
     Itest itest = new Itest(){};
}

我想创建一个提供接口的实用函数,returns 匿名 class。类似下面的内容

class MyUtil{
    public static <T> T get(Class<T> interface){
        // returns the anonymous class for the interface argument
        // Something like return new interface(){};
    }
}

public class A{
     Itest itest = MyUtil.get(Itest.class);
}

如果可能的话有人帮助我以及如何在 MyUtil.get() 函数中实现它?

用例:我很少有这样的接口(有默认方法)。现在,如果在设置中没有可用于这些接口的实现 class,我想创建匿名 class 实例,以便可以调用默认方法。当我只需要这些默认方法本身时,这将节省创建实现 classes 的工作。

interface Itest{
    default String get(){
            return "My name is ITest";
    }
}

class ITestImpl implements Itest {

}

class MyUtil{
    public static <T extends Itest> T get(Class<T> impl) {
        try {
            return impl.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }
    }
}

然后

Itest test = MyUtil.get(ITestImpl.class);

我认为无法使用 Class<?> 创建接口实例。您是否尝试过绕过 MyUtil class 并将所有接口方法设为静态。这将使您能够调用这些方法而无需启动它们。例如:

public interface Itest {
    static String get() {
        return "My name is ITest";
    }
}


public class TryingItest {

    public static void main(String[] args) {
        System.out.println(Itest.get());
    }

}

这会将界面中需要实现的部分与静态部分分开。希望这有帮助。

这是一个非常有趣的问题。我想到的第一个解决方案是一个简单的实例化:

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

但结果是:

java.lang.NoSuchMethodException: my.package.Itest.()

记住接口没有构造函数,不能直接实例化。

第 1 步:创建动态代理 class

您必须使用 java.lang.reflect.Proxy 创建动态代理 class 表示匿名 class 实现接口。

public static <T> T get(Class<T> clazz) {
    return (T) java.lang.reflect.Proxy.newProxyInstance(
        clazz.getClassLoader(),
        new java.lang.Class[] { clazz },
        (proxy, method, args) -> null
    );
}

用法:

Itest itest = MyUtil.get(Itest.class);
System.out.println(itest.getClass().getName());  // com.sun.proxy.$Proxy2
System.out.println(itest instanceof Shit.Itest); // true

// all methods invokation are completely ignored (returning null)
System.out.println(itest.get());                 // null 

InvocationHandler::invoke 的 lambda 表达式总是 returns null 不管调用什么方法,只要它是一个 "empty wrapper".

第 2 步:调用默认方法

只要你想调用一个默认的方法,你可以使用修改后的简单技巧在How do I invoke Java 8 default methods reflectively:

public static <T> T get(Class<T> clazz) {
    return (T) java.lang.reflect.Proxy.newProxyInstance(
        clazz.getClassLoader(),
        new java.lang.Class[]{clazz},
        (proxy, method, args) -> {
            if (method.isDefault()) {
                return MethodHandles.lookup()
                    .in(method.getDeclaringClass())
                    .unreflectSpecial(method,method.getDeclaringClass())
                    .bindTo(proxy)
                    .invokeWithArguments(args);
            }
            return null;
        }
    );
}

我们开始:

Itest itest = MyUtil.get(Itest.class);
System.out.println(itest.getClass().getName());  // com.sun.proxy.$Proxy2
System.out.println(itest instanceof Shit.Itest); // true

// default methods are invoked, the implementation is taken from the interface
System.out.println(itest.get());                 // My name is ITest