java学习笔记 - 第十章:面向对象编程(高级部分)

第十章:面向对象编程(高级部分)

总体内容

在这里插入图片描述
在这里插入图片描述

类变量

类变量的引出

  1. 提出问题
    在这里插入图片描述
  2. 用现有方法解决 的思路和分析
    在这里插入图片描述
  3. 正式引出类变量(静态变量)
    类变量是属于类的,所以可以被类的所有对象共享
    在这里插入图片描述

类变量快速入门(静态变量)

  1. 在类中定义一个类变量(加上static)
    在这里插入图片描述
  2. 使用类的不同对象去引用(访问的是同一个变量)
    在这里插入图片描述
  3. 也可用类名访问类变量
    在这里插入图片描述
  4. 简略内存图
    在这里插入图片描述

类变量的内存布局

  1. 在jdk8以前,类变量在方法区的静态域中
  2. 在jdk8以后,类变量在堆的class对象中
  3. 不管类变量在哪,共识是:
    3.1. 类变量被同一个类的所有对象所共享(不同存储地方不影响对它的使用)
    3.2. 类变量在类加载时就生成了
    3.3 类变量是随着类加载而创建,所以即使没有创建对象实例也能访问

在这里插入图片描述

类变量的定义和访问

  1. 什么是类变量
    在这里插入图片描述
  2. 定义类变量的语法
    在这里插入图片描述
  3. 访问类变量
    3.1 类变量是随着类加载而创建,所以即使没有创建对象实例也能访问
    3.2 类变量的访问 必须遵守 相关访问权限(private时,类名.类变量 是访问不到类变量的)
    在这里插入图片描述

类变量使用细节

在这里插入图片描述在这里插入图片描述

类方法

类方法快速入门

  1. 定义类方法的语法
    在这里插入图片描述
  2. 类方法的调用和小例子
    在这里插入图片描述
  3. 类方法快速入门的例子 - 累计学费
    3.1 类中类变量和类方法的编写
    在这里插入图片描述
    3.2 使用
    在这里插入图片描述

类方法最佳实现

不创建实例,也能调用类的方法(方法中不涉及任何和对象相关的成员 或 通用的方法)
在这里插入图片描述在这里插入图片描述

类方法注意事项和细节

  1. 细节1-3
    在这里插入图片描述
  2. 细节4-6
    在这里插入图片描述
    在这里插入图片描述

类成员小练习

  1. 练习一
    访问类变量 访问的是同一个地址 !
    在这里插入图片描述
  2. 练习二
    类方法中不能访问非静态成员
    在这里插入图片描述
  3. 练习三
    类方法中不能用this和super
    在这里插入图片描述

理解main方法语法

main语法说明

在这里插入图片描述

main特别说明

  1. main方法中可以直接访问本类 中的静态成员直接写name,hi()
  2. main方法中不可以直接访问本类 中的非静态成员
  3. 必须创建该类的一个实例对象后,才能通过这个对象去访问类中的非静态成员
    Main01 main01 = new Main01();
    main01.cry();

在这里插入图片描述

main动态传值(在idea中传参)

前面讲的是在cmd命令行中传递参数,这里讲如何在idea中传参
在这里插入图片描述
① 第一步
在这里插入图片描述
② 第二步
在这里插入图片描述
③ 输出
在这里插入图片描述

代码块

基本介绍及语法

  1. 基本介绍
    在这里插入图片描述
  2. 基本语法
    在这里插入图片描述

代码块的好处及快速入门例子

  1. 好处(!)
    在这里插入图片描述
  2. 案例
    在这里插入图片描述

代码块使用细节

  1. 静态代码块和普通代码块 啥时被执行
  2. 静态代码块和普通代码块 执行的顺序
  3. 执行顺序的原因
  4. 综合:继承关系时静态[代码块和属性初始化]、普通、构造方法的综合调用顺序
  5. 静态代码块 只能访问静态方法和变量,普通代码块 可以访问任意
  1. 细节1-3

解读

  • 静态代码块:对类进行初始化类加载时执行只执行一次
  • 普通代码块:可以简单理解为是构造器的补充每次创建对象都会执行(与类加载无关)
  • 重点记忆:类什么时候加载(就是什么时候执行静态代码块)
  • 类加载时,父类是先加载出来的
    在这里插入图片描述
  1. 细节4

解读一个类中的调用顺序:

  • 前面老师讲类属性初始化的时候讲过属性初始化顺序是:①默认初始化,②显示初始化,③构造器初始化
  • 这里讲类中代码块和属性初始化调用的顺序
  • 先调用静态代码块和静态属性初始化(优先级相同,谁在前 就先调用谁)
    public static int num = getNum();这个getNum()也是静态方法
    {//代码块}
    ③ 则会先调用getNum方法初始化静态属性,载调用静态代码块
  • 再调用普通属性和普通代码块
  • 最后调用构造器
    在这里插入图片描述
  1. 细节5(相当于解释了一边细节4的原因)

解读调用顺序的原因分析:

  • 先调用静态代码块和静态属性初始化的原因是:它们在类加载时就执行了,所以它们是最先调用的
  • 在创建对象时会调用 构造器,构造器中隐含了 super()和调用普通代码块,所以会先调用父类构造器(父类中又会默认调用父类隐含的内容) 然后调用自己的普通代码块
    即:顺序就变成了–>父类普通代码块+父类构造器 --> 子类 普通代码块+子类构造器
    在这里插入图片描述
  • 代码演示:
    在这里插入图片描述
  1. 细节6-7(综合:继承关系时静态[代码块和属性初始化]、普通、构造方法的综合调用顺序)

解读:

  • 类加载时:静态[代码块和属性初始化] -> 先父后子
  • 构造器中:先调用隐含内容[父类构造器+普通代码] ,再调用自己的构造器
  • 所以是:
    ① 父类 普通[代码块和属性初始化] -> 父类构造器
    ② 子类 普通[代码块和属性初始化] -> 子类构造器
    在这里插入图片描述
    在这里插入图片描述

代码块小练习

  1. 练习1
    在这里插入图片描述
  2. 练习二(注意:这里没有继承关系哦)
    在这里插入图片描述

单例设计模式

设计模式的介绍

在这里插入图片描述

单例模式的介绍

在这里插入图片描述

单例模式饿汉式

叫饿汉式是因为:在类加载时就创建了单例对象,即使不使用,这个对象仍存在,显得很着急,所以叫饿汉

解读三部曲:

  1. 如果没将构造器私有化,则可以new好几个对象
    private GirlFriend(String name){---}
  2. 若构造器私有化,则不能在外部创建对象,只能在类的内部创建私有对象
    private GirlFriend gf = new GirlFriend("小红红")
  3. 外部不能访问这个私有对象
  4. 所以必须在类中提供一个公共的static方法,返回gf对象(为了能在静态方法中 返回gf对象,需要将其修饰为static)
    public static GirlFriend getInstance(){return gf;}
  5. 获取对象GirlFriend instance = GirlFriend.getInstance();

在这里插入图片描述

单例模式懒汉式

懒汉式 只有在对象使用getInstance时,才返回单例对象,后面再调用时,会返回上次创建的单例对象,从而实现单例模式

三部曲

  1. 构造器私有化
  2. 定义一个静态属性对象(定义而不赋值,在调用返回对象的方法中再赋值,这样就可以解决 饿汉式存在的问题)
  3. 提供一个public的static方法,可以返回一个对象
    在这里插入图片描述

饿汉和懒汉的小结和区别

  1. 区别
    在这里插入图片描述
    懒汉式的线程安全问题

在这里插入图片描述
2. 小结
在这里插入图片描述

final关键字

final基本介绍

在这里插入图片描述

final注意事项和细节

  1. 细节1-5
    在这里插入图片描述
  2. 细节6-9
    在这里插入图片描述

final小练习

在这里插入图片描述

抽象类

引出抽象类

在这里插入图片描述

抽象类快速入门

  1. 一般来说,抽象类会被继承,由它的子类来实现抽象方法
  2. 抽象方法没有方法体
  3. 一个类中有抽象方法,则该类一定是抽象类

在这里插入图片描述
在这里插入图片描述

抽象类的介绍

在这里插入图片描述

抽象类的细节

  1. 细节1-4
    在这里插入图片描述
  2. 细节5-7
    在这里插入图片描述
  3. 细节8
    ①. final类不能被继承,final方法也不能被重写
    ②. static 与方法重写无关
    ③. private方法访问不到
    在这里插入图片描述

抽象类小练习(易)

在这里插入图片描述
抽象类
在这里插入图片描述
实现类
在这里插入图片描述

模板设计模式–> 抽象类最佳实践

模板设计模式引出及步骤

在这里插入图片描述

引出的过程及设计模式讲解

  1. 最先想到的应该是每一个类的方法中 都写
    //得到开始时间 //完成任务代码 //得到结束时间 // 计算所用时间
    这种方法使得 重复的代码每次都要写,造成冗余
    在这里插入图片描述
  2. 所以想到将公共部分提取到一个新方法中,再和job方法进行组合
    但是 如果其它类不能使用这个新方法,还得在其它类中重复这个新方法,所以就想到了 继承抽象方法
    在这里插入图片描述
  3. 模板设计模式 把这个公共方法写到抽象类中,但是job方法现在还不知道怎么完成,所以job()定义为抽象方法让子类继承抽象类子类中实现job()这个抽象方法
    在这里插入图片描述
  4. 模板设计模式的简略结构
    在这里插入图片描述
  5. 模板设计部模式的步骤
    在这里插入图片描述

引申 for循环 快捷模板:

args.length.for 然后回车
生成:
for (int i = 0; i < args.length; i++) {
          
}

引申:获取当前时间

在这里插入图片描述

接口

接口快速入门

在这里插入图片描述

  1. 写一个接口usb
  2. 写两个类(phone和camera)实现接口
  3. 写一个类(computer)使用该接口(接口作为形参传入)

在这里插入图片描述

接口基本介绍

  1. 介绍
    在这里插入图片描述

  2. 接口中,抽象方法 可以省略abstract
    在这里插入图片描述

  3. 一个类实现 接口,就要实现接口的所有方法
    在这里插入图片描述

接口的应用场景

在这里插入图片描述
在这里插入图片描述

接口使用细节

  1. 细节1-4

① 快捷键:alt+enter 快速把要实现的方法写出来
② 接口中的方法默认是public abstract;

在这里插入图片描述
2. 细节5-9

① 一个类可以实现多个接口:
class A implement IB,IC{}
Java是单继承的,一个类只能继承一个类,但可以实现多个接口
② 接口不能继承其他类,但可以继承多个别的接口
③ 接口中的属性默认是public static final
也就是接口中属性 不能被修改,能直接用接口名访问

在这里插入图片描述

接口的小练习1

在这里插入图片描述

接口vs继承

在这里插入图片描述

  1. 形象描述

① 继承是is a的关系,小猴子继承老猴子,所以小猴子天生就会爬树(拥有全部父类属性和方法)

  • java是单继承的,小猴子不能同时继承鸟,鱼
  • 要想实现别的功能,可以通过 实现接口

② 小猴子要游泳,则要实现接口中的方法
③ 小猴子要飞翔,则要实现接口中的方法
④ 所以,接口(like a) 可以简单的看作是 对继承的一种补充

public class Excise {
    public static void main(String[] args) {
        LittleMoney littleMoney = new LittleMoney("悟空");
        //继承父类的爬树
        littleMoney.club();
        //实现Fish接口的方法
        littleMoney.swimming();
        //实现Bird接口的方法
        littleMoney.flying();
    }
}

class Money {
    private String name;

    public Money(String name) {
        this.name = name;
    }

    public void club() {
        System.out.println(name + "会爬树");
    }

    public String getName() {
        return name;
    }
}

//继承
class LittleMoney extends Money implements Fish, Bird {

    public LittleMoney(String name) {
        super(name);
    }

    //实现接口中的方法
    @Override
    public void swimming() {
        System.out.println(getName() + "通过学习,学会了游泳...");
    }

    @Override
    public void flying() {
        System.out.println(getName() + "通过学习,学会了飞翔...");
    }
}

//接口
interface Fish {
    void swimming();
}

interface Bird {
    void flying();
}
  1. 实现接口 vs 继承类
    在这里插入图片描述

接口多态特性

在这里插入图片描述

接口的多态传递

  • 如果IG 继承了IH 接口,而Teacher 类实现了 IG接口
  • 那么,实际上相当于Teacher 类也实现了IH 接口
  • 这就是接口多态传递

在这里插入图片描述

接口的小练习2

  1. 练习题
    在这里插入图片描述

  2. 修改
    在这里插入图片描述

类定义的进一步完善

在这里插入图片描述

四种内部类

基本介绍

内部类是重点,也是难点,后面看源码有很多内部类
在这里插入图片描述
类的五大成员
在这里插入图片描述

四种内部类

在这里插入图片描述
在这里插入图片描述

局部内部类

  1. 细节1-5

① 位置:方法或代码块中

  • 相当于局部变量(局部变量不能加访问修饰符)
  • 可以直接访问全局变量(包含私有的)

② 作用域:仅在定义它的方法或代码块中

  • 外部
  • 外部其他类不能访问局部内部类

③本质:本质仍是一个类

在这里插入图片描述
在这里插入图片描述
2. 细节6-7
在这里插入图片描述

匿名内部类(重要!!!)

匿名内部类的本质(基于接口)

① 这个内部类就是Outer04$1,直接在创建时写上类中的内容new 接口(){ 实现方法 }
② 就相当于new Tiger(),然后再写tiger类实现IA 接口,再写实现的方法

在这里插入图片描述
在这里插入图片描述

tiger对象接收了匿名类的地址,可以使用很多次,
但是Outer04$1这个类只能使用一次(不能再调用)

在这里插入图片描述

匿名内部类的使用(普通类、抽象类)

  1. 创建继承普通类的匿名内部类
    new Father("jack"){//内容};
    1.1 (“jack”)参数列表会传递给 构造器
  2. 创建继承抽象的匿名内部类
    new Animal(){//实现抽象类方法};
  3. 创建实现接口的匿名内部类
    new IA(){//实现接口方法};
  4. 涉及到 继承,多态,动态绑定,内部类

在这里插入图片描述

匿名内部类的细节

  1. 细节2
    在这里插入图片描述
  2. 细节3-6
    在这里插入图片描述
  3. 细节7-8
    在这里插入图片描述

匿名内部类的最佳实践

  1. 匿名内部类当作实参直接传递,简洁高效
public class Excise {
    public static void main(String[] args) {
        //匿名内部类当作实参直接传递,简洁高效
        m(new IA() {
            @Override
            public void show() {
                System.out.println("匿名内部类中重写接口的show方法");
            }
        });
        //传统方法
        Picture picture = new Picture();
        m(picture);
    }
    //静态方法,形参是接口类型
    public static void m(IA ia){
        ia.show();
    }
}

//接口
interface IA{
    void show();
}
//传统方法-类-->实现接口 => 在编程领域称为硬编码
class Picture implements IA{

    @Override
    public void show() {
        System.out.println("传统方法重写接口的show方法");
    }
}

小练习

在这里插入图片描述

public class Excise {
    public static void main(String[] args) {
        CellPhone cellPhone = new CellPhone();
        cellPhone.alarm(new Bell() {
            @Override
            public void ring() {
                System.out.println("小懒猪起床了");
            }
        });
        cellPhone.alarm(new Bell() {
            @Override
            public void ring() {
                System.out.println("小伙伴上课了");
            }
        });
    }
}

interface Bell{
    void ring();
}

class CellPhone{
    public void alarm(Bell bell){
        bell.ring();
    }
}

成员内部类

  1. 细节1-2
    在这里插入图片描述
  2. 细节3-6

访问外部类成员,比如属性name,则new Outer().name
对于成员内部类也是一样的new Outer().new Inner();
普通成员不能通过类名直接访问,得先创建外部类对象,再通过外部类对象创建成员内部类对象当然是不能写成new new Outer().Inner()
在这里插入图片描述
外部其他类访问成员内部类的两种方法
在这里插入图片描述

  1. 细节7
    在这里插入图片描述

静态内部类

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

本章作业

作业1(static)

在这里插入图片描述

作业2(题意->代码(静态属性))

在这里插入图片描述

/**
 * @author 王胖子
 * @version 1.0
 */
public class Excise {
    public static void main(String[] args) {
        System.out.println(Frock.getNextNum());//100100
        System.out.println(Frock.getNextNum());//100200
        Frock frock1 = new Frock();
        Frock frock2 = new Frock();
        Frock frock3 = new Frock();
        System.out.println(frock1.getSeriaNumber());//100300
        System.out.println(frock2.getSeriaNumber());//100400
        System.out.println(frock3.getSeriaNumber());//100500
    }
}

class Frock {
    private static int currentNum = 100000;//出场序列号的起始值
    private int seriaNumber;

    public Frock() {
        this.seriaNumber = getNextNum();
    }

    public static int getNextNum() {//生成上衣唯一序列号的方法
        currentNum += 100;
        return currentNum;
    }

    public int getSeriaNumber() {
        return seriaNumber;
    }
}

作业3(匿名内部类作为参数)

在这里插入图片描述

匿名内部类最经典的用法就是作为参数

  1. 普通传参方法:先创建一个实现了ICalculate接口的类,再创建该类的对象,把该对象作为参数传入test方法中
  2. 匿名内部类方法:直接传入一个实现了ICalculate接口的匿名内部类即可
    该匿名内部类可以灵活的实现work,完成不同的计算任务
/**
 * @author 王胖子
 * @version 1.0
 */
public class Excise {
    public static void main(String[] args) {
        //匿名内部类省去了 创建类实现接口效率低的麻烦
        /*
            匿名内部类是实现了接口的类,同时也是一个对象
            编译类型是ICalculate(),运行类型是匿名内部类
            new ICalculate() {
            @Override
            public double work(double n1, double n2) {
                return n1 +n2;
            }
         */
        CellPhone cellPhone = new CellPhone();
        cellPhone.testWork(new ICalculate() {
            @Override
            public double work(double n1, double n2) {
                return n1 + n2;
            }
        }, 10, 20);
    }
}

//接口类
interface ICalculate {
    //完成计算(用匿名内部类来实现)
    public double work(double n1, double n2);
}

class CellPhone {
    //解读:
    //普通传参方法:先创建一个实现了ICalculate接口的类,再创建该类的对象,把该对象作为参数传入test方法中
    //匿名内部类方法:直接传入一个实现了ICalculate接口的匿名内部类即可
    //该匿名内部类可以灵活的实现work,完成不同的计算任务
    public void testWork(ICalculate iCalculate, double n1, double n2) {
        double result = iCalculate.work(n1, n2);//动态绑定运行类型(上面的匿名内部类)
        System.out.println("计算后的结果是 = " + result);
    }
}

作业4(局部内部类的使用)

/**
 * @author 王胖子
 * @version 1.0
 */
public class Excise {
    public static void main(String[] args) {
        A a = new A();
        a.method();
    }
}

class A {
    private String NAME = "小瘦子";

    public void method() {
        //局部内部类定义在方法或代码块中
        //使用:在类中创建内部类对象,调用内部类方法
        //可以直接访问外部类内容(包括私有的)
        //当内部类和外部类的属性重名时 可以通过外部类.this.属性名来访问外部类属性
        class B {
            private final String NAME = "小胖子";

            void show() {
                System.out.println("B类中的NAME = " + NAME + "\n" + "A类中的name = " + A.this.NAME);
            }
        }
        B b = new B();
        b.show();
    }
}

作业5(工厂类)

在这里插入图片描述

/**
 * @author 王胖子
 * @version 1.0
 */
public class Excise {
    public static void main(String[] args) {
        Person person = new Person("唐僧", new Horse());
        person.common();
        person.passRiver();
        person.passRiver();
    }
}

//抽象产品接口
interface Vehicles {
    public void work();
}

//具体产品类
class Horse implements Vehicles {
    @Override
    public void work() {
        System.out.println("一般情况,用马走");
    }
}

class Boat implements Vehicles {
    @Override
    public void work() {
        System.out.println("过河时,用船走");
    }
}

//工厂类
class Factory {
    //方法定义为静态
    //马只有一匹,用单例设计模式-饿汉式
    private Horse horse = new Horse();

    private Factory() {
    }

    public static Vehicles getHorse() {
        return new Horse();
    }

    public static Vehicles getBoat() {
        return new Boat();
    }
}

//人(整合)
class Person {
    private String name;
    private Vehicles vehicles;

    public Person(String name, Vehicles vehicles) {
        this.name = name;
        this.vehicles = vehicles;
    }

    public void common() {
        //如果vehicles的运行类型不是Horse,则用工厂类返回一个马对象
        if (!(vehicles instanceof Horse)) {
            vehicles = Factory.getHorse();
        }
        vehicles.work();
    }

    public void passRiver() {
        //如果vehicles的运行类型不是Boat,则用工厂类返回一个船对象
        if (!(vehicles instanceof Boat)) {
            vehicles = Factory.getBoat();
        }
        vehicles.work();
    }
}

作业6(成员内部类)

  1. 类与成员内部类 体现类与类的包含关系
  2. 成员内部类 在外部其他类中使用可以调用外部类中的get方法获取内部类的对象
    public Air getAir() {
    return new Air();
    }

在这里插入图片描述

/**
 * @author 王胖子
 * @version 1.0
 */
public class Excise {
    public static void main(String[] args) {
        //实例化不同的car对象
        Car car = new Car(26);
        car.getAir().flow();
        Car car1 = new Car(41);
        car1.getAir().flow();
        Car car2 = new Car(41);
        car2.getAir().flow();
    }
}

class Car {
    private double template;

    public Car(double template) {
        this.template = template;
    }

    //air 成员内部类
    class Air {
        public void flow() {
            if (template > 40) {
                System.out.println("温度大于40,吹冷风");
            } else if (template < 0) {
                System.out.println("温度小于0,吹热风");
            } else {
                System.out.println("温度正常,关闭空调");
            }
        }
    }

    public Air getAir() {
        return new Air();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值