【Java】内部类调用方法内的局部变量为什么必须加final

Java内部类调用方法内的局部变量时,通常需要该变量被声明为final,因为局部变量在方法栈中,当方法结束变量会消失。加final可以使变量在方法区常量池中保存,确保内部类仍能访问。JDK1.8起,编译器会自动处理这个问题,即使不加final也能编译通过,但尝试修改final变量的值依然会出错。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先要明确一点,如果变量在方法外面,是不用加final的,比如:

class Outer{
    int num=3;
    void method(){
        class Inner{
            void show(){
                System.out.println("show.."+num);
            }
        }
        Inner in=new Inner();
        in.show();
    }
}

class Test{
    public static void main(String[]args){
        //输出show..3
        new Outer().method();
    }
}

在JDK1.8以前,如果变量定义在方法内部,或者作为方法的形参,必须加final,这是为什么呢? 

class Outer{
    void method(){
        //定义在内部,或者在形参
        int num=3;
        class Inner{
            void show(){
                System.out.println("show.."+num);
            }
        }
        Inner in=new Inner();
        in.show();
    }
}

class Test{
    public static void main(String[]args){
        //编译失败
        //Cannot refer to a non-final variable num inside an inner class defined in a different method
        new Outer().method();
    }
}

根本原因是方法内的局部变量和实例对象的生存周期不一样罢了。

我们知道Java把对象实例放在堆内存中,把方法的局部变量放在栈内存中,下面我们就从JVM的角度分析一下这个过程。

main方法进栈,遇到Outer这个类,首先加载这个类到方法区,然后在堆内存中创建Outer的对象。

接下来,method方法进栈,在栈帧中创建局部变量num,接着又遇到Inner这个类,加载Inner(包括show方法)到方法区。

接着,在堆内存中创建Inner实例对象,show方法进栈,show方法要去调用method栈帧里的num。OK,此时method没有出栈,自然可以调用到。

但是一旦show出栈,那么method也出栈,此时局部变量num就消亡了。而Inner对象in还在堆内存逍遥着呢(JVM不会立刻回收对象),手里还拽着一个根本就不存在的变量呢,这一下不就矛盾了吗。

所以,解决的方法,就是给这个局部变量加上final修饰符,让它成为一个常量,跑到方法区的常量池躺着,你Inner要用,直接拿就行,不用担心变量出栈突然死亡。


JDK1.8中,不加final也能编译通过,实际上是编译的时候自动加上了final。

如果尝试修改num的值,还是会报错。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值