在讲解之前我们先看一个例子

Husband.java

public class Husband {
private String name;
private String sex;
privateintage;
private Wife wife;
//省略属性的getter和setter方法
}

Wife.java

public class Wife {
private String name;
private int age;
private String sex;
private Husband husband;
//省略属性的getter和setter方法
}

  从这里我们可以看出,Wife、Husband两个类除了各自的husband、wife外其余部分全部相同,作为一个想最大限度实现复用代码的我们是不能够忍受这样的重复代码,如果再来一个小三、小四、小五……我们是不是也要这样写呢?那么我们如何来实现这些类的可复用呢?利用继承!!

  首先我们先离开软件编程的世界,从常识中我们知道丈夫、妻子、小三、小四…,他们都是人,而且都有一些共性,有名字、年龄、性别、头等等,而且他们都能够吃东西、走路、说话等等共同的行为,所以从这里我们可以发现他们都拥有人的属性和行为,同时也是从人那里继承来的这些属性和行为的。

从上面我们就可以基本了解了继承的概念了,继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力。继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承我们能够非常方便地复用以前的代码,能够大大的提高开发的效率。

  看如下代码,首先定义父类

Person.java

public class Person {
private String name;
private String sex;
private int age;
}

Husband.java

public class Husband extends Person {
private Wife wife;
//省略属性的getter和setter方法
}

Wife.java

public class Wife extends Perso {
private Husband husband;
//省略属性的getter和setter方法
}

  对于Wife、Husband使用继承后,除了代码量的减少我们还能够非常明显的看到他们的关系。

  继承所描述的是“is-a”的关系,如果有两个对象A和B,若可以描述为“A是B”,则可以表示A继承B,其中B被称之为继承者的父类或者超类。A是继承者,称之为子类或者派生类。

  实际上继承者是被继承者的特殊化,它除了拥有被继承者的特性外,还拥有自己独有得特性。例如猫有抓老鼠、爬树等其他动物没有的特性。同时在继承关系中,继承者完全可以替换被继承者,反之则不可以,例如我们可以说猫是动物,但不能说动物是猫就是这个道理,其实对于这个我们将其称之为“向上转型”,下面介绍。

  继承定义了类如何相互关联,共享特性。对于若干个相同或者相似的类,我们可以抽象出他们共有的行为或者属性并将其定义成一个父类或者超类,然后用这些类继承该父类,他们不仅可以拥有父类的属性、方法还可以定义自己独有的属性或者方法。

  同时在使用继承时需要记住三句话:

    1、子类拥有父类非private的属性和方法。

    2、子类可以拥有自己属性和方法,即子类可以对父类进行扩展。

    3、子类可以用自己的方式实现父类的方法。(以后介绍)。

  综上所述,使用继承确实有许多的优点,除了将所有子类的共同属性放入父类,实现代码共享,避免重复外,还可以使得修改扩展继承而来的实现比较简单。

  讲到继承一定少不了这三个东西:构造器、protected关键字、向上转型。

构造器

  通过前面我们知道子类可以继承父类的属性和方法,除了那些private的外还有一样是子类继承不了的---构造器。对于构造器而言,它只能够被调用,而不能被继承。调用父类的构造方法我们使用super()即可。

  对于子类而言,其构造器的正确初始化是非常重要的,当且仅当只有一个方法时可以保证这点:在构造器中调用父类构造器来完成初始化,而父类构造器具有执行父类初始化所需要的所有知识和能力。

class Person {
protected String name;
protected int age;
protected String sex;
Person() {
System.out.println("Person Constrctor...");
}
} public class Husband extends Person {
private Wife wife;
Husband() {
System.out.println("Husband Constructor...");
}
public staticvoid main(String[] args) {
Husband husband = new Husband();
}
}
Output:
Person Constrctor...
Husband Constructor...

  通过这个示例可以看出,构建过程是从父类“向外”扩散的,也就是从父类开始向子类一级一级地完成构建。而且我们并没有显示的引用父类的构造器,这就是java的聪明之处:编译器会默认给子类调用父类的构造器。

  但是,这个默认调用父类的构造器是有前提的:父类有默认构造器。如果父类没有默认构造器,我们就要必须显示的使用super()来调用父类构造器,否则编译器会报错:无法找到符合父类形式的构造器。

class Person {
protected String name;
protected int age;
protected String sex;
Person(String name) {
System.out.println("Person Constrctor-----" + name);
}
}
public class Husband extends Person {
private Wife wife;
Husband() {
super("show");//没有这行代码,编译器默认隐式调用父类的无参构造,但是父类没用无参构造,只能显示的调用父类的有参构造
System.out.println("Husband Constructor...");
}
public static void main(String[] args) {
Husband husband = new Husband();
}
}
Output:
Person Constrctor-----show
Husband Constructor...

  综上所述:对于继承而言,子类会默认调用父类的无参构造器,但是如果父类没默认有无参构造器,子类必须要显示的指定父类的构造器,而且必须是在子类构造器中做的第一件事(第一行代码)。

protected关键字

  private访问修饰符,对于封装而言,是最好的选择,但这个只是基于理想的世界,有时候我们需要这样的需求:我们需要将某些事物尽可能地对这个世界隐藏,但是仍然允许子类的成员来访问它们。这个时候就需要使用到protected。

  对于protected而言,就类用户而言,他是private,但是对于任何继承与此类的子类而言或者其他任何位于同一个包的类而言,他却是可以访问的。

class Person {
private String name;
private int age;
private String sex;
protected String getName() {
return name;
}
protected void setName(String name) {
this.name = name;
}
public String toString() {
return"this name is " + name;
}
/** 省略其他setter、getter方法 **/
}
public class Husband extends Person {
private Wife wife;
public String toString() {
setName("show"); // 调用父类的setName();
return super.toString(); // 调用父类的toString()方法
}
publics tatic void main(String[] args) {
Husband husband = new Husband();
System.out.println(husband.toString());
}
}
Output:
this name is show

  从上面示例可以看出子类Husband可以明显地调用父类Person的setName()。

  尽管可以使用protected访问修饰符来限制父类属性和方法的访问权限,但是最好的方式还是将属性保持为private(我们应当一致保留更改底层实现),通过protected方法来控制类的继承者的访问权限。

向上转型

  在上面的继承中我们谈到继承是is-a的相互关系,猫继承于动物,所以我们可以说猫是动物,或者说猫是动物的一种。这样将猫看做动物就是向上转型。如下:

class Person {
public void display() {
System.out.println("Play Person...");
}
static void display(Person person) {
person.display();
}
}
public class Husband extends Person {
public staticvoid main(String[] args) {
Husband husband = new Husband();
Person.display(husband); // 向上转型
}
}

  在这我们通过Person.display(husband)。这句话可以看出husband是person类型。

  将子类转换成父类,在继承关系上面是向上移动的,所以一般称之为向上转型。由于向上转型是从一个叫专用类型向较通用类型转换,所以它总是安全的,唯一发生变化的可能就是属性和方法的丢失。这就是为什么编译器在“未曾明确表示转型”或“未曾指定特殊标记”的情况下,仍然允许向上转型的原因。

小结

上面讲了继承所带来的诸多好处,那我们是不是就可以大肆地使用继承呢?慎用继承。

首先我们需要明确,继承存在如下缺陷:

1、父类变,子类就必须变。

2、继承破坏了封装,对于父类而言,它的实现细节对与子类来说都是透明的。

3、继承是一种强耦合关系。

所以说当我们使用继承的时候,我们需要确信使用继承确实是有效可行的办法。那么到底要不要使用继承呢?《Think in java》中提供了解决办法:问一问自己是否需要从子类向父类进行向上转型。如果必须向上转型,则继承是必要的,但是如果不需要,则应当好好考虑自己是否需要继承。

二、java三大特性--继承的更多相关文章

  1. java三大特性--继承

    定义: 继承就是子类继承父类的特征和行为,使得子类具有父类的各种属性和方法,使得子类具有父类相同的行为. 继承的好处: 有效实现代码复用,避免重复代码的出现. 让类与类之间产生了关系,是多态的前提. ...

  2. Java 三大特性——封装、继承、多态

    一.封装 封装,实际就是把属于同一类事物的共性(包括属性与方法)归到一个类中,以方便使用. 概念:在面向对象程式设计方法中,封装(英语:Encapsulation)是指,一种将抽象性函式接口的实作细节 ...

  3. java三大特性:封装、继承、多态

    Java三大特性之封装   一.定义 封装性指的是将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部的信息,而是通过该类所提供的方法来实现对内部信息的操作和访问. 二.使用封装的好处: 1 ...

  4. JAVA基础第二章-java三大特性:封装、继承、多态

    业内经常说的一句话是不要重复造轮子,但是有时候,只有自己造一个轮子了,才会深刻明白什么样的轮子适合山路,什么样的轮子适合平地! 我将会持续更新java基础知识,欢迎关注. 往期章节: JAVA基础第一 ...

  5. Java提高篇之理解java的三大特性——继承

    在<Think in java>中有这样一句话:复用代码是Java众多引人注目的功能之一.但要想成为极具革命性的语言,仅仅能够复制代码并对加以改变是不够的,它还必须能够做更多的事情.在这句 ...

  6. 浅析Java三大特性封装、继承、多态,及作业分析

    前言 本次博客衔接上次博客,作为这一阶段Java学习的分析.上一篇博客着重介绍了Java的OO编程思维,面向对象与面向过程的区别.本篇博客重心在Java的三大技术特性,附带作业分析. Java三大特性 ...

  7. JAVA三大特性之多态

    面向对象的三大特性:封装.继承.多态.从一定角度来看,封装和继承几乎都是为多态而准备的.这是我们最后一个概念,也是最重要的知识点. 多态的定义:指允许不同类的对象对同一消息做出响应.即同一消息可以根据 ...

  8. [.net 面向对象编程基础] (12) 面向对象三大特性——继承

    [.net 面向对象编程基础] (12) 面向对象三大特性——继承 上节我们说了面向对象的三大特性之一的封装,解决了将对同一对象所能操作的所有信息放在一起,实现统一对外调用,实现了同一对象的复用,降低 ...

  9. Java三大特性

    Java 三大特性,算是Java独特的表现,提到Java 的三大特性, 我们都会想到封装, 继承和多态 这是我们Java 最重要的特性. 封装(Encapsulation) : 封装:是指隐藏对象的属 ...

随机推荐

  1. lfs(systemd版本)学习笔记-第3页

    我的邮箱地址:zytrenren@163.com欢迎大家交流学习纠错! lfs(systemd)学习笔记-第2页 的地址:https://www.cnblogs.com/renren-study-no ...

  2. lfs(systemd版本)学习笔记-第1页

    我的邮箱地址:zytrenren@163.com欢迎大家交流学习纠错! 一名linux爱好者,记录构建Linux From Scratch的过程 经博客园-骏马金龙前辈介绍,开始接触学习lfs,用博客 ...

  3. 自定义基于jquery竖向瀑布流插件

    公司新项目做了一个关于图片的板块,网上找了一些瀑布流插件都不是很适合自己,于是就自己造轮子写一个,并封装成插件github 于是就想分享一下,主要是为了更好的学习与记忆. 如果大家进来了,希望能给我g ...

  4. FIFO、LRU、LFU的含义和原理

    含义: FIFO:First In First Out,先进先出LRU:Least Recently Used,最近最少使用 LFU:Least Frequently Used,最不经常使用 以上三者 ...

  5. JS闭包和引用

    简介 Javascript 中一个最重要的特性就是闭包的使用.因为闭包的使用,当前作用域总可以访问外部的作用域.因为Javascript 没有块级作用域,只有函数作用域,所以闭包的使用与函数是紧密相关 ...

  6. for each....in、for in、for of

    一.一般的遍历数组的方法: var array = [1,2,3,4,5,6,7]; for (var i = 0; i < array.length; i) { console.log(i,a ...

  7. python 类函数,实例函数,静态函数

    一.实现方法 class Function(object): # 在类定义中定义变量 cls_variable = "class varibale" def __init__(se ...

  8. 解决git did not exit cleanly (exit code 128)

    最近在用git提交代码到部门服务器上的时候,总是有 提示 git did not exit cleanly (exit code 128).网上有2种解决方式: 1.替换路径 1.鼠标右键 -> ...

  9. linux编写.sh脚本并赋权限

    今日打包编译项目时,发现缺少一个git pull更新项目的脚本,所以在linux编写了一个gitpull.sh脚本,能够实现更新项目的需求. 1.首先vi  gitpull.sh或者使用vim编辑器. ...

  10. Column Index out of range, 2 > 1 列索引的范围,2 > 1。

    Column Index out of range, 2 > 1  列索引的范围,2 > 1.这个问题是进行数据库查询的时候出现的. 因为查询sql语句时 只查询了 name 然后whil ...