继承是面向对象的三大特征之一,可以使得子类具有父类的属性和方法,还可以在子类中重新定义,追加属性和方法
父类,也被称为基类、超类。子类,也被称为派生类
继承中子类的特点 1、子类可以有父类的内容 2、子类还可以有自己特有的内容
继承的格式:
public class 子类名 extends 父类名{}
继承的练习
package ch6;
public class a_1_1Fu { public void show(){ System.out.println("show方法被调用"); }}
package ch6;
//在原来的类后面加一个extends,后面再跟上父类。就表示子类继承了父类public class a_1_2Zi extends a_1_1Fu { public void method(){ System.out.println("method方法被调用"); }}
xxxxxxxxxxpackage ch6;
public class a_1_3测试 { public static void main(String[] args) { //创建对象,调用方法 a_1_1Fu f = new a_1_1Fu();//无参构造方法 f.show();
a_1_2Zi z = new a_1_2Zi(); z.method();
//在子类的文件里面,在类的位置写一个extends就可以继承了,这里就可以继承父类的show方法 z.show(); }}
继承的好处和弊端
继承好处 1、提高了代码的复用性,多个类相同的成员可以放到同一个类中 2、提高了代码的维护性,如果方法的代码需要修改,修改一处即可
继承弊端 1、继承让类与类之间产生了关系,类的耦合性增强了,当父类发生变化时,子类实现也不得不跟着变化,削弱了子类的独立性
什么时候使用继承 1、继承体现的关系:is a 即什么是什么的一种 2、假设法:我有两个类A和B,如果他们满足A是B的一种,或者B是A的一种,就说明他们存在继承关系,这个时候就可以考虑使用继承来体现,否则就不能滥用继承 3、举例:苹果和水果(可以用继承),猫和动物(可以用继承),猫和狗(不能用继承)
继承中变量的访问特点
在子类方法中访问一个变量 1、子类局部范围找 2、如果子类局部范围没有找到,就去子类成员范围找 3、如果子类成员范围也找不到,就会去父类(亲父亲,不是祖辈父亲)成员范围找 4、都没有找到就会报错
访问特点的练习
package ch6;
public class a_3_1Fu { //年龄 public int age = 40;//年龄用public修饰,为了访问方便}
xxxxxxxxxxpackage ch6;
public class a_3_2Zi extends a_3_1Fu{ //这个子类继承另一个父类
//身高 public int height = 175;
//年龄 //public int age = 100;//当父类和子类都有一个age,会优先输出子类的age
public void show(){ System.out.println(age);//age是父类里的,只有继承了父类才可以访问到父类里面的 System.out.println(height); }
}package ch6;
public class a_3_3测试 { public static void main(String[] args) { //创建对象,调用方法 a_3_2Zi z = new a_3_2Zi(); z.show();//输出子类里的show方法,输出40,175 }}
super关键字
super关键字的用法和this关键字的用法相似 1、this:代表本类对象的引用 2、super:代表父类存储空间的标识(可以理解为父类对象引用)
| 关键字 | 访问成员变量本类 | 访问构造方法 | 访问成员方法 |
|---|---|---|---|
| this | this.成员变量【本类】 | this(…)【本类】 | this.成员方法(…)【本类】 |
| super | super.成员变量【父类】 | super(…)【父类】 | super.成员方法(…)【父类】 |
super关键字的练习
xxxxxxxxxxpackage ch6;
public class a_4_1Fu {
public int age = 40;
}xxxxxxxxxxpackage ch6;//注意这里是子类,但是继承了父类public class a_4_2Zi extends a_4_1Fu {//继承父类 public int age = 100;
public void show(){ int age = 99;//一般来说输出子类的show方法就会输出99 System.out.println(age);
//思考:如果我要访问本类的成员变量age,怎么办。即我想要输出100而不是99 //解决:利用this指向 System.out.println(this.age);//表示访问的是本类的成员变量age,即100
//思考:如果我要访问父类的成员变量age,怎么办。即我想要输出40,而不是100或99 //解决:利用super关键字 System.out.println(super.age);//表示访问的是父类的成员变量age,即40 }
}package ch6;
public class a_4_3测试 { public static void main(String[] args) { //创建对象,调用子类的方法 a_4_2Zi z = new a_4_2Zi(); z.show();//原本是输出99,用了this之后输出100,用了super之后输出40 }}
继承中构造方法的访问特点
子类中所有的构造方法默认都会访问父类中无参的构造方法
理由: 1、因为子类会继承父类中的数据,可能还会使用父类的数据。所以,子类初始化之前,一定要先完成父类数据的初始化 2、每一个子类构造方法的第一条语句默认都是:super(),而super()又是无参构造方法,所以一定会调用(访问)父类的无参构造方法
每一个子类构造方法的第一条语句默认都是:super()。这个super()调用方法在代码里是不显示的,系统自己额外执行的
如果父类中没有无参构造方法,只有带参构造方法,该怎么办,提供两种解决办法 1、通过使用super关键字做到'显示的调用'父类的带参构造方法 2、在父类中自己提供一个无参构造方法 --> 更推荐这种做法
访问特点的练习
package ch6;
public class a_5_1Fu {
public a_5_1Fu(){ System.out.println("Fu无参构造¬SubmitBuild方法被调用"); }
public a_5_1Fu(int age){ System.out.println("Fu带参构造&haveSubmitBuild方法被调用"); }}x
package ch6;
public class a_5_2Zi extends a_5_1Fu{//extends关键字,作用是继承父类
public a_5_2Zi(){ //super(); //默认的super()在这个位置,不写的话,系统会默认自己执行这个super无参方法 //super(20); //也可以指定父类的带参构造方法,即只调用父类的带参构造方法 System.out.println("Zi无参构造¬SubmitBuild方法被调用"); }
public a_5_2Zi(int age){ //super(); //默认的super()在这个位置,不写的话,系统会默认自己执行这个super无参方法 System.out.println("Zi带参构造&haveSubmitBuild方法被调用"); }
}package ch6;
public class a_5_3测试 { public static void main(String[] args) {
//创建对象 a_5_2Zi z = new a_5_2Zi();//通过无参构造方法创建对象 //先输出父类的无参语句,再输出子类的无参语句 //即先输出'Fu无参构造¬SubmitBuild方法被调用'再输出'Zi无参构造¬SubmitBuild方法被调用' //思考:为什么会先去访问父类的构造方法
//创建对象 a_5_2Zi z2 = new a_5_2Zi(20);//通过带参构造方法创建对象 //先输出父类的无参语句,再输出子类的带参语句 //思考:为什么调用子类的带参构造方法时,会访问父类的无参构造方法
}}
继承中成员方法的访问特点
通过子类对象访问一个方法 1、子类成员范围找 2、父类成员范围找 3、如果都没有找到就报错(只在子类和子类的亲父类找)
访问特点的练习
xxxxxxxxxxpackage ch6;
public class a_6_1Fu {
//再把下面的代码在子类里复制一份 public void show(){ System.out.println("Fu中show()方法被调用"); }}package ch6;
public class a_6_2Zi extends a_6_1Fu {
public void method(){ System.out.println("Zi中method()方法被调用"); }
//父类里也有show()方法,这个方法的println输出子类中的show()方法被调用,以便于观察 public void show(){ //当加一个super.show()时,则指定在父类里找show()方法 super.show(); System.out.println("Zi中show()方法被调用"); }}xxxxxxxxxxpackage ch6;
public class a_6_3测试 {
public static void main(String[] args) { //创建对象,调用方法 a_6_2Zi z = new a_6_2Zi(); z.method();//输出Zi中method()方法被调用 //z.show();//输出Fu中show()方法被调用
//当子类里也有一个show()方法时,调用的是'Zi中的show()方法被调用' //z.show();//输出Zi中的show()方法被调用 //说明子类对象调用方法时,首先会在子中找对应的方法,如果子中没有找到,就会去父中找
//当子类里写了super.show()时,则指定在父类里找show()方法 z.show();//先输出父类的show()方法被调用,再输出子类的show()方法被调用 }}
方法重写
方法重写概述 1、子类中出现了和父类中一样的方法声明的现象
方法重写应用 1、当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容
@Override 1、是一个注解 2、可以帮助我们检查重写方法的方法声明是否正确
方法重写的练习
xxxxxxxxxxpackage ch6;//手机类public class a_7_1_1Phone { public void call(String name){ System.out.println("给" + name + "打电话"); }}xxxxxxxxxxpackage ch6;
//新手机类,让这个类继承a_7_1_1Phone类public class a_7_1_2NewPhone extends a_7_1_1Phone{
//注解。写重写方法时,建议自己在方法前面加这一行,如果这一行没报错,那下面的重写方法就正确 public void call(String name){ System.out.println("开启视频功能,start video");
//System.out.println("给" + name + "打电话"); //因为父类有上面那行的输出语句,如何不在子类即本文件里不多余书写上面那句话呢 //需要使用到super方法,如下,先把System.out.println("给" + name + "打电话");注释 super.call(name);//直接调用,把参数传进去,就可以达到跟注释了的那行的同样效果 }}xxxxxxxxxxpackage ch6;
public class a_7_2测试 { public static void main(String[] args) { //创建对象,调用方法 a_7_1_1Phone p = new a_7_1_1Phone(); p.call("lina");//输出'给lina打电话' System.out.println("-----------");
//让a_7_1_2NewPhone继承a_7_1_1Phone之后,创建对象,调用方法 a_7_1_2NewPhone np = new a_7_1_2NewPhone(); np.call("lina");//自己没有call方法,但是继承的对象里面有
//子类:a_7_1_2NewPhone //父类:a_7_1_1Phone //方法重写:子类里出现跟父类一样的方法,比如这里示例的call方法
//子类重写了父类的方法后,就可以加入自己特有的内容,并且能够使用父类的功能
//在子类重写方法时,建议直接把父类的那部分方法复制过来,因为自己写会不小心报错 //还可以在这个重写方法的上面一行添加@Override,如果这个@Override报错就说明自己写的重写方法出错了 }}
方法重写的注意事项
方法重写注意事项 1、父类的私有方法不能被子类重写 2、子类方法访问权限(访问权限修饰符)不能比父类低,常见的访问修饰符的访问权限大小比较(public>默认>private)
方法重写注意事项的练习
package ch6;
public class a_8_1Fu {
private void show(){ System.out.println("Fu中show()方法被调用"); }
//public修饰符的访问权限比private高
/*public void method(){ System.out.println("Fu中method()方法被调用"); }*/ void method(){//删掉这里父类的访问修饰符 System.out.println("Fu中method()方法被调用"); }
}package ch6;
public class a_8_2Zi extends a_8_1Fu {
//下面的重写方法会报错,因为子类不可以重写父类中被private修饰的方法,那是父类的私有内容,子类无法继承 /*private void show(){//重写父类的show方法 System.out.println("Zi中show()方法被调用"); }*/
//下面的重写方法,@Override没有报错,所以是重写正确的 /*public void method(){ System.out.println("Zi中method()方法被调用"); }*/
//如果不写访问修饰符public或private //系统会给一个默认访问修饰符,但是这个默认访问修饰符的访问权限没有public大 void method(){ System.out.println("Fu中method()方法被调用"); } //上面会报错,因为父类的method方法被public修饰了,这里的系统默认修饰符访问权限低,就无法访问父类的method方法 //如果想不报错的话,就把父类的访问修饰符public删掉}
继承的注意事项
1、java中类只支持单继承,不支持多继承 2、java中类支持多层继承(间接实现多继承)
继承注意事项的练习
xxxxxxxxxxpackage ch6;//让这个Father类继承Grandfather类public class a_9_1Father extends a_9_2Grandfather{
public void smoke(){ System.out.println("father爱抽烟"); }}xxxxxxxxxxpackage ch6;
public class a_9_2Grandfather {
public void drink(){ System.out.println("grandfather爱喝酒"); }}xxxxxxxxxxpackage ch6;
public class a_9_3Monther {
public void dance(){ System.out.println("mon爱跳舞"); }}xxxxxxxxxxpackage ch6;//让这个Son类继承Father类。注意,在java中类不能同时继承多个类,只能继承一个类//如果想要这个Son继承多个类,可以通类传递的方式,//即这里的Son继承Father,在Father类里面继承Grandfather,就间接达到了Son同时继承Father和Grandfather的效果//上面的类传递方式就是java中的多层继承public class a_9_4Son extends a_9_1Father{
}
【以下是两个综合练习案例】
老师和学生案例
需求:定义老师类和学生类,然后写代码测试,最后找到老师类和学生类当中的共性内容,抽取出一个父类,用继承的方式改写代码,并进行测试
思路: 1、定义老师类,包括姓名,年龄,教书() 2、定义学生类,包括姓名,年龄,学习() 3、定义测试类,写代码测试
实现如下
xxxxxxxxxxpackage ch6;
public class a_10_1Student {
//成员变量 private String name; private int age;
//无参构造方法 public a_10_1Student() {
}
//带参构造方法 public a_10_1Student(String name,int age) { this.name = name; this.age = age; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public void study() { System.out.println("我是study方法"); }}xxxxxxxxxxpackage ch6;
public class a_10_2Teacher {
private String name; private int age;
public a_10_2Teacher() { }
public a_10_2Teacher(String name,int age){ this.name = name; this.age = age; }
public String getName(){ return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public void teach() { System.out.println("我是ch6包里面的teach方法"); }}xxxxxxxxxxpackage ch6;
public class a_10_3测试 {
public static void main(String[] args) { //创建老师类对象进行测试 //通过无参构造方法创建对象 a_10_2Teacher t1 = new a_10_2Teacher(); t1.setName("张三-无参"); t1.setAge(21); System.out.println(t1.getName() + "," + t1.getAge()); t1.teach();
//通过带参构造方法创建对象 a_10_2Teacher t2 = new a_10_2Teacher("李四-带参", 22); System.out.println(t2.getName() + "," + t2.getAge()); t2.teach(); }}
猫和狗案例
需求: 采用继承的思想实现猫和狗的案例,并测试
xxxxxxxxxx猫:成员变量: 姓名,年龄构造方法: 无参,带参成员方法: get/set方法,抓老鼠()狗:成员变量: 姓名,年龄构造方法: 无参,带参成员方法: get/set方法,看门()共性:成员变量: 姓名,年龄构造方法: 无参,带参成员方法: get/set方法*/
x1、定义动物类成员变量: 姓名,年龄构造方法: 无参,带参成员方法: get/set方法2、定义猫类构造方法: 无参,带参成员方法: 抓老鼠()3、定义狗类构造方法: 无参,带参成员方法: 看门()4、定义测试类,并测试
实现如下
xxxxxxxxxxpackage ch6;
public class a_11_1动物类 {
private String name; private int age;
//无参构造方法 public a_11_1动物类() { }
//带参构造方法 public a_11_1动物类(String name, int age) { this.name = name; this.age = age; }
//get和set方法 public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; }}xxxxxxxxxxpackage ch6;
//继承动物类public class a_11_2Cat extends a_11_1动物类 {
//无参构造方法 public a_11_2Cat() { }
//带参构造方法 public a_11_2Cat(String name, int age) { super(name, age); }
//特有方法 public void catchMouse() { System.out.println("抓老鼠"); }}xxxxxxxxxxpackage ch6;
//继承动物类public class a_11_3Dog extends a_11_1动物类 {
//无参构造方法 public a_11_3Dog() { }
//带参构造方法 public a_11_3Dog(String name, int age) { super(name, age); }
//特有方法 public void lookDoor() { System.out.println("看门"); }}xxxxxxxxxxpackage ch6;
public class a_11_4测试 {
public static void main(String[] args) {
//创建猫类对象并测试 //无参 a_11_2Cat c1 = new a_11_2Cat(); c1.setName("加菲猫"); c1.setAge(2); System.out.println(c1.getName() + "," + c1.getAge()); c1.catchMouse();
//创建猫类对象并测试 //带参 a_11_2Cat c2 = new a_11_2Cat("加菲猫2", 3); System.out.println(c2.getName() + "," + c2.getAge()); c2.catchMouse();
System.out.println("-------------");
//创建狗类对象并测试 //无参 a_11_3Dog c3 = new a_11_3Dog(); c3.setName("田园犬"); c3.setAge(1); System.out.println(c3.getName() + "," + c3.getAge()); c3.lookDoor();
//创建猫类对象并测试 //带参 a_11_3Dog c4 = new a_11_3Dog("田园犬", 2); System.out.println(c4.getName() + "," + c4.getAge()); c4.lookDoor(); }}