Java 在没有公共接口的情况下调用公共方法
我有一些生成的代码(也就是说,它不能被更改),看起来像这样Java 在没有公共接口的情况下调用公共方法,java,reflection,Java,Reflection,我有一些生成的代码(也就是说,它不能被更改),看起来像这样 class Generated1 { public String getA() { return "1"; } public void setB(String b) { } public void setC(String c) { } public void setD(String d) { } } class Generated2 { pu
class Generated1 {
public String getA() {
return "1";
}
public void setB(String b) {
}
public void setC(String c) {
}
public void setD(String d) {
}
}
class Generated2 {
public String getA() {
return "2";
}
public void setB(String b) {
}
public void setC(String c) {
}
public void setD(String d) {
}
}
我正在通过反射探索这些物体。它们都没有实现任何公共接口,但有很多,我想将它们视为实现:
interface CommonInterface {
String getA();
void setB(String b);
void setC(String c);
void setD(String d);
}
这当然应该是可能的。这被认为是非常好的代码
class CommonInterface1 extends Generated1 implements CommonInterface {
// These are perfectly good classes.
}
class CommonInterface2 extends Generated2 implements CommonInterface {
// These are perfectly good classes.
}
我想我要找的是:
private void doCommon(CommonInterface c) {
String a = c.getA();
c.setB(a);
c.setC(a);
c.setD(a);
}
private void test() {
// Simulate getting by reflection.
List<Object> objects = Arrays.asList(new Generated1(), new Generated2());
for (Object object : objects) {
// What is the simplest way to call `doCommon` with object here?
doCommon(object);
}
}
与
我知道我可以像这样使用代理
,但我更喜欢使用更好的代理
private void test() {
// Simulate getting by reflection.
List<Object> objects = Arrays.asList(new Generated1(), new Generated2());
for (Object object : objects) {
// What is the simplest way to call `doCommon` with object here?
doCommon(adapt(object));
}
}
private CommonInterface adapt(Object o) {
return adapt(o, CommonInterface.class);
}
public static <T> T adapt(final Object adaptee,
final Class<T>... interfaceToImplement) {
return (T) Proxy.newProxyInstance(
adaptee.getClass().getClassLoader(),
interfaceToImplement,
// Call the equivalent method from the adaptee.
(proxy, method, args) -> adaptee.getClass()
.getMethod(method.getName(), method.getParameterTypes())
.invoke(adaptee, args));
}
private void test(){
//模拟通过反射获取。
List objects=Arrays.asList(new-Generated1(),new-Generated2());
用于(对象:对象){
//在这里用object调用'docomon'最简单的方法是什么?
doCommon(适应(对象));
}
}
专用公共接口适配(对象o){
返回adapt(o,CommonInterface.class);
}
公共静态T适配(最终对象适配对象,
最终类…接口(实现){
return(T)Proxy.newProxyInstance(
adaptee.getClass().getClassLoader(),
接口执行,
//从适配器调用等效的方法。
(代理、方法、参数)->adaptee.getClass()
.getMethod(方法.getName(),方法.getParameterTypes())
.invoke(adaptee,args));
}
如果使用反射,则不需要两个CommonInterfaceX
类,可以使用代理实现CommonInterface
:
public class Wrapper implements InvocationHandler {
private final Object delegate;
public static <T> T wrap(Object obj, Class<T> intf) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Object proxy = Proxy.newProxyInstance(cl, new Class<?>[] {intf},
new Wrapper(obj));
return intf.cast(proxy);
}
private Wrapper(Object delegate) {
this.delegate = delegate;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Method dmethod = delegate.getClass().getMethod(
method.getName(), method.getParameterTypes());
return dmethod.invoke(delegate, args);
}
}
公共类包装器实现调用处理程序{
私有最终对象委托;
公共静态T换行(对象对象对象,类intf){
ClassLoader cl=Thread.currentThread().getContextClassLoader();
objectproxy=proxy.newProxyInstance(cl,新类[]{intf},
新包装(obj));
返回intf.cast(代理);
}
专用包装器(对象委托){
this.delegate=委托;
}
@凌驾
公共对象调用(对象代理、方法、对象[]参数)
扔掉的{
方法dmethod=delegate.getClass().getMethod(
方法.getName(),方法.getParameterTypes());
返回dmethod.invoke(委托,参数);
}
}
您可以按如下方式使用此类:
List<Object> objects = Arrays.asList(new Generated1(), new Generated2());
for (Object object : objects) {
CommonInterface proxy = Wrapper.wrap(object, CommonInterface.class);
doCommon(proxy);
}
List objects=Arrays.asList(new-Generated1(),new-Generated2());
用于(对象:对象){
CommonInterface proxy=Wrapper.wrap(对象,CommonInterface.class);
doCommon(代理);
}
更新:请注意,相同的
包装器类可用于任何接口。无法在Generated1
和Generated2
之间实现静态类型关系
即使您创建了CommonInterface1
和CommonInterface2
,您仍然不能静态地使用Generated1
对象作为CommonInterface1
,因为newgenerated1()
不是CommonInterface1
(并且永远不会成为一个)
到目前为止,最简单的解决方案是更改代码生成,将CommonInterface
添加到Generated1
和Generated2
如果这是绝对不可能的,那么避免代码重复的唯一其他方法就是进行反射。如果您想替换为注释。我认为你可以很容易地做到
public class Generated {
public String getA() {
return "A";
}
public String sayHello(String name) {
return "hello " + name;
}
}
public class Helper {
private static final String METHOD_NAME = "getA";
private static final String METHOD_WITH_PARAM_NAME = "sayHello";
public static void main(String[] args) throws Exception {
Generated generated = new Generated();
accessMethod(generated);
accessMethodWithParameter(generated);
}
private static void accessMethod(Generated g) throws Exception {
Method[] methods = g.getClass().getDeclaredMethods();
for(Method method : methods) {
if(isCommonMethod(method)) {
String result = (String) method.invoke(g);
System.out.println(METHOD_NAME + "() = " + result);
}
}
}
private static boolean isCommonMethod(Method m) {
return m.getName().equals(METHOD_NAME) && m.getReturnType().equals(String.class);
}
private static void accessMethodWithParameter(Generated g) throws Exception {
Method[] methods = g.getClass().getDeclaredMethods();
for(Method method : methods) {
if(isCommonMethodWithParameter(method)) {
String result = (String) method.invoke(g, "Max");
System.out.println(METHOD_WITH_PARAM_NAME + "(\"Max\") = " + result);
}
}
}
private static boolean isCommonMethodWithParameter(Method m) {
return m.getName().equals(METHOD_WITH_PARAM_NAME) &&
m.getReturnType().equals(String.class) &&
m.getParameterTypes().length == 1 &&
m.getParameterTypes()[0].equals(String.class);
}
}
首先,创建接口CommonInterface
interface CommonInterface {
String getA();
void setB(String b);
void setC(String c);
void setD(String d);
}
class Generated1 implements CommonInterface {
@overide
public String getA() {
return "1";
}
@overide
public void setB(String b) {
}
@overide
public void setC(String c) {
}
@overide
public void setD(String d) {
}
}
class Generated2 implements CommonInterface {
@overide
public String getA() {
return "2";
}
@overide
public void setB(String b) {
}
@overide
public void setC(String c) {
}
@overide
public void setD(String d) {
}
}
然后,创建2个类Generated1
和Generated2
继承的CommonInterface
interface CommonInterface {
String getA();
void setB(String b);
void setC(String c);
void setD(String d);
}
class Generated1 implements CommonInterface {
@overide
public String getA() {
return "1";
}
@overide
public void setB(String b) {
}
@overide
public void setC(String c) {
}
@overide
public void setD(String d) {
}
}
class Generated2 implements CommonInterface {
@overide
public String getA() {
return "2";
}
@overide
public void setB(String b) {
}
@overide
public void setC(String c) {
}
@overide
public void setD(String d) {
}
}
你可以通过思考手动完成
public class Generated {
public String getA() {
return "A";
}
public String sayHello(String name) {
return "hello " + name;
}
}
public class Helper {
private static final String METHOD_NAME = "getA";
private static final String METHOD_WITH_PARAM_NAME = "sayHello";
public static void main(String[] args) throws Exception {
Generated generated = new Generated();
accessMethod(generated);
accessMethodWithParameter(generated);
}
private static void accessMethod(Generated g) throws Exception {
Method[] methods = g.getClass().getDeclaredMethods();
for(Method method : methods) {
if(isCommonMethod(method)) {
String result = (String) method.invoke(g);
System.out.println(METHOD_NAME + "() = " + result);
}
}
}
private static boolean isCommonMethod(Method m) {
return m.getName().equals(METHOD_NAME) && m.getReturnType().equals(String.class);
}
private static void accessMethodWithParameter(Generated g) throws Exception {
Method[] methods = g.getClass().getDeclaredMethods();
for(Method method : methods) {
if(isCommonMethodWithParameter(method)) {
String result = (String) method.invoke(g, "Max");
System.out.println(METHOD_WITH_PARAM_NAME + "(\"Max\") = " + result);
}
}
}
private static boolean isCommonMethodWithParameter(Method m) {
return m.getName().equals(METHOD_WITH_PARAM_NAME) &&
m.getReturnType().equals(String.class) &&
m.getParameterTypes().length == 1 &&
m.getParameterTypes()[0].equals(String.class);
}
}
输出为
getA() = A
sayHello("Max") = hello Max
实例化接口的实现。使用列表而不是列表类CommonInterface1 extends Generated1实现CommonInterface
意味着所有CommonInterface1
对象也都是Generated1
对象,但反过来则不成立。如果您new
Generated1
对象,则它不是CommonInterface1
对象。如果您通过反射来探索它们,则不需要接口。只需通过反射查找特定的命名方法。如果有,就叫它。@ScaryWombat-添加了一个简单的问题。你有多少生成的X类?因为如果只有几个适配器类,那么只需编写几个适配器类即可实现公共接口并委托给adaptee对象。并使用instanceof了解要创建的适配器。即使你有很多,因为你正在使用代码生成,你也可以生成适配器类遗憾的是,生成的…
类无法更改。使用代理当然是一种选择,但如果可能的话,我想避免它。另请参见我的问题的结尾(在您发布此答案后添加),这是一种更简单的创建代理的机制。它们非常强大,但如果有其他选择,它们仍然值得避免。因为这只是更多的反射,不应该被需要。看看我的//这些都是非常好的类。