2012-04-06 72 views
3

我想为我的应用程序制作一个特殊的附加组件。我需要在不编辑类文件的情况下重写某个类的某些方法。Java - 重写一个外部方法

这里是一个方案:

class A 
{ 
    public void method1() 
    { 
     // Do something here 
    } 

    public int method2() 
    { 
     // Do something 
    } 
} 

现在从我的B类,我想覆盖从A级的方法1 FUNC,并迫使A类用我的新方法。

class B 
{ 
    public void method1() 
    { 
     Do something 
    } 
} 

我想在不编辑A类的情况下更新我的A类代码。那可能吗?

谢谢。

+0

不知道我理解。你说你现在想'A a = new A(); a.method1()'调用'B.method1'? – 2012-04-06 11:50:48

+0

你不能改变已经在'A'类中定义的行为,你可以做的最好的事情是从'A'类扩展并改变'B'类的行为。然后调用类'B'对象上的所有方法。 – 2012-04-06 11:51:49

+0

在Java中,您不能“替换”原始类,类似于Objective C中的可能 - 您需要重写并确保其他人正在使用新类。 – Vlad 2012-04-06 11:53:42

回答

1

听起来像代理可以解决您的问题。看看cglib

Enhancer e = new Enhancer(); 
e.setSuperclass(A.class); 
e.setCallback(new MyCallback()); 
A proxied = e.create(); 

这里是myCallBack函数类的样本实现了一套...

class MyCallback implements MethodInterceptor{ 
     public Object intercept(Object obj, 
             Method method, 
             Object[] args, 
             MethodProxy proxy){ 
      Object stuffToReturn = null; 
      if ("method1".equals(method.getName()) { 
       //Class B's method1 impl 
      } else { 
       //call the original method in class A 
       stuffToReturn = method.invoke(proxy, args); 
      } 

      return stuffToReturn; 
     } 
    } 
+0

谢谢,我现在就试试! – Manitoba 2012-04-06 12:20:24

+1

好吧,这不会影响由简单的'new A'实例化的对象的行为。 – Vlad 2012-04-06 12:21:54

+0

那么,海报只会要求不要修改类A,所以听起来他可以将新的A()更改为e.create()?如果海报甚至不能更改新的A()语句,那么可能不得不动态修改类A的字节代码... – Alvin 2012-04-06 12:32:02

0

通过继承,是的。只需更改B类定义:class B extends A

+2

不,新'A()。method1()'仍然会调用原始的。你修改了B类而不是A类的行为 – amit 2012-04-06 11:51:22

+0

@amit如果你读了这篇文章,OP说他不想修改A类。 – 2012-04-06 11:52:37

+0

@HunterMcMillen:他想修改'A'' s *行为*而不修改它,而不是'B'的行为。 – amit 2012-04-06 11:53:31

4

使用class B extends A和您想要更改的ovverride方法。如何永远不得不使用类B的实例而不是A。像

class B extends A 
{ 
    public void method1(){ 
     Do something 
    } 
} 
A a = new B(); 
a.method1(); 
+1

再次,这改变了'B'的行为,而不是'A'的行为。这是一种解决方法,并非总是可行。 'new A()。method1()'将具有与之前相同的行为。但是 - 至少这个答案明确提到它只影响'B'。 – amit 2012-04-06 11:58:25

0

这没有任何意义。覆盖意味着重新定义一个从超类继承的方法。因此,这里有一些解决方案:

  • B必须扩展,然后您可以覆盖的A的方法之一,给它相同的签名在A,使用@Override注释是肯定的。
  • A有一些被注入的依赖项:method1和method2使用某个tierce对象(C)来完成工作并且依赖项被注入到A.然后B可以使用一个A来满足自己的需要的自定义C对象。 A的大部分代码不会以这种方式改变。
1

如果使用A构造函数创建对象,则不适用。 你可以有B扩展A,但你将不得不实例化对象为new B()(即使你可以宣布他们为A,如在A obj = new B())。

1

不,在像Java这样的语言中,这是不可能的。 new A将始终在运行时创建A的实例,而不是衍生B的实例。

如果可能(即,如果您控制实例化的所有代码A),则可以使用一些笨拙的解决方法来引入一种间接方式。例如,您可以有一个可配置的工厂生产A(这将根据需要切换到生产B s) - 这似乎是Java的方式。 (您将需要所有代码构造A s不是直接,而是通过工厂。)

如果我没有弄错,您正在寻找的功能可以在Objective-C开箱即用 - 但不是Java的。

+0

感谢您的回答。有什么方法可以在启动方法时捕捉事件? – Manitoba 2012-04-06 12:02:55

+0

没有办法,我知道,对不起:( – Vlad 2012-04-06 12:04:38

+0

+1。另外,附注/问题:我不是C#的专家,但我知道你可以使用反射在空中添加字段 - 也许它可以做到[在C#]? [如果有人知道答案,会很高兴]。然而 - 在Java中,它不能通过反射来实现,而AFAIK根本无法实现。 – amit 2012-04-06 12:11:13

0

实现此目的的一种方法是使用某种类型的factory instance来创建类型A的对象,而不是直接在代码中调用A()构造函数。然后,您的加载项需要提供并注册它自己的这个工厂的实现,它将创建类B的实例。这仅适用于在创建任何A实例之前加载项被加载并初始化的情况。

另一种方法是实现您自己的ClassLoader,并在加载时使用它来修改类A的字节码。您可以搜索aspect oriented programming的工具来执行此操作。这只有在你可以控制类A的类加载过程时才有可能。

0

不,你不能这样做,不可能在没有实际修改类的情况下修改类的行为,但是,有一个解决方法:

  1. B应该从A继承。这是绝对需要的。 A将不会改变,但其子类可能改变行为

  2. 覆盖方法1()和method2()

  3. 假设你有一个类的一个对象。如果将其转换为B,则其行为将是您的新自定义行为。