java关键字
1. final关键字是怎么用的?
(1)当用final修饰一个类时,表明这个类不能被继承。也就是说,如果一个类你永远不会让他被继承,就可以用final进行修饰。final类中的成员变量可以根据需要设为final,但是要注意final类中的所有成员方法都会被隐式地指定为final方法。
(2)使用final方法的原因有两个:
- 第一个原因是把方法锁定,以防任何继承类修改它的含义;父类的final方法是不能被子类所覆盖的,也就是说子类是不能够存在和父类一模一样的方法的。
- 第二个原因是效率。在早期的Java实现版本中,会将final方法转为内嵌调用。
(3)对于一个final变量:
- 如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改; final成员变量表示常量,只能被赋值一次,赋值后值不再改变。
- 如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象,但该引用所指向的对象的内容是可以发生变化的。
- final作用于类的成员变量时,成员变量必须在定义时或者构造器中进行初始化赋值。
2. 介绍一下volatile?
volatile关键字是用来保证有序性和可见性的。
这跟Java内存模型有关。计算机在执行程序时,每条指令都是在CPU中执行的,而执行指令过程中,势必涉及到数据的读取和写入。为了提高指令的执行速度CPU里面就有了高速缓存,也就是,当程序在运行过程中,会将运算需要的数据从主内存复制一份到CPU的高速缓存当中,那么CPU进行计算时就可以直接从它的高速缓存读取数据和向其中写入数据,当运算结束之后,再将高速缓存中的数据刷新到主内存当中。
比如执行代码: i = i + 1;
在多核CPU中,每条线程可能运行于不同的CPU中,因此每个线程运行时有自己的高速缓存(对单核CPU来说,其实也会出现这种问题,只不过是以线程调度的形式来分别执行的)。本文我们以多核CPU为例。++比如同时有2个线程执行这段代码,假如初始时i的值为0,那么我们希望两个线程执行完之后i的值变为2。但是可能存在下面一种情况:
初始时,两个线程分别读取i的值存入各自所在的CPU的高速缓存当中,然后线程1进行加1操作,然后把i的最新值1写入到内存。此时线程2的高速缓存当中i的值还是0,进行加1操作之后,i的值为1,然后线程2把i的值写入内存。最终结果i的值是1,而不是2。所以说如果一个变量在多个CPU中都存在缓存(一般在多线程编程时才会出现),那么就可能存在缓存不一致的问题。
当使用violate去申明一个变量时,volatile主要用于同步线程数据。就等于告诉了虚拟机这个变量极有可能会被某些程序或者线程修改。为了确保这个变量被修改后,应用程序中的其他的线程都可以看到这个改动,虚拟机就必须采用一些特殊的手段,来保证了多核CPU之间数据不一致性问题。
4. 请你介绍一下Syncronized关键字,如果用这个关键字修饰一个静态方法,锁住了什么?如果修饰成员方法,锁住了什么?
synchronized修饰静态方法以及同步代码块的synchronized,其锁就是当前类的 class 类锁。线程想要执行对应同步代码,需要获得类锁。synchronized修饰成员方法,线程获取的是当前调用该方法的对象实例的对象锁。
(1)修饰一个类,其作用的范围是synchronized后面括号括起来的部分,作用的对象是这个类的所有对象。
(2)修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
(3)修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
(4)修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
5. JAVA语言如何进行异常处理,关键字:throws,throw,try,catch,finally分别代表什么意义?在try块中可以抛出异常吗?
Java 通过面向对象的方法进行异常处理,把各种不同的异常进行分类,并提供了良好的接口。在Java中,每个异常都是一个对象,它是Throwable类或其它子类的实例。当一个方法出现异常后便抛出一个异常对象,该对象中包含有异常信息,调用这个对象的方法可以捕获到这个异常并进行处理。
**为什么要抛出异常?**因为如果不抛出异常,程序执行的时候,出现错误,会直接停止执行。如果抛出异常,并且catch捕获了该异常,我们就在捕获异常的时候进行一些操作,并且程序还能继续执行。
在 Java 中,所有的异常都有一个共同的祖先java.lang包中的 Throwable类。Throwable:有两个重要的子类:Exception(异常) 和 Error(错误) ,二者都是 Java 异常处理的重要子类,各自都包含大量子类。
Java的异常处理是通过5个关键词来实现的:try、catch、throw、throws和finally。
- try用来指定一块预防所有异常的程序;
- catch子句紧跟在try块后面,用来指定你想要捕获的异常的类型;
- throw语句用来明确地抛出一个异常;
- throws用来声明一个方法可能抛出的各种异常;
- finally为确保一段代码不管发生什么异常状况都要被执行;
可以在一个成员函数调用的外面写一个try语句,在这个成员函数内部写另一个try语句保护其他代码。每当遇到一个try语句,”异常“的框架就放到堆栈上面,直到所有的try语句都完成。如果下一级的try语句没有对某种”异常”进行处理,堆栈就会展开,直到遇到有处理这种”异常”的try语句。
在以下4种特殊情况下,finally块不会被执行:
- 在finally语句块第一行发生了异常。因为在其他行,finally块还是会得到执行
- 在前面的代码中用了System.exit(int)已退出程序。exit是带参函数 ;若该语句在异常语句之后,finally会执行
- 程序所在的线程死亡。
- 关闭CPU。
6. final, finally, finalize的区别。
- final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。
- finally是异常处理语句结构的一部分,表示总是执行。
- finalize是Object类的一个方法,也就是说每一个对象都有这么个方法。在垃圾收集器执行GC的时候会调用此方法。
- 凡是new出来的对象,gc都能搞定,一般情况下我们又不会用new以外的方式去创建对象),所以一般是不需要程序员去实现finalize的。特殊情况下,需要程序员实现finalize,当对象被回收的时候释放一些资源,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等。