您的位置:首页 > 编程语言 > Java开发

JAVA基础笔记(复习)- 继承

2014-01-14 19:57 489 查看
继承的好处:

   1、提高了代码的复用性

   2、让类与类之间产生了关系,为多态提供了前提

简单的继承图解:

 


Java中支持单继承,不直接支持多继承,但对c++中的多继承机制进行了改良(多重继承和多实现)

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

多继承:一个子类可以有多个直接父类

Java为什么不支持多继承?

因为如果两个父类中有相同的方法时,jvm不知道运行哪一个。会产生不确定性。

但是支持多重继承:B 继承 A,C 继承 B,间接的实现了多继承

这样就会出现继承体系。

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

  1、查看该体系中的顶层类,了解该体系的基本功能

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

什么时候定义继承呢?

      当类与类之间存在着所属关系的时候,就定义继承。如:Xxx是yyy中的一种,xxx extends yyy

  所以判断所属关系,可以简单看,如果继承后,被继承的类中的功能,都可以被该子类所具备,那么继承成立。如果不是,不可以继承。 

成员变量:

     当本类的成员和局部变量同名用this区分。

     当子父类中的成员变量同名用super区分父类

     This与super的用法类似

     This代表本类对象的引用,super:代表一个父类空间。

 


成员函数:

特点:当子父类中出现成员函数一模一样的情况,会运行子类的函数,这种现象,称为覆盖操作

函数两个特性:

    1、重载 :同一个类中()

    2、覆盖 :子父类,覆盖也称为重写,覆写

覆盖注意事项:

    1、子类方法覆盖父类方法时,子类权限必须要大于等于父类权限

    2、静态只能覆盖静态

public class Test{

public static void main(String[] args) {

Zi z = new Zi();

z.show();

}

}

//在继承中,相同的变量定义,调用是就近原则,不存在覆盖一说

//而相同的函数名定义,叫做覆盖,运行子类永远都是运行覆写过的方法

//一样可以用super进行调用父类的函数和变量

class Fu{

int x = 5;

public void show(){

System.out.println(x + " ~~~~~ 父类");

}

}

class Zi extends Fu{

int x = 10;

public void show(){

System.out.println(x + " ~~~~~ " + super.x);

}

}

这样的情况不属于覆盖

class Fu{

int x = 5;

private void show(){  //父类私有化了,在eclipse中也有黄线提示。

System.out.println(x + " ~~~~~ 父类");

}

}

Static 只有一方有的话,也不能覆盖。

class Zi extends Fu{

int x = 10;

public void show(){ //

System.out.println(x + " ~~~~~ " + super.x);

}

}

什么时候使用覆盖操作:

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

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

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

原因是:在子类的构造函数中第一行有一个默认的隐式语句,super();

子类的实例化过程:

    子类中所有的构造函数默认都会访问父类中的空参构造函数

public class Test{

public static void main(String[] args) {

Zi z = new Zi();

}

}

class Fu{

  Fu(int x){//有参数的构造函数存在。空参构造将不存在,须手动创建显示构造空参

 System.out.println("fu"); 

  }

}

class Zi extends Fu{

Zi(){

//super() //隐式语句,调用空参构造,如果父类没有空参构造,则编译出错

//没有空空参?默认是没有其他构造函数的话,就有一个空参。如果有其他构造函数。则隐式空参构造失效,须手动添加

System.out.println("zi");

}

}

Implicit super constructor Fu() is undefined. Must explicitly invoke another constructor

不明确的父类构造Fun()是未定义的,必须显示的创建一个构造函数

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

因为:子类继承了父类,获取到了父类中的内容(属性),所以在使用内容之前要先看父类是如何对自己的内容进行初始化的。

如果父类中没有空参数构造函数,那么子类的构造函数必须用super明确要调用父类中哪个构造函数。

注意:super语句必须要定义在构造函数的第一行,因为,父类的初始化要先完成

注意:如果使用了this()调用了本类构造函数时,那么super就没有了。因为super和this都只能定义在第一行

如果想要同时使用 this() 和super(),可以间接的分开调用本类其他构造函数

子类实例化过程 ---- 图解

 


public class Test {

public static void main(String[] args) {

new Zi().show();

/*

 * 1:new zi() 发现有父类,则先加载父类的空参构造函数,并初始化。

 * 2:父类中有 show();但是子类继承了父类,并且是由子类触发的,所以this.show();并且该方法已经被覆盖,所以会执行子类的show;

 *    此时,子类,成员变量并未完成显示初始化(有默认初始化,局部变量没有默认初始化),所以,第一次打印结果 num = 0;

 * 3:父类初始化完成之后,回到子类构造函数,此时已经完成了初始化,对象创建成功,执行 show();,所以 num = 5

 * */

}

 

}

 

class Fu{

Fu(){

show();

}

public void show(){

System.out.println("~~~~~~~~~~~~父类");

}

}

class Zi extends Fu{

int num = 5;

Zi(){

show(); 

}

public void show(){

System.out.println("子类~~~~~~~~" + num<
9382
/span>);

}

}

 

一个对象实例化过程:

    Person p = new Person();

    1、JVM会读取指定的路径下的Person.class 文件,并加载进内存

      (并会先加载Person的父类(如果有直接的父类的情况下))

2、在堆内存中开辟空间,分配地址。

3、并在对象空间中,对对象中的属性进行默认初始化

4、调用对应的构造函数进行初始化

5、在构造函数中,第一行会先调用父类中的构造函数进行初始化。

6、父类初始化完毕后,再对子类的属性进行显示初始化

7、再进行子类构造函数的特定初始化

    8、初始化完毕后,将地址赋值给引用变量
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: