Java 继承与组合的区别
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2399544/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Difference between Inheritance and Composition
提问by gmhk
Are Composition and Inheritance the same? If I want to implement the composition pattern, how can I do that in Java?
组合和继承是一样的吗?如果我想实现组合模式,我该如何在 Java 中实现呢?
采纳答案by polygenelubricants
They are absolutely different. Inheritance is an "is-a"relationship. Composition is a "has-a".
他们是完全不同的。继承是一种“is-a”关系。组合是一个“has-a”。
You do composition by having an instance of another class C
as a field of your class, instead of extending C
. A good example where composition would've been a lot better than inheritance is java.util.Stack
, which currently extends java.util.Vector
. This is now considered a blunder. A stack "is-NOT-a"vector; you should not be allowed to insert and remove elements arbitrarily. It should've been composition instead.
您可以通过将另一个类的实例作为类C
的字段来进行组合,而不是扩展C
. 一个很好的例子,其中组合比继承要好得多java.util.Stack
,它目前扩展了java.util.Vector
. 这现在被认为是一个错误。堆栈“is-NOT-a”向量;你不应该被允许随意插入和删除元素。它应该是组合而不是。
Unfortunately it's too late to rectify this design mistake, since changing the inheritance hierarchy now would break compatibility with existing code. Had Stack
used composition instead of inheritance, it can always be modified to use another data structure without violating the API.
不幸的是,现在纠正这个设计错误为时已晚,因为现在更改继承层次结构会破坏与现有代码的兼容性。有Stack
使用的组合物的,而不是继承,它总是可以被修改为使用另一数据结构而不违反API。
I highly recommend Josh Bloch's book Effective Java 2nd Edition
我强烈推荐 Josh Bloch 的书Effective Java 2nd Edition
- Item 16: Favor composition over inheritance
- Item 17: Design and document for inheritance or else prohibit it
- 第 16 条:优先组合而不是继承
- 第 17 条:设计和文件继承或禁止继承
Good object-oriented design is not about liberally extending existing classes. Your first instinct should be to compose instead.
好的面向对象设计不是自由扩展现有的类。你的第一直觉应该是写作。
See also:
也可以看看:
回答by BlackICE
as another example, consider a car class, this would be a good use of composition, a car would "have" an engine, a transmission, tires, seats, etc. It would not extend any of those classes.
再举一个例子,考虑一个汽车类,这将是一个很好的组合使用,汽车将“有”一个引擎、一个变速器、轮胎、座椅等。它不会扩展任何这些类。
回答by codaddict
Composition means HAS A
Inheritance means IS A
组合手段HAS A
继承手段IS A
Example
: Car has aEngine and Car is aAutomobile
Example
: 汽车有引擎,汽车就是汽车
In programming this is represented as:
在编程中,这表示为:
class Engine {} // The Engine class.
class Automobile {} // Automobile class which is parent to Car class.
class Car extends Automobile { // Car is an Automobile, so Car class extends Automobile class.
private Engine engine; // Car has an Engine so, Car class has an instance of Engine class as its member.
}
回答by Michael Rodrigues
Composition is just as it sounds - you create an object by plugging in parts.
组合就像听起来一样 - 您可以通过插入零件来创建对象。
EDITthe rest of this answer is erroneously based on the following premise.
This is accomplished with Interfaces.
For example, using the Car
example above,
编辑此答案的其余部分错误地基于以下前提。
这是通过接口完成的。
例如,使用Car
上面的例子,
Car implements iDrivable, iUsesFuel, iProtectsOccupants
Motorbike implements iDrivable, iUsesFuel, iShortcutThroughTraffic
House implements iProtectsOccupants
Generator implements iUsesFuel
So with a few standard theoretical components you can build up your object. It's then your job to fill in how a House
protects its occupants, and how a Car
protects its occupants.
因此,您可以使用一些标准的理论组件来构建您的对象。然后,您的工作就是填写 a 如何House
保护其居住者以及 a 如何Car
保护其居住者。
Inheritance is like the other way around. You start off with a complete (or semi-complete) object and you replace or Override the various bits you want to change.
继承就像相反。您从一个完整(或半完整)的对象开始,然后替换或覆盖要更改的各个位。
For example, MotorVehicle
may come with a Fuelable
method and Drive
method. You may leave the Fuel method as it is because it's the same to fill up a motorbike and a car, but you may override the Drive
method because the Motorbike drives very differently to a Car
.
例如,MotorVehicle
可能带有Fuelable
方法和Drive
方法。您可以保留 Fuel 方法,因为它为摩托车和汽车加油是一样的,但您可以覆盖该Drive
方法,因为 Motorbike 的驱动方式与Car
.
With inheritance, some classes are completely implemented already, and others have methods that you are forced to override. With Composition nothing's given to you. (but you can Implement the interfaces by calling methods in other classes if you happen to have something laying around).
有了继承,一些类已经完全实现了,而另一些类则有你必须重写的方法。使用 Composition 什么也没有给你。(但如果您碰巧有一些东西,您可以通过调用其他类中的方法来实现接口)。
Composition is seen as more flexible, because if you have a method such as iUsesFuel, you can have a method somewhere else (another class, another project) that just worries about dealing with objects that can be fueled, regardless of whether it's a car, boat, stove, barbecue, etc. Interfaces mandate that classes that say they implement that interface actually have the methods that that interface is all about. For example,
组合被认为更灵活,因为如果你有一个像 iUsesFuel 这样的方法,你可以在其他地方(另一个类,另一个项目)有一个方法,它只是担心处理可以加油的对象,不管它是不是汽车,船、炉子、烧烤等等。接口要求那些声称实现该接口的类实际上具有该接口所涉及的方法。例如,
iFuelable Interface:
void AddSomeFuel()
void UseSomeFuel()
int percentageFull()
then you can have a method somewhere else
那么你可以在其他地方有一个方法
private void FillHerUp(iFuelable : objectToFill) {
Do while (objectToFill.percentageFull() <= 100) {
objectToFill.AddSomeFuel();
}
Strange example, but it's shows that this method doesn't care what it's filling up, because the object implements iUsesFuel
, it can be filled. End of story.
奇怪的例子,但它表明这个方法并不关心它正在填充什么,因为对象实现了iUsesFuel
,它可以被填充。故事结局。
If you used Inheritance instead, you would need different FillHerUp
methods to deal with MotorVehicles
and Barbecues
, unless you had some rather weird "ObjectThatUsesFuel" base object from which to inherit.
如果您改用继承,则需要不同的FillHerUp
方法来处理MotorVehicles
and Barbecues
,除非您有一些相当奇怪的“ObjectThatUsesFuel”基础对象可以继承。
回答by Kris
The answer given by @Michael Rodrigues is not correct (I apologize; I'm not able to comment directly), and could lead to some confusion.
@Michael Rodrigues 给出的答案不正确(我很抱歉;我无法直接发表评论),并且可能会导致一些混乱。
Interface implementation is a form of inheritance... when you implement an interface, you're not only inheriting all the constants, you are committing your object to be of the type specified by the interface; it's still an "is-a" relationship. If a car implements Fillable, the car "is-a" Fillable, and can be used in your code wherever you would use a Fillable.
接口实现是继承的一种形式……当你实现一个接口时,你不仅继承了所有的常量,你还提交了你的对象是接口指定的类型;它仍然是一种“ is-a”关系。如果汽车实现了Fillable,则该汽车“是” Fillable,并且可以在您使用Fillable 的任何地方使用您的代码。
Composition is fundamentally different from inheritance. When you use composition, you are (as the other answers note) making a "has-a" relationship between two objects, as opposed to the "is-a" relationship that you make when you use inheritance.
组合与继承有着根本的不同。当您使用组合时,您(正如其他答案所指出的那样)在两个对象之间建立“ has-a”关系,而不是使用继承时建立的“ is-a”关系。
So, from the car examples in the other questions, if I wanted to say that a car "has-a" gas tank, I would use composition, as follows:
所以,从其他问题的汽车例子来看,如果我想说一辆汽车“有一个”油箱,我会使用组合,如下:
public class Car {
private GasTank myCarsGasTank;
}
Hopefully that clears up any misunderstanding.
希望这能消除任何误解。
回答by frictionlesspulley
Inheritancebrings out IS-Arelation. Compositionbrings out HAS-A relation.
Strategy pattern explain that Composition should be used in cases where there are families of algorithms defining a particular behaviour.
Classic example being of a duck class which implements a flying behaviour.
继承带来了IS-A关系。组合带出HAS-A 关系。策略模式解释了在存在定义特定行为的算法系列的情况下应该使用组合。
经典示例是实现飞行行为的鸭类。
public interface Flyable{
public void fly();
}
public class Duck {
Flyable fly;
public Duck(){
fly = new BackwardFlying();
}
}
Thus we can have multiple classes which implement flying eg:
因此,我们可以有多个实现飞行的类,例如:
public class BackwardFlying implements Flyable{
public void fly(){
Systemout.println("Flies backward ");
}
}
public class FastFlying implements Flyable{
public void fly(){
Systemout.println("Flies 100 miles/sec");
}
}
Had it been for inheritance, we would have two different classes of birds which implement the fly function over and over again. So inheritance and composition are completely different.
如果是为了继承,我们将有两种不同的鸟类,它们一遍又一遍地实现飞行功能。所以继承和组合是完全不同的。
回答by John Wilson
Inheritancebetween two classes, where one class extends another class establishes "IS A" relationship.
两个类之间的继承,其中一个类扩展了另一个类,建立了“ IS A”关系。
Compositionon the other end contains an instance of another class in your class establishes "Has A" relationship. Compositionin java is is useful since it technically facilitates multiple inheritance.
另一端的Composition包含您的类中另一个类的实例,建立“ Has A”关系。java中的组合很有用,因为它在技术上促进了多重继承。
回答by Manoj Kumar Saini
How inheritance can be dangerous ?
继承怎么可能是危险的?
Lets take an example
让我们举个例子
public class X{
public void do(){
}
}
Public Class Y extends X{
public void work(){
do();
}
}
1) As clear in above code , Class Y has very strong coupling with class X. If anything changes in superclass X , Y may break dramatically. Suppose In future class X implements a method work with below signature
1) 如上代码所示,Y 类与 X 类有很强的耦合。如果超类 X 发生任何变化,Y 可能会急剧中断。假设将来类 X 实现了一个具有以下签名的方法
public int work(){
}
Change is done in class X but it will make class Y uncompilable. SO this kind of dependency can go up to any level and it can be very dangerous. Every time superclass might not have full visibility to code inside all its subclasses and subclass may be keep noticing what is happening in superclass all the time. So we need to avoid this strong and unnecessary coupling.
更改在 X 类中完成,但会使 Y 类无法编译。所以这种依赖可以上升到任何级别,而且可能非常危险。每次超类可能无法完全了解其所有子类中的代码,而子类可能一直在注意超类中发生的事情。所以我们需要避免这种强而不必要的耦合。
How does composition solves this issue?
组合如何解决这个问题?
Lets see by revising the same example
让我们通过修改同一个例子来看看
public class X{
public void do(){
}
}
Public Class Y{
X x = new X();
public void work(){
x.do();
}
}
Here we are creating reference of X class in Y class and invoking method of X class by creating an instance of X class. Now all that strong coupling is gone. Superclass and subclass are highly independent of each other now. Classes can freely make changes which were dangerous in inheritance situation.
这里我们在 Y 类中创建 X 类的引用,并通过创建 X 类的实例来调用 X 类的方法。现在所有强耦合都消失了。超类和子类现在高度独立。类可以自由地进行更改,这在继承情况下是危险的。
2) Second very good advantage of composition in that It provides method calling flexibility, for example :
2)组合的第二个非常好的优点是它提供了方法调用的灵活性,例如:
class X implements R
{}
class Y implements R
{}
public class Test{
R r;
}
In Test class using r reference I can invoke methods of X class as well as Y class. This flexibility was never there in inheritance
在使用 r 引用的测试类中,我可以调用 X 类和 Y 类的方法。这种灵活性在继承中从未存在过
3) Another great advantage : Unit testing
3)另一大优势:单元测试
public class X {
public void do(){
}
}
Public Class Y {
X x = new X();
public void work(){
x.do();
}
}
In above example, if state of x instance is not known, it can easily be mocked up by using some test data and all methods can be easily tested. This was not possible at all in inheritance as you were heavily dependent on superclass to get the state of instance and execute any method.
在上面的示例中,如果 x 实例的状态未知,则可以使用一些测试数据轻松模拟它,并且可以轻松测试所有方法。这在继承中根本不可能,因为您严重依赖超类来获取实例状态并执行任何方法。
4) Another good reason why we should avoid inheritance is that Java does not support multiple inheritance.
4) 我们应该避免继承的另一个很好的理由是 Java 不支持多重继承。
Lets take an example to understand this :
让我们举个例子来理解这一点:
Public class Transaction {
Banking b;
public static void main(String a[])
{
b = new Deposit();
if(b.deposit()){
b = new Credit();
c.credit();
}
}
}
Good to know :
很高兴知道 :
composition is easily achieved at runtime while inheritance provides its features at compile time
composition is also know as HAS-A relation and inheritance is also known as IS-A relation
组合在运行时很容易实现,而继承在编译时提供其功能
组合也称为 HAS-A 关系,继承也称为 IS-A 关系
So make it a habit of always preferring composition over inheritance for various above reasons.
因此,出于上述各种原因,养成总是喜欢组合而不是继承的习惯。
回答by aunte
I think this example explains clearly the differences between inheritanceand composition.
我认为这个例子清楚地解释了继承和组合之间的区别。
In this exmple, the problem is solved using inheritance and composition. The author pays attention to the fact that ; in inheritance, a change in superclass might cause problems in derived class, that inherit it.
在这个例子中,问题是使用继承和组合来解决的。作者注意到一个事实;在继承中,超类的更改可能会导致继承它的派生类出现问题。
There you can also see the difference in representation when you use a UML for inheritance or composition.
当您使用 UML 进行继承或组合时,您还可以在那里看到表示的差异。
回答by Robert Rocha
Composition is where something is made up of distinct parts and it has a strong relationship with those parts. If the main part dies so do the others, they cannot have a life of their own. A rough example is the human body. Take out the heart and all the other parts die away.
组合是指某物由不同的部分组成,并且与这些部分有很强的关系。如果主体死了,其他人也死了,他们就无法拥有自己的生命。一个粗略的例子是人体。取出心脏,所有其他部分都会消失。
Inheritance is where you just take something that already exists and use it. There is no strong relationship. A person could inherit his fathers estate but he can do without it.
继承是您只需获取已经存在的东西并使用它的地方。没有很强的关系。一个人可以继承他父亲的遗产,但他可以没有它。
I don't know Java so I cannot provide an example but I can provide an explanation of the concepts.
我不知道 Java,所以我不能提供一个例子,但我可以提供这些概念的解释。