我有一些生成的代码(即无法更改),看起来像这样。
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);
}
}
我的问题:我如何对待一个没有implement
和interface
但实际上具有所有代码的对象,就像它确实实现了接口一样
我要替换
private void doCommon(Generated1 c) {
String a = c.getA();
c.setB(a);
c.setC(a);
c.setD(a);
}
private void doCommon(Generated2 c) {
String a = c.getA();
c.setB(a);
c.setC(a);
c.setD(a);
}
...
使用
private void doCommon(CommonInterface c) {
String a = c.getA();
c.setB(a);
c.setC(a);
c.setD(a);
}
我知道我可以像这样使用Proxy
,但我真的更喜欢使用更好的东西。
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));
}
答案 0 :(得分:2)
如果使用反射,则不需要两个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);
}
}
您可以按如下方式使用此类:
List<Object> objects = Arrays.asList(new Generated1(), new Generated2());
for (Object object : objects) {
CommonInterface proxy = Wrapper.wrap(object, CommonInterface.class);
doCommon(proxy);
}
更新:请注意,同一Wrapper
类可用于任何接口。
答案 1 :(得分:0)
无法在Generated1
和Generated2
之间实现静态类型关系。
即使您创建了CommonInterface1
和CommonInterface2
,您也仍然无法将Generated1
对象静态地用作CommonInterface1
,因为new Generated1()
< strong> 不是 ({永远不会成为一个)CommonInterface1
到目前为止,最简单的解决方案是更改代码生成,以将CommonInterface
添加到Generated1
和Generated2
中。
如果这绝对不可能,那么避免这种代码重复的另一种方法就是反思。
答案 2 :(得分:0)
您可以通过反射手动进行操作。
MERGE
输出为
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);
}
}
答案 3 :(得分:-2)
如果要替换为注释。我认为您可以轻松做到
首先,您创建界面CommonInterface
interface CommonInterface {
String getA();
void setB(String b);
void setC(String c);
void setD(String d);
}
然后,您创建2个类Generated1
和Generated2
继承了CommonInterface
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) {
}
}