zoukankan      html  css  js  c++  java
  • Java基类和派生类

    背景:对基类和派生类有更清晰的认识。

    从外部看来,派生类是一个与基类具有相同接口的新类,或许还会有一些额外的的方法和域 。但继承并不仅仅是类的复用。当创建了一个派生类的对象时,该类包含了一个基类的子对象。这个子对象和你用基类直接创建的对象没有什么两样。

    二者的区别在于,后者来自于外部,而基类的子对象来自于派生类对象的内部。对基类的子对象初始化时至关重要的,而且也只有一种方法来保证这一点,那就是在派生类的构造器中调用基类的构造器,而基类的构造器具有执行基类初始化所需的所有能力和知识。

         

    示例

    在无参构造器时, java会自动在派生类的构造器中插入对基类的构造器的调用

    public class Humans {     
        Humans(){  
            System.out.println("我是人!");  
        }  
          
    } 
    public class Student extends Humans{  
      
        Student(){  
            System.out.println("我是学生!");  
        }  
      
    }  
    public class test {  
        public static void main(String args[]){  
              new Student();  
        }  
    }  

    输出结果为:

          我是人!
    
         我是学生!

    可以发现,总是基类的构造器先被初始化。

    示例

    但是当构造器有参数时,那就必须使用关键字super现实地编写调用基类构造器的代码,并且匹配适当的参数列表

    public class Humans {  
          
        private String name;  
      
        Humans(String name){  
            System.out.println("我是叫"+name+"的人");  
        }  
      
        public String getName() {  
            return name;  
        }  
      
        public void setName(String name) {  
            this.name = name;  
        }  
      
    }  
    public class Student extends Humans{  
          
        private String name;  
      
        Student(String name){  
            super(name);  
            System.out.println("我是学生!");  
        }  
      
        public String getName() {  
            return name;  
        }  
      
        public void setName(String name) {  
            this.name = name;  
        }  
    }  
    public class test {  
        public static void main(String args[]){  
            new Student("zhangsan");  
        }  
    } 

     输出结果:

    我是叫zhangsan的人
    
    我是学生!

    如果注释掉上面的super(name);将会报错。原因是派生类必须调用基类构造器。因为实例化派生类时,基类也会被实例化,如果不调用基类的构造器,基类将不会被实例化,所以派生类没有调用基类构造器会报错。

    但是如果Humans的代码变成这样就不会错。如下代码:

    public class Humans {  
          
        private String name;  
      
        Humans(){  
            System.out.println("我是人!");  
        }  
        Humans(String name){  
            System.out.println("我是叫"+name+"的人");  
        }  
      
        public String getName() {  
            return name;  
        }  
      
        public void setName(String name) {  
            this.name = name;  
        }  
      
    }  
    public class Student extends Humans{  
          
        private String name;  
          
        Student(String name){  
            //super(name);  
            System.out.println("我是学生!");  
        }  
      
        public String getName() {  
            return name;  
        }  
      
        public void setName(String name) {  
            this.name = name;  
        }  
    }  
    public class test {  
        public static void main(String args[]){  
            new Student("zhangsan");  
        }  
    }  

    输出结果为:

            我是人!
    
            我是学生!

    原因是,如果基类有一个无参的构造器,就算派生类不用super显示调用基类的构造函数,编译器也会自动去调用基类的无参构造函数。

    所以上面的代码不会报错,输出结果也不是

            我是叫zhangsan的人
    
            我是学生!

    而是

            我是人!
    
            我是学生!

    示例

    派生类继承了基类的所有public和protected属性和方法,代码如下:

    public class Humans {  
          
        public String sex;  
          
        protected int age ;  
          
        private String name;  
      
      
        Humans(String sex,String name,int age){  
            this.sex = sex;  
            this.name = name;  
            this.age = age;  
        }  
      
        public String getName() {  
            return name;  
        }  
      
        public void setName(String name) {  
            this.name = name;  
        }  
      
    }  
    public class Student extends Humans{  
          
        Student(String sex ,String name,int age){  
            super(sex,name,age);  
        }  
    }  
    public class test {  
        public static void main(String args[]){  
            Student s = new Student("男","zhangsan",10);  
            System.out.println(s.sex);  
            System.out.println(s.name);  
            System.out.println(s.age);  
        }  
    }  

    上面的System.out.println(s.name);会报错,因为name是private属性,如需访问,采用get方法:

    System.out.println(s.getName())

    输出结果为:

    男
    
    zhangsan
    
    10 

    示例

    如果派生类定义了和基类一样的属性或方法,将覆盖基类的属性和方法。如将student改为如下代码:

    public class Student extends Humans{  
          
        public String sex;  
          
        protected int age ;  
          
        private String name;  
          
        Student(String sex ,String name,int age){  
            super(sex,name,age);  
        }  
          
        public String getName() {  
            return name;  
        }  
      
        public void setName(String name) {  
            this.name = name;  
        }  
    }  

     输出结果为:

    null
    
    null
    
    0

    因为只有基类的属性在构造时赋值了,派生类的没有,当访问这些属性时,访问的是派生类的属性,所以全为null或者0。

    只有当派生类的属性也被实例化时,才会得到属性的值。代码改为如下:

    public class Student extends Humans{  
          
        public String sex;  
          
        protected int age ;  
          
        private String name;  
          
        Student(String sex ,String name,int age){  
            super(sex,name,age);  
            this.sex = sex;  
            this.name = name;  
            this.age = age;  
        }  
          
        public String getName() {  
            return name;  
        }  
      
        public void setName(String name) {  
            this.name = name;  
        }  
    }  

    输出结果为:

    男
    zhangsan
    10  

    要注意的是,super必须在构造器的最前面,不然会报错

  • 相关阅读:
    JS事件冒泡、事件捕获和事件委托
    实现英文字母排序
    JavaScript异步加载的四种方法
    JavaScript作用域与作用域链
    JavaScript 自定义属性 data-*
    asycn和await
    style collectd
    JavaScript如何比较两个数组的内容是否相同
    VScode插件开发--M2D文档转换插件
    BOM笔记
  • 原文地址:https://www.cnblogs.com/lixuwu/p/8482080.html
Copyright © 2011-2022 走看看