神刀安全网

Java基础进阶 第三天 单例模式、继承、final

今日任务

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

2、能够独立使用继承

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

1. 代码块

1.1.代码块的概念和格式

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

书写格式:

{     代码; } 

1.2.代码块的分类

1.2.1. 静态代码块

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

class Demo{       static{           System.out.pintln("静态代码块")       } } 
Java基础进阶 第三天 单例模式、继承、final

2.png

静态代码块的执行顺序:

Java基础进阶 第三天 单例模式、继承、final

3.png

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

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

1.2.2. 构造代码块

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

class Demo{       {           System.out.pintln("构造代码块")       } } 
Java基础进阶 第三天 单例模式、继承、final

5.png

构造代码块执行顺序:

Java基础进阶 第三天 单例模式、继承、final

6.png

应用:

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

Java基础进阶 第三天 单例模式、继承、final

7.png

Java基础进阶 第三天 单例模式、继承、final

8.png

1.2.3. 局部代码块

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

class Demo{       public static void main(String[] args){          {              System.out.pintln("局部代码块")           }       } } 

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

Java基础进阶 第三天 单例模式、继承、final

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();     } } 
Java基础进阶 第三天 单例模式、继承、final

12.png

代码二:

class Demo  {     Demo demo = new Demo();      Demo(){         System.out.println("构造函数");     } } class Test {     public static void main(String[] args)      {         new Demo();     } } 
Java基础进阶 第三天 单例模式、继承、final

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、对外提供公开的访问方法,获取这个对象

Java基础进阶 第三天 单例模式、继承、final

14.png

这种方式叫做饿汉式;
这种实现方式有点问题:
这种方式,只要使用到这个类,就一定会创建对象,会造成内存的浪费;
好处是:保证对象的唯一性;

Java基础进阶 第三天 单例模式、继承、final

15.png

解决办法:懒汉式

Java基础进阶 第三天 单例模式、继承、final

16.png

原理:

Java基础进阶 第三天 单例模式、继承、final

17.png

懒汉式的问题:
多线程环境下,不能保证每次获取的都是同一个对象;
好处:避免内存浪费;

4.3.单例设计总结

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

单例实现的步骤
1、私有构造函数,避免其他类可以直接创建单例类的对象;
2、在本类中创建唯一实例,使用静态成员变量保存;为保证安全性,私有化这个成员变量;
3、对外提供一个公开的静态方法,供其他类获取本类的唯一实例;

单例的两种实现方法
饿汉式:在加载类的同时就创建了这个类的唯一实例;
好处:可保证这个类的实例的唯一性;
弊端:如果只是使用这个类,但是暂时不需要它的对象,也会创建唯一实例,造成内存的浪费;

懒汉式:在第一次调用获取实例的方法时才创建对象;
好处:第一次调用获取实例的方法时才创建对象,可以避免内存的浪费;
弊端:多线程环境下不能保证实例的唯一性;

5. 面向对象:继承

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

5.1.java中的继承

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

写法:

class  Fu{} class  Zi extends Fu{}//表示Zi类继承里Fu类; 在继承关系中,被其他类继承的类,叫做父类(超类),如本例中的Fu类; 继承其他类的类,叫做子类(派生类),如本例中的Zi类; 

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

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

Java基础进阶 第三天 单例模式、继承、final

18.png

Java基础进阶 第三天 单例模式、继承、final

19.png

问题:

Java基础进阶 第三天 单例模式、继承、final

20.png

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

Java基础进阶 第三天 单例模式、继承、final

21.png

结论:使用继承可以提高代码的复用性;
使用继承可以在两个类中建立一种关系;

使用注意:
1、继承中,父类的私有成员可以被子类继承,但是不能直接被访问使用;
2、继承中的两个类,应该有关系;
只有子类描述的事物是 父类描述的事物的特例的时候,才可以使用继承;

虽然在语法上,可以使用extends关键字在任意两个类之间建立继承关系,但是在开发中,只能是二者之间具有“是” 的关系的时候才使用继承;
如果两个类不具有这种“是”的关系,那么就应该找他们共同的父类,然后将共同的信息放到共同的父类中,然后让两个类分别继承父类;
鱼和 苹果 , 不具有 “是” 的关系,但是有共同的父类,都属于食物,所以可以建立一个食物类,然后让他们分别继承食物类;

5.2.java类的继承特点

5.2.1. 单一继承

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

Java基础进阶 第三天 单例模式、继承、final

22.png

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

5.2.2. 多重继承

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

Java基础进阶 第三天 单例模式、继承、final

23.png

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

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

Java基础进阶 第三天 单例模式、继承、final

24.png

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

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

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

Java基础进阶 第三天 单例模式、继承、final

25.png

Java基础进阶 第三天 单例模式、继承、final

26.png

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

5.4.继承中的成员方法

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

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

Java基础进阶 第三天 单例模式、继承、final

27.png

Java基础进阶 第三天 单例模式、继承、final

28.png

结论:
如果子类中没有定义和父类中一样的成员变量和函数,直接调用,使用的是父类中定义的成员;
如果子类中定义了和父类中一样的成员变量和函数,直接调用,使用都是子类中定义的成员;
此时要使用父中定义的成员,需要通过super关键字调用;调用的格式是:
super.成员变量;
super.成员函数名(参数);

5.5.方法的重写(override)

5.5.1. 重写的概念

在子类中定义和父类中相同的函数,直接调用函数时,实际使用的是子类中的函数,这种情况叫做方法的重写(覆写);
一般开发中,如果父类的功能不满足子类需要,子类都会重写父类的函数;

5.5.2. 重写的应用

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

Java基础进阶 第三天 单例模式、继承、final

29.png

Java基础进阶 第三天 单例模式、继承、final

30.png

5.5.3. 重写的注意事项

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

Java基础进阶 第三天 单例模式、继承、final

31.png

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

Java基础进阶 第三天 单例模式、继承、final

32.png

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

Java基础进阶 第三天 单例模式、继承、final

33.png

4、子类重写的函数要和父类中的函数的访问方式相同
(也就是说,父类的方法是静态的,重写的方法也必须是静态的;父类的方法不是静态的,重写的方法也必须不是静态的);

Java基础进阶 第三天 单例模式、继承、final

34.png

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

Java基础进阶 第三天 单例模式、继承、final

35.png

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

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

5.6.1. 子类实例化的过程

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

Java基础进阶 第三天 单例模式、继承、final

36.png

Java基础进阶 第三天 单例模式、继承、final

37.png

1、为什么任何一个类(不包含Object)的构造函数中都需要一个super() 语句?
因为除了Object类以外,所有类都会继承一个父类;继承父类,那么子类实例化时就需要给父类中的成员变量显示赋值,就需要用到父类中的构造函数;

2、如果父类中没有无参构造函数,子类如何实例化?
super()表示调用父类无参构造函数;如果父类中没有无参构造函数,就会报错;

Java基础进阶 第三天 单例模式、继承、final

38.png

如何解决这个问题呢?
1、在父类中添加一个无参构造函数;

Java基础进阶 第三天 单例模式、继承、final

39.png

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

Java基础进阶 第三天 单例模式、继承、final

40.png

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

Java基础进阶 第三天 单例模式、继承、final

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. 修饰类

Java基础进阶 第三天 单例模式、继承、final

42.png

6.2.2. 修饰函数

Java基础进阶 第三天 单例模式、继承、final

43.png

6.2.3. 修饰变量

Java基础进阶 第三天 单例模式、继承、final

44.png

因为被final修饰的变量的值不可改变,所以java中都使用它表示常量;
如果是常量,变量名的写法是:所有字母全部大写,多个单词之间使用下划线连接;

     final int USER_AGE = 10; 

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

Java基础进阶 第三天 单例模式、继承、final

45.png

Java基础进阶 第三天 单例模式、继承、final

46.png

6.3.final总结

final:最终的,最后的;可以修饰类、变量和函数;
修饰类,表示该类不可被继承;格式是直接写在class关键字前面;
修饰函数,表示继承这个类的子类中不能重写这个函数;格式是直接写在函数的返回值类型前面
修饰变量,表示该变量的值不可改变;格式是直接写在变量的数据类型前面;
注意:如果修饰的是引用类型的变量,则变量中保存的引用不可改变,但是引用指向的堆内存中的数据可以改变;

转载本站任何文章请注明:转载至神刀安全网,谢谢神刀安全网 » Java基础进阶 第三天 单例模式、继承、final

分享到:更多 ()