本文内容为学习笔记,用于个人知识点总结、复习。
原教学视频出自:中国大学MOOC网 |《Java核心技术(高阶)》 ——陈良育
第一章 Java语法糖
第一节 语法糖和环境设置
第二节 语法糖(1)for-each和枚举
-
for vs for-each
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性能接近 -
枚举
Java的enum类型
1.所有的enum类型都是Enum的子类,也继承了相应方法
2.ordinal()返回枚举值所在的索引位置,从0开始
3.compareTo()比较两个枚举值的索引位置大小
4.同String()返回枚举值的字符串表示
5.valueOf()将字符串初始化为枚举对象
6.values()返回所有的枚举值
第三节 语法糖(2)不定项参数和静态导入
-
不定项参数
1.一个方法只能有一个不定项参数,且必须位于参数列表的最后
2.重载的优先级规则:
- 固定参数的方法优先级大于可变参数
- 调用语句,同时与两个带可变参数的方法匹配,则报错 -
静态导入
第四节 语法糖(3)自动拆箱和装箱、多异常并列、数值类型赋值优化
-
自动装箱与拆箱
1.装箱和拆箱是编译器的工作,在class中已经添加转化。虚拟机没有自动装箱和拆箱的语句
2.==:基本类型是内容相同,对象是地址相同
3.基本类型没有空值,对象有null,可能触发NullPointerException
4.当一个基础数据类型与封装类进行运算时,会自动拆箱
5.谨慎使用多个非同类的数值类对象进行运算 -
多异常并列
数值类型赋值优化
1.整数类型用二进制数赋值
2.数字中的下划线
第五节 语法糖(4)接口方法
第六节 语法糖(5)try-with-resource和Resource Bundle文件加载
-
try-with-resource
-
ResourceBundle文件加载
1.Java8以前,需要用native2ascii工具对文件转义
2.JDK9后,ResourceBundle默认以UTF-8方式加载Properties文件,删除native2ascii工具u,Properties文件可以直接以UTF-8保存
第七节 语法糖(6)var类型和switch
-
var
1.可以用在局部变量上,非类成员变量
2.可以用在for/for-each循环中,可用于三元操作符,对继承有效
3.声明时必须初始化
4.不能用在形参和返回类型
5.大面积运用会使代码整体阅读性变差
6.var指在编译时起作用,没有在字节码中引入新的内容,也没有专门的JVM指令处理var -
switch
第二章 Java泛型
第一节 泛型入门
- 泛型的本质:参数化类型
,避免类型转换,代码可复用
第三章 Java反射
第一节 反射入门
- 反射:reflection
1.程序可以访问、检测和修改它本身状态或行为的能力,即自描述和自控制
2.可以在运行时加载、探知和使用编译期间完全未知的类
3.给Java插上动态语言特性的翅膀,弥补强类型语言的不足
4.java.lang.reflect包 -
反射的应用
1.在运行中分析类的能力
2.在运行中查看和操作对象
- 基于反射自由创建对象
- 反射构建出无法直接访问的类
- set或者get到无法访问的成员变量
- 调用不可访问的方法
3.实现通用的数组操作代码
4.类似函数指针的功能
第四章 Java代理
第一节 代理模式和静态代理
-
代理模式
为目标对象提供(包装)了一个代理,这个代理可以控制对目标对象的访问
1.外界不用直接访问目标对象,而是访问代理对象,由代理对象再调用目标对象
2.代理对象中可以添加监控和审查处理-
静态代理
1.代理对象持有目标对象的句柄
2.所有调用目标对象的方法,都吊用代理对象的方法
3.对每个方法,需要静态编码
第二节 动态代理
-
动态代理
第五章 Java注解
第一节 注解入门
-
注解示例
- 注解
1.JDK1.5引入
2.位于源码中(代码/注释/注解),使用其他工具进行处理的标签
3.注解用来修饰程序的元素,但不会对被修饰的对象有直接的影响
4.只有通过某种配套工具才会对注解信息进行访问和处理 -
注解用途
1.提供信息给编译器/IDE工具
2.可用于其他工具来产生额外的代码/配置文件等
3.有一些注解可在程序运行时访问,增加程序的动态性
第六章 嵌套类
第一节 嵌套类入门
-
嵌套类:嵌套,一个类定义在别的类内部
1.静态嵌套类:即类前面有static修饰符
2.非静态嵌套类(内部类)
- 普通内部类(成员内部类)
- 局部内部类
- 匿名内部类
- 嵌套类优缺点
1.不同的访问权限要求,更细粒度的访问控制
2.简洁,避免过多的类定义
3.语言设计过于复杂,较难学习和使用
第七章 Lambda表达式
第一节 Lambda表达式入门
-
示例
- Lambda表达式
1.类似于匿名方法
2.参数,箭头,表达式语句
3.可以忽略写参数类型
4.坚决不声明返回值类型
5.没有public/private/static/final等修饰符
6.单句表达式将直接返回值,不用大括号
7.带return语句,算多句,必须用大括号
第八章 Java Stream流
第一节 流的概述
-
示例
-
Stream语法
第九章 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开发过程
-
.class文件:字节码(bytecode)文件
1.class文件是Java“一次编译,到处运行”的基础
2.class文件具备平台无关性,有JVM执行
3.每个class文件包含一个类或接口或模块的定义
4.class文件是一个二进制文件,有JVM定义class文件的规范
5.任何满足这种规范的class文件都会被JVM加载运行
6.class文件可以由其他语言编译生成,甚至不用程序语言直接生成
7.JDK版本不同,所编译出.class文件略有不同
第十一章 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),程序自定义
-
类加载器双亲委托
1.首先判断是否已经加载
2.若无,找父加载器加载
3.若再无,由当前加载器加载
第二节 Java类双亲委托加载扩展
Java严格执行双亲委托机制
1.类会由最顶层的加载器来加载,如没有,才有下级加载器加载
2.委托是单向的,确保上层核心的类的正确性
3.但是上级类加载器所加载的类,无法访问下级类加载器所加载的类,可能会导致问题。例如:核心类库(由BootStrapClassLoader加载)中有很多接口类需通过自定义类(由PluginClassLoader加载)实现,如JDBC和XML Parser等-
双亲委托的补充
1.执行Java,添加虚拟机参数-Xbootclasspath/a:path,将类路径配置为Bootstrap等级
示例:A工程某类实现a方法,B工程同名类实现b方法。B中主类获取类的类加载器名为AppClassLoader并执行b方法,执行上图操作将A中该类路径配置为BootStrap等级,此时B中主类获取类的类加载器名为BootstrapClassLoader并执行a方法
2.使用ServiceLoader.load方法,来加载底层加载器所加载的类-
示例:java.sql.DriverManager是Bootstrap加载器加载的,需要访问到com.mysql.jdbc.Driver类
第三节 自定义类加载路径
- 自定义加载路径
1.弥补类搜索路径静态的不足
2.URLClassLoader,从多个URL(jar或者目录)中加载类 -
URLClassLoader
1.继承于ClassLoader
2.程序运行时增加新的类加载路径
3.可以从多个来源中加载类(目录/jar包/网络)
4.addURL添加路径
5.close方法关闭
=====示例代码待补充(自定义类加载路径)=====
第四节 自定义类加载器
- 自定义类加载器
1.继承ClassLoader类
2.重写findClass(String className)方法
3.使用时,默认先调用loadClass(className)来查看是否已经加载过,然后委托双亲加载,如果都没有,再通过findClass加载返回
- 在findClass中,首先读取字节码文件
- 然后,调用defineClass(className,bytes,off,len)将类注册到虚拟机中
- 可以重写loadClass方法突破双亲加载
=====示例代码待补充(自定义类加载类)=====
第五节 Java类加载器总结与展望
-
JVM类装载过程
第十二章 JVM内存管理
第一节 JVM概述
-
虚拟机
1.逻辑上,一台虚拟的计算机
2.实际上,一个软件,能够执行一系列虚拟的计算指令
3.系统虚拟机:对物理计算机的仿真,如VMWare
4.软件虚拟机:专门为单个计算程序而设计,如JVM
第二节 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内存参数
-
JVM默认运行参数
1.支持JVM运行的重要配置,根据操作系统/物理硬件不同而不同
2.使用-XX:+PrintFlagsFinal显示VM的参数
-
堆OOM示例
-
JVM栈StackOverflow示例
-
方法区
第四节 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仍存活则放入老年代
- 这些对象可以活很长时间或伴随程序一生,需要常驻内存,可以减少回收次数
第六节 JVM对内存参数和GC跟踪
第七节 JVM内存管理总结和展望
第十三章 Java运行管理
第一节 Java运行管理概述
-
Java开发和运行过程
1.类加载器加载class文件
2.存储在JVM Memory中
3.然后JVM执行机获取memory的东西,获取到字节码指令,翻译成本地方法,然后执行
- OS管理
1.进程级别的管理(黑盒)
2.CPU/内存/IO等具体性能监控 - JVM管理
1.线程/程序级别的管理(白盒)
2.查看虚拟机运行时各项信息
3.跟踪程序的执行过程,查看程序运行时信息
4.限制程序对资源使用
5.将内存导出为文件进行具体分析