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

今日任务

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

2、能够独立使用继承

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

1. 代码块

1.1.代码块的概念和格式

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

书写格式:

{
    代码;
}

1.2.代码块的分类

1.2.1. 静态代码块

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

class Demo{
      static{
          System.out.pintln("静态代码块")
      }
}
2.png

静态代码块的执行顺序:


3.png

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

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

1.2.2. 构造代码块

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

class Demo{
      {
          System.out.pintln("构造代码块")
      }
}
5.png

构造代码块执行顺序:


6.png

应用:

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


7.png
8.png

1.2.3. 局部代码块

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

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

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

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();
    }
}
12.png

代码二:

class Demo 
{
    Demo demo = new Demo();

    Demo(){
        System.out.println("构造函数");
    }
}
class Test
{
    public static void main(String[] args) 
    {
        new Demo();
    }
}
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、对外提供公开的访问方法,获取这个对象


14.png

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


15.png

解决办法:懒汉式

16.png

原理:


17.png

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

4.3.单例设计总结

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

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

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

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

5. 面向对象:继承

                    继承财产;

                    继承皇位;

                    继承传统;

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

5.1.java中的继承

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

写法:

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

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

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

18.png

19.png

问题:


20.png

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


21.png

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

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

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

5.2.java类的继承特点

5.2.1. 单一继承

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


22.png

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

5.2.2. 多重继承

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


23.png

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

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

24.png

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

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

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

25.png
26.png

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

5.4.继承中的成员方法

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

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

27.png
28.png

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

5.5.方法的重写(override)

5.5.1. 重写的概念

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

5.5.2. 重写的应用

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


29.png

30.png

5.5.3. 重写的注意事项

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

31.png

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

32.png

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

33.png

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

34.png

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

35.png

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

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

5.6.1. 子类实例化的过程

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


36.png

37.png

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

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

38.png

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


39.png

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


40.png

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


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

42.png

6.2.2. 修饰函数

43.png

6.2.3. 修饰变量

44.png

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

     final int USER_AGE = 10;

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


45.png
46.png

6.3.final总结

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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,185评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,445评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,684评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,564评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,681评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,874评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,025评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,761评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,217评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,545评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,694评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,351评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,988评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,778评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,007评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,427评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,580评论 2 349

推荐阅读更多精彩内容

  • 一:java概述: 1,JDK:Java Development Kit,java的开发和运行环境,java的开发...
    慕容小伟阅读 1,777评论 0 10
  • 整理来自互联网 1,JDK:Java Development Kit,java的开发和运行环境,java的开发工具...
    Ncompass阅读 1,537评论 0 6
  • 一:java概述:1,JDK:Java Development Kit,java的开发和运行环境,java的开发工...
    ZaneInTheSun阅读 2,635评论 0 11
  • 这是16年5月份编辑的一份比较杂乱适合自己观看的学习记录文档,今天18年5月份再次想写文章,发现简书还为我保存起的...
    Jenaral阅读 2,739评论 2 9
  • 感赏儿子没有妈妈的监督,都可以自己主动去锻炼,主动的复习功课! 感赏儿子主动学习,看着他吊儿郎当的样子,其实是学进...
    晓莉_f92b阅读 112评论 0 0