1、类只能继承一个类,但可以实现多个接口。
2、对于继承性,类继承了父类的方法,子类可以选择是否覆盖父类的方法。
3、接口的方法只有声明,没有实现;而类中的方法必须有方法体。
接口不可以实例化,因为接口可以看成是特殊的抽象类,比抽象类的程度更高,其所有方法都是public abstract类型的,因此不能实例化。
Lambda表达式的原理是:
1、编译器根据Lambda表达式生成一个私有的静态函数,这个私有函数就是执行Lambda表达式里的内容
2、生成一个内部类并调用上述所生成的私有静态函数
3、将Lambda表达式替换为该内部类的一个实例传入方法体中
所以本质上来讲Lambda表达式并非传入一个接口的实例,而是传入一个内部类的实例。
这里引用一下别人的代码:
public class LambdaTest {
public static void printString(String s, Print print) {
print.print(s);
}
public static void main(String[] args) {
printString("test", (x) -> System.out.println(x));
}
}
@FunctionalInterface
interface Print {
public void print(T x);
}
反编译代码:
public class LambdaTest {
public static void PrintString(String s, Print print) {
print.print(s);
}
public static void main(String[] args) {
PrintString("test", new LambdaTest$$Lambda$1());
}
private static void lambda$main$0(String x) {
System.out.println(x);
}
static final class LambdaTest$$Lambda$1 implements Print {
public void print(Object obj) {
LambdaTest.lambda$main$0((String) obj);
}
private LambdaTest$$Lambda$1() {
}
}
}
@FunctionalInterface
interface Print {
public void print(T x);
}
static内部不能直接调用该类的非静态方法,但是如果通过传入一个对象的引用到静态方法,然后通过该引用就可以调用非静态方法和非静态成员了。
逻辑上可以,编译可以通过,但在父类引用指向子类对象的时候,通过父类引用调用的仍然是父类的类方法,而不是子类的。
public class StaticFather {
public static void print() {
System.out.println("I am father");
}
}
public class StaticSon extends StaticFather {
public static void print() {
System.out.println("I am son");
}
}
public class Main {
public static void main(String[] args) {
StaticFather A = new StaticFather();
StaticFather B = new StaticSon();
StaticSon C = new StaticSon();
A.print();
B.print();
C.print();
}
}
Result:
I am father
I am father //通过父类引用调用静态方法时,仍然是父类的静态方法,而非子类的
I am son
底层采用数组+链地址表法实现,jdk1.8后当链地址表的长度超过8时会用一棵红黑树来代替。
put方法工作过程:
1、调用hashcode()函数得到其哈希值
2、根据散列函数(n-1)&hashcode来计算数组下标
3、如果定位到的数组位置没有元素就直接插入;如果有元素就检查该元素是否重复,重复就覆盖,否则判断该数组位置是存放红黑树还是链表,红黑树就调用相应的方法插入,链表就在链表尾部插入
LinkedHashMap继承了HashMap,并定义了一个继承自HashMap.Node的Entry静态内部类,这个类记录了节点的上一个节点和下一个节点,因此在插入数据的时候,就会绑定在上一个最后插入的节点后面来保证有序。
新建(new)
就绪(Runnable)
阻塞(Blocked)
死亡(Dead)
sleep()是Thread类的方法,可使线程暂定指定的时间,进入阻塞状态,指定时间过后会变为就绪态;sleep()可以在任何地方调用,且必须捕获异常,如果不捕获异常,当产生InterruptedException异常时该线程就会进入死亡状态。
而wait()是Object类的方法,可是线程进入阻塞状态,同时进入一个和该对象相关的等待池中,同时释放掉持有的对象锁;wait()方法只能在synchronized同步块中调用,不需要捕获异常。
两者都会进入阻塞状态。
线程池是指管理一组同构工作线程的资源池,线程池的实现与工作队列密切相关,在工作队列中保存了所有等待执行的任务,工作者线程的任务就是从工作队列中获取一个任务、执行任务,然后返回线程池中并等待下一个任务的分配。
当工作队列被填满后,开始执行饱和策略:
1、中止(Abort)策略:抛出未检查的RejectedExecutionException,调用者可以捕获这个异常,并根据需求编写处理代码。
2、调用者运行(Caller-Runs)策略:将某些任务回退到调用者,降低新任务的流量。
3、抛弃(Discard)策略:直接抛弃该任务。
4、抛弃最旧(Discard-Oldest)策略:抛弃下一个被执行的任务,然后尝试重新提交新的任务(如果是优先级队列则会抛弃优先级最高的)。
1、打乱一个数组
public class UpsetArray {
public static void upset(int []array, int n) {
Random random = new Random();
int temp;
int randomNum;
for (int i = 0; i < n; i++) {
randomNum = random.nextInt(n - i) + i;
temp = array[randomNum];
array[randomNum] = array[i];
array[i] = temp;
}
}
public static void test() {
int array[] = { 0, 5, 3, 2, 1, 7, 4};
System.out.println(Arrays.toString(array));
upset(array, array.length);
System.out.println(Arrays.toString(array));
}
}
Result:
[0, 5, 3, 2, 1, 7, 4]
[3, 5, 0, 2, 1, 4, 7]
2、归并排序(见排序算法实现博文)
引用:https://blog.csdn.net/jiankunking/article/details/79825928