1.1概述
继承是面向对象最显著的一个特性。继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力。
以上来自百度百科,通俗来讲继承就是子类继承了父类的方法和属性,子类可以直接访问父类中的非私有的属性和行为(私有的属性可以通过get、set方法来访问),还可以在子类的基础上再定义新的方法和属性,提高了代码的复用性。同时注意Java中的继承是单继承的,一个子类只能有一个直接父类,一个父类可以有多个子类。
1.2继承的格式
通过 extends 关键字,可以声明一个子类继承另外一个父类,定义格式如下:
class 父类 {
...
}
class 子类 extends 父类 {
...
}
举例说明继承:
现在有这样一个需求,要定义与狗品种相关的金毛犬类和拉布拉多犬类用于存储相关狗的信息。金毛犬和拉布拉多犬有一些重复的属性和行为,比如名字,年龄,如果我们在这两个类中都定义这些重复的属性和行为,就降低了代码的复用性,这时通过继承就可以解决。
/**
* 定义父类
*/
public class Dog {
private String name;
private String age;
public void Calls(){
System.out.println("汪汪叫");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
/**
* 定义子类,金毛犬类
*/
public class JinMaoDog extends Dog{
private String colour;
public void motion(){
System.out.println("喜欢运动");
}
public String getColour() {
return colour;
}
public void setColour(String colour) {
this.colour = colour;
}
}
/**
* 测试类
*/
public class Test {
public static void main(String[] args) {
JinMaoDog dog = new JinMaoDog();
//父类属性赋值
dog.setName("金毛");
dog.setAge("2");
//子类属性赋值
dog.setColour("金色");
System.out.println("名字:"+dog.getName()+"--年龄:"+dog.getAge()+"--颜色:"+dog.getColour());
//调用父类方法
dog.Calls();
//调用子类方法
dog.motion();
}
}
输出结果
名字:金毛--年龄:2--颜色:金色
汪汪叫
喜欢运动
1.3继承后成员变量的特点
1、与父类成员变量命名没有重复
当子类成员变量和父类成员变量的命名没有重复,子类对象可以正常访问父类的变量。
2、与父类成员变量命名重复
当子类成员变量和父类的成员变量重复,在子类的内部访问父类的属性时,用super关键字来调用父类的属性,子类对象在调用相同的属性时,会优先调用子类的属性。
/**
* 父类
*/
public class Fu {
private String name = "父";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
/**
* 子类
*/
public class Zi extends Fu{
private String name = "子";
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void print(){
System.out.println("父类属性:"+super.getName()); //子类使用super关键字调用父类属性
System.out.println("子类属性:"+this.name);
}
}
/**
* 测试类
*/
public class Test {
public static void main(String[] args) {
Zi zi = new Zi();
//子类对象调用重名属性
System.out.println(zi.getName());
//调用方法
zi.print();
}
}
输出结果
子
父类属性:父
子类属性:子
1.4继承后成员方法的特点
1、与父类成员方法命名没有重复,子类对象可以正常访问父类的方法。
2、如果子类父类中出现重名的成员方法,这时的访问会有一种特殊的情况,叫做方法重写 (Override)。方法的重写是子类根据需求定义自己的特有行为,同时既沿袭了父类的功能名称,又根据子类的需要重新实现父类方法,从而进行扩展增强。此时当子类创建的对象调用同名方法时,默认调用的是子类中重写后的方法。
方法重写的注意事项:
a.必须保证父子类的方法名相同,参数列表也相同。
b.子类方法的返回值要小于等于父类方法的返回值。
c.子类方法的权限修饰符要大于等于父类的方法的权限修饰符。
d.子类异常不能大于父类异常。
e.推荐使用@Override注解标注在子类重写的方法上,可以增强代码的可读性,同时编译器会检查重写方法是否正确。
/**
* 父类
*/
public class Fu {
//父类独有方法
public void methodFu(){
System.out.println("父类方法");
}
//重名方法
public void method(){
System.out.println("父");
}
}
/**
* 子类
*/
public class Zi extends Fu{
//子类独有方法
public void methodZi(){
System.out.println("子类方法");
}
//重名方法
@Override
public void method(){
System.out.println("子");
}
}
/**
* 测试类
*/
public class Test {
public static void main(String[] args) {
Zi zi = new Zi();
zi.methodZi(); //子类对象调用子类方法
zi.methodFu(); //子类对象调用父类方法
zi.method(); //子类对象调用同名方法
}
}
输出结果:
子类方法
父类方法
子
1.5继承后构造方法的特点
1、父类的构造方法不能被子类继承,因为构造方法名与类名一致。
2、在创建子类对象时,默认会先调用父类的构造方法再调用子类的构造方法,构造方法的作用是初始化成员变量,所以子类的初始化过程中,必须先执行父类的初始化动作。子类的构造方法中默认有一个 super() ,表示调用父类的构造方法。
3.使用super关键字调用父类的构造方法时,必须在写在子类构造方法的第一句,在子类构造方法中不允许多次使用super调用。
/**
* 父类
*/
public class Fu {
private String name;
public Fu() {
super();
System.out.println("父类无参构造器");
}
public Fu(String name) {
super();
this.name = name;
System.out.println("父类有参构造器");
}
}
/**
* 子类
*/
public class Zi extends Fu{
private String name;
public Zi() {
super();
System.out.println("子类无参构造器");
}
public Zi(String name) {
super(name);
System.out.println("子类有参构造器");
}
}
/**
* 测试类
*/
public class Test {
public static void main(String[] args) {
Zi zi = new Zi();
System.out.println("-----------------------------------");
Zi zi2 = new Zi("asdfg");
}
}
输出结果:
父类无参构造器
子类无参构造器
-----------------------------------
父类有参构造器
子类有参构造器
1.6 super关键字
1、super关键字的用法
a.在子类成员方法中,访问父类的成员变量和成员方法。
b.在子类的构造方法中访问父类的构造方法。
/**
* 父类
*/
public class Fu {
private String name;
public Fu(String name) {
super();
this.name = name;
}
public void methodFu(){
System.out.println("父类成员方法");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
/**
* 子类
*/
public class Zi extends Fu{
private String name;
public Zi() {
super("张三");
}
public void methodZi(){
System.out.println(super.getName());//调用父类的属性
super.methodFu();//调用父类的方法
}
}
/**
* 测试类
*/
public class Test {
public static void main(String[] args) {
Zi zi = new Zi();
zi.methodZi();
}
}
输出结果:
张三
父类成员方法