博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Java基础-学习笔记(十一)——类的继承性
阅读量:4573 次
发布时间:2019-06-08

本文共 7957 字,大约阅读时间需要 26 分钟。

1、为什么会有继承性

1 class Person 2 { 3     String name; 4     int age; 5     String getInfo(){...} 6 } 7 class Student 8 { 9     String name;10     int age;11     String school;12     String getInfo(){...}13     String study(){...}14 }

在编写代码过程中,可能会出现如上所示的情况,Student类中包含了Person类中的方法和属性。我们针对这种情况,就引入了继承这个概念,只要表明Student类继承了Person类中的所有属性和方法,就不用再在Student中重写Person类中的属性和方法,也就是简化了类的定义,如下所示:

class Person{    String name;    int age;    void getInfo()    {        System.out.println("name="+name+" "+"age="+age);    }}class Student extends Person{    String school;    void study()    {        System.out.println("school="+school);    }    public static void main(String [] args)    {        s1.name="Jane";        s1.age=23;        s1.school="清华";        s1.getInfo();        s1.study();    }}/*F:\java_example\lesson5>java Studentname=Jane age=20school=清华*/

 

2、继承性的特点

1)可以简化类的定义;

2)java只支持单继承,不允许多重继承。也就是说,一个类不能同时继承多个类;

3)java支持多层继承。即,A类可以继承B类,B类可以继承C类,...,重复再多层也支持。

4)子类只继承父类(或称为基类、超类)所有的成员和方法,不能继承父类的构造函数,需要通过子类构造方法中使用语句super(参数列表)调用父类的构造函数;

1 class Person 2 { 3     String name; 4     int age; 5     Person(String name,int age) 6     { 7         this.name=name; 8         this.age=age; 9     }10     void getInfo()11     {12         System.out.println("name="+name+" "+"age="+age);13     }14 }15 class Student extends Person16 {17     String school;18     Student(String name,int age,String school)19     {20         super(name,age);21         this.school=school;22     }23     void study()24     {25         System.out.println("school="+school);26     }27     public static void main(String [] args)28     {29         Student s1=new Student("Jane",20,"清华");30         s1.getInfo();31         s1.study();32     }33 }34 /*35 F:\java_example\lesson5>java Student36 name=Jane age=2037 school=清华*/

5)子类对象实例化过程

注意事项: 子类对象创建时需要调用父类的构造函数

如下代码在编译过程中出错

1 class Person 2 { 3     String name; 4     int age; 5     Person(String name,int age) 6     { 7         this.name=name; 8         this.age=age; 9     }10         //Person(){}11     void getInfo()12     {13         System.out.println("name="+name+" "+"age="+age);14     }15 }16 class Student extends Person17 {18     String school;19     void study()20     {21         System.out.println("school="+school);22     }23     public static void main(String [] args)24     {25         Student s1=new Student();26         s1.name="Jane";27         s1.age=23;28         s1.school="清华";29         s1.getInfo();30         s1.study();31     }32 }
View Code

报错如下:

F:\java_example\lesson5>javac lesson5.java

lesson5.java:19: 错误: 无法将类 Person中的构造器 Person应用到给定类型;
class Student extends Person
^
需要: String,int
找到: 没有参数
原因: 实际参数列表和形式参数列表长度不同
1 个错误

解决方法:将无参数的Person构造函数注释去掉。以后只要是定义了类有参数的构造函数,需要把其无参数的构造函数同样写上,避免类似错误。

现象说明:在构造Student类的s1对象的过程中,需要调用父类Person的无参数构造函数,但是由于,父类已存在的构造函数是有参数的,那么编译器不会再给Person自动生成无参数的构造函数,所以s1对象就无法创建成功

1 class Person 2 { 3     String name="unknown"; 4     int age=-1; 5     Person(String name,int age) 6     { 7         this.name=name; 8         this.age=age; 9     }10     Person()11     {12         System.out.println("Is calling");13     }14     void getInfo()15     {16         System.out.println("name="+name+" "+"age="+age);17     }18 }19 class Student extends Person20 {21     String school="unknown";22     Student(String name,int age,String school)23     {24         super(name,age);25         this.school=school;26     }27     /*Student(String name,int age)28     {29         super(name,age);30     }31     Student(String name,int age,String school)32     {33         this(name,age);34         this.school=school;35     }36     */37     void study()38     {39         System.out.println("school="+school);40     }41     public static void main(String [] args)42     {43         Student s1=new Student("Jane",20,"清华");44         s1.getInfo();45         s1.study();46     }47 }
View Code

这段代码说明了,子类对象创建时会按需选择父类中对应的构造函数。

具体实例化步骤:

第一步 分配成员变量的内存空间并进行默认的初始化,就是在new对象的过程中,会按照系统的默认值给各个成员赋初值,例如,String类型赋值为“null”,int类型为0等等;

第二步 绑定构造方法参数,就是将new Student("Jane",20,"清华")中的值传给对应的构造函数中的形参

第三步 不会立马将构造函数形参的值赋值给实参,而是,检查有没有this()方法调用。如果有,则调用相应的重载构造函数(被调用的重载构造函数,又从第二步开始执行),该过程结束后,回到当前的构造方法,直接转到第六步;如果没有,则执行下一步骤;

将代码中Student的重载构造函数换成如下

Student(String name,int age)

{
  super(name,age);
}
Student(String name,int age,String school)
{
  this(name,age);
  this.school=school;
}

第四步 显示(就是执行super语句)或者隐式追溯调用父类的构造方法(根据继承性,一直追溯到最上层的父类)。在这个过程中,也是从第二步开始,全部结束后,继续下一步骤;

第五步 进行实例变量的显式初始化操作,也就是执行在定义成员变量时对它赋初值的语句。即,将unknown赋给name。没有则跳过该步骤

第六步 执行当前构造方法中的程序代码,即执行this.school=school。super或this已经在之前的步骤中执行过了,注意区别,上文提到的this()和this.school=school语句,前者调用的是构造方法,后者只是一个普通的语句

super()能和this()放同一个函数中么?我们通过this()间接来调用父类的构造方法,作用是和super()一致的,所以没意义,程序也不允许

super()、this()可以放在方法体中任意位置么?NO,只能放在对应构造方法体中的第一句,要不然就和上面的流程冲突了

3、覆盖父类的方法

在子类中可以根据需要更改从父类继承过来的方法---方法的覆盖或重写

覆盖的方法和被覆盖的方法两者具有相同的名称、参数列表和返回值类型

1 class Person 2 { 3     String name="unknown"; 4     int age=-1; 5     public Person(String name,int age) 6     { 7         this.name=name; 8         this.age=age; 9     }10     public Person()11     {12         System.out.println("Is calling");13     }14     public void getInfo()15     {16         System.out.println("name="+name+" "+"age="+age);17     }18 }19 class Student extends Person20 {21     String school="unknown";22     public Student(String name,int age,String school)23     {24         super(name,age);25         this.school=school;26     }27     public void getInfo()//覆盖父类中的getInfo()28     {29         System.out.println("name="+name+" "+"age="+age+" "+"school="+school);30         //super.getInfo();可以直接调用父类的getInfo()31     }32     public void study()33     {34         System.out.println("I'm studing");35     }36     public static void main(String [] args)37     {38         Student s1=new Student("Jane",20,"清华");39         s1.getInfo();40         s1.study();41     }42 }43 /*44 F:\java_example\lesson5>java Student45 name=Jane age=20 school=清华46 I'm studing
View Code

如果将子类的访问修饰符换成protected,那么编译时会报如下错

F:\java_example\lesson5>javac lesson5.java

lesson5.java:27: 错误: Student中的getInfo()无法覆盖Person中的getInfo()
protected void getInfo()//覆盖父类中的getInfo()
^
正在尝试分配更低的访问权限; 以前为public
1 个错误

这说明了,如果要覆盖父类的方法,则子类的该方法的权限修饰符等级要比父类的高或者是同级;但两者均不能用private来进行修饰,super需要调用父类的getInfo()

4、final关键字

a 在java中声明类、属性、方法时,可以用关键字final来修饰

b final标记的类不能被继承

c final标记的方法不能被子类重写

d final标记的变量(成员变量或局部变量)则为常量,只能赋值一次,并且,只能在声明或者该类的所有构造方法中显式赋值再来使用,还有,赋值后的变量只能在该类中直接使用,在类的外部不能直接使用

java中定义常量,常用public static fianl的组合方式进行标识

e 方法中定义的内部类只能访问该方法的final类型的局部变量,用final定义的局部变量相当于是一个常量,它的生命周期超出方法运行的生命周期

1 class Person 2 { 3     public final String;// name=“Jane”; 4     //要么在声明时初始化,要么在所有显式的构造函数中都进行初始化 5     int age=-1; 6     public Person(String name,int age) 7     { 8         this.name="Jane"; 9         this.age=age;10     }11     public Person()12     {13         this.name="Jane";//如果不写这句,会报错“可能尚未初始化变量name”14         System.out.println("Is calling");15     }16     public void getInfo()17     {18         System.out.println("name="+name+" "+"age="+age);19     }20 }21 class Student extends Person22 {23     String school="unknown";24     public Student(String name,int age,String school)25     {26         super(name,age);27         this.school=school;28     }29     public void getInfo()//覆盖父类中的getInfo()30     {31         System.out.println("name="+name+" "+"age="+age+" "+"school="+school);32         super.getInfo();33     }34     public void study()35     {36         System.out.println("I'm studing");37     }38     public static void main(String [] args)39     {40         Student s1=new Student("Chen",20,"清华");//name已经是常量,且值为Jane41         s1.getInfo();42         s1.study();43     }44 }45 /*46 F:\java_example\lesson5>java Student47 name=Jane age=20 school=清华48 I'm studing

如果将public final String name;写成public static final String name;只是替换这一句,程序会报错,因为用static修饰的变量,可以直接用类名来引用。那么就存在了一种隐患,我如果是通过类名来调用name,那我就不用new一个Person对象,我既然不用创建对象,那也不会调用其构造函数,从而,我的name也就没有进行初始化。所以,在通过publicstatic final修饰的变量,只能在声明时赋值

转载于:https://www.cnblogs.com/tiantianxiangshang33/p/4948626.html

你可能感兴趣的文章
自己动手开发更好用的markdown编辑器-07(扩展语法)
查看>>
maven dependency:tree中反斜杠的含义
查看>>
队列的循环队列
查看>>
程序中的日期格式
查看>>
大众点评CAT错误总结以及解决思路
查看>>
从0开始学爬虫3之xpath的介绍和使用
查看>>
vim下正则表达式的非贪婪匹配
查看>>
一个python的计算熵(entropy)的函数
查看>>
spring源码学习——spring整体架构和设计理念
查看>>
模拟window系统的“回收站”
查看>>
报文格式【定长报文】
查看>>
RDLC报表钻取空白页问题
查看>>
多路电梯调度的思想
查看>>
jQuery-对Select的操作
查看>>
过滤器、监听器、拦截器的区别
查看>>
为什么要进行需求分析?通常对软件系统有哪些需求?
查看>>
一些模板
查看>>
jquery和dom元素相互转换
查看>>
放大的X--HDOJ-201307292012
查看>>
题目831-签到-nyoj-20140818
查看>>