java script和java有什么区别_Java中final finally finalize的区别(其实没什么联系 不过面试官喜欢这么问)
题注:
按我的个人理解,这个题目本身就问的有点问题,因为这3个关键字之间没啥关系,是相对独立的,我猜想这道题的初衷应该是想了解面试者对Java中final finally finalize的使用方法的掌握情况,只是因为3个关键字比较像,而成了现在网上流传的题目“Java中final finally finalize的区别”。
既然是想了解面试者对Java中final finally finalize的使用方法的掌握情况,那么我们就分别讲解下final,finally,finalize的使用方法。
1. final用法
我们先看下final的英文释义:最终的;决定性的;不可更改的,不禁要推测被final修饰的变量,方法或者类是不是不可修改的呢?
1.1 final修饰类
在Java中,被final修饰的类,不能被继承,也就是final类的成员方法没有机会被继承,也没有机会被重写。
在设计类的时候,如果这个类不需要有子类,类的实现细节不允许改变,那么就可以设计为final类。
我们在开发中经常使用的String类就是final类,以下为部分源码:
public final class Stringimplements java.io.Serializable, Comparable<String>, CharSequence {......
}
1.2 final修饰方法
在Java中,被final修饰的方法,可以被继承,但不能被子类重写(覆盖)。
在设计方法时,如果这个方法不希望被子类重写(覆盖),那么就可以设计为final方法。
举个具体的例子,我们新建个父类Animal如下:
package com.zwwhnly.springbootaction;public class Animal {public void eat() {System.out.println("Animal eat.");}public void call() {System.out.println("Animal call.");}public final void fly() {System.out.println("Animal fly.");}private final void swim() {System.out.println("Animal swim.");}
}
然后定义一个子类Cat继承Animal类,代码如下:
package com.zwwhnly.springbootaction;public class Cat extends Animal {@Overridepublic void eat() {System.out.println("Cat eat.");}@Overridepublic void fly() {System.out.println("Cat fly.");}public static void main(String[] args) {Cat cat = new Cat();cat.eat();cat.call();cat.fly();cat.swim();}
}
我们会发现,以上代码中有以下2个错误:
1)当我们重写fly()方法时,因为父类的fly()方法被定义为final方法,重写时会编译错误
2)cat.swim();
报错,因为父类的swim()方法被定义为private,子类是继承不到的
然后我们将报错的代码删除,运行结果如下:
Cat eat.
Animal call.
Animal fly.
也就是eat()方法被子类重写了,继承了父类的成员方法call()和final方法fly()。
但是值得注意的是,在子类Cat中,我们是可以重新定义父类的私有final方法swim()的,不过此时明显不是重写(你可以加@Override试试,会编译报错),而是子类自己的成员方法swim()。
package com.zwwhnly.springbootaction;public class Cat extends Animal {@Overridepublic void eat() {System.out.println("Cat eat.");}public void swim() {System.out.println("Cat swim.");}public static void main(String[] args) {Cat cat = new Cat();cat.eat();cat.call();cat.fly();cat.swim();}
}
此时的运行结果为:
Cat eat.
Animal call.
Animal fly.
Cat swim.
1.3 final修饰成员变量
用final修饰的成员变量没有默认值,可以在声明时赋值或者在构造函数中赋值,但必须赋值且只能被赋值1次,赋值后无法修改。
我们修改下1.2中的Cat类代码,定义2个final成员变量,1个声明完立即赋值,1个在构造函数中赋值:
package com.zwwhnly.springbootaction;public class Cat extends Animal {private final int age = 1;private final String name;public Cat(String name) {this.name = name;}@Overridepublic void eat() {System.out.println("Cat eat.");}public static void main(String[] args) {Cat whiteCat = new Cat("小白");whiteCat.age = 2;System.out.println(whiteCat.age);System.out.println(whiteCat.name);Cat blackCat = new Cat("小黑");blackCat.name = "小黑猫";System.out.println(blackCat.age);System.out.println(blackCat.name);}
}
以上代码有2个编译错误,1个是whiteCat.age = 2;
修改成员变量age时,另1个是blackCat.name = "小黑猫";
修改成员变量name时,都提示不能修改final成员变量。
删除掉错误的代码,运行结果如下:
1
小白
1
小黑
1.4 final修饰局部变量
被final修饰的局部变量,既可以在声明时立即赋值,也可以先声明,后赋值,但只能赋值一次,不可以重复赋值。
修改下Cat类的eat()方法如下:
@Override
public void eat() {final String breakfast;final String lunch = "午餐";breakfast = "早餐";lunch = "午餐2";breakfast = "早餐2";System.out.println("Cat eat.");
}
以上代码中2个错误,1个是lunch = "午餐2";
,1个是breakfast = "早餐2";
,都是对final局部变量第2次赋值时报错。
1.5 final修饰方法参数
方法参数其实也是局部变量,因此final修饰方法参数和1.4中final修饰局部变量的使用类似,即方法中只能使用方法的参数值,但不能修改参数值。
在Cat类中新增方法printCatName,将方法参数修饰为final:
public static void main(String[] args) {Cat whiteCat = new Cat("小白");whiteCat.printCatName(whiteCat.name);
}public void printCatName(final String catName) {//catName = "修改catName"; // 该行语句会报错System.out.println(catName);
}
运行结果:
小白
2. finally用法
提起finally,大家都知道,这是Java中处理异常的,通常和try,catch一起使用,主要作用是不管代码发不发生异常,都会保证finally中的语句块被执行。
你是这样认为的吗?说实话,哈哈。
那么问题来了,finally语句块一定会被执行吗?,答案是不一定。
让我们通过具体的示例来证明该结论。
2.1 在 try 语句块之前返回(return)或者抛出异常,finally不会被执行
package com.zwwhnly.springbootaction;public class FinallyTest {public static void main(String[] args) {System.out.println("return value of test():" + test());}public static int test() {int i = 1;/*if (i == 1) {return 0;}*/System.out.println("the previous statement of try block");i = i / 0;try {System.out.println("try block");return i;} finally {System.out.println("finally block");}}
}
运行结果如下:
也就是说,以上示例中,finally语句块没有被执行。
然后我们将上例中注释的代码取消注释,此时运行结果为:
return value of test():0
finally语句块还是没有被执行,因此,我们可以得出结论:
只有与 finally 相对应的 try 语句块得到执行的情况下,finally 语句块才会执行。
以上两种情况,都是在 try 语句块之前返回(return)或者抛出异常,所以 try 对应的 finally 语句块没有执行。
2.2 与 finally 相对应的 try 语句块得到执行,finally不一定会被执行
那么,与 finally 相对应的 try 语句块得到执行的情况下,finally 语句块一定会执行吗?答案仍然是不一定。
看下下面这个例子:
package com.zwwhnly.springbootaction;public class FinallyTest {public static void main(String[] args) {System.out.println("return value of test():" + test());}public static int test() {int i = 1;try {System.out.println("try block");System.exit(0);return i;} finally {System.out.println("finally block");}}
}
运行结果为:
try block
finally语句块还是没有被执行,为什么呢?因为我们在try语句块中执行了System.exit(0);
,终止了Java虚拟机的运行。当然,一般情况下,我们的应用程序中是不会调用System.exit(0);
的,那么,如果不调用这个方法,finally语句块一定会被执行吗?
答案当然还是不一定,当一个线程在执行 try 语句块或者 catch 语句块时被打断(interrupted)或者被终止(killed),与其相对应的 finally 语句块可能不会执行。还有更极端的情况,就是在线程运行 try 语句块或者 catch 语句块时,突然死机或者断电,finally 语句块肯定不会执行了。当然,死机或者断电属于极端情况,在这里只是为了证明,finally语句块不一定会被执行。
2.3 try语句块或者catch语句块中有return语句
如果try语句块中有return语句, 是return语句先执行还是finally语句块先执行呢?
带着这个问题,我们看下如下这个例子:
package com.zwwhnly.springbootaction;public class FinallyTest {public static void main(String[] args) {try {System.out.println("try block");return;} finally {System.out.println("finally block");}}
}
运行结果:
try block
finally block
结论:finally 语句块在 try 语句块中的 return 语句之前执行。
如果catch语句块中有return语句,是return语句先执行还是finally语句块先执行呢?
带着这个问题,我们看下如下这个例子:
package com.zwwhnly.springbootaction;public class FinallyTest {public static void main(String[] args) {System.out.println("return value of test():" + test());}public static int test() {int i = 1;try {System.out.println("try block");i = i / 0;return 1;} catch (Exception e) {System.out.println("catch block");return 2;} finally {System.out.println("finally block");}}
}
运行结果:
try block
catch block
finally block
return value of test():2
结论:finally 语句块在 catch 语句块中的 return 语句之前执行。
通过上面2个例子,我们可以看出,其实 finally 语句块是在 try 或者 catch 中的 return 语句之前执行的。更加一般的说法是,finally 语句块应该是在控制转移语句之前执行,控制转移语句除了 return 外,还有 break ,continue和throw。
2.4 其它几个例子
示例1:
package com.zwwhnly.springbootaction;public class FinallyTest {public static void main(String[] args) {System.out.println("return value of getValue():" + getValue());}public static int getValue() {try {return 0;} finally {return 1;}}
}
运行结果:
return value of getValue():1
示例2:
package com.zwwhnly.springbootaction;public class FinallyTest {public static void main(String[] args) {System.out.println("return value of getValue():" + getValue());}public static int getValue() {int i = 1;try {return i;} finally {i++;}}
}
运行结果:
return value of getValue():1
也许你会好奇,应该会返回2,怎么返回1了呢?可以借鉴下以下内容来理解(牵扯到了Java虚拟机如何编译finally语句块):
实际上,Java 虚拟机会把 finally 语句块作为 subroutine(对于这个 subroutine 不知该如何翻译为好,干脆就不翻译了,免得产生歧义和误解。)直接插入到 try 语句块或者 catch 语句块的控制转移语句之前。但是,还有另外一个不可忽视的因素,那就是在执行 subroutine(也就是 finally 语句块)之前,try 或者 catch 语句块会保留其返回值到本地变量表(Local Variable Table)中。待 subroutine 执行完毕之后,再恢复保留的返回值到操作数栈中,然后通过 return 或者 throw 语句将其返回给该方法的调用者(invoker)。请注意,前文中我们曾经提到过 return、throw 和 break、continue 的区别,对于这条规则(保留返回值),只适用于 return 和 throw 语句,不适用于 break 和 continue 语句,因为它们根本就没有返回值。
示例3:
package com.zwwhnly.springbootaction;public class FinallyTest {public static void main(String[] args) {System.out.println("return value of getValue():" + getValue());}public static int getValue() {int i = 1;try {i = 4;} finally {i++;return i;}}
}
运行结果:
return value of getValue():5
示例4:
package com.zwwhnly.springbootaction;public class FinallyTest {public static void main(String[] args) {System.out.println("return value of getValue():" + getValue());}public static int getValue() {int i = 1;try {i = 4;} finally {i++;}return i;}
}
运行结果:
return value of getValue():5
示例5:
package com.zwwhnly.springbootaction;public class FinallyTest {public static void main(String[] args) {System.out.println(test());}public static String test() {try {System.out.println("try block");return test1();} finally {System.out.println("finally block");}}public static String test1() {System.out.println("return statement");return "after return";}
}
try block
return statement
finally block
after return
2.5 总结
- finally语句块不一定会被执行
- finally语句块在 try语句块中的return 语句之前执行。
- finally语句块在 catch语句块中的return 语句之前执行。
- 注意控制转移语句 return ,break ,continue,throw对执行顺序的影响
3. finalize用法
finalize()是Object类的一个方法,因此所有的类都继承了这个方法。
protected void finalize() throws Throwable { }
finalize()主要用于在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。
当垃圾回收器(GC)决定回收某对象时,就会运行该对象的finalize()方法。
不过在Java中,如果内存总是充足的,那么垃圾回收可能永远不会进行,也就是说filalize()可能永远不被执行,显然指望它做收尾工作是靠不住的。
java script和java有什么区别_Java中final finally finalize的区别(其实没什么联系 不过面试官喜欢这么问)相关推荐
- Java中string与String区别_JAVA中String与StringBuffer的区别
JAVA中String与StringBuffer的区别 2009-12-3文字大小:大中小 在java中有3个类来负责字符的操作. 1.Character 是执行 单个字符操作的, 2.String ...
- java中的成员变量和局部变量的区别_java中成员变量与局部变量区别分析
本文实例分析了java中成员变量与局部变量区别.分享给大家供大家参考.具体分析如下: 成员变量:在这个类里定义的私有变量,属于这个类. 创建以及使用成员变量 public class Person { ...
- java long 区别_java中long和int的区别
java中long和int的区别 发布时间:2020-06-26 15:37:48 来源:亿速云 阅读:191 作者:Leah 这篇文章将为大家详细讲解有关java中long和int的区别,文章内容质 ...
- JAVA中重写和实现的区别_Java中重载和重写的区别
Java中重载和重写的区别 1.1重载是什么 Overloading 方法重载是让类以统一的方式处理不同类型数据的一种手段,多个同名函数同时存在,具有不同的参数个数/类型 1.2为什么用重载 重载 ...
- java instanceof 区别_Java 中 instanceof 和 isInstance 的区别
今天百度了一下 instanceof 和 isInstance() 的区别,结果不理想.大多数人先贴一段测试代码,然后分别解释它们的用法,根本不是解释它们之间的区别. 本来想快点搜一下看个结论,不料还 ...
- java中堆与栈的区别_java中堆和栈的区别分析
堆和栈是Java数据结构里非常重要的概念,本文较为详细的分析了二者之间的区别.供大家参考.具体如下: Java的堆是一个运行时数据区,类的(对象从中分配空间.这些对象通过new.newarray.an ...
- java 抽象类与接口区别是什么_JAVA中抽象类与接口的区别,分别在什么情况下使用它们...
在网上看到很多人问关于"抽象类与接口的区别",因此本人想通过自己多年对JAVA开发的经验来总结一下抽象类与接口的区别以及分别在什么情况下使用它们. 在Java语言中, abstra ...
- java final f的区别_Java中final、finally、finalize的简单区别,中等区别,详细区别(Lawliet 修改+注释版)...
简单区别: 中等区别: 虽然这三个单词在Java中都存在,但是并没有太多关联: final:java中的关键字,修饰符. 1.如果一个类被声明为final,就意味着它不能再派生出新的子类,不能作为父类 ...
- java中break和return的区别_java 中return和break的区别
在java的方法中,分为带返回参数和无返回参数两种方法.在带返回参数的方法体中,需要用return来返回该参数并表示该方法体执行完毕,该方法体中return后的语句将不会被执行.在无返回参数的方法中, ...
- Java set的区别_java中List 和 Set 的区别
a. 特性 两个接口都是继承自Collection,是常用来存放数据项的集合,主要区别如下: ① List和Set之间很重要的一个区别是是否允许重复元素的存在,在List中允许插入重复的元素,而在S ...
最新文章
- SQL UPDATE SET FROM用法
- java栈实现简易计算器算法
- reload vue 重新加载_vue面试,谈下router拦截
- c语言中栈堆,全程剖析C语言中堆和栈的区别
- WordPress程序伪静态规则(Nginx/Apache)及二级目录规则
- linux7.4 root密码,[RHEL 7.4] 忘记root密码,普通用户又没有sudo权限,怎么办?
- Linux 管道(pipe)原理及使用
- JAVA基础之JDK、JRE、JVM关系
- 千万不能返回局部变量的引用
- qrc文件编译到可执行文件exe
- IT之家精华:苹果iOS系统发布/固件下载/升级更新大全表~
- web前端数据可视化控件
- 用计算机弹苹果手机铃声,苹果手机如何设置铃声
- QT练习samp2_2_test——用按钮编辑文本框特性
- python-转义字符及其使用
- 端午安康,用python给你画盘粽子~啾啾
- 4月22日丨【云数据库技术沙龙】技术进化,让数据更智能
- mysql get seq no_mysql的存储怎么写?帮我看看我这个写的哪里有问题?谢谢
- quartus编译报错:Error (176310): Can‘t place multiple pins assigned to pin location Pin_F16 (IOPAD_X34_Y1
- 二维动画设计软件应用——Flash CS6全书电子教案完整版电子教案