24

这是我现在面临的问题。我有一个类,假设Foo这个类定义了一个getBar返回Bar实例的方法。该类Bar在内部定义Foo并声明public static final。我想做的是定义一个MyFoo扩展的类,但Foo我也想通过添加我自己的功能(方法、属性等)来扩展。我也想回来。BarMyBargetBarMyBar

问题Bar是最终的。这是我想要做的说明:

public class Foo {

  Bar bar = new Bar();

  public Bar getBar(){
      return bar;
  } 

   ....

   public static final class Bar {

    } 
}

我想做的是:

public class MyFoo extends Foo {


   public MyBar getBar(){ // here I want to return an instance of MyBar

   }

  public static final class MyBar extends Bar { // That's impossible since Bar is final

  } 
}

我怎样才能做到这一点?

[编辑] 我正在为我的问题添加更多细节。我实际上正在为 Jenkins 开发一个插件,在搜索之后,我意识到有一个插件可以提供我想要做的基本功能,Foo并且Bar. 我想自定义Fooand Bar,所以它可以满足我的需求。Foo 是插件的主类,并扩展了一个名为 Builder 的类。Foo 定义了一个名为的方法perform,该方法包含执行构建的所有操作。 Bar包含用于配置目的的操作,Foo 需要 Bar 来获取这些信息。

所以我想做的是用 Foo 扩展MyFoo并添加一些配置MyBar。如您所见,MyFoo需要通过调用来获取这些配置getBar();

第二件事是我无法控制MyFooMyBar

阻碍我的是,我无法扩展 Bar。我怎样才能做到这一点?

4

7 回答 7

37

你不能,基本上。看起来开发人员的设计Bar意图是不要扩展它——所以你不能扩展它。您将需要寻找一种不同的设计——可能是一种不太使用继承的设计……当然,假设您无法更改现有代码。

(如果不了解这里的真正目标——整个系统的设计,就很难给出更具体的建议。)

于 2012-11-08T17:42:11.220 回答
13

您不能扩展已声明的类final。但是,您可以创建一个中间类,称为Wrapper. 这个 Wrapper 基本上将包含原始类的一个实例,并提供替代方法来根据您想要做的修改对象的状态。

当然这不会访问final类的私有和受保护字段,但是您可以使用它的 getter 和 setter 方法,结合您在Wrapper类中声明的新方法和字段来获得您想要的结果,或者相对的东西关。

final如果没有正当理由,另一种解决方案是不声明一个类。

于 2012-11-08T18:43:37.213 回答
9

你不能扩展一个final类——这就是final关键字的目的。

但是,(至少)有两种解决方法:

  1. 该类在Jenkins项目中,该项目是开源的,因此您只需下载该项目,对类进行所需的更改并重新构建jar即可
  2. 有点hack,但是您可以使用Javassist之类的库来替换内存中类的实现
于 2012-11-08T22:32:25.827 回答
4

您不能扩展 final 类,这就是声明类 final 的重点。您可以定义最终类继承自的接口和将调用委托给包装的最终类的包装类。那么问题是为什么要把课程放在第一位。

于 2012-11-08T17:42:49.453 回答
3

可能您想要的是代理。这很容易实现。这是一篇很棒的文章:http ://blog.frankel.ch/the-power-of-proxies-in-java

于 2014-09-18T21:10:37.500 回答
0

例如,我们不能在 TreeSet 集合中添加 StringBuffer,因为 TreeSet 不是接口 Comparable 的子级:

public class Main(){
public static void main(String[] args){
   TreeSet treeSetSB = new TreeSet();
   treeSetSB.add(new StringBuffer("A"));  //error, Comparable is not implemented
}

但是我们可以使用包装器来实现 Comparable:

class myWrap implements Comparable{
    TreeSet treeset;
    public myWrap() {
        this.treeset=new TreeSet<>();

    }
    public TreeSet getTreeset() {
        return treeset;
    }
    public void setTreeset(TreeSet treeset) {
        this.treeset = treeset;
    }
}


public class Main(){
public static void main(String[] args){

   myWrap myWrap =new myWrap();
   TreeSet myTrs  =myWrap.getTreeset();
   myTrs.add("b");   // no error anymore
   myTrs.add("a");
   myTrs.add("A");
   System.out.println(myTrs);
}
于 2016-10-09T08:13:20.153 回答
0

如果它实现了一些接口,装饰器设计模式可以解决这个问题。

于 2018-03-08T13:04:00.717 回答