相关文章:html
在《面向对象再探究》这篇文章中已经笼统的介绍过继承的概念了,下面就来具体介绍继承的使用等相关问题。java
以Animal
类和Dog
类例子,下文都会围绕该例展开。oracle
public class Animal { private String name; private int age; public Animal(String name, int age) { this.name = name; this.age = age; } public Animal() { } public void say() { System.out.println("我是" + name + ",今年" + age + "岁了"); } //getters and setters ... }
public class Dog extends Animal { private String address; public Dog(String name, int age, String address) { super(name, age); this.address = address; } public Dog() { } public void say() { System.out.println("我叫" + super.getName() + ",今年" + super.getAge() + "岁了,家住" + address + ",汪汪汪..."); } public void watchDoor() { System.out.println("我在" + address +"看门..."); } //getters and setters ... }
Dog
类继承Animal
类,Animal
类有name
、age
属性和say()
方法,Dog
类增长了address
属性和watchDoor()
方法。this
在现实生活中有许多继承的例子,好比“子承父业”、“继承父母财产”、“继承某人意志”等,这些都是在强调一个体获得另外一个体的东西,他们之间存在“继承关系”。设计
在Java中,继承是类和类之间的关系。在《面向对象再探究》这篇文章中举了动物Animal
类和狗Dog
类、猫Cat
类、兔子Rabbit
类的例子并写了代码,这里直接拿来用再也不列出,请移步此文章。code
咱们能够说狗、猫、兔子是动物,但不能够说动物是狗、猫、兔子。动物广泛有眼睛、耳朵等属性,有跑、吃、叫等行为。狗显然也具备这些属性和行为,可是狗也具备一些它特有的属性和行为,好比灵敏的鼻子、看门等。htm
在这个例子中,Animal
类是父类,Dog
类、Cat
类、Rabbit
类是子类。子类和父类存在继承关系,能够说:子类“是”父类,该关系是继承的一个明显特征。对象
下面是关于继承的几个Q&A:继承
Q1: 何时须要用到继承?教程
A1: 我的认为可从如下两点出发:
Q2: 怎样使用继承?
A2: 子类使用extends
关键字继承父类,也只有使用了该关键字后,才存在继承关系及“父子类”:
public class Animal {//父类 //属性和方法 }
public class Dog extends Animal {//子类继承父类 //属性和方法 }
Q3: 在具体开发中,是先编写父类,而后扩展出子类,仍是先编写子类,而后抽象出父类?
A3: 我的认为不能一律而论。若是你的系统设计很是好,能够先写好父类,而后扩展子类。若是你没设计好,或者考虑不周,那么后期可能会出现许多类有重复代码,这时候能够考虑抽取父类。
Q4: 父类和子类在内容上有什么区别?
A4: 一般,咱们将更通用的一些属性和方法放到父类中,好比狗、猫、兔子都具备的属性和方法会方法动物类中。子类中是更加特别的属性和方法,好比狗的看门行为、猫的抓老鼠行为。因为子类继承了父类,因此子类中只须要编写和父类的不一样之处。
因此,子类每每会比父类拥有更加丰富的属性和方法。
Q5: 子类继承的父类的哪些东西?
A5: 这里先给出结论,下文再详细介绍。子类继承了父类的非私有private
的成员变量、方法、嵌套类,子类不继承父类的构造器,可是子类能够调用父类的构造器。
Q6: Java中能够继承多个类吗?
A6: Java中的继承是单继承,只能继承一个类。
有时子类从父类继承获得的方法不必定适用,这时子类能够重写父类的方法。如Dog
类重写了其父类的say()
方法。
注意要和重载加以区分。
简单来讲,重写涉及到的是两个类的同名方法,重载涉及到的是一个类的同名方法。关于重载介绍请移步这里。
前面提到:子类是对父类的扩展,子类内容比父类更加丰富。因此一般子类都会有本身的属性和方法,好比Dog
类的address
属性和watchDoor()
方法。
子类不继承父类的私有成员,可是若是父类有能访问其私有成员变量的public
或protected
的方法(好比getter方法),那么子类能够经过继承这些方法来使用父类的私有方法(Java官方教程)。
下面用上面的代码例子解释:
Animal
类有私有成员变量、和公有方法say()
。say()
直接访问本类的私有成员变量,没毛病!
public class Animal { private String name; private int age; public void say() { System.out.println("我是" + name + ",今年" + age + "岁了"); } //其余代码... }
如今Dog
类继承Anima
类
public class Dog extends Animal { private String address; public void say() {//name和age报红 System.out.println("我叫" + name + ",今年" + age + "岁了,家住" + address + ",汪汪汪..."); } //其余代码... }
请注意Dog
类的say()
方法,直接访问了name
和age
属性,若是子类继承了父类的私有成员,那么这样写是没问题的,但事实是name
和age
报红了,说明子类没有继承父类的私有成员。
虽然子类没有继承父类的私有成员,可是咱们能够经过父类的公有方法使用其私有成员变量,代码改动以下:
public class Dog extends Animal { private String address; public void say() { System.out.println("我叫" + super.getName() + ",今年" + super.getAge() + "岁了,家住" + address + ",汪汪汪..."); } //其余代码... }
使用super.xxx()
能够调用父类的方法,因为getName()
是父类公有方法,且能访问父类的私有成员变量name
,因此子类调用getName()
方法可使用name
变量。
子类没有继承父类的私有成员变量,固然不能直接赋值。一般有两种方法:调用父类的公有setter方法或调用父类的构造器。本质上仍是子类经过使用父类提供的公有方法(setter或构造器)使用其私有成员变量。
public class Dog extends Animal { private String address; public void setName(String name) { super.setName(name); //注意super } public void setAge(int age) { super.setAge(age); } public void say() { System.out.println("我叫" + super.getName() + ",今年" + super.getAge() + "岁了,家住" + address + ",汪汪汪..."); } //其余代码... }
Dog
类的两个setter方法调用了Animal
类的两个setter方法,因为子类的setter方法名和父类的setter方法名取得同样(重写了),因此必定要使用super
关键字加以区分,不然就成递归了。
public class Dog extends Animal { private String address; public Dog(String name, int age, String address) { super(name, age); //调用父类构造器 this.address = address; } public Dog() { } public void say() { System.out.println("我叫" + super.getName() + ",今年" + super.getAge() + "岁了,家住" + address + ",汪汪汪..."); } //其余代码... }
public class Animal { private String name; private int age; public Animal(String name, int age) { this.name = name; this.age = age; } //其余代码... }
子类使用super()
语句调用父类构造器,该语句必须是子类构造器的第一行代码。
若是子类构造器没有显式调用父类构造器,则会默认调用父类的无参构造器。因此若是父类没有无参构造器,而子类又没有显式调用父类的其余构造器,则会报错。
若有错误,还请指正。