2020/3/17学习笔记-day20

本文详细解析了Java中子类构造器调用父类构造器的原因,super关键字的使用,以及方法重写(覆盖)的规则。通过实例讲解了如何在子类中初始化父类属性,正确调用父类方法,以及实现方法重写的关键要素。

java-day20

子类构造器中为什么要调用父类的构造器?
  • 子类继承了父类,那么就把父类中的属性和方法都继承了过来,但是我们希望子类中继承过来的属性都是已经在父类中完成了初始化工作之后的,因为这样我们就可以拿着这些属性直接使用了,父类中对这些属性完成初始化工作的代码默认就在构造器中,所以我们子类构造器里面首先会调用父类中的构造器,先完成对父类中属性的初始化工作,然后再执行子类自己的构造器中的代码,如果我们对父类构造器中初始化的工作不满意,那么我们还可以在子类构造器的代码中对继承过来的属性进行修改,以便覆盖掉父类初始化的值。
super关键字
  • 子类继承父类之后,在子类可以使用关键字访问子类中的属性、方法、构造器,也可以在子类中使用super关键字表示访问父类中的属性、方法、构造器。

    • 1、访问父类中的属性

      • 如果父类中的属性name被继承了,子类中有写了一个自己的属性那么,那么这时候this和super就可以区分我们访问的name到底是哪一个name属性。

      • public class Person{
            protected String name = "张三";
        }
        
        public class Student extends Person{
            private String name = "李四";
            public void test(){
                System.out.println(name);
                //this和super可以区分是哪个name
        
        		System.out.println(this.name);
        		System.out.println(super.name);
            }
        }
        
        • 如果父类中的属性,是private修饰的,那么使用super也是不能访问的。

        • public class Person{
              private String name = "张三";
          }
          
          public class Student extends Person{
              private String name = "李四";
              public void test(){
                  //编译报错,无法访问父类的private
                  System.out.println(super.name);
              }
          }
          

        如果父类中的属性name被继承了,子类中也没自己定义新的name属性,那么这时候,直接使用name和this . name和super.name这三种方式访问都是同一个name属性

        public class Person{
            protected String name = "张三";
        }
        
        public class Student extends Person{
            
            public void test(){
                System.out.println(name);
        		System.out.println(this.name);
        		System.out.println(super.name);
            }
        }
        
    • 2、调用父类中的方法

      • //例如:
        public class Person{
            public void run(){
                System.out.println("person run..");
            }
        }
        
        public class Student extends Person{
        
            public void run(){
                System.out.println("student run..");
            }
        
            //在这里可以访问到自己类中的run方法
            //也可以访问到父类中的run方法
            //为了区分调用的是哪一个run方法
            //可以使用this和super
            public void test(){
                run();
                this.run();
                super.run();
            }
        }
        
        
        
      • 如果调用或访问的时候,没有因为同名而带来的歧义的话,可以不使用this或者super,直接通过方法名或者属性名进行调用就可以了。

    • 3、调用父类中的构造器

      • public class Person{
           
        }
        
        public class Student extends Person{
            //默认使用super()调用父类无参构造器
            public Student(){
                
            }
        }
        
        public class Person{
        	protected String name;
        	public Person(String name){
                this.name = name;
        	}
        }
        
        public class Student extends Person{
            //编译报错
            //默认执行super()
            //父类没有无参构造器
            public Student(){
                
            }
        }
        
        public class Person{
        	protected String name;
        	public Person(String name){
                this.name = name;
        	}
        }
        
        public class Student extends Person{
            //编译通过
            //手动使用super调用父类无参构造器
            //显示调用
            public Student(){
                super("Tom");
            }
        }
        
        

        注意:无论是隐式调用还是显示调用super语句一定要在子类构造器中的第一行

        public class Person{
        	protected String name;
        	public Person(String name){
                this.name = name;
        	}
        }
        
        public class Student extends Person{
            //编译报错
            public Student(){
            	System.out.println("....");
                super("Tom");
            }
        }
        

        注意:在子类的构造器中可以使用this()来调用子类的构造器,可以使用super()来调用父类的构造器,但是他们不能同时出现(因为都要放在第一行)

        在这里插入图片描述
        在这里插入图片描述
        总结:在创建一个子类对象的时候,肯定要调用到子类中的一个构造器,并且在子类构造器执行之前,一定是会先调用到父类中的构造器的。这样做的目的就是在子类的构造器执行之前,先执行父类的构造器完成对父类中属性的初始化,保证子类继承的父类中的属性是已经初始化好可以直接使用的。

        在这里插入图片描述

方法的重写(覆盖)
  1. 方法的重写,存在于子类和父类之间(包括直接父类可以是间接父类),之前学习过的方法的重载是存在于同一个类中。

    • 方法的重载:同一个类中
    • 方法的重写:子类和父类之间
  2. 父类中的静态方法,在子类中是不能重写的

    1. 父类中的静态方法,不能被子类中重写为非静态方法

      • Person:
        public static void showInfo(){
        		
        	}
        Student:
        public void showInfo(){
        		
        	}
        

        在这里插入图片描述

      • Person:
        public  void showInfo(){
        		
        }
        Student:
        public static void showInfo(){
        		
        }
        

        在这里插入图片描述

      • Person:
        public static void showInfo(){
        		
        }
        Student:
        public static void showInfo(){	
        }
        

        在这里插入图片描述
        编译通过,但是不是重写,重写只能发生在子父类之间的非静态方法上。重写只能发生在子父之间非静态方法上。因为静态方法是属于类的,可以类名直接调用,它和对象没有关系的。

      • 父类中的非静态方法,可以被子类中继承并且重写,但是重写的时候也必须是非静态方法。这个就是正常的方法重写现象。

  3. 父类中的私有方法不能被子类重写

    1. 子类继承父类后,同时也继承到父类中的方法,如果需要对某个方法进行重写,那么这个被继承的方法需要满足以下条件:

      1. 必须是非静态的方法

      2. 该方法在子类中必须可以直接访问的

      3. public class Person{
            private void test(){}
        }
        //编译通过但不是重写,就是两个类中有相同名字的两个私有方法而已
        public class Student extends Person{
            private void test(){}
        }
        
  4. 方法重写的语法要求

    1. 方法名必须相同

    2. 参数列表必须相同

    3. 访问控制修饰符可以相同也可以不同,可以扩大但是不能缩小

      • public > protected > default > private
    4. 方法抛出的异常类型可以相同也可以不同,可以缩小但是不能扩大

      • 异常类型的范围大小根据类型中的子父类关系来确定的
      • Exception异常类型是ArraysIndexOutOfBoundException的父类型
      • 范围:Exception > ArraysIndexOutOfBoundException
    5. 方法的返回类型可以相同,也可以不同,如果不同的话,重写之后方法的返回类型必须是原方法的返回类型的子类型(兼容)

    6. 例子1:

      • Person.java

      • protected Object showInfo() throws Exception{
            return null;
        }
        
      • Student.java

      • protected Object showInfo() throws Exception{
            return null;
        }
        
    7. 例子2:

      • Person.java

      • protected Object showInfo() throws Exception{
            return null;
        }
        
      • Student.java

      • //没有异常也是缩小
        public Object showInfo(){
            return null;
        }
        
  5. 如果各个部分都和父类中方法保持一致,那么这个方法的重写我们重写的是什么?

    • 我们主要重写的是方法中的代码,所以大多数情况方法声明部分和父类中的方法保持一致。
  6. 为什么要对从父类中继承过来的方法进行重写?

    • 子类中继承过来的方法,原来是定义在父类中的,现在被子类继承了,而子类本身又是对父类型的扩展,所以这个时候,从父类中继承过来的方法,可能在子类中已经不是很适用了,所以我们需要重写对这个方法进行重写。

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值