Java基础
Java基础
JDK、JRE、JVM
JVM java虚拟机,运行java程序的程序,包含类加载器、内存、执行引擎
JRE java运行环境,包含JVM和一组运行java程序最基本的类库
JDK java开发工具,包含JRE和一些开发类库,比如java编译命令,javac反编译命令
JVM有哪些实现
hospot、Zing、J9、JRockit
java基本类型
- byte 8位 有符号整形
- short 16位 有符号整形
- char 16位 无符号字符型
- int 32位 有符号整形
- long 64位 有符号整形
- float 32位 有符号单精度浮点型
- double 64位 有符号双精度浮点型
- boolean 1位 true或false
可见性修饰符
- public 可见
- protected 子类可见
- default 同包可见
- private 类内可见
重载和重写
- 重载 方法名相同,参数不同,返回值无所谓;方法名+参数形成全限定名
- 重写 子类继承父类,写一个与父类方法名和参数都一样的方法,会覆盖父类方法;重写的方法可见性修饰符不能低于父类,异常不能超过父类,否则在多态下会有问题
位运算
- &与运算
- |或运算
- ^异或运算 无进位加法
-
左移 相当于/2
-
无符号左移 相当于/2
- <<右移 相当于*2
位运算执行优先级低于加减乘除
final关键字
修饰类 代表此类不可被继承
修饰方法 代表此方法不可被重写
修饰变量 代表此变量一旦赋值就不可以被修改
局部内部类使用局部变量时为什么要加final
局部内部类的生命周期可能会大于创建他的方法,而局部变量的生命周期是跟随方法的,所以为了保证超出方法的生命周期之后还能访问到局部变量,内部类复制局部变量的引用,为了保证局部变量不修改,使用final修饰
String为什么要定义为final
String类被设计成不可变的类,主要执行了三点:
1.char数组使用final修饰
2.提供的方法不会修改char数组元素
3.使用final修饰类,防止方法被重写
String类被设计为不可变的类:
1.主要原因,要复用字符串缓存池,享元模式
2.使用安全,比如在传递字符串过程中,不会导致字符串被改变
3.线程安全,没有并发问题
new一个类的过程
类加载阶段 static属性和static代码块组成<cinit>方法被调用
类实例化阶段 按顺序给成员变量赋值、非静态代码块、构造方法
有父类,优先父类的静态加载和非静态加载
String StringBuilder StringBuffer
String 字符串类 不可变 字符串常量池
StringBuilder 可变长字符串,append操作,内部维护一个char数组,使用System.arraycopy进行数组扩容和拼接;线程不安全
StringBuffer append使用的synconized修饰保证线程安全
抽象类和接口
接口 全是抽象方法,没有成员变量,可以有常量,可以多实现,没有构造方法,描述的是能力
抽象类 可以有抽象方法,也可以有普通方法,不可以new,描述的是一类相同或相似的事物的属性
异常
Throwable 所有异常的顶级父接口
Error 继承Throwable 多为系统级异常 比如OOM
Exception 继承Throwable checked异常
RuntimeException 继承Exception unchecked异常
反射
java提供反射机制,供程序运行阶段创建对象,或动态修改对象内容;
获取filed或者method比较耗时,可以使用缓存提升性能
内部类
- 成员内部类 生命周期依赖外部类实例化对象,可以访问外部类的所有属性
- 静态内部类 static修饰,依赖外部类class对象,可以访问外部类所有静态属性HashMap.Entry
- 局部内部类 定义在方法内部,非静态,可以访问外部类的所有成员属性,访问局部属性需要加final(1.8之后不用加,隐式加)
- 匿名内部类 不需要定义,可以访问外部类的所有成员属性,访问局部属性需要加final(1.8之后不用加,隐式加),多用于lambda表达式创建接口实现。
泛型
提供了编译时类型安全检测机制,编译阶段去泛型,
泛型方法,泛型类可以对参数进行类型限制,返回值使用泛型,可以省却强制转换
<? extend XXXX> <? super XXXX>
序列化和transient
java序列化有两种形式 实现Serializable接口和实现Externalizable
通过ObjectInputStream和ObjectOutputStream进行序列化和反序列化
被transient标记的属性不会被序列化。
如果对象声明了readObject和writeObject方法,对象在被序列化的时候会执行对象的readObject和writeObject方法。
深表复制和浅表复制
java中实现Cloneable接口,才可以使用Object提供clone方法;
默认的clone只是浅表复制,如果需要深表复制,需要自己实现;
浅表复制 基本对象复制值,引用对象复制地址
深表复制 都复制值
深表复制要注意循环;
BIO、NIO、AIO
- 阻塞IO 同步阻塞,用户发出IO操作,会阻塞在那里直到数据准备好,比如read操作
- 非阻塞IO 同步非阻塞,同步指读数据同步,用户发出IO操作,read操作会返回空或抛出异常,告知用户线程数据还没有准备好,可以先去干别的;用户可以将一些没返回的IO操作缓存,定时去轮询read
- IO多路复用 用户发出IO操作,read操作会返回空或抛出异常,告知用户线程数据还没有准备好;内核提供方法,获取一批已经准备好数据的IO,用户直接轮询这些IO操作就好了
- AIO 异步非阻塞,数据准备跟读数据都是异步的,用户发出IO操作,由内核监听IO准备情况,用户先去干别的,内核会在数据准备完成之后通知用户,用户说读数据,然后再去干别的,数据读完会通知用户来使用。
IO多路复用(select/poll/epoll)演变
select是内核内部轮询准备好的数据,但是有数据量限制最多1000;poll本质上还是select,只是没有数据量限制了
epoll是一种信号驱动的,先epoll_create申请一个epoll空间,epoll_ctl向epoll空间中注册监听事件,然后使用epoll_wait等待时间的到来,根据不同的时间类型来进行操作
IO中的阻塞主要在两个阶段,数据准备(硬件->内核)和数据读取(内核->用户)
Java中的NIO
面向缓存,buffer、selector、chanel
socket来了之后绑定一个chanel,selector记录下这个chanel进行轮询,读取到的数据写入buffer
Java集合和Map
ArrayList
内部为数组结构; 初始10,扩容 a+a/2; 按下标检索快,删除元素、扩容慢
LinkedList
内部为链表结构;增删元素快,按下标检索慢,需要迭代;遍历速度比arrayList快一丢丢
HashSet
无序不重复集合,内部复用HashMap
TreeSet
有序set,内部复用TreeMap
TreeMap
有序map,内部为红黑树
HashTable
同步map,内部数组+链表 synconized
HashMap
JDK1.7 数组+链表,链表头插法
JDK1.8 数组+链表+红黑树,数组长度超过64、链表长度超过8转化为红黑树、泊松分布,会退化;链表尾插法
初始16,记载因子0.75;扩容为2的n次幂,超过容量*加载因子后触发扩容;hash 高16^低16 ;数组下标计算 (hash& 数组长度-1) ;扩容需要rehash,创建一个新的数组,hash完成替换老数组;
JDK动态代理
关键是实现InvocationHandler,通过Proxy.newProxyInstance获取代理对象