欢迎各位点赞👍评论✍收藏⭐
目录
1. 继承
1.1 继承的原因
Java 是一种纯面向对象的编程语言,当我们用类来描述多个实体时,那么可能有几个类之间会存在一些关系,那么在设计时就需要考虑一下
比如:学生 和 工人
我们用 Java 语言来描述
//学生类
public class Student {
String name; //姓名
int age; //年龄
float weight; //体重
public void sleep() {
System.out.println("睡觉......");
}
//学生的工作
public void study() {
System.out.println("在教室学习......");
}
}
//工人类
public class Worker {
String name; //姓名
int age; //年龄
float weight; //体重
public void sleep() {
System.out.println("睡觉......");
}
//工人的工作
public void work() {
System.out.println("在工地工作......");
}
}
虽然,学生和工人的类定义出来了,但是他们类中有很多重复代码
我们想一想,如果把这些相同的共性提取出来,就可以实现代码的复用
1.2 继承的概念
一句话:继承是使代码具有复用性的手段,允许了在原有类的基础上进行扩展,添加新内容
继承好处:提取了共性,实现代码复用,那么我们可以在建一个类用来存放这些共性,就不必重复的写代码,只是需要时调用即可
1.3 继承的语法
Java 中用关键字 extends 来表示继承关系
修饰符 class 子类 extends 父类 {
......
}
上述代码进行优化
//父类
public class People {
String name; //姓名
int age; //年龄
float weight; //体重
public void sleep() {
System.out.println("睡觉......");
}
}
//子类---学生
public class Student extends People { //继承
public void study() {
System.out.println("在教室学习......");
}
}
//子类---工人
public class Worker extends People { //继承
public void work() {
System.out.println("在工地工作......");
}
}
- 子类会将父类中成员变量和方法都继承到子类中
- 继承后,子类必须有新的变量或方法,否则就没有继承的必要了
2. 子类访问父类
在继承好了之后,子类就可以访问父类各种成员了
2.1 子类访问父类成员变量
2.1.1 子类与父类不存在同名成员变量
//父类
public class TestClassFather {
int a; //父类变量
int b;
}
//子类
public class Son extends TestClassFather {
int c; //子类变量
public void Fun() { //直接使用即可
a = 100;
b = 200;
c = 300;
}
}
2.1.2 子类与父类存在同名成员变量
//父类
public class TestClassFather {
//父类变量
int a;
int b;
}
//子类
public class Son extends TestClassFather {
//子类变量
int b; //与子类相同
int c;
public void Fun() { //直接使用即可
a = 100;
b = 200; //优先访问自己的变量
c = 300;
}
}
注意事项
- 子类与父类存在同名成员变量时,优先访问自己的
- 访问的成员,子类没有,那就访问父类的,如果都没有,则报错
2.2 子类访问父类成员方法
//父类
public class TestClassFather {
int a;
int b;
public void Fun() {
System.out.println("哈哈");
}
}
//子类
public class Son extends TestClassFather {
int c;
public void method() {
Fun(); //直接访问即可
}
}
2.2.1 子类和父类成员方法同名
//父类
public class TestClassFather {
int a;
int b;
public void Fun() {
System.out.println("哈哈");
}
public void Fun(int a) {
System.out.println("哈哈");
}
}
//子类
class Son extends TestClassFather {
int c;
public void Fun() {
System.out.println("呵呵");
}
public void method() {
Fun(); //访问子类
Fun(10); //访问父类
}
}
- 同名时,优先在子类中寻找,子类没有,在去父类中寻找
- 也可根据方法的参数进行寻找,如果都没有,则报错
3. super 关键字
在编程中,可能会遇到,当子类和父类的成员变量或方法同名时,又想访问父类成员,该怎么做呢?这时,Java 提供了 super 关键字,用来在子类中访问父类的成员
//父类
public class TestClassFather {
int a = 10;
public void Fun() {
System.out.println("父类:Fun()");
}
}
//子类
class Son extends TestClassFather {
int a = 20;
public void Fun() {
System.out.println("子类:Fun()");
}
public void pirnt() {
System.out.println(a); //子类
System.out.println(super.a); //父类
Fun(); //子类
super.Fun(); //父类
}
}
运行结果:
这就是 super 的用法
3.1 子类的构造方法
俗话说,父子父子,先有父,在有子
在执行子类构造方法时,需要先执行父类的构造方法,然后在执行子类的构造方法
public class A {
public A() {
System.out.println("父类构造方法......");
}
}
class B extends A {
public B() {
System.out.println("子类构造方法......");
}
public static void main(String[] args) {
B b = new B();
}
}
运行结果:
- 若父类中无构造方法,编译器会自动添加一个无参构造方法,若果有,则不加
- 若父类定义无参或默认的构造方法,在子类构造方法中第一行,编译器会默认调用 super()
- 若父类定义有参数的构造方法,则要为子类也要显示定义构造方法,否则失败
- super 调用父类时,必须在第一行,否则报错
- super 只能在子类中出现一次,不能和 this 同时出现
3.2 super 和 this 的异同
学了 super 和 this 关键字,那他们有什么区别呢?
相同点
- 都是 Java 的关键字
- 都不能在静态方法中使用
- 在构造方法中使用时,都只能在第一行,且不能同时存在
不同点
- this 用于本类中的方法和属性的引用,而 super 用于访问父类继承下来的方法和属性、
- 调用构造方法时,this 用于调用本类的构造方法,super 用于调用父类的构造方法
- 构造方法中一定会存在 super 的调用,不写编译器自动调用,this 不写就没有
3.3 代码的执行顺序
先看下面代码,思考一下运行结果是什么?为什么?
public class A {
static {
System.out.println("父类静态代码块......");
}
{
System.out.println("父类实例代码块......");
}
public A() {
System.out.println("父类构造方法......");
}
}
class B extends A {
static {
System.out.println("子类静态代码块......");
}
{
System.out.println("子类实例代码块......");
}
public B() {
System.out.println("子类构造方法......");
}
public static void main(String[] args) {
B b = new B();
System.out.println("===========");
B b1 = new B();
}
}
运行结果
通过结果分析,总结顺序规律:
- 父类的静态代码块优先于子类的静态代码块
- 父类的实例代码块和构造代码块接着执行
- 子类的实例代码块和构造代码块接着执行
- 第二次在实例化时,父类和子类的静态代码块不在运行,他们只执行一次
4. 继承方式
Java 中的类只能单继承,不支持多继承,如果想从语法上限制继承,我们可以用 final 关键字来修饰
4.1 final 关键字
final 可以修饰 成员、类、方法
4.1.1 final 修饰成员
被 final 修饰的成员,成员的值不可以被修改
final int a = 10; //不可以被修改
4.1.2 final 修饰方法
被 final 修饰的方法,方法不可以被重写
public final void study() { //不可以被重写
System.out.println("在教室学习......");
}
4.1.3 final 修饰类
被 final 修饰的类,类不可以继承
public final class A {
......
}
5. 多态
5.1 多态的概念
多态就是多种形态,对于某个行为,不同对象去完成会产生不同的状态
一句话:同一种方法,不同对象对应的结果不同
5.2 实现多态条件
- 必须在继承条件下进行
- 存在子类向父类的向上转型
- 子类必须要对父类的方法进行重写
- 通过父类调用重写的方法
5.3 向上转型和向下转型
5.3.1 向上转型
子类对象当作父类对象使用
语法格式
父类类型 对象名 = new 子类类型( );
People people = new Student(); //子类对象当作父类对象
向上转型时通常有三种情况
5.3.1.1 直接赋值
People people = new Student(); //直接赋值
5.3.1.1 方法传参
public class Test {
public static void Fun(People people) { //发生了向上转型
people.work();
}
public static void main(String[] args) {
Student student = new Student();
Fun(student ); //方法传参时出现了向上转型
}
}
5.3.1.1 方法返回
//方法返回时发生了向上转型
public static People Fun(Student student) {
return student;
}
5.3.2 向下转型
向下转型和向上转型相反,父类对象强转为子类对象使用
语法格式
子类类型 对象名 =(子类类型) new 父类类型( );
//强制类型转换
Student student = (Student) new people();
该转型用的较少,且不安全
5.4. 方法的重写
重写:也称为覆盖,是子类对于父类的方法进行重写编写,返回值、形参都不能改变
//父类
public class People {
String name;
int age;
float weight;
public People(String name, int age) {
this.name = name;
this.age = age;
}
public void work() {
System.out.println(name+" 在工作......");
}
}
//子类
public class Worker extends People {
public Worker(String name, int age) {
super(name, age);
}
//对父类中的方法进行了重写
public void work() {
System.out.println(name+" 在工地工作......");
}
}
重写的规则
- 子类重写父类方法时,返回值和形参必须都一致
- 重写的方法的返回值可以不同,但前提必须有父子关系
- 子类方法的访问限制符的范围必须大于等于父类的访问限制符
- 父类方法被 static 或 private 修饰,则不能重写
前面学习了重载,那他们俩区别是?
5.5 实现多态性
//父类
public class People {
String name;
int age;
float weight;
public People(String name, int age) {
this.name = name;
this.age = age;
}
public void work() {
System.out.println(name+" 在工作......");
}
}
//子类---学生
public class Student extends People {
public Student(String name, int age) {
super(name, age);
}
//对父类重写
public void work() {
System.out.println(name+" 在教室学习......");
}
}
//子类---工人
public class Worker extends People {
public Worker(String name, int age) {
super(name, age);
}
//对父类重写
public void work() {
System.out.println(name+" 在工地工作......");
}
}
//多态性的实现
public class Test {
public static void Fun(People people) { //传参进行向上转型
people.work();
}
public static void main(String[] args) {
People people1 = new Student("张三",20);
People people2 = new Worker("工人",30);
Fun(people1);
Fun(people2);
}
}
这就是多态性,对于同一个方法 Fun ( ) ,当我们传入不同对象时,它处理的结果不同,多态性级体现出来了
5.6 多态的优缺点
优点
- 降低了代码的圈复杂度,避免了大量的 if-else
- 使代码的可扩展性增强
缺点
- 代码运行效率降低
6. 小结
以上就是对继承和多态的了解,具体还需宝子们去实践,如果觉得该博客对你有用的话,希望一键三连,点个关注不迷路,谢谢支持 !