JAVA学习第十一课(继承及super使用)

来源:互联网 发布:js字符串替换换行符 编辑:程序博客网 时间:2024/06/15 09:00
继承:(extends)

很多类,但是有一些成员,都是重复的,所以为提供复用性,把重复的代码抽取出来,就应用了继承
1.提高了代码的复用性

2.让类与类之间产生了关系,继承给多态提供了前提,没继承就没多态


class MAN{String name;int age;}class student extends MAN //MAN是student的基类,student是MAN的子类{void study(){System.out.println(name+"正在学习"+age);}}class teacher extends MAN{void work(){System.out.println(name+"正在工作"+age);}}public class Main{public static void main (String[] args) {student BLF = new student();BLF.name = "BLF2";BLF.age = 20;BLF.study();}} 


概念理解图:


单继承和多继承

JAVA支持单继承,不直接支持多继承,但是在C++的多继承机制上进行了改良。

定义:


1、单继承:一个子类只能有一个直接父类。

class A extends B ,B extends C;


2、多继承:一个子类可以有多个直接父类,(java中不允许)进行了改良。

class A extends B;A extend C;


多继承的优点:
类A 中有一些变量,类B中有一些东西,如果C继承了A和B,那么C就同时拥有了A,B的东西
C++多继承的缺点:

见代码:

#include <iostream>using namespace std;class A{public :void show(){cout<<"sd"<<endl;}}class B{public :void show(){cout<<"sssd"<<endl;}}class C :public A,public B//A,B的show都是同一个函数名{}C BLF;int main(){BLF.show();//此处C++代码的多继承,就会出现混乱,必须让show,show1、show2,名字保证不一样,才可以return 0;}


java的多继承:不直接支持多继承,因为,一旦父类中出现了相同的成员,就会产生不确定性,java改良了C++这一缺陷


java的多继承,是通过“多实现”的方式来实现

java支持多层(多重)继承:D 继承 C,C 继承 B,B继承A,就会出现继承体系,

注意:当要使用一个继承体系时:

1.查看体系的最顶层,了解体系的基本功能


2.创建体系的最子类对象,完成功能的使用

继承体系图:





什么时候定义继承?

当类与类之间有所属关系时,使用继承,如:xxx是yyy的一种,那么xxx继承于yyy,谁是谁中的一种
所属关系:A is a B;A继承于B

子父类中成员变量的特点:
1.成员变量  2.成员函数  3.构造函数

一、成员变量

class father{int num = 5;}class son extends father{int num = 6;void show(){System.out.print(num+" : "+num);//6 : 6}}public class Main{public static void main(String[] args){son zSon = new son();zSon.show();}}



子类中的有,坚决不找父类

当本类的成员和局部变量重名,用this来区分,当子父类中的成员重名,用super区分。

super的用法和this相似。

class father{int num = 5;}class son extends father{int num= 6;void show(){System.out.print(this.num+" : "+super.num);// 6 :5}}public class Main{public static void main(String[] args){son zSon = new son();zSon.show();}}



上述代码,作为了解,父类有num,子类继承于父类自然也有num

两者区别:
this:代表一个类的引用
super:代表一个父类的空间

子父类内存图:



子类不能直接访问,父类中的私有内容,但是可以间接访问,开发时不常见,面试多见

class father{private int num = 5;public int getnum(){return num;}}class son extends father{int num= 6;void show(){System.out.print(this.num+" : "+super.getnum());}}public class Main{public static void main(String[] args){son zSon = new son();zSon.show();}}


二、成员函数


class father{void show1(){System.out.println("father");}}class son extends father{void show2(){System.out.println("son");}}public class Main{public static void main(String[] args){son zSon = new son();zSon.show1();zSon.show2();}}

当子父类中出现成员函数一样(函数名一样,返回类型一致,函数参数列表相同)时,会运行子类的函数,成为覆盖操作,父类的操作被覆盖了,这是函数在子父类中的特性

class father{void show(){System.out.println("father");}}class son extends father{void show(){System.out.println("son");}}public class Main{public static void main(String[] args){son zSon = new son();zSon.show();zSon.show();}}



函数的两个特性:1.重载 2.覆盖(重写/复写)

重载是同一个类中,覆盖是在子类中

覆盖注意

1.子类方法覆盖父类方法时,子类权限必须 >= 父类的权限,才能覆盖(上述代码父类show前加public就无法覆盖,son的show也加public就行,不能用static修饰其中一个,必须两个都static才行)

2.静态只能覆盖静态,或被静态覆盖


什么时候使用覆盖?

当对一个类,进行子类的扩展时,子类需要保留父类的功能声明,但是在定义子类中功能的特有功能时,就使用覆盖操作完成


比如电话:来电显示功能,后期想添加 号码来自地区

class phone{ void show(){System.out.println("number");} void call() {} void memssage() {} //....}class phone2 extends phone//phone中有一些功能不需要改,所以采用继承{ void show()//只需修改show的功能{System.out.println("from");super.show();//保留父类的功能}}public class Main{public static void main(String[] args){phone2 zSon = new phone2();zSon.show();}}

子父类中的构造函数的特点

class father{father() {System.out.println("fu");}}class son extends father{son() {System.out.println("so");}}public class Main{public static void main(String[] args){//super();new son();}}



打印 fu
     so


在子类构造对象时,发现,访问子类构造函数时,父类构造函数也运行了?

在子类构造函数的第一行有一个默认的隐式语句 super();有super() ,表示正在调用父类中的空参数的构造函数。
(父类构造函数如果有参的话,那么super就要自己写了)

class father{father() {System.out.println("A");}father(int x) {System.out.println("B");}}class son extends father{son() {//super();System.out.println("C");}son(int x) {super(x);System.out.println("D"+x);}}public class Main{public static void main(String[] args){new son(6);}}



子类的实例化过程,子类中所有的构造函数都会访问父类中空参数的构造函数

为什么实例化的时候,要访问父类的构造函数?

子类继承了父类,拥有了父类的内容(属性和行为)所以在使用父类内容之前,要知道父类是如何进行初始化的,所以子类在构造对象时,就必须访问父类中的构造函数,为了完成这个必须的动作,就在子类的构造函数中加入默认的super()。
如果父类中,没有定义空参数的构造函数,那么子类的构造函数必须用super明确的调用父类中对应构造函数

class father{int num;father() {num = 8;System.out.println("A");}}class son extends father{son() {System.out.println("C"+num);}}


如果子类不访问父类的构造函数的话,那么打印 C 0,所以访问父类构造函数成为了必须。
内存空间一建立,父类中的num会在子类的num都会在内存中展现出来,所以子类必须知道父类怎么初始化的

注意:super语句必须在子类构造函数的第一行。因为父类的初始化的动作在子类前,必须先完成。

this和super:


this 和super 在构造函数都必须在一行,那是不是就引起冲突呢。
子类函数中,如果使用了this调用了本来的构造函数,但是this和super都必须房子本类构造函数的第一行,所以只能有一个
但是,子类中肯定有其他的构造函数访问父类的构造函数。


代码如下:

class father{int num;father() {num = 8;System.out.println("A");}}class son extends father{son(){}son(int x) {this();//使用this,省掉super,原因:使用this调用本类的son(),而son(){} 继承于father,son(){}中有默认//的super();肯定至少有一个访问父类的构造函数System.out.println("C"+num);}}public class Main{public static void main(String[] args){new son(6);}}


子类的实例化过程:

class father{father() {show();}void show(){System.out.println("asdf");}}class son extends father{int num = 8;son(){super();//System.out.println("dfsdf");}void show(){System.out.println("num is "+num);}}public class Main{public static void main(String[] args){son s = new son();s.show();}}
打印:
num is 0
num is 8


再看把上述代码注释部分打开
打印:
num is 0
dfsdf
num is 8


class father{father() {show();}void show(){System.out.println("asdf");}}class son extends father{int num = 8;son(){super();//通过super初始化父类内容时,子类并未进行初始化,等super()父类初始化        //完毕后,才进行子类的成员变量,显示初始化->分水岭}void show(){System.out.println("num is "+num);}}public class Main{public static void main(String[] args){son s = new son();s.show();}}

/* * 一个对象实例化过程 * son s = new son(); * 1.JVM会读取指定路径下的son.class文见,并加载进内存,如果有直接父类,先加载父类 * 2.在堆内存中开辟空间,分配地址 * 3.并在对象空间中,对对象中的属性进行默认初始化 * 4.调用对应的构造函数进行初始化 * 5.在构造函数中第一行,会先调用父类的构造函数,进行初始化 * 6.父类初始完毕,再对子类的属性进行显示初始化, * 7.再进行子类构造函数的特定初始化 * 8.子类初始化完毕后将地址值给引用变量 * */


PS:C++针对多继承体系重复继承相同基类的同一成员多次继承的弊端,改用虚基类来改良,但是,子类的必须要写他的每一个直接基类的构造函数,代码冗杂,java利用super,来代替原来的基类的构造函数,且是单继承,每一个类的构造函数都含指向有他的直接基类的空间地址

class FU{public int num;public String name;public FU(int num,String name) {this.num = num;this.name = name;System.out.println("FU.FU()");}class ZI extends FU{private int age;ZI(int age,int num,String name){super(num,name);this.age = age;}

子类在继承父类时,是把父类所有的东西都拿过来了,包括私有成员,只是子类不能用

在子类的toString()方法中,调用父类的私有成员的get方法,可以得到验证


关于垃圾回收机制,JVM在判断栈中没有对象引用的指针指向堆中的对应的对象地址时,才会回收该对象和空间




0 0