在Java final类中覆盖构造函数

时间:2015-11-06 12:57:52

标签: java

我需要用Java覆盖最终类的构造函数。我知道这不是理想的,但不幸的是,这是必要的。是否有任何聪明的解决方法能够实现这一目标?具体来说,有一个方法是从最终类中的构造函数内部调用的,我需要使用不同的参数调用(现在使用最终类的包中定义的常量调用它)。

3 个答案:

答案 0 :(得分:4)

它不是理想的,它是不可能的,因为它是最终的。您最好的选择是创建一个包装类:

  class WrapperClass {
    private FinalClass finalClass;

    public WrapperClass() {
      finalClass = new FinalClass();
    }

    public void doStuff() {
      finalClass.doStuff(); // <- this would be the final method you want to override

      // Do your own stuff
    }
  }

答案 1 :(得分:1)

规避最终方法没有好办法,但there is a good trick against (static or not) final fields 。如果改变你所谈论的那个常数是一个选项,那么你可以通过使用反射来做到这一点:

private static void setDefault(String newDefault) throws Exception {
  Field staticField = SomeFinalClass.class.getDeclaredField("CONSTANT");
  setValue(null, staticField, newDefault);
}

protected static void setValue(Object owner, Field field, Object value) throws Exception {
  makeModifiable(field);
  field.set(owner, value);
}

/**
 * Force the field to be modifiable and accessible.
 */
protected static void makeModifiable(Field nameField) throws Exception {
  nameField.setAccessible(true);
  int modifiers = nameField.getModifiers();
  Field modifierField = nameField.getClass().getDeclaredField("modifiers");
  modifiers = modifiers & ~Modifier.FINAL;
  modifierField.setAccessible(true);
  modifierField.setInt(nameField, modifiers);
}

}

注意:显然,如果有可用的常规设计模式,应谨慎处理并避免这种技巧。

答案 2 :(得分:0)

如果要修改的类具有界面,则可以使用java.lang.reflect.Proxy

public class ProxyTest {

  @Test
  public void proxy() throws Throwable {

    InvocationHandler handler = new MyInvocationHandler(new MyClass());
    MyInterface f = (MyInterface) Proxy.newProxyInstance(MyClass.class.getClassLoader(),
            new Class[] { MyInterface.class },
            handler);

    int result = f.test();

    assertThat(result).isEqualTo(20);
  }
}

class MyInvocationHandler implements InvocationHandler {

  private MyInterface wrappedInstance;
  public MyInvocationHandler(MyInterface object) {
    this.wrappedInstance = object;
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

    if(method.getName().equals("test")){
        return 20;
    } else {
        return method.invoke(this.wrappedInstance, args);
    }
  }
}