《Java核心技术(高级)》

本文内容为学习笔记,用于个人知识点总结、复习。
原教学视频出自:中国大学MOOC网 |《Java核心技术(高阶)》 ——陈良育

第一章 Java语法糖

第一节 语法糖和环境设置

第二节 语法糖(1)for-each和枚举

  • for vs for-each


    语法糖(for-each).png

    1.for-each从JDK5.0引入
    2.for-each语法更简洁
    3.for-each避免越界错误
    4.for可以删除元素,for-each不可以删除/替换元素
    5.for-each便利的时候,不知道当前元素的具体位置索引
    6.for-each只能正向遍历,不能反向遍历
    7.for-each不能同时遍历2个集合
    8.for和for-each性能接近

  • 枚举


    语法糖(枚举1).png

    语法糖(枚举2).png
  • Java的enum类型
    1.所有的enum类型都是Enum的子类,也继承了相应方法
    2.ordinal()返回枚举值所在的索引位置,从0开始
    3.compareTo()比较两个枚举值的索引位置大小
    4.同String()返回枚举值的字符串表示
    5.valueOf()将字符串初始化为枚举对象
    6.values()返回所有的枚举值

第三节 语法糖(2)不定项参数和静态导入

  • 不定项参数


    语法糖(不定项参数).png

    1.一个方法只能有一个不定项参数,且必须位于参数列表的最后
    2.重载的优先级规则:
    - 固定参数的方法优先级大于可变参数
    - 调用语句,同时与两个带可变参数的方法匹配,则报错

  • 静态导入


    语法糖(静态导入1).png
语法糖(静态导入2).png

第四节 语法糖(3)自动拆箱和装箱、多异常并列、数值类型赋值优化

  • 自动装箱与拆箱


    语法糖(自动装箱与拆箱1).png

    语法糖(自动装箱与拆箱2).png

    1.装箱和拆箱是编译器的工作,在class中已经添加转化。虚拟机没有自动装箱和拆箱的语句
    2.==:基本类型是内容相同,对象是地址相同
    3.基本类型没有空值,对象有null,可能触发NullPointerException
    4.当一个基础数据类型与封装类进行运算时,会自动拆箱
    5.谨慎使用多个非同类的数值类对象进行运算

  • 多异常并列


    语法糖(多异常并列1).png

    语法糖(多异常并列2).png
  • 数值类型赋值优化
    1.整数类型用二进制数赋值
    2.数字中的下划线

语法糖(整数类型用二进制数赋值).png

语法糖(数字中的下划线).png

第五节 语法糖(4)接口方法

第六节 语法糖(5)try-with-resource和Resource Bundle文件加载

  • try-with-resource


    语法糖(try-with-resource1).png
  • ResourceBundle文件加载
    1.Java8以前,需要用native2ascii工具对文件转义
    2.JDK9后,ResourceBundle默认以UTF-8方式加载Properties文件,删除native2ascii工具u,Properties文件可以直接以UTF-8保存


    语法糖(try-with-resource2).png

第七节 语法糖(6)var类型和switch

  • var


    语法糖(var1).png

    1.可以用在局部变量上,非类成员变量
    2.可以用在for/for-each循环中,可用于三元操作符,对继承有效
    3.声明时必须初始化
    4.不能用在形参和返回类型
    5.大面积运用会使代码整体阅读性变差
    6.var指在编译时起作用,没有在字节码中引入新的内容,也没有专门的JVM指令处理var

  • switch


    语法糖(switch1).png
语法糖(switch2).png
语法糖(switch3).png

第二章 Java泛型

第一节 泛型入门

  • 泛型的本质:参数化类型,避免类型转换,代码可复用
    泛型分类.png

    泛型(ArrayList源码).png

第三章 Java反射

第一节 反射入门

  • 反射:reflection
    1.程序可以访问、检测和修改它本身状态或行为的能力,即自描述和自控制
    2.可以在运行时加载、探知和使用编译期间完全未知的类
    3.给Java插上动态语言特性的翅膀,弥补强类型语言的不足
    4.java.lang.reflect包
  • 反射的应用
    1.在运行中分析类的能力
    2.在运行中查看和操作对象
    - 基于反射自由创建对象
    - 反射构建出无法直接访问的类
    - set或者get到无法访问的成员变量
    - 调用不可访问的方法
    3.实现通用的数组操作代码
    4.类似函数指针的功能


    创建对象方法(1).png
创建对象方法(2).png
创建对象方法(3).png
创建对象方法(45).png

第四章 Java代理

第一节 代理模式和静态代理

  • 代理模式


    代理示意图.png
  • 为目标对象提供(包装)了一个代理,这个代理可以控制对目标对象的访问
    1.外界不用直接访问目标对象,而是访问代理对象,由代理对象再调用目标对象
    2.代理对象中可以添加监控和审查处理

  • 静态代理
    1.代理对象持有目标对象的句柄
    2.所有调用目标对象的方法,都吊用代理对象的方法
    3.对每个方法,需要静态编码


    静态代理示意图.png

    静态代理代理类代码.png

第二节 动态代理

  • 动态代理


    动态代理示意图.png

    动态代理流程图.png

    动态代理代理处理器类代码.png

    动态代理主类代码.png

    动态代理(实现多接口)主类代码.png

第五章 Java注解

第一节 注解入门

  • 注解示例


    压制警告注解示例.png

    重写方法标记注解示例.png
  • 注解
    1.JDK1.5引入
    2.位于源码中(代码/注释/注解),使用其他工具进行处理的标签
    3.注解用来修饰程序的元素,但不会对被修饰的对象有直接的影响
    4.只有通过某种配套工具才会对注解信息进行访问和处理
  • 注解用途
    1.提供信息给编译器/IDE工具
    2.可用于其他工具来产生额外的代码/配置文件等
    3.有一些注解可在程序运行时访问,增加程序的动态性


    注解(普通)示例.png

    注解(元)示例.png

第六章 嵌套类

第一节 嵌套类入门

  • 嵌套类:嵌套,一个类定义在别的类内部
    1.静态嵌套类:即类前面有static修饰符
    2.非静态嵌套类(内部类)
    - 普通内部类(成员内部类)
    - 局部内部类
    - 匿名内部类


    静态嵌套类.png

    普通内部类.png

    局部内部类.png

    匿名内部类.png
  • 嵌套类优缺点
    1.不同的访问权限要求,更细粒度的访问控制
    2.简洁,避免过多的类定义
    3.语言设计过于复杂,较难学习和使用

第七章 Lambda表达式

第一节 Lambda表达式入门

  • 示例


    字符串数组排序(一般方法).png

    字符串数组排序(Lambda方法).png
  • Lambda表达式
    1.类似于匿名方法
    2.参数,箭头,表达式语句
    3.可以忽略写参数类型
    4.坚决不声明返回值类型
    5.没有public/private/static/final等修饰符
    6.单句表达式将直接返回值,不用大括号
    7.带return语句,算多句,必须用大括号
Lambda表达式(12).png
Lambda表达式(3).png
Lambda表达式(4).png
Lambda表达式(5).png

第八章 Java Stream流

第一节 流的概述

  • 示例


    字符串数组筛选统计(一般方法).png

    字符串数组筛选统计(流方法).png
  • Stream语法


    Stream语法示例.png

第九章 Java模块化

第一节 Java模块化概述

  • 现状:以Jar为中心
    1.jar文件无法控制别人访问其内部的public的类
    2.无法控制不同jar包中,相同的类名(包名+类名)
    3.Java运行时,无法判定classpath路径上的jar中有多少个不同版本文件。Java加载第一个符合名字的类
    4.Java运行时,无法预判classpath路径上是否缺失了一些关键类
  • 模块化三原则
    1.强封装性:能对其他模块隐藏部分代码
    2.定义接口良好:模块必须向其他模块公开定义良好且稳定的接口
    3.显示依赖:明确一个模块需要哪些模块的支持才能完成工作
  • 模块化系统:Jigsaw拼图
    1.以模块为中心
    2.对JDK本身进行模块化
    3.提供一个应用程序可以使用的模块系统
    4.优点
    - 可靠的配置
    - 强封装性
    - 可扩展开发
    - 安全性
    - 性能优化

第十章 Java字节码

第一节 字节码概述

  • Java开发过程


    Java开发过程.png
  • .class文件:字节码(bytecode)文件
    1.class文件是Java“一次编译,到处运行”的基础
    2.class文件具备平台无关性,有JVM执行
    3.每个class文件包含一个类或接口或模块的定义
    4.class文件是一个二进制文件,有JVM定义class文件的规范
    5.任何满足这种规范的class文件都会被JVM加载运行
    6.class文件可以由其他语言编译生成,甚至不用程序语言直接生成
    7.JDK版本不同,所编译出.class文件略有不同


    Java字节码跨平台示意图.png

第十一章 Java类加载器

第一节 Java类加载机制

  • 类加载过程
    1.程序是依靠多个Java类共同协作完成的
    2.JVM一句classpath执行的类库的顺序来查找类
    3.潜在的问题
    - 如何找到正确的类,如classpath路径的前后
    - 如何避免恶意的类,如一个假的String类
    - 加载的顺序,如先加载父类,还是子类
  • 类加载器ClassLoader
    1.负责查找、加载、校验字节码的应用程序
    2.java.lang.ClassLoader
    - load(String className)根据名字加载一个类,返回类的实例
    - defineClass(String name,bute【】 b,int off,int len)将一个字节流定义一个类
    - findClass(String name)查找一个类
    - findLoadedClass(String name)在已加载的类中,查找一个类
    - 成员变量ClassLoader parent;
  • JVM四级类加载器
    1.启动类加载器(Bootstrap),系统类rt.jar
    2.扩展类加载器(Extension),jre/lib/ext
    3.应用类加载器(App),classpath
    4.用户自定义加载器(Plugin),程序自定义


    JVM四级类加载器示意图.png
  • 类加载器双亲委托
    1.首先判断是否已经加载
    2.若无,找父加载器加载
    3.若再无,由当前加载器加载


    类加载器源码.png

    类加载机制示例代码.png

第二节 Java类双亲委托加载扩展

  • Java严格执行双亲委托机制
    1.类会由最顶层的加载器来加载,如没有,才有下级加载器加载
    2.委托是单向的,确保上层核心的类的正确性
    3.但是上级类加载器所加载的类,无法访问下级类加载器所加载的类,可能会导致问题。例如:核心类库(由BootStrapClassLoader加载)中有很多接口类需通过自定义类(由PluginClassLoader加载)实现,如JDBC和XML Parser等

  • 双亲委托的补充
    1.执行Java,添加虚拟机参数-Xbootclasspath/a:path,将类路径配置为Bootstrap等级


    java-X帮助.png
  • 示例:A工程某类实现a方法,B工程同名类实现b方法。B中主类获取类的类加载器名为AppClassLoader并执行b方法,执行上图操作将A中该类路径配置为BootStrap等级,此时B中主类获取类的类加载器名为BootstrapClassLoader并执行a方法
    2.使用ServiceLoader.load方法,来加载底层加载器所加载的类

  • 示例:java.sql.DriverManager是Bootstrap加载器加载的,需要访问到com.mysql.jdbc.Driver类


    DriverManager源码.png

    MysqlJar包Driver接口文件.png

    调用服务示意图.png

第三节 自定义类加载路径

  • 自定义加载路径
    1.弥补类搜索路径静态的不足
    2.URLClassLoader,从多个URL(jar或者目录)中加载类
  • URLClassLoader
    1.继承于ClassLoader
    2.程序运行时增加新的类加载路径
    3.可以从多个来源中加载类(目录/jar包/网络)
    4.addURL添加路径
    5.close方法关闭


    URLClassLoader构造方法.png

    自定义类加载路径代码.png

=====示例代码待补充(自定义类加载路径)=====

第四节 自定义类加载器

  • 自定义类加载器
    1.继承ClassLoader类
    2.重写findClass(String className)方法
    3.使用时,默认先调用loadClass(className)来查看是否已经加载过,然后委托双亲加载,如果都没有,再通过findClass加载返回
    - 在findClass中,首先读取字节码文件
    - 然后,调用defineClass(className,bytes,off,len)将类注册到虚拟机中
    - 可以重写loadClass方法突破双亲加载
    =====示例代码待补充(自定义类加载类)=====

第五节 Java类加载器总结与展望

  • JVM类装载过程


    JVM类装载过程.png

第十二章 JVM内存管理

第一节 JVM概述

  • 虚拟机
    1.逻辑上,一台虚拟的计算机
    2.实际上,一个软件,能够执行一系列虚拟的计算指令
    3.系统虚拟机:对物理计算机的仿真,如VMWare
    4.软件虚拟机:专门为单个计算程序而设计,如JVM


    JVM概览.png

第二节 JVM内存分类

  • Java自动内存管理:程序员申请使用,系统检查无用对象并回收内存,内存使用相对高效,但也会出现异常
  • JVM内存
    1.线程私有内存
    - 程序计数器
    - Java虚拟机栈
    - 本地方法栈
    2.多线程共享内存
    - 堆
    - 方法区(运行时常量池)
  • 程序计数器
    1.一块小内存,每个线程都有
    2.存储当前方法(线程正在执行的方法)
    3.当前方法为本地方法(native)(如c语言方法)时,pc值未定义(undefined)
    4.当前方法为非本地方法(如java方法)时,pc包含了当前正在执行指令的地址
    5.当前唯一一块不会引发OutOfMemoryError异常
  • Java虚拟机栈(Java JVM stack)
    1.每个方法从调用到完成对应一个栈帧在栈中入栈、出栈的过程
    - 栈帧存储局部变量表、操作数栈等
    - 局部变量表存放方法中存在“栈”里面的东西
    2.引发的异常
    - 栈的深度超过虚拟机规定深度,StackOverflowError异常
    - 无法扩展内存,OutOfMemoryError异常
  • 本地方法栈(Native Method Stacks)
    1.存储native方法的执行信息(调用c函数时)
    2.异常:
    - 栈的深度超过虚拟机规定深度,StackOverflowError异常
    - 无法扩展内存,OutOfMemoryError异常
  • 堆(Heap)
    1.虚拟机启动时创建,所有线程共享,占地最大
    2.对象实例和数组都是在堆上分配内存(int等小数据放在虚拟机栈)
    3.垃圾回收的主要区域
    4.设置大小:-Xms初始堆值,-Xmx最大堆值
    5.异常:无法满足内存分配要求,OutOfMemoryError异常
  • 方法区
    1.存储JVM已经加载类的结构,所有线程共享:运行时常量池、类信息、常量、静态变量等
    2.JVM启动时创建,逻辑上属于堆的一部分
    3.很少做垃圾回收
    4.异常:无法们组内存分配要求,OutOfMemoryError异常
  • 运行时常量池
    1.Class文件常量池的运行时表示
    2.方法区的一部分
    3.动态性:Java语言并不要求常量一定只有在编译期产生,比如String.intern方法
    4.异常:无法满足内存分配要求,OutOfMemoryError异常


    JVM内存.png

第三节 JVM内存参数

  • JVM默认运行参数
    1.支持JVM运行的重要配置,根据操作系统/物理硬件不同而不同
    2.使用-XX:+PrintFlagsFinal显示VM的参数


    JVM运行参数.png

    JVM程序启动参数.png
  • 堆OOM示例


    堆OOM示例.png
  • JVM栈StackOverflow示例


    JVM栈StackOverflow示例.png

    JVM栈StackOverflow示例2.png
  • 方法区


    方法区OOM示例.png

第四节 Java对象引用

  • GC
    1.什么内存需要收集(判断无用对象)
    2.什么时候回收(何时启动,不影响程序正常运行)
    3.如何回收(回收过程,要求速度快/时间短/影响小)

  • Java对象的生命周期
    1.对象通过构造函数创建,但是没有析构函数回收内存
    2.对象存活在离他最近的一对大括号中

  • 内存回收API
    1.Object的finalize方法,垃圾回收器在回收对象时调用,有且仅被调用一次
    2.System的gc方法,运行垃圾收集器

  • Java队形引用
    1.基于对象引用判定无用对象:零引用,互引用
    2.对象引用链

  • GC Roots:可达性分析起点
    1.虚拟机栈中引用的对象
    2.方法区中类静态属性引用的对象
    3.方法区中常量引用的对象
    4.本地方法栈中引用的对象

  • Java引用方式
    1.强引用,只要强引用还存在,对象就不会被回收,哪怕发生OOM异常,如:Object obj= new Object();Object obj2=obj;
    2.软引用,描述有用但并非必须的对象,OOM时回收
    3.弱引用,只能存活到下一次垃圾收集之前
    4.虚引用,目的是能在某个对象被收集器回收时收到一个系统通知,用于对象回收跟踪

第五节 垃圾收集算法

  • 引用计数法
    1.每个对象有一个引用计数器,有引用计数器加一,引用失效计数器减一,计数器为0,将被回收
    2.优点:简单,效率高;缺点:无法识别对象之间的相互循环引用
  • 标记-清除
    1.标记:标记出所有需要回收的对象(引用计数法);回收:统一回收所有被标记的对象
    2.优点:简单;缺点:效率不高,内存碎片
  • 复制算法
    1.将可用内存分成两份,一份用完后把其中存活对象复制到另一份,使用过的内存全部清除
    2.优点:简单、高效;缺点:可用内存减少,对象存活率高是复制操作较多
  • 标记-整理
    1.标记:标记待回收对象,让所有存活对象向一边移动,然后清理掉段边界以外内存
    2.优点:避免碎片产生,无需两块相同内存;缺点:计算代价大,标记清除+碎片整理,更新引用地址
  • 分代收集
    1.Java对象生命周期不同有长有短
    2.根据对象存活周期,将内存分成新生代和老年代
    3.新生代:复制算法
    - 主要存放短暂生命周期的对象
    - 新创建的对象都先放入新生代,大部分新建对象在第一次gc时被回收
    4.老年代:标记清除或标记整理
    - 一个对象经过几次gc仍存活则放入老年代
    - 这些对象可以活很长时间或伴随程序一生,需要常驻内存,可以减少回收次数


    堆内存示意图.png

    新生代gc算法1.png
新生代gc算法2.png

第六节 JVM对内存参数和GC跟踪

堆内存参数.png

堆内存参数示意图.png

第七节 JVM内存管理总结和展望

第十三章 Java运行管理

第一节 Java运行管理概述

  • Java开发和运行过程


    Java开发过程.png

    1.类加载器加载class文件
    2.存储在JVM Memory中
    3.然后JVM执行机获取memory的东西,获取到字节码指令,翻译成本地方法,然后执行


    Java运行管理.png
  • OS管理
    1.进程级别的管理(黑盒)
    2.CPU/内存/IO等具体性能监控
  • JVM管理
    1.线程/程序级别的管理(白盒)
    2.查看虚拟机运行时各项信息
    3.跟踪程序的执行过程,查看程序运行时信息
    4.限制程序对资源使用
    5.将内存导出为文件进行具体分析

你可能感兴趣的:(《Java核心技术(高级)》)