🥰🥰🥰来都来了,不妨点个关注叭!
👉博客主页:欢迎各位大佬!👈
文章目录
- 1. 继承
- 1.1 继承是什么
- 1.2 继承的意义
- 1.3 继承的语法
- 1.4 继承的方式
- 1.5 子类中访问父类成员
- 1.5.1 子类中访问父类成员变量
- 1.5.2 子类中访问父类成员方法
- 1.6 super关键字
- 1.7 子类构造方法
- 2. super与this关键字
- 3. final 关键字
- 3.1 修饰变量或字段
- 3.2 修饰类
- 3.3 修饰方法
1. 继承
面向对象三大特性:封装、继承、多态
今天我们一起来看看继承这一特性~~~
1.1 继承是什么
Java中使用类对现实世界中实体来进行描述,类实例化后的对象来表示现实中的实体,but现实世界错综复杂,事物之间可能会存在一些关联,对于这些有关联的事物,我们需要合理地设计程序。
比如:狗和猫,它们都是动物,我们可以用Java来描述狗和猫的属性和方法,如下:
public class Dog {int legNumber;String name;String gender;int age;float weight;void eat() {System.out.println(name+"在吃饭");}void sleep() {System.out.println(name+"在睡觉");}void bark() {System.out.println(name+"汪汪叫");}
}public class Cat {int legNumber;String name;String gender;int age;float weight;void eat() {System.out.println(name+"在吃饭");}void sleep() {System.out.println(name+"在睡觉");}void meow() {System.out.println(name+"喵喵叫");}
}
从上述代码中,我们直观清晰看到,狗和猫类中存在大量重复,它们的属性都有腿的数量、名字、性别、年龄、体重和吃饭这个行为,它们的叫声不同。显然,这个代码存在大量重复,是不合理的。
解决办法:面向对象思想中提出了继承的概念,专门用来进行共性抽取,实现代码复用
【继承】
继承是面向对象最显著的一个特性,继承是从已有的类(父类)中派生出新的类(子类),新的类能吸收已有类的数据属性和行为,并能扩展新的能力。
在上述狗和猫的场景中,我们将狗和猫的共性抽取,它们都是动物,很多属性都有共性,我们将这些共性抽取出来,而狗和猫又各自有属于自己的属性,利用继承的思想达到代码共用的思想,动物类则是父类,狗和猫是子类,子类可以复用父类中成员,子类在实现时只需关心自己新增加的成员
1.2 继承的意义
继承有什么意义呢?
【继承的意义】在于对共性抽取,实现代码复用,是多态性的基础,子类能够更灵活地适应不同的需求,提高代码的通用性和可扩展性,并层次化分类,使程序结构更易于管理。
1.3 继承的语法
在Java中,表示类之间的继承关系,需借助extends关键字,具体语法如下:
class 父类名称 {
// 父类的属性和方法
}
修饰符 class 子类名称 extends 父类名称 {
// 子类特有的属性和方法
// 子类可以覆盖父类的方法
}
通过上述的分析,使用继承的思想重新设计,各部分代码如下:
public class Animal {int legNumber;String name;String gender;int age;float weight;void eat() {System.out.println(name+"在吃饭");}void sleep() {System.out.println(name+"在睡觉");}
}
public class Dog extends Animal{void bark() {System.out.println(name+"汪汪叫");}
}
public class Cat extends Animal {void meow() {System.out.println(name+"喵喵叫");}
}
public class Test {public static void main(String[] args) {Dog dog = new Dog();Cat cat = new Cat();dog.name = "球球";cat.name = "毛毛";dog.bark();cat.meow();}
}
【注意事项】
1)一个.java文件写一个类,如下写法:
2)Dog类和Cat并没有定义成员变量,name是从父类Animal继承过来的,eat()和sleep()方法也是继承来的,即子类会将父类中的成员变量或者成员方法继承到子类中
3) 子类继承父类后,必须要新添加自己特有的成员,体现出与基类的不同,否则就没有必要继承,完全可以直接用父类呀~所以,必须要新添加自己特有的成员
1.4 继承的方式
在现实世界中,事物之间的关系是十分复杂的~那Java支持哪些继承方式呢!
Java支持单继承、多层继承、不同类继承同一类
不支持多继承(一个子类继承多个父类,不支持)!!!
Java中不支持多继承
尽管在写代码时候,我们可能会碰到类之间有非常复杂的关系,但是仍然不希望类之间的继承关系超过三层, 继承层次太多, 需要考虑对代码进行重构
如果想从语法上进行限制继承,使用 final 关键字修饰类,表示该类不可以被继承
1.5 子类中访问父类成员
1.5.1 子类中访问父类成员变量
【子类和父类不存在同名成员变量】
public class Parent {String a;String b;
}
public class Child extends Parent{String c;public void method() {a = "我是父类的a";b = "我是父类的b";c = "我是子类特有的c";System.out.println(a);System.out.println(b);System.out.println(c);}
}
public class Test {public static void main(String[] args) {Child child = new Child();child.method();}
}
运行结果如图:
解释:子类中没有a和b变量,a、b访问从父类Parent类继承下来的a、b,子类中有变量c,c是访问子类自己的c
【子类和父类存在同名成员变量】
public class Parent {String a;String b;String c;
}
public class Child extends Parent{String a;char b;public void method() {a = "我是子类Child类中的a";b = 'b';c = "我是父类Parent类中的c";System.out.println(a);System.out.println(b);System.out.println(c);}
}
public class Test {public static void main(String[] args) {Child child = new Child();child.method();}
}
运行结果如图:
解释:子类中有变量a则访问的是自己的a,而变量b在父类与子类中均有,类型不同,可以看到,优先访问的是子类中的变量b,子类中没有变量c则访问从父类继承下来的c
【总结】
通过子类对象或者在子类方法中访问成员时,以下3种情况:
(1) 访问的成员变量子类中有,优先访问自己的成员变量
(2) 访问的成员变量子类中无,则访问父类继承下来的,如果父类也没有定义,则编译报错
(3) 访问的成员变量与父类中成员变量同名,则优先访问自己的
即成员变量访问遵循就近原则,自己有则优先访问自己的,否则在父类中寻找
1.5.2 子类中访问父类成员方法
【子类和父类不存在同名成员方法】
public class Parent {public void methodA() {System.out.print("父类Parent类中的methodA()方法!");}
}
public class Child extends Parent{public void methodB() {System.out.print("子类Child类中的methodB()方法!");}public void methodC() {methodA();methodB();}
}
public class Test {public static void main(String[] args) {Child child = new Child();child.methodC();}
}
运行结果如图:
解释:子类中没有methodA()方法,子类访问父类Parent类继承下来的methodA()方法,methodB()方法是访问子类自己的methodB()方法
【子类和父类存在同名成员方法】
public class Child extends Parent{public void methodA(int a) {System.out.println("Child子类中的methodA(int)方法");}public void methodB() {System.out.println("子类Child类中的methodB()方法!");}public void methodC() {methodA();methodA(12);methodB();}
}
public class Parent {public void methodA() {System.out.println("父类Parent类中的methodA()方法!");}public void methodB() {System.out.println("父类Parent类中的methodB()方法!");}
}
public class Test {public static void main(String[] args) {Child child = new Child();child.methodC();}
}
运行结果如图:
解释:子类中的methodA()和父类中的methodA()构成重载,根据调用方法,调用哪个就是哪个,methodA()未传参,调用父类的,methodA(12)传参了,调用子类Child的methodA(12)方法。methodB同名,调用子类自己的methodB()方法
【总结】
(1) 子类对象访问父类与子类中不同名方法时,优先在子类中找,找到则访问,否则在父类中找,找到则访问父类的,否则编译报错
(2) 子类对象访问父类与子类同名方法时,如果父类和子类同名方法的参数列表不同(重载),根据调用方法适传递的参数选择合适的方法访问,如果参数列表一致,优先在子类中找访问自己的
即成员方法访问遵循就近原则,自己有则优先访问自己的,否则在父类中寻找,如果方法重载,根据调用方法选择一致的
1.6 super关键字
我们知道,如果子类自己有变量c,那么优先访问子类的c,如果我想访问父类的c,该如何做捏!
此时super关键字,闪亮登场!!!
Java提供super关键字,该关键字主要作用就是在子类方法中访问父类的成员!
public class Parent {String a = "我是父类Parent类中的a";String b = "我是父类Parent类中的b";String c;public void methodA() {System.out.println("我是父类Parent类中的methodA()");}
}
public class Child extends Parent{String a = "我是子类Child类中的a";char b;public void methodA() {System.out.println("我是子类Child类中的methodA()");}public void method() {System.out.println(a);//a相当于this.aSystem.out.println(super.a);methodA();//methodA()相当于this.methodA()super.methodA();}
}
public class Test {public static void main(String[] args) {Child child = new Child();child.method();}
}
运行结果如下:
优先访问子类中的成员,无法访问到父类中的成员,通过关键字super可以访问到父类的成员变量和方法
【注意事项】
(1) 只能在非静态方法中使用
(2) 在子类方法中,访问父类的成员变量和方法。
1.7 子类构造方法
父子,即先有父再有子,在子类构造方法内,必须先帮助父类构造
在子类构造方法中,虽然并没有写任何关于父类的构造的代码,通过代码运行结果得知,在构造子类对象时,先执行父类的构造方法,后执行子类的构造方法
public class Parent {public Parent() {System.out.println("父类Parent构造方法");}
}
public class Child extends Parent{public Child() {
//super(); 被隐藏了
//子类构造方法中默认会调用父类的无参构造方法super()
//没有写时,编译器会自动添加,且super()必须是子类构造方法中第一条语句,
//且只能出现一次System.out.println("子类Child构造方法");}
}
public class Test {public static void main(String[] args) {Child child = new Child();}
}
运行结果如下:
【原因】子类对象中成员由两部分组成,父类继承下来的+子类新增加的部分,先有父再有子,所以在构造子类对象时候 ,先要调用父类的构造方法,将从父类继承下来的成员构造完整,再调用子类自己的构造方法,将子类自己新增加的成员初始化完整
【注意事项】
(1) 父类显式定义无参或者默认的构造方法,在子类构造方法第一行默认有隐含的super()调用,即调用父类构造方法
public Parent() {
}public Child() {super();
}
(2) 父类构造方法是带有参数的,此时需要为子类显式定义构造方法,并在子类构造方法中选择合适的父类构造方法调用,否则编译失败,即子类必须先帮助父类构造
public class Parent {String name;int age;public Parent(String name, int age) {this.name = name;this.age = age;}
}
public class Child extends Parent{int index;public Child(String name, int age,int index) {super(name,age); //必须先帮助父类构造且super为第一条语句,交换顺序则会报错,且super只出现一次!this.index = index;}
}
(3) 在子类构造方法中,super(…)调用父类构造时,必须是子类构造函数中第一条语句,且只能出现一次并且不能和this同时出现!!!即this和super调用构造器不能同时出现
public class Child extends Parent{int index;public Child(String name, int age,int index) {super(name,age);this("1",2,4);//将会报错!!不能同时出现}
}
2. super与this关键字
【相同点】
(1) 均为Java中的关键字
(2) 均只能在类的非静态方法中使用,用来访问非静态成员方法和变量
(3) 在构造方法中调用时,必须是构造方法中的第一条语句,并且不能同时存在
【不同点】
(1) this是当前对象的引用,当前对象即调用实例方法的对象,super是子类对象中从父类继承下来部分成
员的引用
(2) 在非静态成员方法中,this访问本类的方法和属性,super访问父类继承下来的方法和属性
(3) 在构造方法中:this(…)调用本类构造方法,super(…)调用父类构造方法,两种调用不能同时在构造方法中出现
(4) 构造方法中一定会存在super(…)的调用,用户没有写编译器也会增加,但是this(…)用户不写则没有
3. final 关键字
final关键字可以用来修饰变量、成员方法以及类
3.1 修饰变量或字段
表示该变量不能被修改(即常量)
final int a = 100;
a = 20;
//编译出错,变量a被final修饰,不能被修改
3.2 修饰类
表示该类不能被继承
final public class Animal {...
}public class Cat extends Animal{...
}
//编译出错,Animal类被final关键字修饰,表示不能被继承
3.3 修饰方法
表示该方法不能被重写
本期内容到这里结束啦~以下为本期内容回顾!
下期再见啦~