java 常见面试题
1.java中 sleep 和 wait 的区别
- 来自不同的类 : sleep来自Thread类,是Thread类的静态方法。而wait来自于object类。
sleep是Thread的静态方法,那个线程调用的了sleep,那个线程就会休眠(睡觉)
- 持有锁:这一点很重要,sleep是没有释放锁的,使得该线程仍然占用这系统资源,wait方法则会释放锁,使得其他线程可以使用同步控制块或者方法。
sleep 不释放系统资源并且有时间限制,需要调用sleep(milliseconds)来指定休眠时间 wait会释放资源,并且进入线程等待池等待,这个时候其他线程可以占用CPU,直到其他线程调用notify/notifyAll唤醒等待池中的线程,然后进入就绪队列等待系统分配资源
- 使用范围: wait,notify,notifyAll只能在synchronized块中或者synchronied控制的方法中调用。而sleep可以在任何地方调用
2.异常中Throw和Throws的区别
- throw代表的是动作,throws是状态
- throw用在方法中,而throws用在方法声明中
- throw只能抛出一种异常,而throws可以抛出多个
3.内存溢出和内存泄露
- 内存溢出(out of memory),是指程序在申请内存时,没有足够的内存空间供其使用
- 内存泄露(menory leak):是指程序在申请内存后,无法释放已申请的内存空间。简单点说及就是,内存中存在可到达(即在有向图中,存在通路可以与其相连)且不再使用的对象。例如
Vector v = new Vector (10);
for(int i = 0;i<100;i++){
Object object = new Object();
v.add(object);
object=null;
}
//假设以后不再使用v了
java 是通过引用来找到对象的,这里object是引用,可通过它来找到新创建的对象,简单比喻下就是,object是门牌号,这个门牌号背后的院子就Object对象,系统可以通过门牌号找到这个对象。当运行
v.add(object)
后相当于将门牌号复制了一份交给v,然后这个时候再将object = null
相当于将Object的门牌号给擦除了。但因为v的手中还有门牌号的拷贝,所以系统能根据牌号找到它,而它又不会再被使用到,这样就造成了内存泄露。
4.Java是如何管理内存
Java使用有向图的方式进行内存管理,可以消除引用循环的问题,例如有三个对象,相互引用,只要它们和根进程不可达的,那么GC也是可以回收它们的。这种方式的优点是管理内存的精度很高,但是效率较低。另外一种常用的内存管理技术是使用计数器,例如COM模型采用计数器方式管理构件,它与有向图相比,精度行低(很难处理循环引用的问题),但执行效率很高。
5.String,StringBuffer 和 StringBuilder的区别
- 可变与不可变: String类中使用字符数组保存字符串,如下就是,因为有“final”修饰符,所以可以知道string对象是不可变的。
private final char value[];
StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,如下就是,可知这两种对象都是可变的。char[] value;
- 是否线程安全 String中的对象是不可变的,也就可以理解为常量,显然线程安全。 StringBuilder并没有对方法进行加同步锁,所以是非线程安全的。 StringBuffer对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的。
public synchronized StringBuffer reverse() {
super.reverse();
return this;
}
public int indexOf(String str) {
return indexOf(str, 0);
//存在 public synchronized int indexOf(String str, int fromIndex) 方法
}
未完待续