java继承后 赋值返回_Java基础进阶 第三天 单例模式、继承、final

今日任务

1、能够理解单例设计模式

2、能够独立使用继承

3、能够独立使用final关键字

1. 代码块

1.1.代码块的概念和格式

代码块,就是使用大括号括起来的一段代码;

书写格式:

{

代码;

}

1.2.代码块的分类

1.2.1. 静态代码块

静态代码块,就是使用static修饰的代码块,直接写在类中的代码块;

class Demo{

static{

System.out.pintln("静态代码块")

}

}

84f8c10b55d5

2.png

静态代码块的执行顺序:

84f8c10b55d5

3.png

注意:一般在开发中,静态代码块都要写在类的下面;

作用:

因为在类加载完成时,静态代码块已经执行结束,所以某些需要提前完成的工作,可以放在静态代码块中执行;

1.2.2. 构造代码块

构造代码块,也是直接写在类中的代码块;在构造代码块前面不需要任何的关键字修饰;

class Demo{

{

System.out.pintln("构造代码块")

}

}

84f8c10b55d5

5.png

构造代码块执行顺序:

84f8c10b55d5

6.png

应用:

原来凡是创建对象执行构造函数,都要执行构造代码块,所以如果某些操作在所有构造函数中都存在,那么可以提取到构造代码块中;

84f8c10b55d5

7.png

84f8c10b55d5

8.png

1.2.3. 局部代码块

局部代码块的写法和构造代码块一模一样;不同的时,局部代码块只能写在局部位置(函数中);

class Demo{

public static void main(String[] args){

{

System.out.pintln("局部代码块")

}

}

}

局部代码块的作用,就是用来限定部分代码的使用范围的;

84f8c10b55d5

10.png

2. 类中可以书写的成员

class Demo{

//静态成员变量

static int a = 10;

//非静态成员变量

int b =20;

//静态方法

static void show(){

System.out.pintln("静态方法")

}

//非静态方法

void func(){

System.out.pintln("非静态方法")

}

//构造方法

Demo(){

System.out.pintln("构造方法")

}

//静态代码块

static {

System.out.pintln("静态方法")

}

{

System.out.pintln("构造代码块")

}

}

3. 类加载和对象创建的过程

面试题:

class Demo {

int x;

int y = 3;

static int z = 10;

static {

System.out.println("z=" + z);

}

Demo() {

System.out.println("x=" + x);

System.out.println("y=" + y);

}

}

class DemoTest2 {

public static void main(String[] args) {

Demo d = new Demo();

}

}

3.1.类加载过程

1、JVM发现要使用一个类,首先要到方法区中找;如果找到了,就直接使用,如果没有找到,才会去找这个类的class文件,然后加载;

(在找class文件时,是根据classpath配置的地址去找;如果没有配置,就在当前目录找)

2、在硬盘上找到class文件后,就开始加载这个class,根据书写顺序,先后将静态成员加载到静态区域,非静态成员加载到非静态区域;

3、接下来为所有的静态成员变量分配变量空间,同时赋默认值;

4、接下来根据书写的顺序为静态成员变量显示赋值,同时执行静态代码块;

上面的步骤都执行完毕,类加载完成;

3.2.对象的创建过程

1、首先JVM在堆内存中开辟空间;

2、在对象空间中为类中的所有非静态成员变量分配空间,赋默认值;

3、调用相应的构造函数进栈;

4、在执行构造函数中的代码之前,先要执行隐式三步:

a) super():调用父类构造函数

b) 给对象空间中的非静态成员变量显示赋值

c) 执行构造代码块

5、完成隐式三步后,接下来开始执行构造函数中的代码;

构造函数结束出栈,对象创建完成;

3.3.练习

下列代码执行结果是什么?为什么?

代码一:

class Demo

{

static Demo demo = new Demo();

Demo(){

System.out.println("构造函数");

}

}

class Test

{

public static void main(String[] args)

{

new Demo();

}

}

84f8c10b55d5

12.png

代码二:

class Demo

{

Demo demo = new Demo();

Demo(){

System.out.println("构造函数");

}

}

class Test

{

public static void main(String[] args)

{

new Demo();

}

}

84f8c10b55d5

13.png

4. 单例设计模式

4.1.单例设计(singleton)模式介绍

4.1.1. 设计模式:

就是对一些常见问题进行归纳总结,并针对具体问题给出一套通用的解决办法(强调的是解决问题的思想);在开发中,只要遇到这类问题,就可以直接使用这些设计模式解决问题;

最早起源于建筑领域,在建筑领域把一些问题和经验进行归纳总结,形成一套可以用来在建筑领域解决大多数问题的方案;

后来计算机领域借鉴了建筑领域的设计模式,把计算机领域中经常遇到的问题进行归纳和总结,形成计算机领域23中设计模式;

4.1.2. 单例(单态、原子)设计模式:

在程序运行中,一个类最多只能有一个对象;

//需求:模拟月亮,不管哪里调用的月亮,都是同一个对象;

class Moon//描述月亮

{

/*

要创建对象,有两个条件:new关键字;构造函数;

要保证单例,就不能让别人随便创建对象;

在这两个条件中,new关键字程序员无法控制;

就只能考虑不让别人使用构造函数;

要想别人不能随意使用构造函数,就需要将构造函数私有化;

*/

private Moon(){}

/*

私有化构造函数,确实可以避免随意创建对象;

但是还是得有一个对象;

而构造函数私有化后在别的地方无法创建对象,

就只有在本类中创建这个唯一的对象;

创建的对象需要有一个变量接收,以后其他地方需要这个对象,

通过这个变量就可以获取这个对象了;

因为在使用这个变量之前还没有对象,所以这个变量必须是静态的;

为了保证数据的安全,不被外界修改,必须将他封装起来(也就是私有化)

*/

private static Moon moon = new Moon();

/*

要想外界还能访问到被封装的数据,必须向外提供一个公开的访问方法

而且只有访问这个方法之后才会有对象,所以这个方法应该是静态的

*/

public static Moon getMoon(){

return moon;

}

}

class Test

{

public static void main(String[] args)

{

Moon m1 = Moon.getMoon();

Moon m2 = Moon.getMoon();

System.out.println(m1);

System.out.println(m2);

System.out.println(m1 == m2);

}

}

4.2.单例设计模式的代码模板

总结实现单例的步骤:

1、私有化构造函数;

2、在本类中创建唯一实例对象;

3、对外提供公开的访问方法,获取这个对象

84f8c10b55d5

14.png

这种方式叫做饿汉式;

这种实现方式有点问题:

这种方式,只要使用到这个类,就一定会创建对象,会造成内存的浪费;

好处是:保证对象的唯一性;

84f8c10b55d5

15.png

解决办法:懒汉式

84f8c10b55d5

16.png

原理:

84f8c10b55d5

17.png

懒汉式的问题:

多线程环境下,不能保证每次获取的都是同一个对象;

好处:避免内存浪费;

4.3.单例设计总结

设计模式:针对某一类问题的通用的解决办法;

单例设计模式:解决程序运行中一个类最多只能有一个实例对象的问题;

单例实现的步骤:

1、私有构造函数,避免其他类可以直接创建单例类的对象;

2、在本类中创建唯一实例,使用静态成员变量保存;为保证安全性,私有化这个成员变量;

3、对外提供一个公开的静态方法,供其他类获取本类的唯一实例;

单例的两种实现方法:

饿汉式:在加载类的同时就创建了这个类的唯一实例;

好处:可保证这个类的实例的唯一性;

弊端:如果只是使用这个类,但是暂时不需要它的对象,也会创建唯一实例,造成内存的浪费;

懒汉式:在第一次调用获取实例的方法时才创建对象;

好处:第一次调用获取实例的方法时才创建对象,可以避免内存的浪费;

弊端:多线程环境下不能保证实例的唯一性;

5. 面向对象:继承

继承财产;

继承皇位;

继承传统;

继承都是发生在两类事物之间的,这两类事物都有关系,现实生活中是父子关系;

5.1.java中的继承

概念:

java中的继承,是使用extends关键字在两个类之间建立的一种关系;

写法:

class Fu{}

class Zi extends Fu{}//表示Zi类继承里Fu类;

在继承关系中,被其他类继承的类,叫做父类(超类),如本例中的Fu类;

继承其他类的类,叫做子类(派生类),如本例中的Zi类;

作用:

继承中子类可以直接拥有父类的成员;

继承演示:

案例:使用java代码描述人和学生的信息;

84f8c10b55d5

18.png

84f8c10b55d5

19.png

问题:

84f8c10b55d5

20.png

要解决这种应该是自身所有的属性和行为重复的问题,应该使用继承;

84f8c10b55d5

21.png

结论:使用继承可以提高代码的复用性;

使用继承可以在两个类中建立一种关系;

使用注意:

1、继承中,父类的私有成员可以被子类继承,但是不能直接被访问使用;

2、继承中的两个类,应该有关系;

只有子类描述的事物是 父类描述的事物的特例的时候,才可以使用继承;

虽然在语法上,可以使用extends关键字在任意两个类之间建立继承关系,但是在开发中,只能是二者之间具有“是” 的关系的时候才使用继承;

如果两个类不具有这种“是”的关系,那么就应该找他们共同的父类,然后将共同的信息放到共同的父类中,然后让两个类分别继承父类;

鱼和 苹果 , 不具有 “是” 的关系,但是有共同的父类,都属于食物,所以可以建立一个食物类,然后让他们分别继承食物类;

5.2.java类的继承特点

5.2.1. 单一继承

就是一个类只能直接继承一个父类;

84f8c10b55d5

22.png

如果可以继承两个父类,那么当这两个父类中都具有共同的属性或行为时,在子类中调用,就不清楚到底会调用哪个(调用的不确定性)

5.2.2. 多重继承

java中继承中,父类可以再继承其他类,叫做多重继承;

84f8c10b55d5

23.png

一个类只能直接继承一个父类,但是可以有多个子类;

一个类的父类还可以继承父类;

84f8c10b55d5

24.png

5.3.继承中的成员变量的特点

5.3.1. 子类直接拥有父类非私有成员变量

5.3.2. 子类中存在和父类中同名的成员变量,在子类中直接使用的是子类中定义的;

84f8c10b55d5

25.png

84f8c10b55d5

26.png

一般开发中,如果父类定义了某个成员变量,子类中一般不需要再定义;

5.4.继承中的成员方法

5.4.1. 子类直接拥有父类非私有成员方法

5.4.2. 子类中可以定义和父类中同样的成员方法,直接调用的是子类中定义的函数

84f8c10b55d5

27.png

84f8c10b55d5

28.png

结论:

如果子类中没有定义和父类中一样的成员变量和函数,直接调用,使用的是父类中定义的成员;

如果子类中定义了和父类中一样的成员变量和函数,直接调用,使用都是子类中定义的成员;

此时要使用父中定义的成员,需要通过super关键字调用;调用的格式是:

super.成员变量;

super.成员函数名(参数);

5.5.方法的重写(override)

5.5.1. 重写的概念

在子类中定义和父类中相同的函数,直接调用函数时,实际使用的是子类中的函数,这种情况叫做方法的重写(覆写);

一般开发中,如果父类的功能不满足子类需要,子类都会重写父类的函数;

5.5.2. 重写的应用

需求:描述手机这类事物。原始的手机和现代的手机

84f8c10b55d5

29.png

84f8c10b55d5

30.png

5.5.3. 重写的注意事项

1、子类重写的函数要和父类中的函数名要相同;

84f8c10b55d5

31.png

2、子类重写的函数要和父类中的函数参数列表要相同;

84f8c10b55d5

32.png

3、子类重写的函数要和父类中的函数返回值类型相同;

84f8c10b55d5

33.png

4、子类重写的函数要和父类中的函数的访问方式相同

(也就是说,父类的方法是静态的,重写的方法也必须是静态的;父类的方法不是静态的,重写的方法也必须不是静态的);

84f8c10b55d5

34.png

5、子类重写的函数,访问权限不能比父类的低;(可以和父类的访问权限不同,但是不能比父类访问权限低)

84f8c10b55d5

35.png

直接将父类中的函数复制粘贴到子类中,然后修改方法体的代码,可以保证不会出现格式上的问题;

5.6.继承中构造方法的使用

5.6.1. 子类实例化的过程

继承中类的加载顺序,是先加载父类,然后再加载子类;

84f8c10b55d5

36.png

84f8c10b55d5

37.png

1、为什么任何一个类(不包含Object)的构造函数中都需要一个super() 语句?

因为除了Object类以外,所有类都会继承一个父类;继承父类,那么子类实例化时就需要给父类中的成员变量显示赋值,就需要用到父类中的构造函数;

2、如果父类中没有无参构造函数,子类如何实例化?

super()表示调用父类无参构造函数;如果父类中没有无参构造函数,就会报错;

84f8c10b55d5

38.png

如何解决这个问题呢?

1、在父类中添加一个无参构造函数;

84f8c10b55d5

39.png

2、在子类的构造函数中显示的调用父类有参构造函数;

在子类中调用父类的构造函数,需要使用super关键字;格式是:super(参数);

84f8c10b55d5

40.png

在子类构造函数中使用super调用父类构造函数需要注意,这个super语句必须写在构造函数的第一行;

84f8c10b55d5

41.png

3、子类构造函数中,this() 和 super() 能否同时存在?

不能;因为他们都要写在构造函数的第一行;

所以如果一个构造函数中有this()语句,就没有super()语句,super()存在于this调用的那个构造函数里面;

4、如果一个类的构造函数全部私有了,还可以有子类吗?

不能;因为在子类的构造函数中一定要调用父类的构造函数;而一旦一个类的构造函数都私有了,就只能在本类中使用,其他类(也包括子类)都无法使用;

5.7.继承总结

继承的概念:通过extends关键字在两个类之间建立的一种关系;其中继承其他类的类叫做子类(派生类),被其他类继承的类叫做父类(超类);

继承关系,一般用来表示子类和父类的 是的关系,即子类描述的事物是 父类描述的事物的一个特例;

继承的格式:

class Fu{}//父类

class Zi **extends **Fu{}//子类

继承的作用:子类可以直接拥有父类成员;其中,私有成员和构造函数不参与继承;

java中类继承的特点:只支持单一继承和多重继承,不支持多继承(一个类不能同时继承多个类)

继承中成员变量的特点:

子类中可以直接使用父类中定义的非私有的成员变量;

如果子类中定义了和父类中相同的成员变量,直接调用,实际使用的是子类中定义的成员变量;要使用父类中定义的成员变量,需要使用关键字super,格式是:super.变量名;

继承中一般函数的特点:

子类中可以直接使用父类中定义的非私有的一般函数;

如果子类中定义了和父类中一样的函数,直接调用,实际使用的是子类定义的函数;要使用父类中定义的一般函数,需要使用关键字super,格式是:super.函数名(参数);

方法重写的概念:在继承中,如果子类中定义了和父类中一样的函数,则子类对象实际使用的是子类中定义的函数,这种情况叫做函数的重写;

子类重写父类函数需要注意的事项:

1、子类中重写的函数,函数名、参数列表、返回值类型和是否静态,必须和父类中函数相等;

2、子类中重写的函数,访问权限不能比父类中函数低;

继承中子类实例化的特点:

1、子类实例化时,实际只创建子类一个对象;

2、子类对象中会为父类中的非静态成员变量分配空间;

3、在执行子类的构造函数时,必须要先调用父类的构造函数,作用是给父类的成员变量显示赋值;

4、子类调用父类的构造函数,需要使用super关键字,格式是:super(参数);并且super语句必须在子类构造函数的第一行;

5、子类构造函数中调用其他构造函数的this语句不能和调用父类构造函数的super语句共存;

super小结:super,表示父类;作用是区分子类和父类的成员,以及在子类的构造函数中调用父类构造函数;

6. final关键字

6.1.final简介

final:表示最终的,最后的,主要用来修饰类、函数和变量;

final修饰类,直接写在class关键自前面,表示这个类不能被继承;

final修饰函数,直接写在函数的返回值类型前面,表示这个函数不能被重写,但是可以被继承;

final修饰变量,表示这个变量的值不能被修改;

6.2.final演示

6.2.1. 修饰类

84f8c10b55d5

42.png

6.2.2. 修饰函数

84f8c10b55d5

43.png

6.2.3. 修饰变量

84f8c10b55d5

44.png

因为被final修饰的变量的值不可改变,所以java中都使用它表示常量;

如果是常量,变量名的写法是:所有字母全部大写,多个单词之间使用下划线连接;

final int USER_AGE = 10;

被修饰的变量只是直接保存在变量中的值不能被修改,所以如果修饰的变量的数据类型是引用数据类型,那么这个引用不能修改,但是引用指向的对象中的数据可以修改;

84f8c10b55d5

45.png

84f8c10b55d5

46.png

6.3.final总结

final:最终的,最后的;可以修饰类、变量和函数;

修饰类,表示该类不可被继承;格式是直接写在class关键字前面;

修饰函数,表示继承这个类的子类中不能重写这个函数;格式是直接写在函数的返回值类型前面

修饰变量,表示该变量的值不可改变;格式是直接写在变量的数据类型前面;

注意:如果修饰的是引用类型的变量,则变量中保存的引用不可改变,但是引用指向的堆内存中的数据可以改变;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值