Java基础数据类型
Java Object类包含的方法
package java.lang;
public class Object {
...
private static native void registerNatives();
public final native Class<?> getClass();
public native int hashCode() {};
public boolean equals() {}
protected native Object clone() throws CloneNotSupportedException {};
public String toString() {};
public final native void notify() {};
public final native void notifyAll() {};
public final native void wait(long timeout) throws InterruptedException {} // 有多个重载
protected void finalize() throws Throwable {}
...
}
native
关键字:一个方法被native
关键字修饰,就成为了Native Method
。简单地讲,一个Native Method
就是一个java调用非java代码的接口。Native Method
的实现并非是java语言,其实现方法体在java语言外面。
native
可以与除了abstract
之外的关键字连用,因为它暗示方法存在可调用的实现体,只是不是由java编写的。
Java异常类继承树
更详细:
检查异常(CheckedException)
: Exception
类下除了RuntimeException
类及其子类的异常,这些异常都应当被try-catch
捕获并处理。
注:除了IOException
之外,还有其他类型的检查异常,比如SQLException
。
非检查异常(UncheckedException)
:RuntimeExcpetion
类及其子类,运行时异常。Error
类及其子类也是UncheckedException
,无法预先处理。
wait()和sleep()的区别
-
wait()是Object类的方法,用于线程间交互/通信;sleep()是Thread类的静态方法,通常被用于暂停执行,是线程用来控制自身流程的;
-
wait()方法在同步控制方法和同步代码块中使用,sleep()方法则可以在任何地方使用。
-
sleep()方法不会释放锁;wait()方法则会释放锁;
-
wait()方法调用后,线程不会自动苏醒,需要别的线程调用同一对象的notify()或者notifyAll()方法。sleep()方法执行完成后,线程会自动苏醒,或者可以使用wait(long timeout)超时后线程会⾃动苏醒。
-
sleep()方法需要捕获异常,wait()方法不需要。
实现一个ReentrantLock
下面是使用AQS实现的ReetrantLock
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
public class MyReentrantLock implements Lock {
private Synchronizer synchronizer = new Synchronizer();
private class Synchronizer extends AbstractQueuedSynchronizer {
protected boolean tryAcquire() {
int state = this.getState();
if(state == 0) {
if(this.compareAndSetState(0, 1)) {
this.setExclusiveOwnerThread(Thread.currentThread());
}
return true;
} else {
Thread currentThread = Thread.currentThread();
Thread ownerThread = this.getExclusiveOwnerThread();
if(currentThread == ownerThread) {
this.setState(state+1);
// this.compareAndSetState(state, state+1)
return true;
}
}
return false;
}
protected boolean tryRelease() {
if(Thread.currentThread() != this.getExclusiveOwnerThread()) {
// throw new RuntimeException();
return false;
} else {
int state = this.getState();
this.setState(--state);
if(state == 0) {
this.setExclusiveOwnerThread(null);
return true;
}
}
return false;
}
protected Condition newCondition() {
return new ConditionObject();
}
}
@Override
public void lock() {
synchronizer.acquire(1);
}
@Override
public void lockInterruptibly() throws InterruptedException {
synchronizer.acquireInterruptibly(1);
}
@Override
public boolean tryLock() {
return synchronizer.tryAcquire();
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return synchronizer.tryAcquireNanos(1, unit.toNanos(time));
}
@Override
public void unlock() {
synchronizer.release(1);
// synchronizer.tryRelease()
}
@Override
public Condition newCondition() {
return synchronizer.newCondition();
}
}
Java中有序的集合包括哪些?
实现了List接口的集合类全部有序:比如ArrayList
、LinkedList
、Vector
。
LinkedHashMap
:使用双向链表来维持有序。
Sorted Map
:接口,有ConcurrentSkipListMap
和TreeMap
两种实现。继承自Map
接口,有CurrentNavigableMap
和NavigableMap
两个子接口。
ConcurrentSkipListMap
:基于跳表实现。
TreeMap
:基于红黑树。
TreeSet
:基于TreeMap实现。
JAVA中排序算法实现的具体原理是什么?
在JDK7以前的版本中,基本类型使用优化后的快排,双枢轴随机快排,其他类型使用优化后的归并排序。
JDK7及以后如果JVM参数设置了Djava.util.Arrays.useLegacyMergeSort=true
那么就会执行上面的排序策略,否则将会执行TimSort
排序。TimSort
排序也是一种优化后的归并排序算法,它对已经反向排好序的输入做了特别优化,对已经正向排好序的输入减少回溯。对两种情况混合存在(一会升序,一会降序,实际情况常见)的输入处理比较好。
TimSort算法, 大致思路是这样的:
- 元素个数 < 32, 采用二分查找插入排序(Binary Sort)
- 元素个数 >= 32, 采用归并排序,归并的核心是分区(Run)
- 找连续升或降的序列作为分区,分区最终被调整为升序后压入栈
- 如果分区长度太小,通过二分插入排序扩充分区长度到分区最小阈值
- 每次压入栈,都要检查栈内已存在的分区是否满足合并条件,满足则进行合并
- 最终栈内的分区被全部合并,得到一个排序好的数组
Timsort的合并算法非常巧妙:
- 找出左分区最后一个元素(最大)及在右分区的位置
- 找出右分区第一个元素(最小)及在左分区的位置
- 仅对这两个位置之间的元素进行合并,之外的元素本身就是有序的
选择归并排序的原因是,归并排序是一种最好最坏以及平均时间复杂度均为O(nlogn)的稳定排序算法。
C++ STL
里面的sort()
不是简单的快排。而是快排、归并、插入、堆排序四种的结合。在数据量大的时候使用快排分段排序,合并分段使用归并排序,一旦数据量小于一定阈值(16),转而使用插入排序,以避免快排递归调用的额外负荷。快排递归调用过深时,还会使用堆排序。