Java 空接口
空接口是没有包含任何方法的接口。叫标记接口。
标记接口是没有任何方法和属性的接口.它仅仅表明它的类属于一个特定的类型,供其它代码来测试允许做一些事情。
标记接口作用:简单形象的说就是给某个对象打个标(盖个戳),使对象拥有某个或某些特权。
没有任何方法的接口被称为标记接口。标记接口主要用于以下两种目的
- 建立一个公共的父接口:
正如EventListener接口,这是由几十个其它接口扩展的Java API,你可以使用一个标记接口来建立一组接口的父接口。
例如:当一个接口继承了EventListener接口,Java虚拟机(JVM)就知道该接口将要被用于一个事件的代理方案。
- 向一个类添加数据类型:
这种情况是标记接口最初的目的,实现标记接口的类不需要定义任何接口方法(因为标记接口根本就没有方法),实际上就是为了实现多态性。
我自己在实际项目也用到过标记接口,我在项目中负责ES的入库接口的开发,为了防止,其他开发人员随意调用接口往ES入数据,我在接口的入参定义了一个泛型
public void bulk(Class<? extends IndexModel> indexmodel)
这里的IndexModel
就是一个标记接口,没有任何方法和属性,在一定程度减少了异常。
jdk中的空接口有:
import java.io.Serializable;//在ArrayList继承
import java.lang.annotation.Annotation;
import java.rmi.Remote;
import java.util.RandomAccess; //在ArrayList继承
Java断言关键字assert
java断言关键字assert需要在vm添加-ea参数。
- assert condition;
这里condition是一个必为真(true)的表达式。如表达式的结果为true,那断言为真,并且无任何行动
如果表达式为false,则断言失败,则会抛出一个AssertionError对象。这个AssertionError继承于Error对象,
而Error继承于Throwable,Error是和Exception并列的一个错误对象,通常用于表达系统级运行错误。
2. asser condition:expr;
这里condition是和上面样的这个冒号后跟的是个表达式,常用于断言败后的提示信息,白了它是一个
传到AssertionError构造函数的值,如果断言失败,该值被转化为它对应的字符串,并显示出来。
当执行代码时,使用-ea
选项使断言有效,也可以使用-da
选项使断言无效(默认为无效)
同样,也可以通过在-ea
或-da
后面指定包名来使一个包的断言有效或无效。例如,要使一个com.test
包中的断言
无效,可以使用:
-da:com.test
要使一个包中的所有子包中的断言能够有效或无效,在包名后加上三个点。例如:
-ea:com.test...
即可使com.test
包及其子包中的断言无效。
Java多态
多态是同一个行为具有多个不同表现形式或形态的能力。
多态就是同一个接口,使用不同的实例而执行不同操作
多态的优点
- 消除类型之间的耦合关系
- 可替换性
- 可扩充性
- 接口性
- 灵活性
- 简化性
多态存在的三个必要条件
- 继承
- 重写
- 父类引用指向子类对象
线程停止
情景模拟
假设现在又一个业务场景:这个业务场景的计算量非常大,非常耗时,为了不影响主线程的业务流程,需要启动一个新的线程去执行的,同时如果发现这个线程运行时间超过我们的预期时间限制(比如8小时)还没有运行完,就需要停止这个线程。防止系统内线程数量越来越多,最终导致OOM。
解决方案
方案一:stop()方法
public static void main(String[] args) {
test();
}
public static void test(){
Runnable thread = new Runnable() {
@Override
public void run() {
Integer num = new Integer(0);
System.out.println("thread is start");
for (int i = 0; i < 1000000000; i++) {
num++;
//do something
}
System.out.println("thread has end");
}
};
Thread thread1 = new Thread(thread);
thread1.start();
System.out.println("start");
try {
Thread.sleep(1000);
}catch (InterruptedException ignore){}
thread1.stop();
System.out.println("end");
}
这种方法也是可行,但是JAVA手册不推荐使用stop方法。
方案二:interrupt()方法
public static void main(String[] args) {
test();
}
public static void test(){
Runnable thread = new Runnable() {
@Override
public void run() {
Integer num = new Integer(0);
System.out.println("thread is start");
for (int i = 0; i < 1000000000; i++) {
num++;
//do something
if (Thread.interrupted()){
break;
}
/**
* 也可写成
* if (Thread.currentThread().isInterrupted()){
* break;
* }
*/
}
System.out.println("thread has end");
}
};
Thread thread1 = new Thread(thread);
thread1.start();
System.out.println("start");
try {
Thread.sleep(1000);
}catch (InterruptedException ignore){}
thread1.interrupt();
System.out.println("end");
}
Thread.sleep()为什么需要抛InterruptedException
当一个线程处于等待,睡眠,或者占用,也就是说阻塞状态,而这时线程被中断就会抛出这类错误。
Java6之后结束某个线程A的方法是A.interrupt()。如果这个线程正处于非阻塞状态,比如说线程正在执行某些代码的时候,不过被interrupt,那么该线程的interrupt变量会被置为true,告诉别人说这个线程被中断了(只是一个标志位,这个变量本身并不影响线程的中断与否),而且线程会被中断,这时不会有interruptedException。但如果这时线程被阻塞了,比如说正在睡眠,那么就会抛出这个错误。请注意,这个时候变量interrupt没有被置为true,而且也没有人来中断这个线程。
假设我们要结束一个线程。java6以后不推荐使用stop方法,而是interrupt方法,但是我们调用interrupt方法时不知道现成的状态是等待,睡眠,或者占用,当处于这几种状态之一时,我们调用interrupt中断线程。就会报异常。
public static void main(String[] args) {
test();
}
public static void test(){
Runnable thread = new Runnable() {
@Override
public void run() {
Integer num = new Integer(0);
System.out.println("thread is start");
//do something
try {
Thread.sleep(100000);
}catch (InterruptedException e){
e.printStackTrace();
}
System.out.println("thread has end");
}
};
Thread thread1 = new Thread(thread);
thread1.start();
System.out.println("start");
try {
Thread.sleep(1000);
}catch (InterruptedException ignore){}
thread1.interrupt();
System.out.println("end");
}
多个finally和return的执行顺序
finally不一定执行
- 在System.exit(0)之后的finally不执行
private static void testfinaly(){
int i = 0;
try{
try {
try {
}finally {
i = 4;
System.out.println(i);
}
i = 6;
System.out.println(i);
throw new RuntimeException();
}catch (Exception e){
}finally {
i = 2;
System.out.println(i);
}
i = 7;
System.out.println(i);
System.exit(0);
}finally {
i = 1;
System.out.println(i);
}
i = 5;
System.out.println(i);
}
结果
4
6
2
7
- 其他线程干扰,如stop
多个finally执行顺序
没有return的情况
private static void test(){
int i = 0;
try {
try {
try{
try{
i = 100;
}catch(Exception e){
}finally{
i = 1;
System.out.println(i);
}
i = 6;
System.out.println(i);
}finally{
i = 2;
System.out.println(i);
}
i = 7;
System.out.println(i);
try{
Thread.sleep(10);
}catch(Exception e){
}finally{
i = 8;
System.out.println(i);
}
}finally {
i = 3;
System.out.println(i);
}
}finally {
i = 4;
System.out.println(i);
}
i = 5;
System.out.println(i);
}
结果
1
6
2
7
8
3
4
5
finally依次执行
有return的情况
private static int testfinaly(){
int i = 0;
try {
try {
try{
try{
i = 100;
System.out.println(i);
return i;
}catch(Exception e){
}finally{
i = 1;
System.out.println(i);
}
i = 6;
System.out.println(i);
}finally{
i = 2;
System.out.println(i);
}
i = 7;
System.out.println(i);
try{
Thread.sleep(10);
}catch(Exception e){
}finally{
i = 8;
System.out.println(i);
}
}finally {
i = 3;
System.out.println(i);
}
}finally {
i = 4;
System.out.println(i);
}
i = 5;
System.out.println(i);
return i;
}
结果
100
1
2
3
4
返回:100
private static int testfinaly(){
int i = 0;
try {
try {
try{
try{
i = 100;
System.out.println(i);
}catch(Exception e){
}finally{
i = 1;
System.out.println(i);
}
i = 6;
System.out.println(i);
}finally{
i = 2;
System.out.println(i);
}
i = 7;
System.out.println(i);
try{
Thread.sleep(10);
}catch(Exception e){
}finally{
i = 8;
System.out.println(i);
}
return i;
}finally {
i = 3;
System.out.println(i);
}
}finally {
i = 4;
System.out.println(i);
}
}
结果
100
1
6
2
7
8
3
4
返回:8
return之前的finally在return之前运行,在return之后的finally在之后return之后执行。
20200624补充
public class Main {
private static int testA(){
int a = 9;
a = a +9;
a = a - 9;
a = a+19;
return a;
}
private static int testB(){
int a = 9;
a = a +9;
a = a - 9;
a = a+19;
return a;
}
private static int test(){
try{
return testA();
}finally {
testB();
}
}
public static void main(String[] args) {
test();
}
}
这段代码先执行testA() 还是testB() ?
答案是testA()