Java 易错点
1.运算符
1.位移运算符
运算符>>指的是对它左边的操作数带符号右移位,负数,右移补1.
运算符>>>也是右移,但它与>>的区别是对于负数,右移不是用1填补,而是用0填补
另外:>>>的左边操作数如果是char,byte,short,运算前会先转换成int,运算结果也就成了int
2.短路运算符
短路域: 逻辑与(&&),左操作数为false,不计算右侧
非短路与:逻辑与(&)、逻辑或(|):不管左操作数的运算结果如何,都一律计算右边的操作数。
3.switch:
支持byte,short,char,int(及他们对应的包装类)String,Enum
不加break,就一直执行,不管是否匹配case
4.三目运算符
自动类型转换: 如果操作数之一的类型为`T`,其中`T`是`byte`,`short`,或`char`,另一操作数的类型的常量表达式(§15.29) `int`,其值是在式表示的`T`,则该条件表达式的类型是`T`
char alpha = 'A';
int foo = 65;
boolean trueExp = true;
System.out.println(trueExp ? alpha : 65);
// result A
System.out.println(trueExp ? alpha : foo);
// result 65
// 条件运算符的结合方向为"自右至左
public static int compare(Integer o1, Integer o2) {
return o1 > o2 ? 1 : (o1 == o2) ? 0 : -1;
}
System.out.println(compare(new Integer(1),new Integer(1)));
// result -1
2.容器
线程安全的容器:Vector,HashTable,ConcurrentHashMap,Stack
1.Map元素的遍历,entrySet速度明显快于KeySet
HashMap:基础hash表,非线程安全,性能高,支持null为key和value
TreeMap:有序键值对,按key排序
Hashtable:类似于HashMap,线程安全。性能低。不支持null
ConCurrentHashMap:HashMap + Hashtable。线程安全且性能较好。
HashMap基于数组和链表实现
ConCurrentHashMap
在Java1.7中采用分段锁,在Java1.8中采用了 CAS + synchronized
来保证并发安全性。
3.执行顺序
编译器按照:
静态对象 -> 静态变量 -> 构造方法的顺序初始化。
继承执行顺序:父类静态->子类静态 -> 父类非静态 ->父类构造方法
通过多个catch捕获异常,子类异常必须在父类异常之前
浅拷贝和深拷贝都是clone,它们本质区别是对象内部的成员属性(非原生类型属性,如int等)在拷贝时是否处理为引用。如果仍然保留为引用,则称为浅拷贝,反之称为深拷贝。
4.Interface接口
接口的方法可以有方法体,但必须加default或static关键字
接口中的属性默认为:public static final
接口中的方法默认为:public abstract
default:Java 8 引入了新的语言特性——默认方法(Default Methods)。针对接口而言——在接口中的方法签名前加上了 default
关键字的实现方法。
5.类和对象
不可变类:String,Integer,BigInteger,BigDecimal
子类可以扩大访问权限, 不能缩小(最常见的例子:父类protected,子类为public)
子类不能抛出更多异常
方法具有多态性,属性不具备多态性,不能动态绑定。
6.多线程
关键字:
**wait()**暂停当前线程并释放锁
**notify()**任意唤醒一个等待池中的线程,放入锁标志等待池,准备获取锁标志;
**notifyAll()**则从对象等待池中移走所有等待那个对象的线程并放到锁标志等待池
这三个方法用于协调多个线程对共享数据的存取,所以必须在synchronized语句块内使用(因为会对对象的“锁标志”进行操作)
**notify()**不会释放锁
Yield():使当前线程重新回到可执行状态,所有执行yield()的线程有可能在进入到可执行状态后马上又被执行。
线程同步
通信是指线程之间以何种机制来交换信息,主要有两种:共享内存和消息传递。
Java内存模型(JMM)
CPU的处理速度和主存的读写速度不是一个量级的,为了平衡这种巨大的差距,每个CPU都会有缓存。因此,共享变量会先放在主存中,每个线程都有属于自己的工作内存,并且会把位于主存中的共享变量拷贝到自己的工作内存,之后的读写操作均使用位于工作内存的变量副本,并在某个时刻将工作内存的变量副本写回到主存中去。并且JMM决定了一个线程对共享变量的写入何时对其他线程是可见的。
Exchanger 可以在两个线程之间交换数据,只能是2个线程,他不支持更多的线程之间互换数据,当线程A调用Exchange对象的exchange()方法后,他会陷入阻塞状态,直到线程B也调用了exchange()方法,然后以线程安全的方式交换数据,之后线程A和B继续运行
Semaphore: 可以控同时访问的线程个数,通过 acquire() 获取一个许可,如果没有就等待,而 release() 释放一个许可; 比如多个窗口叫号,窗口都忙时,顾客等待,有空闲时,最新等待的被通知
体系结构 :
7.锁
Synchronized:同步方法和代码块,Java每个对象都可以作为锁。
禁止基于可被重用的对象进行同步,禁止使用封包的基本类型,禁止使用Interned String对象,禁止使用Public、非静态对象。
调用intern()方法的String类似一个全局变量。上面的错误示例中,该对象的所有实例共享同一个 锁,或使用String lock = “LOCK”;也可以获取对应的锁
// private int count = 0;
// private final Integer lock = count; // Boxed primitive Lock is shared
(1)普通同步方法,锁是当前实例对象 (2)静态同步方法,锁是当前类的class对象 (3)同步方法块,锁是括号里面的对象接下来
8.异常
Throwable子类:| ERROR 终止
| Exception RuntimeException 终止
CheckedException 必检
敏感异常:
FileNotFoundException,ConcurrentModificationException ,BindException,OutOfMemoryError,SQLException
Java多线程程序中,线程不允许抛出未捕获的Checked Exception
Java多线程程序中,建议使用Thread对象的setUncaughtExceptionHandler方法注册Runtime异常的处理者
线程池异常将被Future.get封装在ExecutionException中重新抛出
9.Java工具
jps JVM进程状态工具(JVM Process Status Tool),得到PID和LvmID。在目标系统上列出HotSpot Java虚拟机进程的描述信息
jstat JVM统计监控工具(JVM Statistics Monitoring Tool),内存和GC。根据参数指定的方式收集和记录指定的jvm进程的性能统计信息。
故障排查:
jinfo Java的配置信息工具(Java Configuration Information),用于打印,修改指定Java进程、核心文件或远程调试服务器的配置信息。
jhat Java堆分析工具(Java Heap Analysis Tool),用于分析Java堆内存中的对象信息。
jmap Java内存映射工具(Java Memory Map),dump堆信息。主要用于打印指定Java进程、核心文件或远程调试服务器的共享对象内存映射或堆内存细节。
jsadebugd 适用于Java的可维护性代理调试守护程序(Java Serviceability Agent Debug Daemon),主要用于附加到指定的Java进程、核心文件,或充当一个调试服务器。
jstack Java的堆栈跟踪工具,主要用于打印指定Java进程、核心文件或远程调试服务器的Java线程的堆栈跟踪信息。
10.容量
ArrayList**、Vector默认初始容量为10**
HashSet**、HashMap:默认初始容量为16**
Vector:加载因子为1:即当 元素个数 超过 容量长度 时,进行扩容
扩容增量:原容量的 1倍,如 Vector的容量为10,一次扩容后是容量为20
ArrayList: 扩容增量:原容量的 0.5倍+1
HashSet:默认初始容量为16,加载因子为0.75 ,扩容增量:原容量的 1 倍
Map是一个双列集合
HashMap**:默认初始容量为16**,加载因子为0.75,扩容增量:原容量的 1 倍
其他
使用transient定义敏感数据,防止敏感数据被序列化。
可能触发fullgc的条件有以下几点: 1)调用system.gc 2)老年代空间不足 3)永久带空间不足 4)gc空间分配担保失败
转载自:https://juejin.cn/post/6898587221960933389