只有秃头才能变强
继承
- 多个类中存在相同属性和行为时,将这些相同的属性和内容都单独放在一个类中,那么多个类就无需定义这些属性和方法,直接继承该类
- 格式:class 子类名 extends 父类名(超类)
-定义一个类后我们可以在一个已经存在的类的基础上,继承其属性和范围,同时也可以定义新的属性和范围
package Demo1;
//使用继承后,猫和狗都属于动物类,都要吃和叫
//所以建立一个动物类
class Animals{
public void eat() {
System.out.println("吃");
}
public void barking() {
System.out.println("叫");
}
}
//猫和狗都继承动物类
class Cat extends Animals{}
class Dog extends Animals{}
public class ExtendsDemo {
public static void main(String[] args) {
//创建一只小狗,并调用eat和barking方法
Dog dog=new Dog();
dog.eat();
dog.barking();
//创建一只小猫,并调用eat和barking方法
Cat cat=new Cat();
cat.eat();
cat.barking();
}
}
复制代码
运行结果
吃
叫
吃
叫
使用继承的优点:
- 提高了代码的复用性:多个类相同的成员可以放到一个类中
- 提高了代码的维护性:若代码需要修改,则修改一处即可
- 让类与类之间产生关系,是多态的前提
弊端
- 类的耦合性很强
设计原则:高内聚低耦合,内聚就是自己完成某件事的能力,耦合是类与类之间的关系。我们在设计的时候原则是这样的:自己能完成的事情就不麻烦别人,如果将来对方需要修改时,对于我们的影响比较小。
Java中继承的特点
- Java只支持单继承,不支持多继承:一个类只能有一个父类,不可以有多个父类,就好比我们每个人只有一个父亲。
- Java支持多层继承
class A{}
class B extends A{}
class C extends B{}
//Java只支持单继承,不支持多继承
class Father{}
class Mother{}
//正确的写法
class Son extends Father{}
//错误的写法
class Son extends Father and Mother{}
复制代码
package Demo1;
//Java支持多重继承
class GrandFather {
public void say() {
System.out.println("我是你爷爷");
}
}
class Father extends GrandFather {
public void show() {
System.out.println("我是你爸爸");
}
}
class Son extends Father {
}
public class ExtendsDemo {
public static void main(String[] args) {
// 创建一个儿子对象
Son son = new Son();
// 调用父亲的方法
son.show();
// 调用爷爷的方法
son.say();
}
}
复制代码
运行结果:
我是你爸爸
我是你爷爷
注意事项
- 子类只能继承父类的非私有成员(成员方法和成员变量),体现了继承的另一个弊端,封装性。
- 子类不能继承父类的构造方法,可以通过super关键字去访问父类的构造方法。
- 当满足 is a的关系时可以考虑使用继承,如猫是动物的一种,树是植物的一种
示例
package Demo1;
class Father {
private int num = 10;
public int num1 = 20;
// 私有方法,子类不能继承
private void show() {
// num可以在父类中访问
System.out.println(num);
System.out.println(num1);
}
public void say() {
System.out.println(num);
System.out.println(num1);
}
}
class Son extends Father {
public void funtion() {
// 子类不能继承父类的私有成员
// System.out.println(num);
System.out.println(num1);
}
}
public class ExtendsDemo {
public static void main(String[] args) {
// 创建对象
Son son = new Son();
// s.show(),子类不能继承父类的私有成员方法
son.say();
son.funtion();
}
}
复制代码
输出结果
10
20
20
继承中成员变量的关系,当子类中成员变量与父类中的成员变量名称一样时,在子类方法中访问一个变量的查找顺序:
- 在子类方法的局部范围找,有就使用
- 在子类的成员范围找,有就使用
- 在父类的成员范围找,有就使用
- 如果都没有找到,则报错
super关键字
- super的用法和this的用法很像,super代表父类引用,可以操作父类的成员。this代表本类对应的引用。
- 访问成员变量: this.成员变量:调用本类的成员变量,super.成员变量:调用父类的成员变量。
- 访问构造方法:this(…)调用本类的构造方法,super(…)调用父类的构造方法
- 访问成员方法:this.成员方法()调用本类的成员方法,super.成员方法()调用父类的构造方法
继承中构造方法的关系
- 子类的所有的构造方法都默认访问父类中空参数的构造方法,子类会继承父类中的数据,所以在子类初始化之前,一定要先完成父类数据的初始化
- 注意:子类的每一个构造方法第一条默认都是:super()。
package Demo1;
class Father {
public Father() {
System.out.println("Father的无参构造");
}
public Father(String name) {
System.out.println("Father的有参构造");
}
}
class Son extends Father {
public Son() {
//super(),子类的每个构造方法第一条语句默认super()
System.out.println("son的无参构造");
}
public Son(String name) {
//super()
System.out.println("son的有参构造");
}
}
public class ExtendsDemo {
public static void main(String[] args) {
// 创建对象
Son son = new Son();
System.out.println("***************");
Son son2=new Son("tom");
}
}
复制代码
输出结果
Father的无参构造
son的无参构造
Father的无参构造
son的有参构造
从运行结果可以看出,每次创建一个子类对象都会访问父类的无参构造方法,当父类中没有无参构造方法时,项目会报错,解决方法:
- 在父类中添加一个无参的构造方法
- 通过使用super关键字显示地调用父类的带参构造方法
- 子类通过this去调用本类的其他构造方法
- 子类中一定要有一个访问父类的构造方法,否则父类数据就没有初始化
- 注意事项:
- this(…)或者super(…)必须出现在语句的第一条,如果不放在语句的第一条,那么就有可能对父类数据进行多次初始化,所以必须放在第一条语句上
package Demo1;
class Father {
/*
* public Father() { System.out.println("Father的无参构造"); }
*/
public Father(String name) {
System.out.println("Father的有参构造");
}
}
class Son extends Father {
public Son() {
super("John");
System.out.println("son的无参构造");
// super("John");
}
public Son(String name) {
// super("Jimmy");
this();
System.out.println("son的有参构造");
}
}
public class ExtendsDemo {
public static void main(String[] args) {
// 创建对象
Son son = new Son();
System.out.println("***************");
Son son2 = new Son("tom");
}
}
复制代码
输出结果
Father的有参构造
son的无参构造
Father的有参构造
son的无参构造
son的有参构造
继承中成员方法的关系
- 若子类中的成员方法与父类中的成员方法一样,通过子类调用对象的顺序为:先找子类中有没有这个方法,有就使用,没有就在父类中找,有就使用,再没有则报错
方法的重写与重载
- 方法的重写:子类中出现与父类中一模一样的方法声明,也被称为方法覆盖,方法重写
- 方法的重载:本类中出现的方法名一样,参数列表不一样的方法,与放回值没有关系
- 使用特点:如果方法名不一样,就调用对应的方法,如果方法名相同,则使用的是子类的方法
- 方法重写的应用:当子类需要父类的功能时,而该父类的功能主体中又有子类自己的内容,此时子类既可以重写父类的方法,又定义了子类特有的内容。
- 注意事项:
- 父类中的私有方法不能被重写,因为父类中的私有方法子类根本无法继承
- 子类重写父类方法时,访问权限不能更低,最好一致,假设一个父类A拥有的方法为public void set(){},可以被其他任意对象调用,这个方法被子类B覆盖后写为protected void set(){}即默认为protected的访问权限,只能被本包及其子类所访问,假设其他包中的对象C调用方法为get(A a){a.set()},而此时传入的对象为B类对象,假设B此时转型为A,但是B此时set()调用权限已经缩小了将造成错误,所以子类对象的访问修饰要比父类的访问修饰要大。
package Demo1;
class Laptop extends Pc{
public void Read(String name) {
super.Read(name);
System.out.println("我可以看视频");
}
}
class Pc{
public void Read(String name) {
System.out.println("我可以看小说");
}
}
public class ExtendsDemo1 {
public static void main(String[] args) {
//创建对象
Laptop lt=new Laptop();
lt.Read("哈利波特");
}
}
复制代码
输出结果:
我可以看小说
我可以看视频
方法重写(override)与重载的区别(overload)
- 方法重写:在子类中,出现和父类一模一样的方法声明
- 方法重载:在同一个类中,出现的方法名相同,参数列表不同的现象
- 方法重载可以改变返回值类型,重写则不行
浑浑噩噩一天又过去了