【Java SE】面向对象三大特性之继承(二)

简介: 【Java SE】面向对象三大特性之继承

🐳 子类构造方法:

子类对象构造时,需要先调用基类构造方法,然后执行子类的构造方法。

1. //Car.java
2. public class Car {
3. int a;
4. int b;
5.     String name;
6. 
7. public Car(){
8.         System.out.println("基类构造方法");
9.     }
10. 
11. }
12. 
13. //BMW.java
14. public class BMW extends Car{
15. int b;
16. int c;
17. public BMW(){
18.         System.out.println("子类构造方法");
19.     }
20. 
21. 
22. }
23. 
24. //Test.java
25. public class Test {
26. public static void main(String[] args) {
27.      BMW bmw=new BMW();
28.     }
29. }

子类对象中成员是有两部分组成的,基类继承下来的以及子类新增加的部分 。父子肯定是先有父再有子,所以在构造子类对象时候 ,先要调用基类的构造方法,将从基类继承下来的成员构造完整,然后再调用子类自己的构造方法,将子类自己新增加的成员初始化完整。

注意:

1. 若父类显式定义无参或者默认的构造方法,在子类构造方法第一行默认有隐含的super()调用,即调用基类构造方法
2. 如果父类构造方法是带有参数的,此时需要用户为子类显式定义构造方法,并在子类构造方法中选择合适的父类构造方法调用,否则编译失败。
3. 在子类构造方法中,super(...)调用父类构造时,必须是子类构造函数中第一条语句。
4. super(...)只能在子类构造方法中出现一次,并且不能和this同时出现

🐳super和this的区别:

🐳 代码块在继承关系中的执行顺序:

1. //Car.java
2. public class Car {
3. int a;
4. int b;
5.     String name;
6.     {
7.         System.out.println("父类实例代码块执行");
8.     }
9. 
10. static {
11.         System.out.println("父类静态代码块执行");
12.     }
13. public Car(){
14.         System.out.println("基类构造方法执行");
15.     }
16. 
17. }
18. //BMW.java
19. public class BMW extends Car{
20. int b;
21. int c;
22.     String name;
23.     {
24.         System.out.println("子类实例代码块执行");
25.     }
26. 
27. static {
28.         System.out.println("子类静态代码块执行");
29.     }
30. public BMW(){
31.         System.out.println("子类构造方法");
32.     }
33. 
34. 
35. }
36. //Test.java
37. public class Test {
38. public static void main(String[] args) {
39.      BMW bmw=new BMW();
40.     }
41. }

当我们第二次实例化对象的时候,我们可以清楚的看到:

1. public class Test {
2. public static void main(String[] args) {
3.      BMW bmw=new BMW();
4.      System.out.println("第二次实例化子类对象:");
5.      System.out.println("==================================");
6.      BMW bmw1=new BMW();
7.     }
8. }

通过分析执行结果,得出以下结论:
1、父类静态代码块优先于子类静态代码块执行,且是最早执行
2、父类实例代码块和父类构造方法紧接着执行
3、子类的实例代码块和子类构造方法紧接着再执行
4、第二次实例化子类对象时,父类和子类的静态代码块都将不会再执行

🐳protected 关键字

在封装的那一篇开头介绍了访问控制修饰符:【Java SE】面向对象三大特性之封装

感兴趣的可以再去了解一下。

这边建立了2个不同的包:

其中一个是同一个包中的2个类,另一个类在另一个包中:

首先在同一个包中:

1. package TestDemo;
2. //A.java
3. public class A {
4. public int a;
5. private int b;
6. protected int c;
7. int d;
8. }
9. //B.java
10. package TestDemo;
11. 
12. public class B extends A{
13. 
14. public void method(){
15. 
16. super.a=20;
17. super.b=100;
18. super.c=30;
19. super.d=40;
20. 
21. 
22. }
23. 
24. }

虽然不能访问,但是也继承了父类的b成员变量。

现在是两个包中的:

1. package TestDemo;
2. //A.java
3. 
4. public class A {
5. public int a;
6. private int b;
7. protected int c;
8. int d;
9. }
10. //C.java
11. package TestDemo1;
12. 
13. import TestDemo.A;
14. 
15. public class C extends A {
16. public void method(){
17. 
18. super.a=20;
19. super.b=100; //编译报错,父类中private成员在不同包子类中不可见
20. super.c=30;// 父类中protected修饰的成员在不同包子类中可以直接访问
21. super.d=40;// 父类中默认访问权限修饰的成员在不同包子类中不能直接访问
22. 
23.     }
24. }

注意:我们在使用的时候应该尽可能的使用 比较严格的访问权限. 例如如果一个方法能用 private, 就尽量不要用 public.

🐳继承方式

继承方式有单继承,多层继承和不同类继承同一个类。

一般我们不希望出现超过三层的继承关系. 如果继承层次太多, 就需要考虑对代码进行重构了.

如果想从语法上进行限制继承, 就可以使用 final 关键字

🐳final 关键字

final关键可以用来修饰变量、成员方法以及类

1. 修饰变量或字段,表示常量(即不能修改)

2. 修饰类:表示此类不能被继承

3. 修饰方法:表示该方法不能被重写

🐳重写

当子类对象调用重写的方法时,调用的是子类的方法,而不是父类中被重写的方法。

要想调用父类中被重写的方法,则必须使用关键字 super。

1. public class Animals {
2. public void call(){
3.         System.out.println("动物叫...");
4.     }
5. }
6. 
7. 
8. public class Cat extends Animals{
9. @Override
10. public void call() {
11.         System.out.println("喵喵喵...");
12.     }
13. }
14. 
15. 
16. public class Dog extends Animals{
17. @Override
18. public void call() {
19. super.call();
20.     }
21. 
22. public static void main(String[] args) {
23. Animals dog = new Dog();
24.         dog.call();//动物叫...
25. Animals cat = new Cat();
26.         cat.call();//喵喵喵...
27.     }
28. }

🐳继承与组合

继承表示对象之间是is-a的关系,比如:狗是动物,猫是动物
组合表示对象之间是has-a的关系,比如:汽车有发动机,轮胎等等组成

1. class D{
2. 
3. }
4. class E{
5. 
6. }
7. //F由D,E构成(组合)
8. class F{
9. private D d; // 可以复用D的属性和方法
10. private E e; // 可以复用E的属性和方法
11. 
12. }

组合和继承都可以实现代码复用,应该使用继承还是组合,需要根据应用场景来选择,一般建议:能用组合尽量用组合。

相关文章
|
17天前
|
Java 关系型数据库 数据库
面向对象设计原则在Java中的实现与案例分析
【10月更文挑战第25天】本文通过Java语言的具体实现和案例分析,详细介绍了面向对象设计的五大核心原则:单一职责原则、开闭原则、里氏替换原则、接口隔离原则和依赖倒置原则。这些原则帮助开发者构建更加灵活、可维护和可扩展的系统,不仅适用于Java,也适用于其他面向对象编程语言。
12 2
|
22天前
|
Java 开发者
在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口
【10月更文挑战第20天】在Java多线程编程中,创建线程的方法有两种:继承Thread类和实现Runnable接口。本文揭示了这两种方式的微妙差异和潜在陷阱,帮助你更好地理解和选择适合项目需求的线程创建方式。
16 3
|
22天前
|
Java
在Java多线程编程中,实现Runnable接口通常优于继承Thread类
【10月更文挑战第20天】在Java多线程编程中,实现Runnable接口通常优于继承Thread类。原因包括:1) Java只支持单继承,实现接口不受此限制;2) Runnable接口便于代码复用和线程池管理;3) 分离任务与线程,提高灵活性。因此,实现Runnable接口是更佳选择。
30 2
|
22天前
|
Java
Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口
【10月更文挑战第20天】《JAVA多线程深度解析:线程的创建之路》介绍了Java中多线程编程的基本概念和创建线程的两种主要方式:继承Thread类和实现Runnable接口。文章详细讲解了每种方式的实现方法、优缺点及适用场景,帮助读者更好地理解和掌握多线程编程技术,为复杂任务的高效处理奠定基础。
28 2
|
22天前
|
Java 开发者
Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点
【10月更文挑战第20天】Java多线程初学者指南:介绍通过继承Thread类与实现Runnable接口两种方式创建线程的方法及其优缺点,重点解析为何实现Runnable接口更具灵活性、资源共享及易于管理的优势。
28 1
|
1月前
|
Java 测试技术 编译器
Java零基础-继承详解!
【10月更文挑战第4天】Java零基础教学篇,手把手实践教学!
34 2
|
1月前
|
Java 编译器
在Java中,关于final、static关键字与方法的重写和继承【易错点】
在Java中,关于final、static关键字与方法的重写和继承【易错点】
21 5
|
1月前
|
Java
java继承和多态详解
java继承和多态详解
42 5
|
30天前
|
Java 测试技术 编译器
Java零基础-继承详解!
【10月更文挑战第6天】Java零基础教学篇,手把手实践教学!
22 0
|
1月前
|
存储 Java 程序员
Java基础-面向对象
Java基础-面向对象
16 0