2015-11-06 78 views
-1

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

+1

final类不能被覆盖,看'String'类。 – SamTebbs33

回答

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

}

注:显然这样的伎俩应轻拿轻放,避免如果有一个常规设计模式可用。

+0

谢谢,我会试试看看它是否有效:) – user16655

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 
    } 
    } 
+0

谢谢!事情是,从最后一个类的构造函数中调用一个方法。我需要覆盖,以便使用不同的参数进行调用(使用与最终类相同的包中定义的常量发送它)。我写了这个问题有点快。 – user16655

+0

我认为你最好的选择是重写被调用的方法并改变你的参数,但所有这些对我来说听起来就像你改变了一些不适合你当前设计的东西。如果可能,我会建议您检查设计,并且只有在这些解决方案是最后的解决方案时才继续。 – Stefan

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