final说明

final说明

  • 修饰类:表示类不可被继承
  • 修饰方法:表示方法不可被子类覆盖,但是可以重载
  • 修饰变量:表示变量一旦被赋值就不可以更改它的值
  1. 修饰成员变量

    • 如果final修饰的是类变量,只能在静态初始化块中指定初始值或者声明该类变量时指定初始值。
    • 如果final修饰的是成员变量,可以在非静态初始化块、声明该变量或者构造器中执行初始值。
  2. 修饰局部变量

    系统不会为局部变量进行初始化,局部变量必须显示初始化。因此使用final修饰局部变量时,即可在定义时指定默认值(后面的代码不能对变量再赋值),也可以不指定默认值,而在后面的代码中对final变量赋初始值(仅一次)

    package com.dameng;
    
    /**
     * @author Allen
     */
    public class FinalVar {
    
        /**
         * 声明时就要赋值,或者在静态代码块中赋值
         */
        private final static int A = 0;
    
    //    static {
    //        A = 1;
    //    }
    
        /**
         * 声明时、代码块或者构造函数赋值
         */
        private final int b = 0;
    
    //    {
    //        b = 1;
    //    }
    
    //    public FinalVar() {
    //        b = 2;
    //    }
    
        public static void main(String[] args) {
            // 局部变量只声明不初始化,不会报错
            final int localA;
            // 在使用之前一定要赋值
            localA = 0;
            // 报错,不允许修改
    //        localA = 1;
        }
    
    }
    
  3. 修饰基本类型数据和引用类型数据

    • 如果是基本类型的变量,则其数值一旦在初始化之后便不能更改;
    • 如果是引用类型的变量,则初始化之后不能再指向另一个对象,但引用值可以修改。
    package com.dameng;
    
    /**
     * @author Allen
     */
    public class FinalReferenceTest {
    
        public static void main(String[] args) {
            final int[] arr = {1, 2, 3, 4};
            arr[2] = 3;
            // 报错,不能对arr重新赋值
    //        arr = null;
    
            final Person person = new Person();
            person.setAge(24);
            // 报错,不能对arr重新赋值        
    //        person = null;
        }
    
        private static class Person {
            private int age;
    
            public int getAge() {
                return age;
            }
    
            public void setAge(int age) {
                this.age = age;
            }
        }
    }
    

为什么局部内部类和匿名内部类只能访问局部final变量(<=jdk7)?

匿名内部类

package com.dameng;

/**
 * 编译之后会生成两个class文件,Test.class Test$1.class
 *
 * @author Allen
 */
public class Test {

    public static void main(String[] args) {
    }

    public void test(final int b) {
        final int a = 10;
        new Thread() {
            @Override
            public void run() {
                System.out.println(a);
                System.out.println(b);
            }
        }.start();
    }

}
package com.dameng;

public class Test {
    public Test() {
    }

    public static void main(String[] args) {
    }

    public void test(final int b) {
        int a = true;
        (new Thread() {
            public void run() {
                System.out.println(10);
                System.out.println(b);
            }
        }).start();
    }
}
package com.dameng;

class Test$1 extends Thread {
    Test$1(Test this$0, int var2) {
        this.this$0 = this$0;
        this.val$b = var2;
    }

    public void run() {
        System.out.println(10);
        System.out.println(this.val$b);
    }
}

局部内部类

package com.dameng;

/**
 * 编译之后生成两个class文件,Test.class Test$1InClass.class
 *
 * @author Allen
 */
public class Test {

    private int age = 12;

    public static void main(String[] args) {

    }

    public void outPrint(final int x) {
        class InClass {
            public void inPrint() {
                System.out.println(x);
                System.out.println(age);
            }
        }

        new InClass().inPrint();
    }
}
package com.dameng;

public class Test {
    private int age = 12;

    public Test() {
    }

    public static void main(String[] args) {
    }

    public void outPrint(final int x) {
        class InClass {
            InClass() {
            }

            public void inPrint() {
                System.out.println(x);
                System.out.println(Test.this.age);
            }
        }

        (new InClass()).inPrint();
    }
}
package com.dameng;

class Test$1InClass {
    Test$1InClass(Test this$0, int var2) {
        this.this$0 = this$0;
        this.val$x = var2;
    }

    public void inPrint() {
        System.out.println(this.val$x);
        System.out.println(this.this$0.age);
    }
}

内部类和外部类是处于同一个级别的,内部类不会因为定义在方法中就随着方法的执行结束而被销毁。

而当外部类的方法结束时,外部类的局部变量会被销毁,但内部类对象可能还存在(只有没有被调用时才会死亡),这时就出现一个矛盾:内部类对象访问了一个不存在的变量。为了解决这个问题,就将局部变量复制了一份作为内部类的成员变量,这样当局部变量死亡后,内部类还可以访问它(实际访问的是局部变量的copy),这样就好像延长了局部变量的生命周期。

将局部变量复制为内部类的成员变量时,必须保证这两个变量是一样的,也就是如果我们在内部类中修改了成员变量,方法中的局部变量也跟着改变,怎么解决这个问题呢?

就将局部变量设置为final,对它初始化后,就无法再修改这个变量,就保证了内部类的成员变量和方法的局部变量的一致性。这实际上也是一种妥协,使得局部变量与内部类建立的拷贝保持一致。

jdk8以后匿名内部类可以直接访问局部变量

匿名内部类

package com.dameng;

/**
 * 编译之后只生成一个class文件,Test.class
 *
 * @author Allen
 */
public class Test {

    public static void main(String[] args) {
    }

    // final可有可无
    public void test(final int b) {
        // final可有可无
        final int a = 10;
        new Thread(() -> {
            System.out.println(a);
            System.out.println(b);
        }).start();
    }

}
package com.dameng;

public class Test {
    public Test() {
    }

    public static void main(String[] args) {
    }

    public void test(int b) {
        int a = true;
        (new Thread(() -> {
            System.out.println(10);
            System.out.println(b);
        })).start();
    }
}

局部内部类

package com.dameng;

/**
 * 编译之后生成两个class文件,Test.class Test$1InClass.class
 *
 * @author Allen
 */
public class Test {

    private int age = 12;

    public static void main(String[] args) {

    }

    // final可有可无
    public void outPrint(final int x) {
        class InClass {
            public void inPrint() {
                System.out.println(x);
                System.out.println(age);
            }
        }

        new InClass().inPrint();
    }
}
package com.dameng;

public class Test {
    private int age = 12;

    public Test() {
    }

    public static void main(String[] args) {
    }

    public void outPrint(final int x) {
        class InClass {
            InClass() {
            }

            public void inPrint() {
                System.out.println(x);
                System.out.println(Test.this.age);
            }
        }

        (new InClass()).inPrint();
    }
}
package com.dameng;

class Test$1InClass {
    Test$1InClass(Test this$0, int var2) {
        this.this$0 = this$0;
        this.val$x = var2;
    }

    public void inPrint() {
        System.out.println(this.val$x);
        System.out.println(this.this$0.age);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值