抽象类中的私有引用

时间:2016-02-17 11:25:38

标签: java reference abstract-class decorator private

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

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构造函数不应覆盖ccomponent的过去作业吗?或者是否为我创建的每个装饰器提供了某种私有引用的副本?我找不到解决方案,因为这个引用是私有的,不能被子类继承。

2 个答案:

答案 0 :(得分:1)

  

我的问题是:不应该DecoratorB构造函数覆盖cComponent的过去作业吗?'

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

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

正如您所看到的,Parent的{​​{1}}的第二个分配不会更改第一个(无论您在构造函数中设置i的位置 - 还是其他任何位置)。这是因为:

  1. i实例变量。每个实例都为自己的i分配了内存。
  2. 实例化类时,还会实例化其所有超类层次结构。
  3. 这意味着引用int ip1包含2 不同的 p2 - 更改一个不会改变另一个。

    但是,如果您要声明int i,那么static int i将成为变量,该变量将在该类的所有实例中共享。在这种情况下,第一个赋值将被第二个赋值覆盖。

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

    编辑:处理评论

      

    在我的例子中,当我创建一个装饰器对象时,它的超类无法实例化,因为它是抽象的。所以我无法理解为什么每个装饰者都有自己的组件。

    此处我们处于JLS技术细节中。

    您说我们无法使用i实例化abstract课程。 JLS 8.1.1.1。 new MyAbstClass()课程:

      

    如果尝试使用类实例创建表达式(第15.9.1节)创建abstract类的实例,那么这是一个编译时错误。

    可是:

      

    可以实例化abstract类本身不是abstract的子类,从而导致执行abstract类的构造函数,从而执行字段该类的实例变量的初始值设定项。

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

答案 1 :(得分:0)

它们是不同的对象,因此它不应该将组件赋值覆盖到c。

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