Java笔记(一):基础
JDK, JRE, JVM
JDK(Java Development Kit)
- 开发工具
- 基本类库
- javac 编译
- javap 反编译
- javadoc
- 运行环境 JRE(Java Runtime Environment)
- JVM(Java Virtual Mechinal) 不同操作系统的机器指令是有可能不一样的,所以就导致不同操作系统上的JVM是不一样的。凡是编译后是Java字节码的都可以在JVM上运行,如Apache Groovy,Scala and Kotlin等等。
- JVM工作所需要的类库
Math.Round()
向右取整
Byte范围
Java 中用补码
来表示⼆进制数,补码的最高位是符号位,最高位用0
表示正数,最高位1
表示负数,正数的补码就是其本身
,由于最高位是符号位,所以正数表示的就是0111 1111
,也就是127
。最⼤负数就是1111 1111
,这其中会涉及到两个0
,⼀个+0
,⼀个-0
,+0
归为正数,也就是0
,-0
归为负数,也就是-128
,所以 byte 的范围就是 -128 - 127。
Integer 缓存池
它的默认值⽤于缓存 -128 - 127 之间的数字,如果有 -128 - 127 之间的数字的话,使⽤ new Integer
不⽤创建对象,会直接从缓存池中取,此操作会减少堆中对象的分配,有利于提⾼程序的运⾏效率。
例如创建⼀个 Integer a = 24,其实是调⽤ Integer 的 valueOf
UTF-8 和 Unicode 的关系
由于每个国家都有⾃⼰独有的字符编码,所以Unicode 的发展旨在创建⼀个新的标准,⽤来映射当今使用的大多数语⾔中的字符,这些字符有⼀些不是必要的,但是对于创建⽂本来说却是不可或缺的。
Unicode 统⼀了所有字符的编码,是⼀个 Character Set,也就是字符集,字符集只是给所有的字符⼀个唯⼀编号,但是却没有规定如何存储,不同的字符其存储空间不⼀样,有的需要⼀个字节就能存储,有的则需要2、 3、 4个字节。
UTF-8 只是众多能够对⽂本字符进行解码的⼀种⽅式,它是⼀种变长的方式。 UTF-8 代表 8 位⼀组表示 Unicode 字符的格式,使⽤ 1 - 4 个字节来表示字符。
U+ 0000 ~ U+ 007F: 0XXXXXXX
U+ 0080 ~ U+ 07FF: 110XXXXX 10XXXXXX
U+ 0800 ~ U+ FFFF: 1110XXXX 10XXXXXX 10XXXXXX
U+10000 ~ U+1FFFF: 11110XXX 10XXXXXX 10XXXXXX 10XXXXXX
可以看到, UTF-8 通过开头的标志位位数实现了变⻓。对于单字节字符,只占⽤⼀个字节,实现了向下兼容 ASCII,并且能和 UTF-32 ⼀样,包含 Unicode 中的所有字符,⼜能有效减少存储传输过程中占⽤的空间。
char 在 java 中是2个字节。 java 采用 unicode,2个字节(16位)来表示一个字符。所以 char = '中' 合法。
fail-fast 和 fail-safe
fail-fast
是 Java 中的⼀种快速失败
机制, java.util 包下所有的集合都是快速失败的,快速失败会抛出ConcurrentModificationException
异常, fail-fast 你可以把它理解为⼀种快速检测机制,它只能⽤来检测错误,不会对错误进⾏恢复, fail-fast 不⼀定只在多线程
环境下存在, ArrayList 也会抛出这个异常,主要原因是由于 modCount 不等于 expectedModCount。fail-safe
是 Java 中的⼀种安全失败
机制,它表示的是在遍历时不是直接在原集合上进⾏访问,而是先复制原有集合内容,在拷⻉的集合上进⾏遍历。 由于迭代时是对原集合的拷⻉进⾏遍历,所以在遍历过程中对原集合所作的修改并不能被迭代器检测到,所以不会触发ConcurrentModificationException。java.util.concurrent
包下的容器都是安全失败的,可以在多线程条件下使⽤,并发修改。
反射的基本原理,反射创建类实例的三种方式是什么
反射机制就是使 Java 程序在运⾏时具有 自省(introspect) 的能力,通过反射我们可以直接操作类和对象,比如获取某个类的定义,获取类的属性和方法,构造方法等。
创建类实例的三种⽅式是:
- 对象实例.getClass()
- 通过 Class.forName() 创建
- 对象实例.newInstance() ⽅法创建
类加载机制
类的生命周期:(class 文件 -> Java虚拟机内存 -> 卸载)
- 加载
- 验证
- 准备
- 解析
- 初始化
- 使用
- 卸载
类的加载过程:
- 加载:查找并加载类的二进制数据(Class文件)
- 方法区:类的类信息
- 堆:Class 文件对应的类实例
- 验证:确保加载的类信息是正确的
- 准备:为类的静态变量进行初始化,分配空间并赋予初始值
- 解析:是将符号应用转换为直接引用
- 初始化:JVM对类进行初始化,对静态变量赋予正确值
- 静态代码块
类加载器:
- BootStrapClasserLoader C语言实现,加载 JDK/JRE/lib 下类路径 java.* 开头的类
- ExtClassLoader 扩展类加载器 加载 JDK/JRE/lib/ext 下类路径 javax.* 开头的类
- AppClassLoader 加载自己定义的类,类路径下面。用户自定义类加载器 可以用流、文件、数据库、网络形式加载
双亲委派模型
当一个类加载器收到了类加载的请求的时候,他不会直接去加载指定的类,而是把这个请求委托给自己的父加载器去加载。只有父加载器无法加载这个类的时候,才会由当前这个加载器来负责类的加载。(这样就保证了我们不能篡改 java.己有的类)
异常
参考文献:看完这篇 Exception 和 Error ,和面试官扯皮就没问题了
Java中的所有异常都来自顶级父类 Throwable(实现 Serializable 接口)。
Throwable下有两个子类Exception和Error。
- Eror表示非常严重的措误,比 StakOverFlowError 和 0ut0fMemoryError,通常这些误出现时,仅仅想靠程序自己是解决不了的,可能是虚拟机、磁盘、操作系统层面出现的问题了,所以通常也不建议在代码中去捕获这些Eror,因为捕获的意义不大,因为程序可能已经根本运行不了了。
- Exception表示异常,表示程序出现 Exception时,是可以靠程序自己来解决的,比 NullPointerException、 IllealAcessException等,我们可以捕获这些异常来做特殊处理。Exception的子类通常又可以分为RuntimeException和非RuntimeException两类。
- RuntimeException 表示运行期异常(又称 uncheckedException),表示这个异常是在代码运行过程中抛出的,这些异常是非检查异常,程序中可以选泽浦获处理,也可以不处理,这些导一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生,比如 NullPointerException、IndexOutOfBoundsException 等
- 非RuntimeException表示非运行期异常,也就是我们常说检查异常,是必须进行处的异常,如果不处理,程序就不能检查异常通过,如 IOExeption、SQLException 等以及用户自定义的 Exception 异常