Java.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET.NET: 从作为参数传递的接口创建匿名类。

问题描述 投票:0回答:1

这与Java 8接口有关。我有一个接口,它只有一个默认方法。我可以为这个接口创建一个匿名的实例。

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

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

我想创建一个 Utility 函数,向其中提供一个 Interface,返回匿名类。类似于下面的东西,我想创建一个Utility函数,向其中提供一个Interface,返回匿名类。

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()函数中如何实现?

用例。我有几个这样的接口(有默认方法)。现在,如果在设置中没有这些接口的实现类,我想创建一个匿名类实例,这样就可以调用默认方法。当我只需要这些默认方法时,这样就可以省去创建实现类的工作。

java generics interface anonymous-class
1个回答
0
投票

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

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

但它的结果是:

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

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

第一步:创建动态代理类

你必须使用 java.lang.reflect.Proxy 来创建一个动态代理类,代表一个实现接口的匿名类。

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 

的lambda表达式。InvocationHandler::invoke 总是返回 null 无论调用什么参数的方法,只要它是一个 "空包装 "就可以了。

第二步:调用默认方法

只要你想调用一个默认的方法,你就可以使用一个修改后的简单技巧,答案在 如何反思性地调用Java 8默认方法?:

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

0
投票

我认为不可能使用以下方法来创建接口的实例: Class<?>. 你有没有试过绕过MyUtil类,把所有的intefaces方法都做成静态的。这将使你能够调用这些方法而无需启动它们。比如说,你可以把你的接口中需要实现的部分和需要静态化的部分分开。

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());
    }

}

这将把你的接口中需要实现的部分和静态的部分分开. 希望这能帮到你。


-1
投票
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);
最新问题
© www.soinside.com 2019 - 2024. All rights reserved.