Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/397.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java中组合优于继承的优点_Java - Fatal编程技术网

Java中组合优于继承的优点

Java中组合优于继承的优点,java,Java,以下段落引自Bruce Eckel的《用Java思考》一书 构图具有很大的灵活性。新类的成员对象通常是私有的,因此使用该类的客户端程序员无法访问它们。这允许您在不干扰现有客户端代码的情况下更改这些成员还可以在运行时更改成员对象,以动态更改程序的行为。下面将介绍的继承没有这种灵活性,因为编译器必须对使用继承创建的类设置编译时限制 我不明白,成员对象是如何动态更改的,以及它是如何优于继承的。 如果您的类扩展了ArrayList,那么您的类的用户可以访问ArrayList的所有公共方法。您不能将类更改

以下段落引自Bruce Eckel的《用Java思考》一书

构图具有很大的灵活性。新类的成员对象通常是私有的,因此使用该类的客户端程序员无法访问它们。这允许您在不干扰现有客户端代码的情况下更改这些成员还可以在运行时更改成员对象,以动态更改程序的行为。下面将介绍的继承没有这种灵活性,因为编译器必须对使用继承创建的类设置编译时限制

我不明白,成员对象是如何动态更改的,以及它是如何优于继承的。
如果您的类扩展了
ArrayList
,那么您的类的用户可以访问
ArrayList
的所有公共方法。您不能将类更改为扩展LinkedList,因为这可能会破坏现有代码

 public class Inheritence extends ArrayList<String>
 {
     // here your class depends on ArrayList implementation
 }

如果您使用继承,您几乎看不到整个画面,您必须大量研究代码才能理解发生了什么。若你们改变了父类中的一个小东西,你们就有麻烦了。那么所有的后代呢?这种变化对他们有影响吗

也要考虑测试。父类是不可分离的,您必须测试所有内容,而且测试非常复杂,通常根本不进行测试,因为工作量太大,无法进行测试

另一方面,当您使用组合时,您可以轻松地分离功能,您可以使用依赖项注入,当您阅读其他人的代码时,您可以专注于较小的功能。如果使用组合的更高级别类需要用其他实现替换一些次要功能,那么就容易得多,因为您更了解代码中发生了什么。在几个继承级别中分散的代码没有被封装,通常完全不可读

继承也是危险的。例如,当您想要计数时,您向HashSet添加了多少项。您可以重写add和addAll方法,但不知道addAll是否为每个项调用方法add。看到这个了吗


为了回答您最初的问题,您可以通过构造函数或setter传递内部对象。

更广泛地看待组合和继承的方式是,组合是实现
具有-a
关系的设计技术,而继承是实现
具有-a
关系的技术。让我们从面向对象的角度来更好地理解这一点

当我说,
是一种
哺乳动物
是一种
爬行动物
,但两者都是
动物
,设计可以像,应该有一个名为
动物
的超级类和两个名为
哺乳动物
爬行动物
的子类,它们应该扩展
。有关代码如下:

public abstract class Animal {
    public abstract void move();
    public abstract void sleep();
    public abstract void reproduce();

}
任何动物都可以做这三个动作

public abstract class Mammal extends Animal{
    @Override
    public void reproduce(){
        System.out.println("Gives birth!!");
    }

}

public abstract class Reptile extends Animal{
    @Override
    public void reproduce(){
        System.out.println("Lays Eggs!!");
    }
}
所有哺乳动物/爬行动物都将以共同的方式执行这一规定的功能

public class Dog extends Mammal{

    @Override
    public void move() {
        System.out.println("Uses it's limbs");

    }

    @Override
    public void sleep() {
        System.out.println("Sleeps on it's tummy");

    }

}


public class Snake extends Reptile{

    @Override
    public void move() {
        System.out.println("Crawls");

    }

    @Override
    public void sleep() {
        System.out.println("");

    }

}
正如您在本例中所观察到的,
扩展了
哺乳动物
扩展了
爬行动物
。因此,在任何给定的时间点,
总是哺乳动物,
总是爬行动物。因此,这种is-a关系在两个实体之间建立了牢固的纽带。在执行过程中,只要
扩展
哺乳动物
,它就不能是
爬行动物
或其他任何东西

回到有一个关系(组合),我可以说一个
有一辆
。我没有指定此人拥有的
汽车的类型。让我们回到OO视角来更好地理解这一点

考虑一下这个

public class Person {
    private String name;
    private String address;

    private Car car;

    public Person(String name, String address, Car car) {
        super();
        this.name = name;
        this.address = address;
        this.car = car;
    }


}
从这里可以看出,一个人有一个名字、地址和汽车。 Car和相关类别的代码如下所示:

public class Car {
    //Car related methods
}

public class Ferrari extends Car{
    //Ferrari specific methods, attributes
}

public class Bmw extends Car{
    //BMW specific attributes, methods.
}
可以看出
宝马
法拉利
都是
汽车
的类型。 现在回到“人有车”这句话,这辆车可以是任何一辆车。它可能是法拉利或宝马或其他任何东西。这可以在创建
Person
对象期间传入

Person john=新人(“约翰”,“第二街81号,…”,新法拉利())

可以看出,约翰开了一辆法拉利
汽车
。在这里,John可以接收对象创建过程中传递的任何类型的
Car
(动态性质)。因此,具有一种(组合)关系,从而提供了灵活性水平


我希望这能澄清您的疑问。

成员对象可以通过引用字段获得,如果它们是可变的,您可以使用赋值来更改它们,即
=
您能给出一个代码示例为什么否决?您能澄清您对赋值和使用字段的疑问吗?如果不清楚OP想要什么,有些人会对问题投否决票。我发表了一条评论…我明白你的意思。我只想看一个有用的例子,上面提到的以这种方式使用组合将比使用继承更为有利。
public class Car {
    //Car related methods
}

public class Ferrari extends Car{
    //Ferrari specific methods, attributes
}

public class Bmw extends Car{
    //BMW specific attributes, methods.
}