java基础进阶-day26(继承)
继承
继承的实现(掌握)
-
继承的概念
- 继承是面向对象三大特征之一,可以使得子类具有父类的属性和方法,还可以在子类中重新定义,以及追加属性和方法
-
实现继承的格式
- 继承通过extends实现
- 格式:class 子类 extends 父类 { }
- 举例:class Dog extends Animal { }
-
继承带来的好处
- 继承可以让类与类之间产生关系,子父类关系,产生子父类后,子类则可以使用父类中非私有的成员。
-
例如:
package com.itheima_01;
class Fu {
public void show() {
System.out.println("show方法被掉用");
}
}
class Zi extends Fu {
public void method() {
System.out.println("method方法被调用");
}
}
public class Demo {
public static void main(String[] args) {
Fu f = new Fu();
f.show();
Zi zi = new Zi();
zi.method();
zi.show();
}
}
继承的好处和弊端(理解)
- 继承的好处
- 提高了代码的复用性(多个类相同的成员可以放到同一个类中)
- 提高了代码的维护性(如果方法的代码需要修改,修改一处即可)
- 继承的弊端
-继承让类与类之间产生了关系,类的耦合性增强了,当父类发生变化时,子类实现也不得不跟着变化,削弱了子类的独立性。 - 继承的应用场景:
- 使用继承,需要考虑类与类之间是否存在is…a的关系,不能盲目使用继承
- is…a的关系:谁是谁的一种,例如:老师和学生时人的一种,那人就是父类,学生和老师就是子类。
- 使用继承,需要考虑类与类之间是否存在is…a的关系,不能盲目使用继承
java中继承的特点
- java中继承的特点
1.java中类只支持单继承,不支持多继承
2.java中的类支持多层继承 - 多层继承示例代码
package com.itheima_01;
class Granddad {
public void drink() {
System.out.println("爷爷爱喝酒");
}
}
class Father extends Granddad {
public void smoke() {
System.out.println("爸爸爱吸烟");
}
}
class Monther {
public void dance() {
System.out.println("妈妈爱跳舞");
}
}
class son extends Father {
}
public class Demoo {
public static void main(String[] args) {
son s = new son();
s.drink();
s.smoke();
}
}
继承中的成员访问特点
继承中变量的访问特点(掌握)
在子类方法中访问一个变量,采用的是就近原则。
- 子类局部范围找
- 子类成员范围找
- 父类成员范围找
- 如果没有就报错
- 示例代码
package com.itheima_01;
class Fu {
int num = 10;
}
class Zi {
int num = 20;
public void show() {
int num = 30;
System.out.println(num);
}
}
public class Demo01 {
public static void main(String[] args) {
Zi zi = new Zi();
zi.show();
}
}
super(掌握)
- this&super关键字:
- this:代表本类对象的引用
- super:代表父类存储空间的标识(可以理解为父类对象的引用)
- this和super的使用分别
- 成员变量:
- this.成员变量:访问本类成员变量
- super.成员变量:访问父类成员变量
- 成员方法:
- this.成员方法“访问本类成员方法
- super.成员方法:访问父类成员方法
- 成员变量:
- 构造方法:
- this(…):访问本类构造方法
- super(…):访问父类构造方法
继承中构造方法的访问特点(理解)
注意:子类中所有的构造方法默认都会访问父类中无参的构造方法
子类会继承父类中的数据,可能还会使用父类的数据。所以,子类初始化之前,一定要先完成父类数据的初始化,原因在于,每一个子类构造方法的第一天语句默认都是:super()
问题:如果父类中没有无参构造方法,只有带参构造方法,该怎么办呢?
- 通过使用super关键字去显示的调用父类的带参构造方法
- 子类通过this去调用本类的其他构造方法,本类其他构造方法再通过super去手动调用父类的带参构造方法。
注意:this(…)super(…)必须放在构造方法的第一行有效语句,并且二者不能共存。
继承中成员方法的访问特点
通过子类对象访问一个方法
- 子类成员范围找
- 父类成员范围找
- 如果都没有就报错(不考虑父亲的父亲)
super内存图
- 对象再堆内存中,会单独存在一块super区域,用来存放父类数据。
方法重写
-
方法重写概念
- 子类出现了和父类中一模一样的方法声明(方法名一样,参数列表也必须一样)
-
方法重写的应用场景
- 当子类需要父类的功能,而功能主题子类有自己特有的内容时,可以重写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容
-
override注解
- 用来检测当前的方法,是否重写的方法,起到【校验】的作用。
方法重写的注意事项(掌握)
- 方法重写的注意事项
- 私有方法不能被重写(父类私有成员子类是不能被继承的)
- 子类方法访问权限不能更低(public>默认(default)>私有)
- 静态方法不能被重写,如果子类也有相同的方法,并不是重写父类的方法。
- 示例代码:
package com.itheima_02;
class Fu {
private void show() {
System.out.println("Fu中show方法被调用");
}
void method() {
System.out.println("Fu中的method方法被调用了");
}
}
class Zi extends Fu {
@Override
protected void method() {
System.out.println("Zi中的method方法被调用");
}
}
public class Demo01 {
public static void main(String[] args) {
Zi z = new Zi();
z.method();
}
}
抽象类
抽象类的概述(理解)
当我们再做子类共性功能的抽取时,有些方法在父类中并没有具体体现,这个时候就需要抽象类。
在java中,一个没有方法体的方法应该被定义为抽象方法,而类中如果中抽象方法,该类必须被定义为抽象类。
抽象类的特点
- 抽象类和抽象方法必须使用abstract关键字修饰
//抽象类的定义
public abstract class 类名{}
//抽象方法的定义
public abstract void eat();
- 抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类。
- 抽象类不能实例化
- 抽象类可以有构造方法
- 抽象类的子类
- 要么重写抽象类中的所用抽象方法
- 要么是抽象类
抽象类的案例(应用)
- 案例需求
- 定义猫类(Cat)和狗类(Dog)
- 猫类成员方法:eat(猫吃鱼)drink(喝水…)
- 狗类成员方法:eat(狗吃肉)drink(喝水…)
- 实现步骤
- 猫类和狗类存在共性内容,抽取出来一个动物了(Animal)
- 父类Animal中,无法将eat方法具体实现描述清楚,所以定义为抽象方法
- 抽象方法需要存活在抽象类中,将animal定义为抽象类
- 让Cat和Dog分别继承Animal,重写eat方法。
- 测试类中创建Cat和Dog对象,调用方法测试
- 代码实现
- 动物类
package com.itheima_07;
public abstract class Animal {
public void drink() {
System.out.println("喝水");
}
public Animal() {
}
public abstract void eat();
}
- 猫类
package com.itheima_07;
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
}
- 狗类
package com.itheima_07;
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗吃肉");
}
}
- 测试类
package com.itheima_07;
public class Demo {
public static void main(String[] args) {
Dog d = new Dog();
d.eat();
d.drink();
Cat c = new Cat();
c.drink();
c.eat();
}
}
模板设计模式
- 设计模式
设计模式(Design pattern)是一套被反复使用,多数人知晓的,经过分类,代码设计经验的总结
使用设计模式是为了可重用代码,让代码更容易被他人理解,保证代码可靠性,程序的重用性。 - 模板设计模式
把抽象类整体就可以看做成一个模板,模板中不能定义成抽象方法,让使用模板的类(继承抽象类的类)去重写抽象方法的实现需求。 - 模板设计模式的优势
模板已经定义了通用结构,使用者只需要关心自己需要实现的功能即可。 - 示例代码
模板类
package com.itheima_08;
public abstract class CompositionTemplate {
public final void write() {
System.out.println("<<我的爸爸>>");
body();
System.out.println("啊~这就是我的爸爸");
}
public abstract void body();
}
实现类A
package com.itheima_08;
public class Tom extends CompositionTemplate {
@Override
public void body() {
System.out.println("那是一个秋天, 风儿那么缠绵,记忆中, " +
"那天爸爸骑车接我放学回家,我的脚卡在了自行车链当中, 爸爸蹬不动,他就站起来蹬...");
}
}
实现类B
package com.itheima_08;
public class Tony extends CompositionTemplate {
@Override
public void body() {
System.out.println("我的爸爸是个好人!");
}
}
测试类
package com.itheima_08;
public class Test {
public static void main(String[] args) {
Tom t = new Tom();
t.write();
Tony tony = new Tony();
tony.write();
}
}
final(应用)
- final关键字的作用
- final代表最终的意思,可以修饰成员方法,成员变量,类
- final修饰类,方法,变量的效果
- final修饰类:该类不能被继承(不能有子类,但可以有父类)
- final修饰方法:该方法不能被重写
- final修饰变量:表明该变量是一个常量,不能再次赋值
- 变量是基本类型 ,不能改变的是值
- 变量是引用类型,不能改变的是地址值,但地址里面的内容可以改变。
代码块
代码块的概述(理解)
在Java中,使用{}括起来的代码称为代码块
代码块的分类(理解)
- 局部代码块
- 位置:方法中定义
- 作用:限定变量的生命周期,及早释放,提高内存利用率。
- 示例代码
package com.itheima_09;
public class Test {
public static void main(String[] args) {
{
int a = 10;
System.out.println(a);
}
}
}
- 构造代码块
- 位置:类中方法外定义
- 特点:每次构造方法执行时,都会执行该代码块中的代码,并且在构造方法执行前执行。
- 作用:将多个构造方法中相同的代码,抽取到构造代码块中,提高代码的复用性。
示例代码
package com.itheima_09;
public class TestDemo {
public static void main(String[] args) {
Student stu1 = new Student();
Student stu2 = new Student(10);
}
}
class Student {
{
System.out.println("好好谢谢");
}
public Student() {
System.out.println("空参构造方法");
}
public Student(int a) {
System.out.println("带参构造方法....");
}
}
- 静态代码块
- 位置:类中方法外定义
- 特点:需要通过static关键字修饰,随着类的加载而加载,并且只执行一次
- 作用:在类加载的时候做一些数据初始化的操作
- 示例代码
package com.itheima_10;
public class Test {
public static void main(String[] args) {
Person p1 = new Person();
Person p2 = new Person(10);
}
}
class Person {
static {
System.out.println("我是静态代码块,我执行了");
}
public Person() {
System.out.println("我是Person类的空参数构造方法");
}
public Person(int a) {
System.out.println("我是Person类的带参数构造方法");
}
}