java switch语句支持的类型
Incompatible types. Found: ‘long’, required: ‘char, byte, short, int, Character, Byte, Short, Integer, String, or an enum’
这是switch接收long 参数的编译报错,从提示可以看出,switch只支持“char, byte, short, int, Character, Byte, Short, Integer, String, or an enum”
java 自动装箱经典题
- case1
Integer i1 = 128;
Integer i2 = 128;
System.out.println("i1==i2: "+(i1==i2));
System.out.println("i1 == 128: " + (i1==128));
输出结果
i1==i2: false
i1 == 128: true
- case 2
Integer i1 = 100;
Integer i2 = 100;
System.out.println("i1==i2: "+(i1==i2));
System.out.println("i1 = 100: " + (i1==100));
输出结果:
i1==i2: true
i1 = 100: true
分析:
默认情况下,-128–127 的常量对象在自动装箱时会被复用;
所以case2 时,i1和i2指向同一个常量对象。
如果是new的对象,则不会复用。
finalize是干嘛的?调用了就能表示对象被回收了吗?
finalize 是在 java.lang.Object 里定义的方法,也就是说每一个对象都有这么个方法,这个方法在 gc 启动,表示该对象可能被回收。
一个对象的 finalize 方法只会被调用一次,finalize 被调用不一定会立即回收该对象,所以有可能调用 finalize 后,该对象又不需要被回收了,然后到了真正要被回收的时候,因为前面调用过一次,所以不会再次调用 finalize 了,进而产生问题,因此不推荐使用 finalize 方法。
==和 equals 的区别
本质上,== 是运算符,而equals是方法,二者根本没有可比性;
不过从逻辑上,二者又相似之处; == 比较的是两个对象地址是否相等,也就是是否是同一个对象;equals默认实现和== 一致,但是如果子类override了此方法,则多数情况下就是指内容是否相等。
hashCode()的默认值是什么?为什么重写equals也必须重写hashCode
对象的内存地址 通过hash 函数转化后得到的一个整数。
逻辑上来说,相等的对象,hashCode一定相等;如果重写了equals,两个不同的对象内容相等,我们认为相等,equals返回true,但原始的hashCode却是不等的,逻辑错误。
String str1 = new String(“abc”)和 String str2 = “abc” 和 区别?
- 相同点:均会在常量池中查找是否有"abc"这个字符串,如果有,则都直接使用;如果没有则创建新的。
- 不同点:
String str2 = “abc” 在常量池无"abc"时创建对象,并将引用赋值给str2;
new String(“abc”) 会额外堆中创建一个新的对象"abc".
StringBuffer 和StringBuilder 的区别
- 相同点:
都是用来创建字符串,不产生中间对象;String 是不可变的字符串。
直接使用字符串拼接 +, 编译后会变为StringBuilder 来append。 - 不同点:
StringBuffer:效率低、线程安全; A thread-safe, mutable sequence of characters
StringBuilder:效率高、线程不安全; 如果单线程情况,推荐使用这个而不是StringBuffer,因为其效率较高。
java 的异常体系
整体来说,Java的异常基类为Throwable,总的分为两类: Error和Exception。
Exception 是程序逻辑错误引起的异常,JVM自己抛的;
而Error是JVM内部的错误,是进程的异常,java程序没法处理。
java try catch 能够捕获异步跨线程的异常吗?
举个例子
点击查看代码public static void test() {
try {
Logger.i("run outside: " + Thread.currentThread().getId());
new Thread(()->{
Logger.i("run in child: " + Thread.currentThread().getId());
throw new RuntimeException("this is from child");
}).start();
} catch (Exception e){
Logger.i("run in catch: " + Thread.currentThread().getId());
e.printStackTrace();
}
}
直接抛异常了,说明兜不住。事实上,try 只能对同一个线程有用。
run in child: 16
Exception in thread "Thread-0" java.lang.RuntimeException: this is from child
at com.company.exception.TryCatchAsyncThreadExp.lambda$test$0(TryCatchAsyncThreadExp.java:13)
at java.base/java.lang.Thread.run(Thread.java:831)
finally 经典题目
public static int test1() {
try {
return 2;
} finally {
return 3;
}
}
// test1 输出 3
//------------------------------
private static int innerTryFinally() {
try {
return 1;
} catch (Exception e) {
return 2;
} finally {
System.out.print("3");
}
}
// innerTryFinally 先输出3,再返回1
//-----------------------------------------------------
public static int test2() {
int i = 0;
try {
i = 2;
return i;
} finally {
i = 3;
}
}
// test2 返回2, 可能有人会问了,finally不是会把i改掉吗?
//但是,再返回之前,返回值是i的一个副本,所以还是 返回2
finally 会在return之前执行。
Object的wait方法底层原理
wait
object.wait 需要先拿到该对象的锁(Monitor对象的所有权),也即在synchronized 块中。
wait在JVM的实现中,会找到对象对应的ObjectMonitor对象,然后调用其ObjectMonitor::wait方法,
ObjectMonitor::wait -> addWaiter() 会将线程包装为ObjectWaiter对象,添加到ObjectMonitor的等待队列中_waitSet, 然后调用ObjectMonitor::exit释放锁,接着 thread_ParkEvent->park 也就是实现了当前线程的wait。
Monitor有两个队列:
*_WaitSet ** :处于wait状态的线程,会被加入到wait set;
_EntryList:处于等待锁block状态的线程,会被加入到entry set;
notify、notifyAll
当有其他线程调用notify或者notifyAll时,
notify会选择该monitor对象的waitSet中的某个线程放到等待锁的双向链表EntryList中;
notifyAll会将该monitor对象的waitSet中的所有线程放到等待锁的双向链表EntryList中;;
notify并不会释放锁,也不会唤醒线程;真正唤醒线程是在释放锁时,ObjectMonitor::exit方法中
大概为这样:
// 释放锁
OrderAccess::release_store_ptr (&_owner, NULL) ;
OrderAccess::fence() ;
// 唤醒线程
Trigger->unpark() ;
notify 并不会释放锁,真正释放锁是在monitor exit时
package com.company.thread;
public class WaitAndNotify {
private static Object lock = new Object();
public static void test() {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println(" Thread1 enter.. going to get lock");
synchronized (lock) {
System.out.println(" Thread1 enter.. get lock");
try {
System.out.println(" Thread1 .. before wait");
lock.wai