`

final、finally、finalize

    博客分类:
  • Java
阅读更多

final关键字
先看看final关键字,它可以被用于以下几个地方:
1、修饰属性、局部变量、方法参数:
如果final修饰的是一个基本类型,就表示这个变量所赋予的值不可修改,即它是个常量;如果final修饰的是一个对象,就表示这个变量被赋予的引用不可修改(但我们可以修改该引用所指向对象里的内容,这里所说的不可修改是指final修改的引用一但指向了谁,就不能再指向别的对象了)。下面来看看修改属性与变量时需要注意的几点:

在方法中定义的内部类只能访问方法中的final类型的局部变量,因为用final定义的局部变量是一个常量,运行时不是放在栈里的,因此它的生命同期超出了方法运行的生命周期:

//final不能去掉,否则编译通不过
public Comparable f(final Comparable o1) {
    return new Comparable() {
        public int compareTo(Object o2) {
            return o1.compareTo(o2);
        }
    };
}

final修改的静态属性,必须在声明的同时或者在静态块中初始化;final修饰的非静态属性,必须在声明的同时、或非静态块中或者是构造函数中初始化:

public class A {
    private final int a = 1;//非静态属性在定义时初始化
    private final static int b = 1;//静态属性在定义时初始化

    private final int c;//非静态属性在定义时未初始化
    {
        //非静态属性在非静态块中初始化
        c = 1;
    }

    private final static int d;//静态属性在定义时未初始化
    static {
        //静态属性在静态块中初始化
        d = 1;
    }

    private final int e;//非静态属性在定义时未初始化

    A() {
        //非静态属性在构造函数中初始化
        e = 1;
    }
}

静态属性不能在非静态块中初始化 (因为非静态块是在new时才调用,而静态属性在对象还没有创建时也能使用,所以有可能还未初始化就使用了,也还有可能初始化多次),当然非静态属性更不能在静态块中、构造函数中初始化(因为在静态块中不能访问非静态属性、变量及方法):

public class A {
    private final int a;//!! 非静态属性未初始化
    private final static int b;//!! 静态属性未初始化

    private final int c;
    static {
        //!! 非静态属性不能在静态块中初始化
        c = 1;
    }

    private final static int d;
    {
        //!! 静态属性在非静态块中初始化
        d = 1;
    }

    private final static int e;

    A() {
        //!! 静态属性不能在构造函数中初始化
        e = 1;
    }
}

接口中的属性成员默认就是 public final static,只能在定义时就初始化:

package A;

public interface A {
    //接口中的属性成员默认就是 public final static
    int i = 1;

    // !! 接口中的访问修饰符只能是 public ,但可不写
    //protected int a = 1;

    // !! 接口中的属性只能在定义时就初始化
    //    public static final b;

    // !! 接口中的属性是常量,不能在静态块与非静态块中初始化,因为接口中不能有静态块与非静态块
    //    static{
    //        b=1;
    //    }

    //    {
    //        b=1;
    //    }
}

package B;

import A.A;

public class B {
    public static void main(String[] args) {
        // !! 不能修改,因为接口中的定义的属性默认就是final
        //A.i = 2;

        //接口中的定义的属性默认就是public static,因为可以被不同包静态访问
        System.out.println(A.i);
    }
}

这里提到了静态区与非静态区,它们的区别是,静态区在类装载时执行一次,而非静态区每在实例化一个对象时就执行一次:

public class A {
    static {
        System.out.println("static block");
    }

    {
        System.out.println("block");
    }

    public static void main(String[] args) {
        new A();
        new A();
    }
    /* output:
    static block
    block
    block
     */
}

另外,用final修饰的变量会有更高的效率,如果一个变量不在变化时,那么它就应该定义成常量,所以在需要的地方我们尽量使用常量,因为这样在编译时期就能确定。

2、修饰方法:
被final修改的方法不能被覆写。

class A {
    public final void f() {}
}

class B extends A {
    // !! 不能覆写final方法
    //    public void f() {}
    //    public final void f() {}
}

private方法默认就是final方法,编译器在处理private方法时,是按照final方法来对待的,这样可以提高该方法被调用时的效率。

3、修饰类
final类不允许被继承(如果String类),编译器在处理时把它的所有方法都当作final的(但数据成员既可以是final,也可以不是,以定义时前面修饰为准),因此final类比普通类拥有更高的效率:

final class A {
    //注,final中的属性可以是final,也可以不是,以定义时前面修饰为准
    int i = 1;

    public final void f() {}

    //final类中的所有方法默认就是final方法
    void m() {}
}

// !! final 类不能继承
//class B extends A {}

public class C {
    public static void main(String[] args) {
        A a = new A();
        a.i = 2;//可以修改final类的非final属性成员
    }
}

接口与抽象类不能用final来修饰,即final interface、final abstract class是不允许的:

// !! 接口不能用final来修饰
public final interface A {}

// !! 抽象类不能用final来修饰
public final abstract class A {}

 
finally关键字
finally关键字用在try/catch语句最末,表示不管是否抛出异常,finally块中的语句最终肯定、一定会被执行,执行的顺序为 try块 —> finally块(不抛异常情况下)或 try块 —> catch块(抛异常情况下)—> finally块

try {//不抛异常情况下
    System.out.println("try");
}
catch (Exception e) {
    System.out.println("catch");
}
finally {
    System.out.println("finally");
}
/* output:
try
finally
 */

try {//抛异常情况下
    System.out.println("try");
    throw new NullPointerException();
}
catch (NullPointerException e) {
    System.out.println("catch");
    throw e;//再次抛出
}
finally {
    //不管是try块还是catch块里抛异常,finally块最后一定会执行
    System.out.println("finally");
}
/* output:
try
catch
finally
 */

下面看看try、catch、finally有return语句时,到底从哪里返回:

class A {
    public static void main(String[] args) {
        System.out.println(A.f1());//3
        System.out.println(A.f2());//2
        try {
            System.out.println(A.f3());//方法异常结束
        }
        catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(A.f4());//1
        System.out.println(A.f5());//4

        try {
            System.out.println(A.f6());//方法异常结束
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

    /*
     * 如果 finally 块中有 return 语句,则忽略 try、catch 块中的retrun ,
     * 但 finally 中有return不是一种好的编程方式,这样会引起编译时警告
     */
    public static int f1() {
        System.out.println("--f1()--");
        try {
            System.out.println("f1 - 1");
            nullExcp();//抛空指针异常
            return 1;
        }
        catch (NullPointerException e) {
            System.out.println("f1 - 2");
            return 2;
        }
        finally {
            System.out.println("f1 - 3");
            return 3;//从这里返回
        }
        /*
         * !! 这里不能有语句,因为方法在此前已从finally块中返回,或者finally 块中已抛
         * 异常后方法结束,但要注意的是,不管catch块中是否抛异常,最会执行finally块
         */
        // return 4;
    }

    /*
     * 如果 finally 块中没有 return 语句,但 try、catch 块中有时,如果try中不抛
     * 异常,则从try语句块中正常返回,如果try中抛出异常,则从catch块中正常返回或者
     * catch抛出异常时方法异常结束
     */
    public static int f2() {
        System.out.println("--f2()--");
        try {
            System.out.println("f1 - 1");
            nullExcp();//抛空指针异常
            return 1;
        }
        catch (NullPointerException e) {
            System.out.println("f1 - 2");
            return 2;//从这里返回
        }
        finally {
            System.out.println("f1 - 3");
        }
        /*
         * !! 这里也不能有其他语句了,因为到此方法已经正常或异常结束了
         */
        // return 4;
    }

    //try与catch块都抛异常,最后方法在执行完finally块后从catch块中异常结束
    public static int f3() {
        System.out.println("--f3()--");
        try {
            System.out.println("f1 - 1");
            nullExcp();//抛空指针异常
            return 1;
        }
        catch (NullPointerException e) {
            System.out.println("f1 - 2");
            nullExcp();//抛空指针异常,从这里方法异常结束
            return 2;
        }
        finally {
            System.out.println("f1 - 3");
        }
        /*
         * !! 这里也不能有其他语句了,因为到此方法已经正常或异常结束了
         */
        // return 4;
    }

    //这是我们通常写法,只在try或最后返回结果:正常从try中返回
    public static int f4() {
        System.out.println("--f4()--");
        try {
            System.out.println("f1 - 1");
            return 1;//从这里返回
        }
        catch (NullPointerException e) {
            System.out.println("f1 - 2");
        }
        finally {
            System.out.println("f1 - 3");
        }
        return 4;
    }

    //这是我们通常写法,只在try或最后返回结果:异常后从最后返回
    public static int f5() {
        System.out.println("--f5()--");
        try {
            System.out.println("f1 - 1");
            nullExcp();//抛空指针异常
            return 1;
        }
        catch (NullPointerException e) {
            System.out.println("f1 - 2");
        }
        finally {
            System.out.println("f1 - 3");
        }
        return 4;//从这里返回
    }

    public static int f6() {
        System.out.println("--f6()--");
        try {
            System.out.println("f1 - 1");
            nullExcp();//抛空指针异常
            return 1;
        }
        catch (NullPointerException e) {
            System.out.println("f1 - 2");
            nullExcp();//抛空指针异常,从这里方法异常结束
        }
        finally {
            System.out.println("f1 - 3");
        }
        return 4;
    }

    private static void nullExcp() {
        throw new NullPointerException();
    }
}

从上面例子可以看出return语句是不会阻止finally块执行的,那么continue和break能否阻止?答案是不会的,与return一样,finally语句块是在循环被跳过(continue)和中断(break)之前被执行的:

class A {
    public static void main(String[] args) {
        int i = 0;
        System.out.println("--continue--");
        while (i++ <= 1) {
            try {
                System.out.println("i=" + i);
                continue;
            }
            catch (Exception e) {
                e.printStackTrace();
            }
            finally {
                System.out.println("finally");
            }
        }
        System.out.println("--break--");
        while (i++ <= 3) {
            try {
                System.out.println("i=" + i);
                break;
            }
            catch (Exception e) {
                e.printStackTrace();
            }
            finally {
                System.out.println("finally");
            }
        }
    }
}

 

finalize关键字
finalize()是Object类的一个方法,finalize()方法是GC(garbage collector)运行机制的一部分,由对象的垃圾回收器调用此方法,当一个对象被回收时,finalize()方法将会被调用。但我们要注意的是,如果 finalize 方法抛出未捕获的异常,那么该异常将被忽略,并且该对象的终结操作将终止:

protected void finalize() throws Throwable {
    System.out.println("finalize");
}

public static void main(String[] args) {
    A a = new A();
    a = null;
   
    //加快GC回收,但不一定马上执行加收动作,由虚拟机决定
    System.gc();

    //System.gc()实质上与下面等同
    //Runtime.getRuntime().gc();

    // 该方法虚拟机也只是尽最大努力去完成所有未执行的终止方法,不一定会执行
    //System.runFinalization();

    /*
     * !! 该方法一定会回收,但不安全,已被废弃。因为它可能对正在使用的对象调用终结方法,而
     * 其他线程同时正在操作这些对象,从而导致不正确的行为或死锁
     */
    // System.runFinalizersOnExit(true);
}
分享到:
评论
1 楼 k_kid9157 2011-11-01  
学习了 感谢前辈分享!

相关推荐

    final, finally, finalize的区别

    在Java编程语言中,"final", "finally", 和 "finalize" 这三个关键字有着截然不同的含义和用途,它们各自在程序设计的不同层面扮演着重要角色。深入理解这些概念对于编写高效、健壮的Java代码至关重要。 ### final ...

    java面试题 谈谈final, finally, finalize的区别

    在Java编程语言中,`final`, `finally`, 和 `finalize` 是三个非常重要的关键字,它们各自扮演着不同的角色,尤其在处理程序的可预测性、数据的不可变性和垃圾回收等方面。下面将详细阐述这三个关键字的区别及其应用...

    Java中final,finally,finalize三个关键字的区别_动力节点Java学院整理

    Java中final,finally,finalize三个关键字的区别_动力节点Java学院整理

    final,finally,finalize .mm

    对于Java中final、finally、finalize的有关问题做下的思维导图,便于深化记忆,希望对你有帮助!注意:文件为.mm后缀建议下载freemind打开,免费的思维导图软件!

    java 基础之final、finally和finalize的区别

    Java 基础之 final、finally 和 finalize 的区别 Final、finally 和 finalize 是 Java 语言中三个常用的关键字,然而它们的作用和用法却有很大的区别。下面我们将详细介绍这三个关键字的区别。 Final Final 是一...

    详解Java编程中final,finalize,finally的区别

    Java编程中的`final`, `finalize`, 和`finally`是三个重要的关键字,它们各自在不同的场景下发挥着关键作用。理解这三个关键字的区别对于Java开发者来说至关重要,尤其是在面试中常常会被问及。 首先,`final`是一...

    final、fianlly、finalize区别

    final:修饰符(关键字)如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为 父类被继承。因此一个类不能既被声明为abstract 的,又被声明为final 的。将变量或 方法声明为 final,可以保证它们在...

    java中 final, finally, finalize 的区别

    java中final, finally, finalize 的区别

    第3讲 谈谈final、finally、 finalize有什么不同1

    【Java核心技术】final、finally和finalize是Java编程中三个重要的关键字,它们各自有着独特的功能和用法。 **final关键字** final在Java中扮演着“不可改变”的角色。它可以用来修饰类、方法和变量: 1. **修饰类...

    《剑指offer》Java深入理解final、finally、finalize.pdf

    Java编程中的`final`、`finally`和`finalize`关键字对于理解Java程序的运行机制至关重要。它们各自有独特的用途和特点。 首先,`final`关键字是Java中的一个多面手,它可以用于修饰类、方法和变量。当`final`用于...

    简单谈谈java中final,finally,finalize的区别

    Java中的`final`、`finally`和`finalize`都是关键字,但它们的作用和用途各不相同,对于初学者来说,理解这些概念可能会有些困难。让我们逐一解析它们。 **final** `final`是一个修饰符,主要用于以下几个方面: ...

    浅析final,finally,finalize 的区别

    在Java编程语言中,`final`, `finally`, 和 `finalize` 是三个非常重要的关键字,它们分别在不同的场景下发挥着独特的作用。下面我们将详细解析这三个关键字的区别和用途。 1. **final** - **final 修饰类**:当 `...

    Android源码中final关键字的用法及final,finally,finalize的区别

    hi 大家好,今日,天气剧变,非常冷,不想出门,于是给大家写了篇文章,关于android final关键字及final,finally,finalize的区别相关知识,具体详情如下所示: 先预告一下,下文中仅涉及java语法的讨论,和Android...

    JAVA 面试宝典(美团、阿里、京东等一线大厂)

    13. **final finally finalize**:final用于变量和方法;finally确保代码块始终执行,通常用于资源清理;finalize是对象被垃圾回收前调用的方法,但不推荐依赖它进行资源释放。 14. **String对象比较**:`String ...

    Java面试题,他会给你很好的Java面试准备,第一,谈谈final, finally, finalize的区别,第二,Anonymous Inner Class (匿名内部类) 是否可以extends(继承)其它类,是否可以implements(实现)interface(接口)?

    在Java面试中,了解final、finally、finalize的区别是非常重要的。final是一个修饰符(关键字),如果一个类被声明为final,意味着它不能再派生出新的子类,不能作为父类被继承。将变量或方法声明为final,可以保证...

    3谈谈final、finally、finaliz1

    总结来说,final、finally和finalize在Java中分别扮演着不同的角色。final用于增强代码的语义清晰度和安全性,finally保证了资源清理的可靠性,而finalize则是尝试提供对象销毁前的清理机会,但由于其缺陷已被逐渐弃...

    2016 Java 基础 面试题

    **final finally finalize 的区别** - **final**:用于声明常量或不可变对象。 - **finally**:在try-catch-finally语句块中使用,确保无论是否发生异常都会执行的代码块。 - **finalize**:对象的垃圾回收机制的...

    leetcode题库-java-interview:Java研发基础相关

    finally finalize 反射 序列化与反序列化 transient 枚举 注解 JDK7新特性 JDK8新特性 JDK9新特性 JDK10新特性 运行时数据区 对象 OOM & SOF 内存模型 垃圾回收算法 垃圾收集器 内存分配与回收策略 类加载 参数优化 ...

Global site tag (gtag.js) - Google Analytics