IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> javaSE基础复习之面向对象(多态,内部类,内存回收) -> 正文阅读

[Java知识库]javaSE基础复习之面向对象(多态,内部类,内存回收)

课程笔记Day11

  • 多态
  • 内部类
  • 内存回收

第一章 多态

第01节 基础理论

回顾前面的知识点

面向对象三要素:
	(1)封装
	(2)继承
	(3)多态

什么是多态?

小诗:苏轼的诗 "横看成岭侧成峰,远近高低各不同。不识庐山真面目,只缘身在此山中。"  --- 《题西林壁》
你站在不同的视角,可以得到不同的结果。 本质是一样的。

生活实例: 水 H2O 三种不同的状态: 冰、水蒸气

现在有一个类
	class Pig extends Animal{ ... }

//创建对象1:
Pig one = new Pig();   //猪是猪
//创建地下2:
Animal two = new Pig(); //猪是动物  is a

多态的前提条件

(1)父子关系  继承或者实现关系
(2)方法重写
(3)左父右子  父类引用指向子类对象  Animal two = new Pig();

第02节 快速入门

案例代码

父类

//多态快速入门 父类
public class FuLei {
    String name = "王健林";
    int ageFu = 60;

    public void say(){
        System.out.println("给你一个小目标");
    }
    public void methodFu(){
        System.out.println("我是BABA");
    }
}

子类

//多态快速入门 子类
public class ZiLei extends FuLei{
    String name = "王思聪";
    int ageZi = 30;

    public void say(){
        System.out.println("你们都没我有钱");
    }
    public void methodZi(){
        System.out.println("我是儿子");
    }
}

测试类

//测试类
public class Test {

    public static void main(String[] args) {

        //采用多态的形式创建对象。左父右子
        FuLei ooo = new ZiLei();

        //调用成员变量
        System.out.println(ooo.ageFu);  //60
        //System.out.println(ooo.ageZi);  //报错了
        System.out.println(ooo.name);   //王健林
        //成员变量的结论1: 看等号左边是谁,则优先使用谁,没有则向上找
        //成员变量的结论2: 编译看左边,运行看左边
        System.out.println("=======");
        //调用成员方法
        ooo.methodFu();  //我是BABA
        //ooo.methodZi();  //报错了
        ooo.say();  //你们都没我有钱
        //成员方法的结论1: 看等号右边是谁,则优先使用谁,没有则向上找
        //成员方法的结论2: 编译看左边,运行看右边。
    }
}

//多态的缺点: 无法访问子类特有的成员(成员变量和成员方法)

效果图

在这里插入图片描述

第03节 两种转型

基础理论

1. 向上转型
	A. 含义: 将子类对象看做父类的对象(儿子看做父亲)
	B. 举例: Animal aa = new Pig();  //猪是动物
	
2. 向下转型
	A. 含义: 将父类对象看做儿子的对象(父亲看做儿子)
	B. 举例: Pig  pp = (Pig)aa;   //动物是猪
	C. 应用: 多态的缺点是无法访问子类特有的成员,就需要使用向下转型,得到子类对象,再去调用特有成员

注意事项

在向下转型的过程当中,需要注意异常: ClassCastException 类型转换异常。
解释: 在向上转型的过程当中,原本是什么类型,转换的时候,就要变成什么类型,不要变成他的兄弟。

效果图

在这里插入图片描述

如何解决问题?

解决类型转换异常的问题 ClassCastException

//判断当前的对象 是否来自于 类
if(对象名称  instanceof  类名称){
    //向下转型的代码...
    //调用子类特有成员的代码...
}

举例说明

//判断 对象ooo 他的类型是否是 来自于 Brother 类
if(ooo instanceof Brother){
    //进行向下转型
    Brother bbb = (Brother) ooo;  
    //调用子类特有的成员
    System.out.println(bbb.ageZi);
    bbb.methodBro();
}

第04节 指鹿为马

案例代码

动物接口

//动物接口
public interface Animal {
    //吃
    public abstract void eat();
}

马类

//马类
public class Ma implements Animal{
    @Override
    public void eat() {
        System.out.println("马吃草...");
    }
    public void pao(){
        System.out.println("马儿跑.");
    }
}

鹿类

//鹿类
public class Lu implements Animal{
    @Override
    public void eat() {
        System.out.println("鹿吃艹");
    }
    public void tiao(){
        System.out.println("鹿儿跳.");
    }
}

测试类

//测试类
public class Test {

    public static void main(String[] args) {
        //创建对象
        Ma make = new Ma();
        use(make);
        //直接调用方法(匿名对象的写法)
        use(new Lu());
    }

    // 一个方法,既可以接收马的对象, 又可以接收鹿的对象
    // 这个方法的参数应该怎么写呢?
    // 这里就可以写 父类或者是父接口,采用多态传参
    public static void use(Animal aa){ //Animal aa  = new Ma();
        //调用方法【共性方法父亲调用】
        aa.eat();
        //调用方法【如果想要访问特有的,应该向下转型】
        //如果说 aa对象来自于 Ma类。 则向下转型成为Ma
        if (aa instanceof Ma){
            //向下转型
            Ma make = (Ma) aa;
            //调用子类特有方法
            make.pao();
        }
        //再次判断 如果说 aa对象来自于 Lu类。
        if (aa instanceof Lu){
            //向下转型
            Lu luhan = (Lu) aa;
            //调用子类特有方法
            luhan.tiao();
        }
    }
}

第05节 优点缺点

优点

1. 提高代码的扩展性
	解释: 如果说,我们将方法的参数定义为 父类或者是父接口。那么就可以传递 子类或者实现类。
	以前的写法是 每一个子类都需要作为方法的参数,可能写很多的方法。
	
2. 提高代码的复用性
	解释:根据多态的前提条件,有父子关系。在继承的优点当中,就是提高代码的复用性。
	我们将共性的代码交给父类。共性的方法交给父接口,这类写法,可以提高复用性。
	父亲里面定义一份,多个儿子都可以使用。

缺点

无法访问子类 特有的成员(成员变量和成员方法)
如果想要访问,则需要判断和转型

第二章 内部类

第01节 基础理论

什么是内部类呢?

内部类就是说在一个类大括号里面,包含着另外一个类。
注意: 这里的包含关系,不是继承关系。(继承关系存在 is A 关系,子类可以看做父类)

生活实例:
	身体和心脏的关系,就是一种包含关系。 在身体里面包含的有心脏。

内部类的分类有哪些?

(1)成员内部类。独立的分支:静态成员内部类
(2)局部内部类。独立的分支:匿名内部类

内部类的应用场景?什么时候会使用内部类

以前在学习 界面编程当中,有点击事件。(JavaScript 讲过点击的效果) 这里就会使用到内部类。
在 Android 编程当中使用较多。
有些 Java底层源代码当中,会使用到内部类。

第02节 成员内部类

位置

在一个类的成员变量或者成员方法的地方,编写类。(类当中,方法外)

代码

外部类和内部类

//身体(外部类)
public class Body {

    String name = "身体";
    private int age = 18;

    public void exercise(){
        System.out.println("身体成员方法...锻炼");
    }

    //-------------------
    class Heart{
        String name = "心脏";
        public void jump(){
            System.out.println("心脏跳...蹦蹦蹦..");
        }
        public void show(){
            String name = "嘿嘿嘿";
            System.out.println(name);  //嘿嘿嘿
            System.out.println(this.name); //心脏
            System.out.println(Body.this.name); //身体
            System.out.println(Body.this.age);  //18
        }
    }
    //-------------------
}

测试类

//测试类
public class Test {

    public static void main(String[] args) {

        //如果想要创建,内部类的对象,应该怎么使用呢?
        //公式是: 外.内
        Body.Heart  bh = new Body().new Heart();
        //调用成员变量和成员方法
        System.out.println(bh.name); //心脏
        bh.jump();  //心脏跳...蹦蹦蹦..
        System.out.println("--------");
        bh.show();

    }
}

第03节 静态成员内部类

理论

1. 位置: 类中方法外的类。保证他是一个成员内部类
2. 添加 static 关键字。
3. 效果: 可以直接使用类名称打点调用

代码

外部类和内部类

//外部类
@SuppressWarnings("all")
public class Outer {

    //静态变量
    static String name = "外部类";

    //内部类:静态内部类
    static class Inner {
        String name = "内部类";

        public void inNoStatic() {
            System.out.println("内部类...非静态方法");
        }

        public static void inYesStatic() {
            System.out.println("内部类...静态方法");
        }
    }
}

测试类

public class Test {

    public static void main(String[] args) {

        //创建对象。访问非静态方法
        Outer.Inner one = new Outer.Inner();
        //调用方法
        one.inNoStatic();  //内部类...非静态方法

        //如果想要调用静态内部类当中的静态方法。
        Outer.Inner.inYesStatic(); //内部类...静态方法
    }
}

第04节 局部内部类

理论

什么是局部内部类啊?

1. 位置:
	定义在方法当中的类,叫做局部内部类。

2. 范围:
	只能在方法里面使用,出了方法,无法使用。

代码

外部类和内部类

//外部类:演示局部内部类
@SuppressWarnings("all")
public class Outer {

    String name = "外部类";

    //成员方法
    public void show() {
        //局部变量
        int age = 18;
        //打印输出
        System.out.println(age);
    }

    //成员方法
    public void method() {
        //-------------------
        class Inner {
            String name = "内部类";

            public void say() {
                System.out.println("我是局部内部类成员方法");
            }
        }
        //-------------------
        //创建对象
        Inner iii = new Inner();
        iii.say();
    }
}

测试类

//测试类
public class Test {

    public static void main(String[] args) {

        //只能创建外部类的对象
        Outer ooo = new Outer();
        //调用方法
        ooo.method();
    }
}

面试问题

在这里插入图片描述

第05节 匿名内部类

理论

1. 介绍:
	匿名内部类指的是没有名字的内部类,他是局部内部类的一种。

2. 写法:
	new 类名称/接口名称(参数){
		//...方法...
	};

由来

动物的接口

//动物的接口
@SuppressWarnings("all")
public interface Animal {
    //吃的方法
    public abstract void eat();
}

实现类

//实现类
@SuppressWarnings("all")
public class Dog implements Animal {
    @Override
    public void eat() {
        System.out.println("狗吃SHI");
    }
}

测试类

//测试类
public class Test {

    //思考问题:我们能不能省略 实现类(Dog) 不写呢?
    public static void main(String[] args) {
        //版本1:原始的用法,创建实现类的对象,去调用方法
        Dog one = new Dog();
        one.eat();  //狗吃SHI

        System.out.println("---------");

        //版本2: 多态的写法,左父右子
        Animal two = new Dog();
        two.eat(); //狗吃SHI

        System.out.println("--------");

        //版本3: 匿名内部类的写法
        Animal three = new Animal() {
            @Override
            public void eat() {
                System.out.println("狗吃SHISHI");
            }
        };
        three.eat();
    }
}

应用场景

如果方法的参数写的是接口,传递的是接口的实现类。(匿名内部类他也是接口的实现类)

拓展点:反编译的指令 javap 类名称.class

在这里插入图片描述

接口代码

//定义接口
public interface Usb {

    //定义抽象方法: 连接
    public abstract void connect();
}

测试类

public class Test {

    public static void main(String[] args) {
        //直接调用方法
        useUsb(new Usb() {
            @Override
            public void connect() {
                System.out.println("连接电脑");
            }
        });
    }

    //定义一个使用USB接口的方法
    public static void useUsb(Usb sb){
        //调用方法
        sb.connect();
    }
}

//小结:
//如果我们方法的参数写的是接口或者是类
//那么传递参数的时候,写的是实现类或者是子类。(也可以是匿名内部类)
//本质上面来说,匿名内部类就是子类或者实现类。 也就是多态的用法
//反编译操作: javap  类名称.class

第三章 内存回收

第01节 内存管理

内存划分图区域

在这里插入图片描述

五个区域介绍

1、程序计数器

1. 较小
    程序计数器是一块较小的内存空间,它的作用是当前线程执行指向字节码的行号指示器。
    简单一点说,就是指挥程序执行那一条指令。(分支、循环、跳转、异常)
    
2. 线程私有
    Java虚拟机的执行,是由多条线程轮流切换处理器的时间来执行,
    在任何一个时刻当中,一个处理器只会执行一条指令。
    那么每个线程,都会存在一个独立的程序计数器,各个线程之间的程序计数器,不会受到影响的,独立存储。

3. 无异常
    如果线程正在执行的是一个 Java的方法,这个计数器记录的是正在执行的虚拟机字节码地址。
    如果正在执行的是 Native 形式的方法,则计数器的值记录为空 Undefined
    此时此刻内存区域是唯一一个在 Java规范当中没有任何的 OutOfMemoryError 情况区域。

2、虚拟机栈

1. 线程私有
    与程序计数器一样,Java虚拟机栈也是线程私有的,他的生命周期与线程相同。

2. 描述Java方法执行的内存模型
    每个方法被执行的时候,都会同时创建一个栈帧(Stack Frame 栈帧是方法运行时的基础数据结构)
    用于存储局部变量表、操作栈、动态链接、方法出口灯信息。
    每个方法被调用直到执行完毕的整个过程,都会对应一个栈帧在虚拟机栈,从入栈到出栈的过程。

3. 异常
    在Java虚拟机当中,规定了下面的两种异常情况。
    【1】StackOverflowError   JVM规定了栈的最大深度,如果执行方法超过最大深度,则出现栈溢出
    【2】OutOfMemoryError     JVM在扩展时候,无法申请到足够的内存,则出现内存溢出

3、本地方法栈

1. 为 native 服务
    虚拟机栈是为 Java服务的
    本地方法栈是为 native 方法服务的(native方法底层是C\C++调用的是操作系统底层,例如声卡)

2. 异常
    与虚拟机栈一样,本地方法栈也会抛出 StackOverflowError 和 OutOfMemoryError

4、Java堆

1. 最大
    对于大多数应用来说,Java堆是 Java虚拟机管理的内存当中,最大的一块

2. 线程共享
    Java堆是被所有线程共享的一块内存区域,在虚拟机启动的时候创建

3. 存放实例
    堆区域,唯一的目的就是存放对象的实例,几乎所有的对象实例,都是在这里分配。
    另外说明:在Java虚拟机规范当中描述,所有的对象和数组都是在堆上面分配,
    但是随着JIT编译器发展,在堆上分配的方式,渐渐地已经不再是那么的绝对了。
    
4. GC
    Java堆是垃圾收集器管理的主要区域。
    如果从内存的回收的角度来看,现在收集器采用的是分代收集算法。在 Java的堆当中,细分为 新生代和老年代。
    如果从内存分配的角度来看,线程共享的Java堆可以划分多个线程私有分配缓冲区。
    不过,无论如何划分,都与存放内容无关,无论哪个区域,存储的都依然是对象实例。
    进一步的划分,目的只是为了更好的回收内存,或者更快的分配内存。

5、方法区

方法区,存储的是已经被虚拟机加载的数据,他有以下三个特点:
    1. 线程共享。 方法区和Java堆一样,也是被各个线程共享的内存区域
    2. 存储数据类型。 类信息、常量、静态变量、即时编译器编译后的代码
    3. 异常。  如果系统定义太多的类,导致方法区溢出,虚拟机同样会出现内存溢出溢出 OutOfMemeryError

方法区,又可以划分成为两个区域:
    1. 运行时常量池。
        存储的是编译期间生产的各类字面量和符号引用,这部分内容加载后会进入方法运行时常量池存放。
        运行时常量池,受到方法区内存限制,当常量池无法申请到内存空间的时候,则出现 OutOfMemeryError
    2. 直接内存, 存在以下四个特点
        A. 在虚拟机外的数据 (说明:直接内存,不是虚拟机当中的内容,而是虚拟机之外的内存)
        B. 直接分配 (说明:在JDK1.4之后的NIO,引入通道 Channel 缓冲区Buffer,可以操作直接内存)
        C. 受到设备内存大小限制 (说明:受到设备总大小限制,而不是Java堆大小限制)
        D. 异常(说明:如果超过内存容量,也会出现 OutOfMemeryError)

第02节 垃圾回收

基础理论

对于 Java 而言,好处: 系统帮我们去控制垃圾回收的。(系统自动完成的,不由程序员控制)
对于 C++ 而言,不是这样的,他的垃圾需要手动清理。(程序员自己去控制)

一个对象生命周期

1. 刚刚出世的阶段
2. 青年期
3. 老年期

配图

在这里插入图片描述

标记清除算法
在这里插入图片描述

说明

生活实例:
    相当于先把货架上面的货物,标记记录下来,(有人买的、没人买的、空着的商品和位置记录)
    然后再把没人买的商品统一的进行下架处理,这是垃圾收集器的 早期策略

工作原理:
    1. 标记所有需要回收的对象
    2. 标记完毕后,统一回收所有标记的对象

缺点:
    1. 效率低:
        标记和清除的效率都不高
    2. 内存碎片:
        标记清除后,会产生大量的不连续的内存碎片。
        导致程序需要分配较大对象时,无法找到足够连续空间,不得不提前触发GC垃圾收集器

复制算法

在这里插入图片描述

说明

目的:
    为了解决效率的问题,复制(copying)收集算法就出现了

工作原理:
    1. 将内存按照容量大小,划分成为大小相同的两个区域。(例如A区域和B区域)
    2. 每次使用A区域的时候,B区域空闲。
    3. 当A区域使用完毕之后,将存活的对象,复制到B区域当中,一次性清理掉A区域的内容。
    4. 这样的操作,每次都是回收半块内存,内存分配过程当中,无需考虑内存碎片的问题。

优点:
    1. 每次针对于半个内存区域进行内存的回收。
    2. 分配内存的过程当中不需要考虑内存碎片的复杂情况,只需要移动堆顶指针,按照顺序分配内存即可。

缺点:
    1. 浪费空间。把内存缩小一半用,太浪费空间。
    2. 有时候效率低。在对象存活率高的时候,需要进行较多的复杂操作,这时候,效率就低了。

标记整理算法

在这里插入图片描述

说明

目的:
    在复制算法当中,如果不想浪费 50% 的空间,就需要有额外的空间进行分配担保。
    以应对被使用内存当中,所有对象都存活的低端情况,所以养老区不能用这种算法。

工作原理:
    1. 标记所有需要存活的对象
    2. 标记完毕后,统一让存活的对象向一端移动 
    3. 直接清理掉边界外的内存

分代收集算法

4、分代收集算法

说明

目的:
    现代的商业虚拟机,垃圾回收都是采用分代收集算法。
    这种算法会根据对象存活周期的不同,将内存划分成为几块,根据各个区域的特点采用最合适的收集算法。

分代收集内存划分:
    1. 新生代 Young Generation Space  ----> YGC
        别称:也叫做新生区
        特点:每次垃圾收集都会有大批量的对象死去,只有少量的存活。
        算法:采用的是复制算法。
    2. 老年代 Tenure Generation Space
        别称:也叫做养老区
        特点:因为对象的存活率高,没有额外的空间进行担保。
        算法:标记清除算法 和 标记整理算法进行回收
    3. 持久代  Permanent Space
        别称:也叫做永久存储区
        特点:存储静态文件,例如 Java类、方法等。持久代对垃圾回收没有显著的影响。

在这里插入图片描述

小结:老年代过程说明

1、在年轻代中经历了N次垃圾回收后仍然存活的对象,就会被放到年老代中。

2、老年代的内存比新生代也大很多(大概比例是1:2)

3、老年代内存满时,触发Major GC即Full GC 但是频率会比较低

今日学习小结:

今天学习了java中很重要的东西之一多态

就是水的三种状态,固态,液态,气态
优点:多态的好处,体现在,可以使程序编写的更简单,并有良好的扩展。
缺点:无法访问子类 特有的成员(成员变量和成员方法),如果想要访问,则需要判断和转型

今天学习了java中很重要的东西之一匿名内部类

内部类
重点:匿名内部类
匿名内部类:是内部类的简化写法,它的本质是一个 带具体实现的 父类或者父接口的 匿名的 子类对象
开发中,最常用到的内部类就是匿名内部类了。以接口举例,当你使用一个接口时,似乎得做如下几步操作,

  1. 定义子类
  2. 重写接口中的方法
  3. 创建子类对象
  4. 调用重写后的方法
    我们的目的,最终只是为了调用方法,那么能不能简化一下,把以上四步合成一步呢?匿名内部类就是做这样的快捷方式。
    前提:存在一个类或者接口,这里的类可以是具体类也可以是抽象类
    格式:
new 父类名或者接口名(){ 
	// 方法重写 
	@Override 
	public void 方法名() { 
		// 执行语句 
	} 
};

动物的接口

//动物的接口
@SuppressWarnings("all")
public interface Animal {
    //吃的方法
    public abstract void eat();
}

测试类

//测试类
public class Test {

    //思考问题:我们能不能省略 实现类(Dog) 不写呢?
    public static void main(String[] args) {
        //版本1:原始的用法,创建实现类的对象,去调用方法
        Dog one = new Dog();
        one.eat();  //狗吃SHI

        System.out.println("---------");

        //版本2: 多态的写法,左父右子
        Animal two = new Dog();
        two.eat(); //狗吃SHI

        System.out.println("--------");

        //版本3: 匿名内部类的写法
        Animal three = new Animal() {
            @Override
            public void eat() {
                System.out.println("狗吃SHISHI");
            }
        };
        three.eat();
    }
}
  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-07-27 16:04:44  更:2021-07-27 16:05:33 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/3 15:17:14-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码