本文内容:
- 基础
- 面向对象
- 集合
- JVM
- 多线程和线程安全
- Java Web
基础
JDK和JRE
- JRE是运行环境,包含JVM实现、核心类库
- JDK是Java开发工具包,包含JRE、开发工具(编译器、反汇编、debug、调试监控、文档生成器等)
- jmap pid:查看进程的内存使用情况
- jconsole:可视化,堆内存、CPU使用情况
jps(JVM Process Status Tool):打印当前运行的Java进程的运行状态(进程对应一个临时文件)
- -v:输出虚拟机参数
- -m:输出主函数的参数
- -q:只输出进程id
- -l:输出类的全限定名
jstack:打印指定进程中的线程的堆栈信息
关键字
- 访问控制修饰符:public, protected, 缺省默认, private
- 逻辑控制符:break, continue, goto, switch(deafult)
- 类修饰符:public, final(不可被继承), abstract
- 变量修饰符:final(基本类型值不变,对象引用不可变、值可变), static, volatile(可见性)
- 方法修饰符:final(不可被重写), static, synchronized(同步), default(接口,允许默认实现)
- 类关系符:extends, implement, class, interface
数据类型
基础数据类型(栈中存放数据):4个整数类型,两个浮点数类型,一个char字符类型,一个布尔型
引用数据类型(栈中存放引用,指向堆中的对象),数组也是引用类型,对基础类型的包装引用类型(Integer会缓存128以下的数)
强引用:存在时就不会被GC回收
软引用:内存不够时,会被回收
弱引用:下次GC时就被回收
虚引用
变量
类变量 成员变量 局部变量 出现位置、标志 类中,static修饰 类中 类方法中 生命周期 与类同生同灭 与对象 方法执行期间 有无默认值 有 有 无
枚举
概述:enum表示一种特殊类型的类,总是继承java.lang.Enum类
优势:
- 替代常量,代码更具可读性
- 预先记录可接受值的列表,允许进行编译时检查
- 将类相关的常量统一放置到枚举类型,更易管理
- == 比较枚举类型时,可提供 编译时和运行时 的安全性
- 编译时,在枚举值相同而类型不同情况下的安全性(False,类型不兼容错误)
- 运行时,none的比较的安全性(NullPointerException)
字符串
字符串也是对象不过它有点特殊,因为它不光可以在堆中分配内存,还可以在常量池中分配(唯一)
{ String str1 = "Hi";//常量池 String str2 = new String("Hi2");//堆,实际创建了两个对象(一个在常量池,一个在堆) }
- length()方法
这个访问是返回编码单元的个数,在utf-16编码中,一个编码单元是16位=2字节,一个字符可以是2字节或4字节,即占据1个码元或2个码元
在Java中,char,String是使用utf-16编码的,所以一个字符的字符串使用length()是可能返回1,可能返回2的
- 不可变带来的好处
- 线程安全
- 相同值的可以唯一化
- 作为hash表的key时,可以不用重复计算hashcode
- +,StringBuffer,StringBuilder
- 由于String是不可变的,所以在使用+号连接时会创建很多多余的对象
- 可变,StringBuffer线程安全,StringBuilder没有同步处理所以效率更高
- intern()方法
- 若常量池中存在值,则返回其引用
- 否则在常量池中创建对象,返回引用
- 用处:
- equals方法的比较流程(1. == ; 2. 比较每一个字符)
- 这样在频繁的值相等地址不同的比较时,就会费时,用intern方法可以使它们指向同一个池中的对象,==直接返回true
注:字符串常量池的位置:1.6以前是在方法区,1.7移到堆里了
公共父类Object的方法
- wait/notify/notifyAll()
- 用于挂起、唤醒线程,必须在synchronized块中使用,因为得拿到对象锁
- notify随机唤醒阻塞在synchronized对象锁上的一个线程
- 只能先wait再notify
- hashcode() 和 equals()
- hashcode()计算hash码,equals()是比较相等, 未覆盖前是比较地址
- Set里判断对象是否相等时,是先判断hashcode(),所以重写了equals()一定要重写hashcode()
jdk8的新特性
- lambda表达式
- 接口的默认方法:default,允许接口方法有默认实现
- 函数式接口
- stream API
面向对象
抽象类和接口的区别
- 一个被继承、一个被实现
- 抽象类能包含普通成员,接口只能包含静态、常量
- 接口不能有构造器
- 接口中的方法必须是public
静态内部类和非静态内部类的区别
静态内部类 非静态内部类 区别1 允许有静态成员、方法 不允许静态 区别2 只能引用外部的静态方法、成员 可以引用外部类的成员 区别3 可以直接实例化 必须先实例化外部对象
多态的实现机制
运行时进行方法选择时,查找this对象的方法表,如果找到则直接使用,没有就按继承关系查找
重载:静态多分派,根据静态类型、参数选择
重载:动态单分派,根据实际类型选择,通过虚函数表实现(继承虚方法索引号与父类一致)
集合
ArrayList
扩容机制
当列表中元素个数与 内置数组长度相同时,再添加元素,就引起扩容grow(),扩容后容量变大50%,
- 如果扩容后无法满足需要,则用最小所需容量进行扩容;
- 如果扩容后的长度超过了MAX_INTEGER-8 ,则看MAX_INTEGER-8 能不能满足最小需求,不能就MAX_INTEGER
MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; int grow(int minCapacity){ int oldCapacity = elementData.length(); int newCapacity = oldCapacity+(oldCapacity<<1);//扩容50% if(newCapacity<minCapacity) return minCapacity;//扩容后不够,则返回最小所需容量 if(newCapacity>MAX_ARRAY_SIZE){ return minCapacity>MAX_ARRAY_SIZE ? Integer.MAX_VALUE : MAX_ARRAY_SIZE; } return newCapacity; boolean add(e){ if(size==elementData.length()){ newCapacity = grow(size+1); //分配内存,迁移数据 } }
Collections工具类常用方法
- 排序:reverse反转,shuffle随机排序,sort,swap交换元素,rotate循环移动
- 查找, 替换:binarySearch,max,frequency统计频率,fill使用指定元素替换所有元素,replaceAll使用指定元素替换某个元素
- 同步控制:synchronizedXxx()将指定集合包装成线程安全的集合(效率低,考虑用JUC并发包下的并发集合)
- 集合类型转化
- Arrays.asList:此方法作为基于数组和基于集合的API之间的桥梁,与Collection.toArray()结合使用
使用注意事项:
它是泛型方法,传递的数组必须是对象数组,而不是基本类型
当传入一个原生数据类型数组时,Arrays.asList() 的真正得到的参数是数组对象本身!此时 List 的唯一元素就是这个数组
使用集合的修改方法:add()、remove()、clear()会抛出异常,因为返回的并不是 java.util.ArrayList ,而是 java.util.Arrays 的一个内部类,中并没有重写这些方法,重写了get,set,indexOf,contains
集合遍历--快速失败与安全失败
快速失败 :Java 集合遍历时的错误检测机制
- 集合有个modCount变量,在用迭代器遍历时如果进行修改也会修改这个变量,
- 迭代器hashNext()/next()遍历下一个元素之前
- 检测modCount 变量是否为 遍历前的 expectedModCount 值,
- 是的话就返回遍历;否则抛出ConcurrentModificationException异常,终止遍历。
安全失败:集合容器遍历时,先复制原有集合内容,在拷贝的集合上进行遍历
注:
- 增强 for 循环也是借助迭代器进行遍历。
- 通过 Iterator 提供的方法 修改集合的话会修改到 expectedModCount 的值,所以不会抛出异常
- util包下的集合是快速失败,JUC包下的集合是安全失败
HashSet和LinkedHashSet的区别:(维护一条双向链表,使得遍历顺序与插入顺序一致有序)