第三章 -- 继承的概念

来源:互联网 发布:qsv转换flv软件 编辑:程序博客网 时间:2024/05/22 15:45

一丶继承的概念

(1) 多个类中存在相同属性和行为时将这些内容抽取到单独一个类中那么多个类无需再定义这些属性和行为只要继承那个类即可

(2) 和构造代码块区分构造代码块针对的是对象的相同属性进行初始化继承这是针对多个类相同的行为和属性提取到同一个类中的行为

二丶继承的好处和坏处

1.好处

(1) 提高了代码的复用性(最大的好处)

(2) 提高了代码的维护性

(3) 让类与类产生了关系是多态的前提(也是它的弊端)

类的耦合性增强了

开发原则低耦合高内聚

耦合类与类之间的关系

内聚就是自己完成某件事情的能力

2.坏处

(1) 破坏了封装性

(2) 类与类之间产生了关系高耦合了

 

总结不要乱用继承

 

三丶Java支持单继承但支持多继承接口类

四丶开发中什么使用继承???

采用假设法

如果两个类, A,B 只有他们符合 A的一种或者 是 的一种我们就可以考虑使用继承

五丶继承中成员变量的关系

1. 子类中的成员变量和父类中的成员变量名称不同这个太简单了

2. 子类中的成员变量和父类中的成员变量的名字一样这个时候使用就近原则

这个时候就退出了 super 和 this 

六丶super 和 this

1. 区别

(1). this 代表本类对象的引用

(2). super 代表着父类的存储空间可以理解为父类的引用(可以操作父类的成员和方法)

2. 怎么用?

(1) 调用成员变量

this,成员变量

super.成员变量

(2) 调用构造方法

this(...) 调用本类的构造方法

super(...) 调用父类的构造方法

(3) 调用成员方法

this.成员方法

super.成员方法

七丶继承中构造方法的关系

1. 子类中所有的构造方法默认都会访问父类中空参数的构造方法

2. 为什么???

因为子类会继承父类中的数据可能还会使用父类的数据,所以子类初始化之前一定要完成为父类数据的初始化注意子类每一个构造方法的第一条默认都调用了 super()

注意super必须放在子类构造函数的第一行如果不是的话子类也会在第一行调用super然后再是我们写的super, 所以这里的话调用了两次 super

拓展:

c++子类构造函数执行时会调用默认的无参构造函数但是如果使用了构造函数的初始化成员列表的话这样子的话就会调用我们初始化成员列表上面的构造函数而不再默认调用父类的无参构造函数

 

面试要点1:

首先要注意的点:

1. 成员变量 ----------  就近原则

2. this 和 super 的问题

this 本类对象

super 父类对象

3. 子类构造方法执行前默认先执行父类的无参构造函数方法

4. 一个类的初始化过程

1) 成员变量初始化

默认初始化

显示初始化

构造方法初始化

面试要点2:

1. 一个类的静态代码块构造代码块构造方法的执行流程

静态代码块 构造代码块 构造方法

2. 静态的内容是随着类的加载而加载

静态代码块的内容会优先执行

3. 子类初始化之前先会优先执行父类的初始化

 

--------------------------------------------------------------------------------

package com.bagiao.Test;

 

import org.junit.Test;

 

// JVM 的加载器在加载执行 Zi z = new Zi(); 的 Zi z 这句话的时候

// 就会让加载器去加载 Zi 但是 Zi 是 Fu 的之类, 加载器便会先加载父类 Fu

// 的类, 这个时候加载时, 发现Fu 存在 static 代码块, 就先执行 static块中

// 的代码, 然后Fu 类加载完毕后, 回到子类让加载器去加载子类Zi 的类

// 由于 static 随着类的存在而存在所以先执行 static 代码块加载完毕后回到

// Zi z = new Zi(); 发现存在 new Zi 这句话, 便会去调用子类的构造方法

// 然后通过子类的构造方法函数入口点进入父类的构造方法这时JVM会先去

// 执行构造代码块中的代码, 然后在执行父类的构造函数, 之后回到子类的构造函数入口点

// 这时会先去加载 构造代码块中的代码, 之后执行子类的构造方法, 最后放回一个对象

// 由 z 指向(引用) 这个对象

class Fu

{

    static 

    {

        System.out.println("父类的静态代码块"); // (1)

    }

    

    {

        System.out.println("父类的构造代码块"); // (3)

    }

    

    public Fu() // (4)

    {

        System.out.println("父类的构造方法");

    }

}

 

class Zi extends Fu

{

    static

    {

        System.out.println("子类的静态代码块"); // (2)

    }

    

    {

        System.out.println("子类的构造代码块"); // (5)

    }

    

    public Zi() // (6)

    { // 这里隐藏着一个 super() 初始化地方, { 和 super() 一样, super 并不是一个语句, 而是一个标记, 标记的作用优先执行父类

        System.out.println("子类的构造方法");

    }

}

public class _Main

{

    @Test

    public void test1()

    {

        Zi z = new Zi();

    }

}

 

 

输出结果:

父类的静态代码块

子类的静态代码块

父类的构造代码块

父类的构造方法

子类的构造代码块

子类的构造方法

--------------------------------------------------------------------------------

 

3丶分层初始化

 

面试要点3:

--------------------------------------------------------------------------------

package com.bangiao.继承的面试题二;

class X

{

// 这个相当于初始化成员列表, 或者是构造代码块, 比构造方法要早的初始化

    Y b = new Y();

    X()

    {

        System.out.println("X");

    }

}

class Y 

{

    Y()

    {

        System.out.println("Y");

    }

}

public class Z extends X

    Y y = new Y();

    Z()

    {

        super();

        System.out.println("Z");

    }

    public static void main(String[] args)

    {

        new Z();

    }

}

 

输出结果

Y

X

Y

Z

--------------------------------------------------------------------------------

总结下来便是:

注意:

1. 在执行构造函数时会先去执行第一行的 super 之后再初始化这个类的成员变量也就是先初始化父类的成员变量之后再初始化子类的成员

 

Super的注意点:

虽然子类中构造方法默认有一个super()

初始化的时候不是按照那个顺序进行的

而是按照分层初始化进行的

它仅仅表示先初始化父类数据在初始化子类数据

 

注意方法重写和方法重载的方法

首先方法的重写便是

函数名相同函数参数相同

其次方法的重载是

函数名字相同函数的参数不同, (但是函数的返回值不相同)

当相同的函数签名存在但函数的返回值不同时这个时候便会报错

--------------------------------------------------------------------------------

void print()

{

}

int print()

{

return 0;

}

--------------------------------------------------------------------------------

八丶方法重写的注意事项

1. 父类私有化方法不能被重写

因为父类私有化方法子类根本就无法继承

2. 子类重写父类方法时访问权限不能更低最好一致

3. 父类静态方法子类也必须通过静态方法进行重写

其实这个算不上方法重写但是现象确实如此至于为什么算不上方法重写看多态

 

九丶面试题

1. 方法重写成立的条件

(1) 发生在父类与子类之间(作用域)

(2) 子类存在一个函数的参数丶函数名和参数和父类相同

2. 方法重载成立的条件

(1) 发生在同一个作用域之间

(2) 方法的名字相同但是它的参数列表不同(函数签名的问题)

(3) 方法重载和返回值没多大关系函数返回值不同可以同时存在,c++也可以存在

3. thissuper 的区别

(1) this 表示该对象的引用

(2) super 表示标识父类对象的存储空间

其中注意下:

super 这个是关键字它不是一个函数是一个标记放在子类的第一行的话表示的是告诉JVM去调用父类的构造函数或者方法属性说白了你可以把super和隐藏的super当成是构造方法的 这个括号

 

this() 必须放在构造函数的第一行和显示调用 super 一样所以 super 和 this 不能同时调用用

 

 

 

Day01总结:

--------------------------------------------------------------------------------

 

1:如何制作帮助文档(了解)

(1)写一个类

(2)加入文档注释

(3)通过javadoc工具生成即可

javadoc -d 目录 -author -version ArrayTool.java

 

2:通过JDK提供的API学习了Math(掌握)

(1)API(Application Programming Interface)

应用程序编程接口(帮助文档)

(2)如何使用呢?

请参照

day08\code\02_如何使用JDK提供的帮助文档\如何使用帮助文档.txt

(3)Math

A:是针对数学进行操作的类

B:没有构造方法,因为它的成员都是静态的

C:产生随机数

public static double random(): [0.0,1.0)

D:如何产生一个1-100之间的随机数

int number = (int)(Math.random()*100)+1;

E:猜数字小游戏

 

3:代码块(理解)

(1){}括起来的代码。

(2)分类:

A:局部代码块

用于限定变量的生命周期,及早释放,提高内存利用率。

B:构造代码块

把多个构造方法中相同的代码可以放到这里,每个构造方法执行前,首先执行构造代码块。

C:静态代码块

对类的数据进行初始化,仅仅只执行一次。

(3)静态代码块,构造代码块,构造方法的顺序问题?

静态代码块 构造代码块 构造方法

4:继承(掌握)

(1)把多个类中相同的成员给提取出来定义到一个独立的类中。然后让这多个类和该独立的类产生一个关系,

   这多个类就具备了这些内容。这个关系叫继承。

(2)Java中如何表示继承呢?格式是什么呢?

A:用关键字extends表示

B:格式:

class 子类名 extends 父类名 {}

(3)继承的好处:

A:提高了代码的复用性

B:提高了代码的维护性

C:让类与类产生了一个关系,是多态的前提

(4)继承的弊端:

A:让类的耦合性增强。这样某个类的改变,就会影响其他和该类相关的类。

原则:低耦合,高内聚。

耦合:类与类的关系

内聚:自己完成某件事情的能力

B:打破了封装性

(5)Java中继承的特点

A:Java中类只支持单继承

B:Java中可以多层()继承(继承体系)

(6)继承的注意事项:

A:子类不能继承父类的私有成员

B:子类不能继承父类的构造方法,但是可以通过super去访问

C:不要为了部分功能而去继承

(7)什么时候使用继承呢?

A:继承体现的是:is a的关系。

B:采用假设法

(8)Java继承中的成员关系

A:成员变量

a:子类的成员变量名称和父类中的成员变量名称不一样,这个太简单

b:子类的成员变量名称和父类中的成员变量名称一样,这个怎么访问呢?

子类的方法访问变量的查找顺序:

在子类方法的局部范围找,有就使用。

在子类的成员范围找,有就使用。

在父类的成员范围找,有就使用。

找不到,就报错。

B:构造方法

a:子类的构造方法默认会去访问父类的无参构造方法

是为了子类访问父类数据的初始化

b:父类中如果没有无参构造方法,怎么办?

子类通过super去明确调用带参构造

子类通过this调用本身的其他构造,但是一定会有一个去访问了父类的构造

让父类提供无参构造

C:成员方法

a:子类的成员方法和父类中的成员方法名称不一样,这个太简单

b:子类的成员方法和父类中的成员方法名称一样,这个怎么访问呢?

通过子类对象访问一个方法的查找顺序:

在子类中找,有就使用

在父类中找,有就使用

找不到,就报错

(9)两个面试题:

A:OverrideOverload的区别?Overload是否可以改变返回值类型?

B:thissuper的区别和各自的作用?

(10)数据初始化的面试题

A:一个类的初始化过程

B:子父类的构造执行过程

C:分层初始化

(11)案例:

A:学生和老师案例

继承前

继承后

B:猫狗案例的分析和实现

--------------------------------------------------------------------------------

 

九丶final 修饰符的使用

// (1) 首先 final 可以修饰类, 方法, 变量

// (2) 被修饰的东西, 被标记为最终形态

//      1) 修饰类的话, 该类    不能被继承

//      2) final 修饰方法, 该方法不能被重写(覆盖, 复写)

//      3) final 可以修饰变量, 被修饰的变量将成为常量

//  常量分两类

//      (1) 字面量常量

//          "hello" 10 true

//      (2) 自定义常量

//          final int x = 10;

// 修饰变量, 只能被赋值一次

// 修饰方法, 不能被重写

 

例子 final 的面试题

package com.bangiao.Final04;

import org.junit.Test;

 

// 总结下:

/*

* 这个 final final修饰谁, 谁就是最终变量

* 这里的 final Student ss = new Student(); ss 这个变量, 而不是它的值

* 所以 ss = new Student(); 这个的话是错误的, 这个和 c++ 中的

* const int x = 10; 修饰的是 x

* const Student s = Student();

* 这里修饰的是 s

* const int * p = null;

* 这里修饰的 是 int * 这个值 这个是底层const

* int * const p = null;

* 这个修饰的是 p 这个变量 这个是一个顶层 const

* */

 

class Student 

{

    int age = 10;

}

 

public class TestFinal面试题

{

    @Test

    public void test1() 

    {

        int x = 10;

        x = 100;

        

        

        final int y = 100;

//      y = 19;

        

        

        Student s = new Student();

        System.out.println(s.age);

        s.age = 100;

        System.out.println(s.age);

        

        final Student ss = new Student();

        System.out.println(ss.age);

        ss.age = 100;

        System.out.println(ss.age);

//      ss = new Student();

    }

}

 

final 修饰基本数据类型的值不能发生改变但是final修饰的变量之只能被初始化一次

引用类型的地址不能发生改变但是堆的值是可以被改变的

 

--------------------------------------------------------------------------------

 

十丶final修饰变量的初始化时机

(1)final 修饰的变量只能赋值初始化一次

(2) 在构造方法完毕前(非静态的常量)

 

课后作业

1:代码块是什么?代码块的分类和各自特点?

代码块是对作用域的一种方位的定义

分类代码块是  构造代码块 局部代码块 静态代码块 同步代码块

特点

构造代码块 快于构造函数用于初始化多个对象的属性或多个对象需要执行的代码

每次调用构造函数前都会执行构造代码块中的代码

局部代码块 在局部代码块中放入执行代码或者变量之类的在代码块执行完毕后资源将被回收

静态代码块 用于初始化类中的静态变量或者执行方法的在这里面的代码只执行一次

同步代码块 用于线程同步时使用

2:静态代码块,构造代码块,构造方法的执行流程?

静态代码块 构造代码块 构造方法

3:继承概述

继承提高了代码的复用性简化了代码

让类与类之间产生了继承的关系是多态的基础

4:继承的好处

提高代码的维护性

5:Java中继承的特点

Java中的继承是单继承可以多层继承

6:Java中继承的注意事项?以及我们什么时候使用继承?

A: 子类不能继承父类的私有成员

B: 子类不能继承父类的构造方法但是可以通过 super 去访问

C: 不要为了部分功能而去使用继承

7:继承中的成员访问特点

A:成员变量

在子类方法中访问一个变量

B:成员方法

在测试类中通过子类对象去访问一个方法

8:继承中构造方法的执行流程?假如父类没有无参构造方法,子类应该怎么办?

构造方法的执行流程:

先执行父类的构造方法在执行父类的构造方法前先执行构造初始化代码块包括变量和{} 构造代码块

然后执行构造函数最后执行子类的构造代码块和初始化构造变量最后执行构造函数

9:面试题:

方法重写和方法重载的区别?方法重载能改变返回值类型吗?

Overload

重载

在同一个作用域中存在不同的函数签名便产生了函数重载而函数的签名不包括函数的返回值

public void print(int num);

public int print(int num);  // 这两个方法的函数签名是相同的虽然返回值不同

Override

重写:

在不同的作用域(通常是父子类), 存在相同的函数签名和函数返回值这个时候便产生了函数重写

产生多态时父类同名方法将被重写替换掉

this关键字和super关键字分别代表什么?以及他们各自的使用场景和作用。

this 便是对象的引用, super 是父类的对象的存储空间

this 用于调用类内的变量和方法

super 用于在类内调用父类的方法和变量

10:继承案例练习

11:猜数字小游戏练习。

通过API学习并使用Math类的random()方法。