Java中final、finally、finalize的区别和用法

1.简单区别

  • final用于声明属性,方法和类,分别表示属性不可交变,方法不可覆盖,类不可继承。
  • finally是异常处理语句结构的一部分,表示总是执行。
  • finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,供垃圾收集时的其他资源回收,例如关闭文件等。

2.中等区别

  • final:java中的关键字,修饰符。

A).如果一个类被声明为final,就意味着它不能再派生出新的子类,不能作为父类被继承。因此,一个类不能同时被声明为abstract抽象类的和final的类。

B).如果将变量或者方法声明为final,可以保证它们在使用中不被改变.
                  1)被声明为final的变量必须在声明时给定初值,而在以后的引用中只能读取,不可修改。
                  2)被声明final的方法只能使用,不能重载。

  • finally:java的一种异常处理机制。

  finally是对Java异常处理模型的最佳补充。finally结构使代码总会执行,而不管无异常发生。使用finally可以维护对象的内部状态,并可以清理非内存资源。特别是在关闭数据库连接这方面,如果程序员把数据库连接的close()方法放到finally中,就会大大降低程序出错的几率。

  • finalize:Java中的一个方法名。

       Java技术使用finalize()方法在垃圾收集器将对象从内存中清除出去前,做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没被引用时对这个对象调用的。它是在Object类中定义的,因此所的类都继承了它。子类覆盖finalize()方法以整理系统资源或者执行其他清理工作。finalize()方法是在垃圾收集器删除对象之前对这个对象调用的。

3.详细区别

  • final:final关键字我们首先来说说final。它可以用于以下四个地方:

1).定义变量,包括静态的和非静态的。
           2).定义方法的参数。
           3).定义方法。
           4).定义类。

(1)定义变量,包括静态的和非静态的。定义方法的参数

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;}

扫描二维码关注公众号,回复: 4714272 查看本文章

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 L;

//静态final变量未被初始化,编译时就会报错
//public static final int STATIC_J;
}

(2)定义方法:当final用来定义一个方法时,它表示这个方法不可以被子类重写,但是并不影响它被子类继承。

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

(3)定义类:final的类的所方法都不能被重写,但这并不表示final的类的属性(变量值也是不可改变的,要想做到final类的属性值不可改变,必须给它增加final修饰。

public final class FinalTest{
    int i =20;
    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);
    }
}

 

  • finally语句:finally只能用在try/catch语句中并且附带着一个语句块,表示这段语句最终总是被执行。

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语句块请大家注意,捕获程序抛出的异常之后,既不加处理,也不继续向上抛出异常,并不是良好的编程习惯,它掩盖了程序执行中发生的错误,这里只是方便演示,请不要学习。那么,没一种情况使finally语句块得不到执行呢?

return、continue、break这个可以打乱代码顺序执行语句的规律。

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){
                    System.out.println("con");
                }
            } 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语句
执行了finally语句

0
执行了finally语句
1
con
执行了finally语句
2
执行了finally语句

0
执行了finally语句
1
执行了finally语句

很明显,return、continue和break都没能阻止finally语句块的执行。从输出的结果来看,return语句似乎在finally语句块之前执行了,事实真的如此吗?我们来想想看,return语句的作用是什么呢?是退出当前的方法,并将值或对象返回。如果 finally语句块是在return语句之后执行的,那么return语句被执行后就已经退出当前方法了,finally语句块又如何能被执行呢?因此,正确的执行顺序应该是这样的:编译器在编译return new ReturnClass();时,将它分成了两个步骤,new ReturnClass()和return,前一个创建对象的语句是在finally语句块之前被执行的,而后一个return语句是在finally语句块之后执行的,也就是说finally语句块是在程序退出方法之前被执行的。同样,finally语句块是在循环被跳过(continue和中断(break之前被执行的 。

  •  finalize方法

最后,我们再来看看finalize,它是一个方法,属于java.lang.Object类,它的定义如下:protected void finalize()throws Throwable{}众所周知,finalize()方法是GC(garbagecollector运行机制的一部分,在此我们只说说finalize()方法的作用是什么呢?finalize()方法是在GC清理它所从属的对象时被调用的,如果执行它的过程中抛出了无法捕获的异(uncaughtexception,GC将终止对改对象的清理,并且该异常会被忽略;直到下一次GC开始清理这个对象时,它的finalize()会被再次调用。

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()等同于调用下面这行代码:Runtime.getRuntime().gc();调用它们的作用只是建议垃圾收集器(GC启动,清理无用的对象释放内存空间,但是GC的启动并不是一定的,这由JAVA虚拟机来决定。直到 JAVA虚拟机停止运行,些对象的finalize()可能都没被运行过,那么怎样保证所对象的这个方法在JAVA虚拟机停止运行之前一定被调用呢?答案是我们可以调用System类的另一个方法: 

public static void FunFinalizersOnExit(boolean value){
    //othercode
}  

      给这个方法传入true就可以保证对象的finalize()方法在JAVA虚拟机停止运行前一定被运行了,不过遗憾的是这个方法是不安全的,它会导致有用的对象finalize()被误调用,因此已不被赞成使用了。由于finalize()属于Object类,因此所类都这个方法,Object的任意子类都可以重写(override该方法,在其中释放系统资源或者做其它的清理工作,如关闭输入输出流。通过以上知识的回顾,我想大家对于final、finally、finalize的用法区别已经很清楚了。

猜你喜欢

转载自blog.csdn.net/liu066154/article/details/84571352