摘要中的私有引用 class

Private reference in abstract class

我有这段装饰器模式的代码:

public interface AbstractComponent {

    public void operation();
}


public class Component implements AbstractComponent {

    public void operation() {
        // do something
    }
}


public abstract class AbstractDecorator implements AbstractComponent {

    private AbstractComponent component;

    public AbstractDecorator(AbstractComponent ac) {
        component=ac;
    }

    public void operation() {
        component.operation();
    }
}


public class DecoratorA extends AbstractDecorator {

    public DecoratorA (AbstractComponent ac) {
        super(ac);
    }

    public void addedOperation() {
        // adds features to Component
    }

    public void operation() {
        addedOperation();
        super.operation();
    }
}


public class DecoratorB extends AbstractDecorator {

    public DecoratorB (AbstractComponent ac) {
        super(ac);
    }

    public void addedOperation() {
        // adds features to Component
    }

    public void operation() {
        addedOperation();
        super.operation();
    }
}


public class Tester {

    public static void main(String args[]) {
        AbstractComponent c = new Component();
        AbstractComponent d1 = new DecoratorA(c);
        AbstractComponent d2 = new DecoratorB(d1);
        d2.operation();
    }
}

创建 DecoratorA 时,其构造函数调用超类构造函数,将引用 c 分配给 component。创建 DecoratorB 时,其构造函数调用将引用 d1 分配给 component.

的同一个超类构造函数

我的问题是:DecoratorB 构造函数不应该将 c 的过去赋值覆盖到 component 吗?还是我创建的每个装饰器都有某种私有引用的副本?我找不到解决方案,因为这个引用是私有的,不能被子类继承。

它们是不同的对象,因此根本不应该覆盖对 c 的组件分配。

你有: 对象 b,其组件是 d1,和 对象 d1,其组件为 c

My question is: shouldn't DecoratorB constructor overwrite the past assignment of c to Component?'

没有。让我们看一个具有完全相同行为的稍微简单的案例:

class Parent {

    int i;
}

class ChildA extends Parent {}
class ChildB extends Parent {}

public class Main {

    public static void main(String[] args) {

        Parent p1 = new ChildA();
        Parent p2 = new ChildB();
        p1.i = 3;
        p2.i = 4;
        System.out.println(p1.i); // Output: 3
    }
}

如您所见,Parenti 的第二个赋值不会改变第一个(无论您在哪里设置 i - 在构造函数中或其他任何地方) .这是因为:

  1. i 是一个 实例 变量。每个实例都为自己的 int i.
  2. 分配了内存
  3. 当一个class被实例化时,它所有的超级class层级也被实例化。

这意味着引用 p1p2 保持 2 不同 int is - 改变一个不会改变另一个。

但是,如果你声明static int i,那会使i成为class 变量,它在 class 的所有实例之间共享。在这种情况下,第一个赋值将被第二个赋值覆盖。

如果您对手续感兴趣,JLS 中有很多关于此的内容...

编辑: 处理评论

In my case, when I create a decorator object, its superclass cannot be instantiated, because it's abstract. So I can't understand yet why every decorator has its own component.

这里是 JLS 技术细节。

你说得对,我们不能用 new MyAbstClass() 实例化 abstract class。 JLS 8.1.1.1。 abstract 类:

It is a compile-time error if an attempt is made to create an instance of an abstract class using a class instance creation expression (§15.9.1).

但是:

A subclass of an abstract class that is not itself abstract may be instantiated, resulting in the execution of a constructor for the abstract class and, therefore, the execution of the field initializers for instance variables of that class.

当您实例化 DecoratorADecoratorB 时,将调用 AbstractComponent 的构造函数并初始化实例字段 component。所以实际上,您确实有 2 个 component 字段。