Java 是否有一种方法可以将类实例中变量的更改传播到从该类实例派生的其他类实例?

Java 是否有一种方法可以将类实例中变量的更改传播到从该类实例派生的其他类实例?,java,class,object,inheritance,composition,Java,Class,Object,Inheritance,Composition,问题:我想要实现的是让一个父类的实例将其局部变量的更改传播到直接从父类派生的子类实例。我当前的方法是将父类扩展到子类,但它没有提供任何方法来访问父类实例变量 示例:假设父类存储一个包含名称的字符串。我想让一个孩子来自一个String名字是“George”的父母,另一个孩子来自一个String名字是“Nick”的父母。当存储在“George”父类中的字符串从“George”更改为“Patrick”时,我希望为他的孩子而不是为“Nick”的孩子更改该字符串 这可以在没有太多计算开销的情况下完成吗 代

问题:我想要实现的是让一个
父类
的实例将其局部变量的更改传播到直接从
父类
派生的
子类
实例。我当前的方法是
父类
扩展到
子类
,但它没有提供任何方法来访问
父类
实例变量

示例:假设父类存储一个包含名称的
字符串。我想让一个孩子来自一个
String
名字是“George”的父母,另一个孩子来自一个
String
名字是“Nick”的父母。当存储在“George”父类中的
字符串从“George”更改为“Patrick”时,我希望为他的孩子而不是为“Nick”的孩子更改该字符串

这可以在没有太多计算开销的情况下完成吗

代码参考

public class Parent {
    private String name;

    public Parent(String name) {
        this.name = name;
    }

    public void changeName(String newName) {
        name = newName;
    }

    public String getName() {
        return name;
    }
}

public class Child extends Parent {
    private String parentName;
    /**
     * Currently derives the String directly which won't react to
     * changes to the Parent class.
     */
    public Child(Parent p) {
        this.parentName = p.getName();
    }

    public getParentName() {
        return parentName;
    }
}

public class mainApp {
    public static void main(String[] cmdArgs) {
        Parent George = new Parent("George");
        Parent Nick = new Parent("Nick");

        Child a = new Child(George);
        Child b = new Child(Nick);

        George.changeName("Patrick");

        // Prints "George", should print "Patrick"
        System.out.println(a.getParentName());

        // Prints "Nick", should print "Nick"
        System.out.println(b.getParentName());
    }
}
解决方案:通过使用,实际上可以实现上述目标

通过保留对创建
子类实例时使用的原始
父类
的引用,在
父类
实例上执行的所有更改都将反映在
子类
实例上

通过这种方式,
子级
也可以处于孤立状态,其中没有使用
父级
实例来创建它

解决方案代码

public class Parent {
    private String name;

    public Parent(String name) {
        this.name = name;
    }

    public void changeName(String newName) {
        name = newName;
    }

    public String getName() {
        return name;
    }
}

// Extension is not required
public class Child {
    private Parent parentReference;

    public Child(Parent parentReference) {
        this.parentReference = parentReference;
    }

    public getParentName() {
        // We need to manually handle the case of a non-existent parent
        if (parentReference == null) {
            return "None";
        } else {
            return parentReference.getName();
        }
    }
}

public class mainApp {
    public static void main(String[] cmdArgs) {
        Parent George = new Parent("George");
        Parent Nick = new Parent("Nick");

        Child a = new Child(George);
        Child b = new Child(Nick);
        Child c = new Child(null);

        George.changeName("Patrick");

        // Prints "Patrick", should print "Patrick"
        System.out.println(a.getParentName());

        // Prints "Nick", should print "Nick"
        System.out.println(b.getParentName());

        // Prints "None", should print "None"
        System.out.println(c.getParentName());
    }
}

使用继承来解决您实际遇到的问题,这相当复杂,当您开始扩展服务时,您将遇到问题(组合将是一种更好的现实世界方法,但组合从一开始就有一个更大的学习曲线,但提供了更大灵活性的附加好处):

然后您可以这样使用它:

ArrayList<ServiceProvider> serviceProviders = new ArrayList<>();
serviceProviders.add(new MobileCellularProviderMobileContract(ProviderDef.PROVIDER_1, "Client 1"));
serviceProviders.add(new MobileCellularProviderMobileContract(ProviderDef.PROVIDER_1, "Client 2"));
serviceProviders.add(new MobileCellularProviderCardContract(ProviderDef.PROVIDER_1, "Client 3"));
serviceProviders.add(new MobileInternetProvider(ProviderDef.PROVIDER_1, "Client 4"));
serviceProviders.add(new MobileInternetProvider(ProviderDef.PROVIDER_2, "Client 1"));
ArrayList serviceProviders=new ArrayList();
添加(新的MobileCellularProviderMobileContract(ProviderDef.PROVIDER_1,“客户端1”);
添加(新的MobileCellularProviderMobileContract(ProviderDef.PROVIDER_1,“客户端2”);
添加(新的MobileCellularProviderCardContract(ProviderDef.PROVIDER_1,“客户端3”);
添加(新的MobileInternetProvider(ProviderDef.PROVIDER_1,“客户端4”);
添加(新的MobileInternetProvider(ProviderDef.PROVIDER_2,“客户端1”);
原始答案

当一个子类被实例化时,它有超类字段,因此在更新子类“
name
字段和更新超类“
name
字段之间没有区别。。。实例中只有一个字段

所以当你说:

例如,假设父类存储一个包含名称的字符串。我希望3个孩子来自一个字符串名为“George”的家长,另外3个孩子来自一个字符串名为“Nick”的家长。当“George”父类中存储的字符串从“George”更改为“Patrick”时,我希望为其子类更改该字符串,但不为“Nick”的子类更改该字符串

这真的没有道理

你问题的标题是

父类实例的变量是否有任何方式可供其子类(子类)直接引用

答案是肯定的!但是你所描述的问题与问题的标题无关。在你的例子中,术语“父母”和“孩子”是字面意义上的,但这并不总是适用的

仅当类型和子类型之间存在固定关系时,才能使用继承。比如,“自行车是交通工具”或者“长颈鹿是动物”。这些关系对于自行车和长颈鹿的每一个例子都是相同的。但你描述的不是这样的

对于您的案例,您可以使用合成来建模

  • 每个
    都有一个
    名字
  • 每个
    都有一个
    父母
    (可以将其保留为
    ,以表示“不知道”或“不在乎”)
  • 每个
    都有零个或多个
    子女

在我看来,您的解决方案是一个使用继承的代码解决方案,而最好的解决方案可能根本不使用继承,而是使用组合。你所说的这些“子对象”应该被视为集合树中的节点对象,而不是子类。他只是在学习循环,还不要用合成来攻击他:p@Neilos当前位置也许吧,但你必须承认他找错人了。这不是通过继承来解决的。我目前已经实现了一个解决方案,我根本不使用继承,而是将“父”对象直接存储在子类中。然而,我只是想知道继承是否可行。我们被要求做一个关于继承的练习,但问题本身并不是继承能有效地解决什么问题。好的,我可以回答你:不,这不是继承的目的。这是为了继承行为。我认为反对票是指措辞。“更新子类的字段和更新超类的字段…它们是同一件事”使它们看起来实际上是同一个内存引用,但至少据我所知,它们不是。我的回答有点含糊不清,我想说的是,实例化的类既是自身的实例,也是其超类的实例,因此,如果一个超类有一个字段
name
,那么子类将继承该字段,它可能无权访问该字段,但该实例只有一个引用,而不是子类和超类的单独引用,这就是我认为您在问题中所暗示的,那完全没有道理。如果是这样的话,我想我不太明白什么是推荐信
ArrayList<ServiceProvider> serviceProviders = new ArrayList<>();
serviceProviders.add(new MobileCellularProviderMobileContract(ProviderDef.PROVIDER_1, "Client 1"));
serviceProviders.add(new MobileCellularProviderMobileContract(ProviderDef.PROVIDER_1, "Client 2"));
serviceProviders.add(new MobileCellularProviderCardContract(ProviderDef.PROVIDER_1, "Client 3"));
serviceProviders.add(new MobileInternetProvider(ProviderDef.PROVIDER_1, "Client 4"));
serviceProviders.add(new MobileInternetProvider(ProviderDef.PROVIDER_2, "Client 1"));
class Person {
    String name;
    Person parent;

    Person(String name, Person parent) {
        this.name = name;
        this.parent = parent;
    }

    // etc (getters, setters)
}

public class MainApp {
    public static void main(String[] cmdArgs) {
        Person george = new Person("George", null);
        Person nick = new Person("Nick", null);
        Person a = new Person("a", george);
        Person b = new Person("b", george);
        Person c = new Person("c", nick);
        // etc.
    }
}