- 浏览: 149752 次
- 性别:
- 来自: 上海
文章分类
- 全部博客 (166)
- Spring (7)
- JavaSE (16)
- web (1)
- Struts2 (2)
- Maven (1)
- 面试 (8)
- Hibernate (4)
- mysql (2)
- WebSerice (2)
- 工作心得 (23)
- 北京 (1)
- 上海 (27)
- groovy (1)
- 生活 (9)
- Linux (12)
- junit (1)
- oracle (5)
- h2db嵌入式数据库 (1)
- redis (14)
- 生活感悟 (1)
- cron (1)
- tomcat (4)
- 设计模式 (7)
- 正则表达式 (1)
- html5 (2)
- 网络编程 (3)
- 微信公众号 (1)
- Java nio (5)
- jdbc (1)
- 框架漏洞 (1)
- 安全 (8)
- 分布式 (2)
- 数据结构 (5)
- xml,json (0)
- xml (1)
- json (1)
- netty (0)
- java8 (1)
- javascript (1)
- 2016计划 (1)
- Java集合源码分析 (1)
- 工作心得,jvm性能调优 (3)
- 转载 (14)
- 产品 (1)
- JVM (10)
最新评论
-
oplife:
都不太难
返利网面试 -
飞翔神话:
谢谢 7 楼 cnrainbing
联想中望面试心得体会 -
飞翔神话:
5 楼 home198979,相比您可能还差点,但是我还是有一 ...
联想中望面试心得体会 -
cnrainbing:
支持小伙子
联想中望面试心得体会 -
jahu:
这简单啊,
联想中望面试心得体会
本文主要说明Java中继承与组合的概念,以及它们之间的联系与区别。首先文章会给出一小段代码示例,用于展示到底什么是继承。然后演示如何通过“组合”来改进这种继承的设计机制。最后总结这两者的应用场景,即到底应该选择继承还是组合。
1、继承
假设我们有一个名为Insect(昆虫)的类,这个类包含两个方法:1)移动move(); 2)攻击attack()。
代码如下:
现在,你想要定义一个名为Bee(蜜蜂)的类。Bee(蜜蜂)是Insect(昆虫)的一种,但实现了不同于Insect(昆虫)的attack()和move方法。这时候我们可以用继承的设计机制来实现Bee类,就像下面的代码一样:
InheritanceVSComposition作为一个测试类,在其main方法中生成了一个Bee类的实例,并赋值给Insect类型的引用变量 i。所以调用i的attack方法时,对应的是Bee类实例的attack方法,也就是调用了Bee类的attack方法。
类的继承结构图如下,非常简单:
Fly被打印了两次,也就是说move方法被调用了两次。但按理来讲,move方法只应当被调用一次,因为无论是昆虫还是蜜蜂,一次攻击前只移动一次。
问题出在子类(即Bee类)的attack方法的重载代码中,也就是super.attack()这一句。因为在父类(即Insect类)中,调用 attack方法时会先调用move方法,所以当子类(Bee)调用super.attack()时,相当于也同时调用了被重载的move方法(注意是子 类被重载的move方法,而不是父类的move方法)。
为了解决这个问题,我们可以采取以下办法:
删除子类的attack方法。这么做会使得子类的attack方法的实现完全依赖于父类对于该方法的实现(因为子类继承了父类的attack方法)。如果 父类的attack方法不受控制而产生了变更。比如说,父类的attack方法中调用了另外的move方法,那么子类的attack方法也会产生相应的变 化,这是一种很糟糕的封装。
也可以重写子类的attack方法,像下面这样:
这样保证了结果的正确性,因为子类的attack方法不再依赖于父类。但是,子类attack方法的代码与父类产生了重复(重复的attack方法会使得很多事情变得复杂,不仅仅是多打印了一条输出语句)。所以第二种办法也不行,它不符合软件工程中关于重用的思想。
如此看来,继承机制是有缺点的:子类依赖于父类的实现细节,如果父类产生了变更,子类的后果将不堪设想。
2、组合
在上面的例子中,可以用组合的机制来替代继承。我们先看一下运用组合如何实现。
attack这一功能不再是一个方法,而是被抽象为一个接口。
通过对Attack接口的实现,就可以在实现类当中定义不同类型的attack。
因为attack功能已经被抽象为一个接口,所以Insect类不再需要有attack方法。
Bee类一种Insect类,它具有attack的功能,所以它实现了attack接口:
类图:
测试类代码,将AttackImpl的实例作为Attack类型的参数传给Bee类的构造函数:
3、什么时候该用继承,什么时候该用组合?
以下两条原则说明了应该如何选择继承与组合:
如果存在一种IS-A的关系(比如Bee“是一个”Insect),并且一个类需要向另一个类暴露所有的方法接口,那么更应该用继承的机制。
如果存在一种HAS-A的关系(比如Bee“有一个”attack功能),那么更应该运用组合。
总结来说,继承和组合都有他们的用处。只有充分理解各对象和功能之间的关系,才能充分发挥这两种机制各自的优点。
参考:
Bloch, Joshua. Effective Java. Pearson Education India, 2008.
http://stackoverflow.com/questions/49002/prefer-composition-over-inheritance
http://www.javaworld.com/article/2076814/core-java/inheritance-versus-composition–which-one-should-you-choose-.html
该文章引自http://www.importnew.com/12907.html
1、继承
假设我们有一个名为Insect(昆虫)的类,这个类包含两个方法:1)移动move(); 2)攻击attack()。
代码如下:
class Insect { private int size; private String color; public Insect(int size, String color) { this.size = size; this.color = color; } public int getSize() { return size; } public void setSize(int size) { this.size = size; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } public void move() { System.out.println("Move"); } public void attack() { move(); //假设昆虫在攻击前必须要先移动一次 System.out.println("Attack"); } }
现在,你想要定义一个名为Bee(蜜蜂)的类。Bee(蜜蜂)是Insect(昆虫)的一种,但实现了不同于Insect(昆虫)的attack()和move方法。这时候我们可以用继承的设计机制来实现Bee类,就像下面的代码一样:
class Bee extends Insect { public Bee(int size, String color) { super(size, color); } public void move() { System.out.println("Fly"); } public void attack() { move(); super.attack(); } } public class InheritanceVSComposition { public static void main(String[] args) { Insect i = new Bee(1, "red"); i.attack(); } }
InheritanceVSComposition作为一个测试类,在其main方法中生成了一个Bee类的实例,并赋值给Insect类型的引用变量 i。所以调用i的attack方法时,对应的是Bee类实例的attack方法,也就是调用了Bee类的attack方法。
类的继承结构图如下,非常简单:
Fly被打印了两次,也就是说move方法被调用了两次。但按理来讲,move方法只应当被调用一次,因为无论是昆虫还是蜜蜂,一次攻击前只移动一次。
问题出在子类(即Bee类)的attack方法的重载代码中,也就是super.attack()这一句。因为在父类(即Insect类)中,调用 attack方法时会先调用move方法,所以当子类(Bee)调用super.attack()时,相当于也同时调用了被重载的move方法(注意是子 类被重载的move方法,而不是父类的move方法)。
为了解决这个问题,我们可以采取以下办法:
删除子类的attack方法。这么做会使得子类的attack方法的实现完全依赖于父类对于该方法的实现(因为子类继承了父类的attack方法)。如果 父类的attack方法不受控制而产生了变更。比如说,父类的attack方法中调用了另外的move方法,那么子类的attack方法也会产生相应的变 化,这是一种很糟糕的封装。
也可以重写子类的attack方法,像下面这样:
public void attack() { move(); System.out.println("Attack"); }
这样保证了结果的正确性,因为子类的attack方法不再依赖于父类。但是,子类attack方法的代码与父类产生了重复(重复的attack方法会使得很多事情变得复杂,不仅仅是多打印了一条输出语句)。所以第二种办法也不行,它不符合软件工程中关于重用的思想。
如此看来,继承机制是有缺点的:子类依赖于父类的实现细节,如果父类产生了变更,子类的后果将不堪设想。
2、组合
在上面的例子中,可以用组合的机制来替代继承。我们先看一下运用组合如何实现。
attack这一功能不再是一个方法,而是被抽象为一个接口。
interface Attack { public void move(); public void attack(); }
通过对Attack接口的实现,就可以在实现类当中定义不同类型的attack。
class AttackImpl implements Attack { private String move; private String attack; public AttackImpl(String move, String attack) { this.move = move; this.attack = attack; } @Override public void move() { System.out.println(move); } @Override public void attack() { move(); System.out.println(attack); } }
因为attack功能已经被抽象为一个接口,所以Insect类不再需要有attack方法。
class Insect { private int size; private String color; public Insect(int size, String color) { this.size = size; this.color = color; } public int getSize() { return size; } public void setSize(int size) { this.size = size; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } }
Bee类一种Insect类,它具有attack的功能,所以它实现了attack接口:
// 这个封装类封装了一个Attack类型的对象 class Bee extends Insect implements Attack { private Attack attack; public Bee(int size, String color, Attack attack) { super(size, color); this.attack = attack; } public void move() { attack.move(); } public void attack() { attack.attack(); } }
类图:
测试类代码,将AttackImpl的实例作为Attack类型的参数传给Bee类的构造函数:
public class InheritanceVSComposition2 { public static void main(String[] args) { Bee a = new Bee(1, "black", new AttackImpl("fly", "move")); a.attack(); // if you need another implementation of move() // there is no need to change Insect, we can quickly use new method to attack Bee b = new Bee(1, "black", new AttackImpl("fly", "sting")); b.attack(); } } 输出结果: fly move fly sting
3、什么时候该用继承,什么时候该用组合?
以下两条原则说明了应该如何选择继承与组合:
如果存在一种IS-A的关系(比如Bee“是一个”Insect),并且一个类需要向另一个类暴露所有的方法接口,那么更应该用继承的机制。
如果存在一种HAS-A的关系(比如Bee“有一个”attack功能),那么更应该运用组合。
总结来说,继承和组合都有他们的用处。只有充分理解各对象和功能之间的关系,才能充分发挥这两种机制各自的优点。
参考:
Bloch, Joshua. Effective Java. Pearson Education India, 2008.
http://stackoverflow.com/questions/49002/prefer-composition-over-inheritance
http://www.javaworld.com/article/2076814/core-java/inheritance-versus-composition–which-one-should-you-choose-.html
该文章引自http://www.importnew.com/12907.html
发表评论
-
for循环删除(ArrayList.remove)报错及解决办法
2017-01-12 15:50 1795[size=small]代码: JSONArray bin ... -
Java的接口和抽象类区别
2016-07-23 15:10 3841.语法层面上的区别 ... -
transient关键字
2016-07-04 14:56 495transient的用途 Q:transient关键字能实现 ... -
volatile的作用和使用场景
2016-05-07 17:00 10711、线程可见性,volatile修饰的变量是存放在主内存区域, ... -
Java synchronized
2016-04-26 23:30 438一、当两个并发线程访问同一个对象object中的这个synch ... -
java对象的强引用,软引用,弱引用和虚引用
2016-03-24 22:56 554[size=x-small] 众所 ... -
Java链式编程
2016-01-24 22:42 2043简介:每个方法(接口)的返回值都是this(当前对象),调用多 ... -
jdk switch使用
2015-12-29 17:09 571jdk1.6及之前的jdk中switch中的变量有10种,分别 ... -
单例模式的两种方式
2013-08-28 21:36 866首先,单例模式是指在程序运行的过程中,保证该类的实例只有一 ... -
解决Java中浮点型数据计算时产生的精度误差
2013-08-18 21:06 2665关于double和float的精度问题,在进行数值运算时, ... -
Java自定义注解(原理和API)初探
2013-07-21 00:25 1695今天稍稍学习了 ... -
Java中反射和动态代理学习心得和总结
2013-07-18 23:19 761下面对反射和动态代理做下总结: 对于反 ... -
使用反射对类的私有方法和属性进行调用
2013-07-17 17:40 1700公司不忙,没事可做,springMVC没有调试成功,很郁 ... -
JDK动态代理实现原理
2013-07-13 22:17 1007昨天下午终于签好 ... -
Java反射初探
2013-07-12 11:52 699目前非常多的开源 ...
相关推荐
### Java中的继承与组合在图形类定义中的应用 在Java编程语言中,继承与组合是面向对象编程(OOP)的两大核心概念。通过继承,一个类可以从另一个类那里继承属性和方法,从而实现代码的复用;而通过组合,则是在类...
Java 中继承与多态的题目 本资源摘要信息是关于 Java 中继承和多态的题目,涵盖了面向对象编程的基本概念和继承机制的应用。 继承的概念 继承是面向对象编程的一种机制,允许一个类(子类)继承另一个类(父类)...
java封装 继承与多态 程序设计 类与对象
在Java编程语言中,继承和组合是两种主要的面向对象设计原则,它们分别代表了类之间的不同关系。本文将深入探讨这两个概念以及它们在实际编程中的应用和选择。 首先,让我们了解一下继承。继承是Java中一种强大的...
Java中的继承和接口是面向对象编程的关键特性,它们在软件设计中扮演着至关重要的角色,实现了代码的重用和类的层次结构。 继承是Java中创建新类的一种方式,它允许一个子类(SubClass)从一个已存在的父类...
java集合继承结构图
在Java编程语言中,接口(Interface)和继承(Inheritance)是面向对象设计的重要特性,它们为代码提供了灵活性、可扩展性和复用性。本文将深入探讨这两个概念以及它们在实际开发中的应用。 首先,我们来看一下接口...
由于继承,`Stack`继承了`Vector`的所有方法,包括与栈行为不符的`add(int index, E element)`等,这些方法在实际使用中可能导致逻辑错误或不必要的性能开销。Sun Microsystems(现为Oracle)对此的建议是谨慎使用`...
JAVA 封装继承与多态是面向对象程序设计语言中三个重要的概念,本文将对这三个概念进行详细的解释。 一、封装 封装是指隐藏对象的内部细节,使对象外部不能随意存取对象的内部数据的过程。JAVA 中,对象就是一个...
继承是 Java 中的一种机制,允许一个类继承另一个类的属性和方法。继承的语法是使用 `extends` 关键字,例如 `public class Child extends Parent`。在 Java 中,只支持单一继承,也就是说一个类只能有一个直接父类...
上课老师讲得太快 没听懂 可以看看这个 讲的很详细
Java中的继承是面向对象编程的一个核心特性,它允许一个类(子类)继承另一个类(父类)的属性和方法,从而实现代码的复用和扩展。在这个"java关于继承的思维导图(Xmind)"中,我们可以看到作者对Java继承机制的详细...
在Java编程语言中,继承是面向对象编程的一个核心特性,它允许一个类(子类或派生类)从另一个类(父类或基类)继承属性和方法,从而实现代码的复用和扩展。这个小例子可能是为了演示如何在Java中实现继承以及它所...
Java继承和多态的程序设计 ...* 方法重写:Java语言中的方法重写是指子类提供了与父类相同的方法,但提供了不同的实现。 * 方法重载:Java语言中的方法重载是指多个方法具有相同的方法名,但具有不同的参数列表。
java继承学习教案.pptx
Java 中的继承 Java 中的继承是一个对象获取父对象的所有属性和行为的机制。它是 Java 面向对象编程技术的一块基石,因为它允许创建分等级层次的类。继承的概念是指子类继承父类的特征和行为,使得子类对象(实例)...
在Java编程语言中,泛型是一种强大的特性,它允许我们在类、接口和方法中使用类型参数,从而提高代码的灵活性和安全性。当我们谈论“继承泛型类”时,这意味着一个类(子类)正在扩展一个已经定义了泛型的类(父类)...
类的继承格式、继承的关系表示图、访问限制、子类对象的实例化过程、方法的覆写、属性的覆盖、Super关键字、this与super的区别
在Java中,继承是通过`extends`关键字来实现的。 类的继承格式通常如下: ```java class 父类 { // 父类的属性和方法 } class 子类 extends 父类 { // 子类的属性和方法 } ``` 在给定的描述中,我们看到一个...
7.java继承的语法.zip7.java继承的语法.zip7.java继承的语法.zip7.java继承的语法.zip7.java继承的语法.zip7.java继承的语法.zip7.java继承的语法.zip7.java继承的语法.zip7.java继承的语法.zip7.java继承的语法.zip...