📅  最后修改于: 2020-03-29 06:16:56             🧑  作者: Mango
这是关于访谈观点的重要问题。
final(小写)是Java中的保留关键字。我们不能将其用作标识符,因为它已被保留。我们可以将此关键字与变量,方法以及类一起使用。Java中的final关键字具有不同的含义,具体取决于将其应用于变量,类或方法。
class A {
public static void main(String[] args)
{
// 非final变量
int a = 5;
// final变量
final int b = 6;
// 修改非final变量,合法
a++;
// final变量,编译错误,非法
b++;
}
}
如果我们将任何变量声明为final,则因为它是final,所以无法修改其内容;如果我们对其进行修改,则会出现编译时错误。
final class RR {
public static void main(String[] args)
{
int a = 10;
}
}
// 编译错误
class KK extends RR {
// 待写
}
class QQ {
final void rr() {}
public static void main(String[] args)
{
}
}
class MM extends QQ {
// 编译错误
void rr() {}
}
注意:如果将一个类声明为final,则默认情况下,该类中存在的所有方法都将自动为final,但变量不是。
// Java展示final关键字
final class G {
// 默认为final.
void h() {}
// 默认不是final.
static int j = 30;
public static void main(String[] args)
{
// 变量j被修改
j = 36;
System.out.println(j);
}
}
输出:
36
finally关键字
就像final是保留关键字一样,同样,finally也是Java中的保留关键字,即我们不能将其用作标识符。finally关键字与try/catch块结合使用,并确保即使抛出异常也将执行一段代码。finally块将在try和catch块之后但在控制权移回其原始位置之前执行。
// Java展示使用finally.
class 芒果 {
static void A()
{
try {
System.out.println("在A");
throw new RuntimeException("demo");
}
finally
{
System.out.println("A的finally");
}
}
// 这个方法也会调用finally
static void B()
{
try {
System.out.println("在B");
return;
}
finally
{
System.out.println("B的finally");
}
}
public static void main(String args[])
{
try {
A();
}
catch (Exception e) {
System.out.println("报出异常");
}
B();
}
}
输出:
在A
A的finally
报出异常
在B
B的finally
finally可以使用多种情况。讨论如下:
// Java展示使用finally,无异常
class B {
public static void main(String[] args)
{
int k = 55;
try {
System.out.println("在try内");
int z = k / 55;
}
catch (ArithmeticException e) {
System.out.println("在catch内");
System.out.println("除以0");
}
finally
{
System.out.println("无论是否异常都会执行");
}
}
}
输出:
在try内
无论是否异常都会执行
在这里,上面的异常不会发生,但是finally块仍然执行,因为finally意味着无论是否发生异常都将执行。
以上程序的流程:首先,它从main方法开始,然后进入try块,在try中,因为没有发生异常,所以流程不会进入catch块,因此流程直接从try到finally块。
// Java展示finally和异常发生
class C {
public static void main(String[] args)
{
int k = 66;
try {
System.out.println("try内");
int z = k / 0;
System.out.println("flow没到这");
}
catch (ArithmeticException e) {
System.out.println("catch内");
System.out.println("除以0");
}
finally
{
System.out.println("无论是否异常都会执行");
}
}
}
输出:
try内
catch内
除以0
无论是否异常都会执行
在此,发生上述异常并且找到了相应的捕获块,但是仍然finally块被执行,因为finally意味着执行是否发生异常或者是否找到相应的捕获块。
以上程序的流程:首先,从main方法开始,然后进入try块,在尝试中发生算术异常,并且相应的catch块也可用,因此流程进入catch块。在那之后,执行finally意味着执行无论是否发生异常或是否找到相应的catch块。
// Java展示发生异常,并且未找到/匹配相应的捕获块
class D {
public static void main(String[] args)
{
int k = 15;
try {
System.out.println("在try内");
int z = k / 0;
}
catch (NullPointerException e) {
System.out.println("在catch内");
System.out.println("除以0");
}
finally
{
System.out.println("无论是否异常都会执行");
}
}
}
输出:
在try内
无论是否异常都会执行
Exception in thread "main":java.lang.ArithmeticException:
/ by zero followed by stack trace.
在此,发生上述异常,并且未找到/匹配相应的捕获块,但仍finally块执行,因为finally意味着执行无论是否发生异常或是否找到/匹配相应的捕获块。
上述程序的流程:首先从main方法开始,然后去try块,和try中出现算术异常和与之对应的catch是不是可用。在那之后,执行finally,从那以后意味着无论是否发生异常,或者是否找到/匹配相应的捕获块。
finally块的应用:因此,finally块的基本用途是资源释放。意味着需要关闭在try块中打开的所有资源(例如网络连接,数据库连接),以便在打开时不会丢失资源。因此,需要在finally块中关闭这些资源。
// Java说明finally块的应用
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
class K {
private static final int SIZE = 10;
public static void main(String[] args)
{
PrintWriter out = null;
try {
System.out.println("try内");
// PrintWriter, FileWriter
out = new PrintWriter(new FileWriter("OutFile.txt"));
}
catch (IOException e) {
// FileWriter在try内报错IOException
}
// finally会清空PrintWriter.
finally
{
if (out != null) {
System.out.println("关闭PrintWriter");
out.close();
} else {
System.out.println("PrintWriter没被打开");
}
}
}
}
输出:
try内
PrintWriter没被打开
注意:finally块是防止资源泄漏的关键工具。当关闭文件或以其他方式恢复资源时,请将代码放在finally块中以确保始终恢复资源。
jdk 1.7如何使使用finally块为可选的
直到jdk 1.6 finally块就像英雄一样,即建议将其用于资源释放,但是从jdk 1.7开始,finally块现在是可选的(但是您可以使用它)。由于当程序流到达try块的末尾时,我们在try块中打开的资源将自动释放/关闭。
不使用finally块的自动资源重新分配的概念称为try-with-resources语句。
finalize方法
该方法是垃圾收集器始终在删除/销毁符合垃圾收集条件的对象之前调用的方法,以执行清理活动。清理活动意味着关闭与该对象关联的资源,例如数据库连接、网络连接,或者我们可以说是收回资源分配。请记住,它不是保留关键字。
一旦finalize方法完成,垃圾收集器立即销毁该对象。finalize方法存在于Object类中,其语法为:
protected void finalize throws Throwable{}
因为Object类包含finalize方法,所以因为Object是所有Java类的超类,所以finalize方法可用于每个Java类。由于每个Java类都可以使用它,因此Garbage Collector可以在任何Java对象上调用finalize方法。
现在,Object类中存在的finalize方法具有空的实现,在我们的类中有清理活动,那么我们就可以重写这个方法来定义我们自己的清理活动。
与finalize方法有关的例子:
class Hello {
public static void main(String[] args)
{
String s = new String("RR");
s = null;
// 要求JVM调用垃圾回收方法
System.gc();
System.out.println("Main完成");
}
// 重写finalize方法
public void finalize()
{
System.out.println("finalize方法被重写");
}
}
输出:
Main完成
注意:上面的输出仅是Main Completes,而不是 “ finalize方法被重写”,因为垃圾回收器Garbage Collector在有资格进行Garbage收集的类对象上调用finalize方法。在上面的代码中,我们完成了->s = null,并且’s’是String类的对象,因此将调用String类的finalize方法,而不是我们的类(即Hello类)。因此,我们将代码修改为->
Hello s = new Hello();
s = null;
现在我们的类,即Hello类的finalize方法被调用。输出:
finalize方法被重写
Main完成
因此,基本上,垃圾收集器会在符合垃圾收集条件的类对象上调用finalize方法,因此,如果String对象符合垃圾收集条件,则将调用String类的finalize方法而不是Hello类的 finalize方法。
class Bye {
public static void main(String[] args)
{
Bye m = new Bye();
// 显示调用finalize方法
m.finalize();
m.finalize();
m = null;
// 要求JVM调用垃圾回收方法
System.gc();
System.out.println("Main完成");
}
// 重写finalize方法
public void finalize()
{
System.out.println("finalize方法被重写");
}
}
输出:
finalize方法被重写
//对象没被销毁
finalize方法被重写
//对象没被销毁.
Main完成
finalize方法被重写
//垃圾回收被调用,对象被销毁.
注意:由于finalize是一个方法,而不是保留的关键字,因此我们可以显式调用finalize方法,然后它将像普通方法调用一样执行,但不会删除/销毁对象。
class Hi {
public static void main(String[] args)
{
Hi j = new Hi();
// 显示调用finalize方法.
j.finalize();
j = null;
// 要求JVM调用垃圾回收方法
System.gc();
System.out.println("Main完成");
}
// finalize方法被重写
public void finalize()
{
System.out.println("finalize方法被重写");
System.out.println(10 / 0);
}
}
输出:
exception in thread "main" java.lang.ArithmeticException:
/ by zero followed by stack trace.
因此关键是:如果程序员调用finalize方法,而在执行finalize方法时出现一些未经检查的异常,那么JVM将通过引发异常异常终止程序。因此,在这种情况下,程序终止是异常的。
class RR {
public static void main(String[] args)
{
RR q = new RR();
q = null;
// 要求JVM调用垃圾回收方法
System.gc();
System.out.println("Main完成");
}
// finalize方法被重写
public void finalize()
{
System.out.println("finalize方法被重写");
System.out.println(10 / 0);
}
}
输出:
finalize方法被重写
Main完成
因此关键是:如果垃圾回收器调用finalize方法,而在执行finalize方法时出现一些未经检查的异常,则JVM将忽略该异常,并且程序的其余部分将继续正常进行。因此,在这种情况下,程序终止为“ 正常”并且不是异常。
重要事项: