Java面向对象学习(二)面向对象三大特性----继承

1.继承的定义

类与类之间的关系:子类和父类。继承的本质是对某一批类的抽象。

在子类中使用extends关键字,意为扩展,子类是父类的扩展,子类可以继承父类的所有属性和方法(如果属性定义为private,要写成封装(get、set)方法来给子类调用)

Java中只有单继承,因为一个儿子只能有一个父,而父可以有多个儿子。

final定义的类是没有子类的,无法被继承。

 

1)继承的程序写法

先创建一个Person类

1 //父类
2 public class Person {
3 
4 }

再创建一个Student子类,因为Student属于Person

1 //Student是Person,也就是Student是Person的子类,或者叫派生类
2 public class Student extends Person{
3  
4 }

这样就完成了Student子类对Person父类的继承

 

2)子类可以继承父类的所有方法,Student类里什么都不写,在Person类中写了如下属性和方法

1 //父类
2 public class Person {
3     public int money=10_0000_0000;
4     public void say(){
5         System.out.println("说了一句话");
6     }
7 }

在Application中调用这些属性和方法,可以正常调用

1 import com.rzd.oop.demo06.Student;
2 
3 public class Application {
4     public static void main(String[] args) {
5         Student student = new Student();
6         System.out.println(student.money);
7         student.say();
8     }
9 }

但是由于属性一般写成私有的,于是就在Person内写成封装

 1 //父类
 2 public class Person {
 3     private int money=10_0000_0000;
 4     public void say(){
 5         System.out.println("说了一句话");
 6     }
 7 
 8     public int getMoney() {
 9         return money;
10     }
11 }
1 import com.rzd.oop.demo06.Student;
2 
3 public class Application {
4     public static void main(String[] args) {
5         Student student = new Student();
6         System.out.println(student.getMoney());
7         student.say();
8     }
9 }

 

3)

Object类

光标放在任意一个中,Ctrl+h可以发现,Object类是所有类的父类,Object类中有很多方法可以调用

 

 在Java中,所有类的父类都默认继承Object类。在代码中可以认为是默认如下

1 public class Person /*extends Object */ {
2     
3 }

 

4)Super()

super关键字用来调用父类的属性或方法

创建一个父类Person类,子类Student类,编写程序如下

1 package com.rzd.oop.demo07;
2 //父类
3 public class Person {
4     protected String name="父name";
5 
6     public void print(){
7         System.out.println("Person");
8     }
9 }

在子类中定义与父类相同的属性名和方法名

 1 package com.rzd.oop.demo07;
 2 //super()
 3 public class Student extends Person{
 4     String name="子name";
 5     public void print(){
 6         System.out.println("Student");
 7     }
 8 
 9 
10 
11     //子类调用父类的属性
12     public void test(String name){
13         //这个name是当前方法的形参,值是调用这个方法传进来的参数
14         System.out.println(name);
15         //this.name表示当前这个类的属性name
16         System.out.println(this.name);
17         //super.name表示父类的属性name
18         System.out.println(super.name);
19     }
20 
21     //子类调用父类的方法
22     public void test1(){
23         print();    //一般不用这个写法,会分不清。指当前类的print方法,可以按住Ctrl点击它来看跳转到具体哪一个方法
24         this.print();   //当前类的print方法
25         super.print();  //父类的print方法
26     }
27 }

在main方法中调用,可以看到,this指代当前类,super指代父类

 1 package com.rzd.oop;
 2 
 3 import com.rzd.oop.demo07.Student;
 4 
 5 public class Application {
 6     public static void main(String[] args) {
 7         Student student = new Student();
 8         student.test("实参name");
 9 
10         student.test1();
11     }
12 }

 

在子类的构造器中,第一行有一行super();是隐藏代码,就像没有定义构造器时,程序有一个隐藏的无参构造器一样,是默认存在的。

1 public class Person {
2     protected String name="父name";
3 
4     public Person() {
5         System.out.println("父类的无参构造执行了");
6     }
7 }
1 public class Student extends Person {
2    //Student的无参构造器
3     public Student() {
4         //这里有一句隐藏代码,就像没有定义构造器时,程序有一个隐藏的无参构造器一样。
5         //super();  //调用父类的无参构造器
6         System.out.println("子类的无参构造执行了");
7     }
8 
9 }

 

这时在main方法中new一个Student时,执行结果如下

 

 由此可见,在子类的无参构造的第一行是有一句super();的。

一些报错的解释:

1.Call to 'super()' must be first statement in constructor body

在子类中调用构造器时,无论是调用本身的构造器,还是调用父类的构造器,都必须写在构造器的第一行。

原因是:this()和super()都是构造方法,作用是在JVM堆中构建出一个对象。如果不写在第一行,例如第一行System.out.println(name);用来输出父类的name属性值,但是此时name对象还没有进行初始化

    所以为了避免操作对象时对象还未构建成功,需要this()和super()的调用在第一行实现【以此来创建对象】,防止异常

    

 

2.Call to 'this()' must be first statement in constructor body

在子类中调用构造器时,super()和this()不能同时出现。

 原因是:this()和super()都是构造方法,作用是在JVM堆中构建出一个对象。super()会调用父类的无参构造器,初始化父类;而this()默认会先调用父类的无参构造器,这样就会对父类进行两次初始化,重复创建两次对象

    所以为了避免多次创建对象,同一个方法内只能调用一次this()或super()。

 那么同理,也不能既调用父类的无参构造,又调用父类的有参构造了,也会造成重复创建对象。

 

3.There is no default constructor available in 'com.rzd.oop.demo08.Person':在Person中没有默认的构造器

如果在父类Person中只提供了有参构造,没有写无参构造,那么此时无参构造自动失效。此时如果在子类Student中调用

 

在类中,如果只定义了有参构造,那么无参构造自动失效。而在上面这个程序中,子类写了一个无参构造,第一行默认是super();没有写出来,意思为调用父类的无参构造,但是现在父类里并没有无参构造,所以会报错。

所以有两种解决办法

解决方法1:在父类中添加无参构造

 

 解决方法2:在子类中指明要调用的是父类的有参构造

  

 小结:

super():

1)super()只能用在子类的构造方法中,且必须在第一行

2)在子类的普通方法中可以调用super.属性,super.方法等

3)super()和this()不能同时调用,会导致重复创建对象

 

this():表示本身类的构造方法

 

5.方法重写

1)只有方法可以重写,和属性无关

2)子类重写父类的方法:方法名、参数列表必须相同,只有方法体可以不同(否则会变成重载)

3)子类的修饰符可以扩大,但不能缩小:public>protected>default<private

4)子类抛出的异常范围可以缩小但不能扩大:ClassNotFoundException<Exception

 

添加一个Father父类,写一个test方法

1 //重写都是方法的重写。
2 public class Father {
3     public void test(){
4 
5         System.out.println("父类的test()");
6     }
7 }

再添加一个Son方法,写一个和父类只有方法体不同的test方法

1 public class Son extends Father{
2     public void test(){
3         System.out.println("子类的test()");
4     }
5 }

在main方法中初始化

1 public class Application {
2     public static void main(String[] args) {
3         Son son = new Son();
4         Father father = new Son();//子类重写了父类的方法
5         son.test();
6         father.test();
7     }
8 }

运行结果为

 

 这里就是方法的重写,会去调用子类test方法。

重写的意义:父类的功能对子类来说太多或不够用。

重写的快捷键:Alt+Insert   override(重写)、Ctrl+o

快捷添加重写会自动添加代码:

1 public class Son extends Father{
2     @Override   //注释
3     public void test() {
4         super.test();
5     }
6 }

然后可以修改方法体。

 

posted @ 2021-07-16 16:49  阮真冬  阅读(591)  评论(0)    收藏  举报