Java中final、finally和finalize的分别

1.final关键字

大家率先来说说final。它可以用来以下七个地点:

  1. 概念变量,包罗静态的和非静态的。
  2. 定义方法的参数。
  3. 定义方法。
  4. 定义类。大家一一来回想一下每一个处境下final的功能。

2.finally语句

接下去大家一并记忆一下finally的用法。那个就比较简单了,它不得不用在try/catch语句中并且附带着2个语句块,表示那段语句最终总是被实践。请看上面的代码:
Java代码

public final class FinallyTest {
public static void main(String[] args) {
try {
throw new NullPointerException();
} catch (NullPointerException e) {
System.out.println("程序抛出了异常");
} finally {
//这里总会被执行,不受break,return影响另如数据库连接的close()一般写在这里,可以降低程序的出错几率
System.out.println("执行了finally语句块");
}
}
}

运作结果印证了finally的功力: 1. 主次抛出了要命 2.
实施了finally语句块请大家小心,捕获程序抛出的11分之后,既不加处理,也不继续升高抛出尤其,并不是可以的编程习惯,它掩盖了程序执行中暴发的一无可取,那里只是利于演示,请不要上学。
那就是说,有没有一种意况使finally语句块得不到实践吗?大家兴许想到了
return、continue、break那多少个可以打乱代码顺序执行语句的法则。那我们就来试试看看,这多个语句是不是能影响finally语句块的实施:
Java代码public final class FinallyTest {
// 测试return语句
结果突显:编译器在编译return new
ReturnClass();时,将它分成了七个步骤,new
ReturnClass()和return,前多少个成立对象的话语是在finally语句块以前被实施的,而后二个return语句是在finally语句块之后执行的,约等于说finally语句块是在先后退出办法此前被执行的

public ReturnClass testReturn() {
try {
return new ReturnClass();
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("执行了finally语句");
}
return null;
}
// 测试continue语句
public void testContinue() {
for (int i = 0; i < 3; i++) {
try {
System.out.println(i);
if (i == 1) {
continue;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("执行了finally语句");
}
}
}
// 测试break语句
public void testBreak() {
for (int i = 0; i < 3; i++) {
try {
System.out.println(i);
if (i == 1) {
break;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
System.out.println("执行了finally语句");
}
}
}
public static void main(String[] args) {
FinallyTest ft = new FinallyTest();
// 测试return语句
ft.testReturn();
System.out.println();
// 测试continue语句
ft.testContinue();
System.out.println();
// 测试break语句
ft.testBreak();
}
}
class ReturnClass {   
  public ReturnClass() {     
     System.out.println("执行了return语句");  
   }
}

很显然,return、continue和break都没能阻止finally语句块的履行。从出口的结果来看,return语句就像在
finally语句块以前实施了,事实真的如此呢?大家来想想看,return语句的法力是怎么着吧?是脱离当前的主意,并将值或对象回来。假如finally语句块是在return语句之后执行的,那么return语句被执行后就已经脱离当前形式了,finally语句块又如何能被实施吗?因而,正确的执行种种应该是那样的:编译器在编译return
new ReturnClass();时,将它分为了三个步骤,new
ReturnClass()和return,前贰个创立对象的口舌是在finally语句块
后边被实践的,而后3个return语句是在finally语句块之后执行的,相当于说finally语句块是在先后退出格局以前被实施的。同样,finally语句块是在循环被跳过(continue)和刹车(break)在此之前被执行的。

1.2 定义方法当final用来定义1个艺术时,会有哪些意义啊?正如我们所知,它代表这几个艺术不得以被子类重写,然而它那不影响它被子类继承。大家写段代码来证可瑞康下:

Java代码

public class ParentClass {    
 public final void TestFinal() {        
  System.out.println("父类--这是一个final方法");    
 }
}
public class SubClass extends ParentClass {   
  /**     * 子类无法重写(override)父类的final方法,否则编译时会报错     */    
 // public void www.gzlij.com TestFinal() {   
  // System.out.println("子类--重写final方法");    
 // }     
public static void main(String[] args) {         
 SubClass sc = new SubClass();          
sc.TestFinal();    
 }
}

此地要求特殊表明的是,具有private访问权限的主意也得以扩充final修饰,但是出于子不能持续private方法,由此也惊惶失措重写它。编译器在处理private方法时,是依据final方来对待的,那样可以拉长该方法被调用时的功能。不过子类如故可以定义同父类中private方法具有同样结构的格局,可是那并不会爆发重写的功力,而且它们中间也不存在必然联系。

1.1 定义变量,包罗静态的和非静态的。定义方法的参数

第①种状态:
若果final修饰的是2个基本项目,就代表这么些变量被赋予的值是不可变的,即它是个常量;
如若final修饰的是3个对象,就代表那几个变量被予以的引用是不可变的
此处需求指示大家注意的是,不可变更的只是其一变量所保存的引用,并不是以此引用所针对的对象。
第2种意况:
final的意义与第①种意况同样。
实际上对于前二种情况,有一种更适用的发表final的意义的讲述,那就是,如若2个变量或形式参数被final修饰,就表示它只可以被赋值一遍,但是JAVA虚拟机为变量设定的专擅认同值不记作五回赋值。
被final修饰的变量必须被早先化。开始化的法门有以下三种:

  1. 在概念的时候开端化。
  2. final变量可以在伊始化块中初阶化,不可以在静态初阶化块中初始化。
  3. 静态final变量可以在静态伊始化块中伊始化,不得以在初始化块中开头化。
  4. final变量还足以在类的构造器中开首化,然而静态final变量不可以。
    透过上面的代码可以表达以上的看法:
    Java代码

public class FinalTest {     
// 在定义时初始化     
public final int A = 10;
// 在初始化块中初始化
public final int B;     
{          
      B = 20;     
}
// 非静态final变量不能在静态初始化块中初始化     
// public final int C;     
// static {          
// C = 30;     
// }
// 静态常量,在定义时初始化     
public static final int STATIC_D = 40;
// 静态常量,在静态初始化块中初始化
public static final int STATIC_E;     
static {       
   STATIC_E = 50;   
  }
// 静态变量不能在初始化块中初始化    
 // public static final int STATIC_F;    
 // {          
// STATIC_F = 60;    
 // }
public final int G;
// 静态final变量不可以在构造器中初始化     
// public static final int STATIC_H;     
// 在构造器中初始化          
public FinalTest() 
{             
  G = 70;
// 静态final变量不可以在构造器中初始化
// STATIC_H = 80;
// 给final的变量第二次赋值时,编译会报错
// A = 99;
// STATIC_D = 99;
}
// final变量未被初始化,编译时就会报错
// public final int I;
// 静态final变量未被初始化,编译时就会报错
// public static final int STATIC_J;
}

大家运维方面的代码之后出了可以发现final变量(常量)和静态final变量(静态常量)被开首化时,编译会报错。
用final修饰的变量(常量)比非final的变量(普通变量)拥有更高的功效,由此大家在际编程中应当尽量多的用常量来取代普通变量,那也是二个很好的编程习惯。

3.finalize方法

说到底,大家再来看看finalize,它是一个格局,属于java.lang.Object类,它的定义如下:Java代码protected
void finalize() throws Throwable {
}家弦户诵,finalize()方法是GC(garbage
collector)运维机制的一有个别在此大家只说说finalize()方法的成效是如何啊?finalize()方法是在GC清理它所从属的目的时被调用的,如若实施它的长河中抛出了无法捕获的百般(uncaught
exception),GC将告一段落对改目的的清理,并且该特别会被忽视;直到下三遍GC开首清理那一个目标时,它的finalize()会被另行调用。请看下边的言传身教:
Java代码

public final class FinallyTest {
// 重写finalize()方法
protected void finalize() throws Throwable {
System.out.println("执行了finalize()方法");
}
public static void main(String[] args) {
FinallyTest ft = new FinallyTest();
ft = null;
System.gc();
}
}

运作结果如下:• 执行了finalize()方法
先后调用了java.lang.System类的gc()方法,引起GC的执行,GC在清理ft对象时调用了它的finalize()方法,由此才有了地点的输出结果。调用System.gc()等同于调用上面那行代码:Java代码Runtime.getRuntime().gc();调用它们的效益只是提出垃圾收集器(GC)运营,清理无用的靶子释放内存空间,不过G的运转并不是必然的,那由JAVA虚拟机来决定。直到
JAVA虚拟机截至运转,有个别对象的finalize()大概都未曾被运维过,那么怎样保险全部目标的那些办法在JAVA虚拟机截至运营此前一定被调用呢?答案是大家得以调用System类的另贰个方法:
Java代码public static void runFinalizersOnExit(boolean value) {//other
code}
给这么些措施传入true就足以确保对象的finalize()方法在JAVA虚拟机甘休运营前一定被周转了,然则遗憾的是以此方式是不安全的,它会导致有用的目的finalize()被误调用,由此已不被赞成使用了。
由于finalize()属于Object类,因而全部类都有其一点子,Object的任意子类都可以重写(override)该方法,在里头释放系统财富可能做任何的清理工作,如关闭输入输出流。
参考
Java中final、finally、finalize的区别

1.3 定义类

末尾大家再来回想一下final用于类的情景。那几个我们应该也很熟练了,因为我们最常用的String类就是final的。由于final类不容许被持续,编译器在处理时把它的有所办法都当作final的,因此final类比普通类拥有更高的功用。而由主要字abstract定义的抽象类含有必须由一而再自它的子类重载达成的悬空方法,因而不只怕同时用final和abstract来修饰同三个类。同样的道理,final也不大概用来修饰接口。
final的类的保有办法都不能够被重写,但那并不代表final的类的质量(变量)值也是不行变更的,要想做到final类的属性值不可变更,必须给它伸张final修饰,请看上面的事例:
Java代码

public final class FinalTest {
int i = 10;
final int j = 50;
public static void main(String[] args) {
FinalTest ft = new FinalTest();
ft.i = 99;          // final类FinalTest的属性值 i是可以改变的,因为属性值i前面没有final修//
// ft.j = 49;         // 报错....因为 j 属性是final 的不可以改变。
System.out.println(ft.i);
}
}

运营方面的代码试试看,结果是99,而不是初叶化时的10。

相关文章