Java局部内部类访问所在方法的变量或参数

简介: 局部内部类是在方法中定义的类。它的可见范围是当前方法,和局部变量一样,局部内部类不能用访问控制修饰符(public、private以及protected)和静态修饰符static来修饰。局部内部类中除了可以访问外部类的所有成员,还可以访问所在方法的最终变量或参数(被final修饰的变量或参数),从JDK8.0开始,还可以访问所在方法的实际上的最终变量或参数(没有被final修饰但只进行了一次赋值的变量或参数)。为什么局部内部类中只能访问所在方法的最终变量或参数以及实际上的最终变量或参数呢?

先来验证局部内部类中只能访问所在方法的最终变量或参数以及实际上的最终变量或参数。如程序1所示,在外部类Out_1的method方法中有一个参数a,两个变量b、c,并在局部内部类Inner_1中访问了这三个量。由于参数a是被final修饰的,那参数a就是最终的参数,故在Inner_1中可以访问它,第7句代码没有编译错误;虽然变量b没有被final修饰,但是变量b仅仅被赋值一次,它是实际上的最终变量,故在Inner_1中可以访问它,第8句代码没有编译错误;变量c没有被final修饰并且被赋值了两次,它不是最终变量也不是实际上的最终变量,故在Inner_1中不可以访问它,第9句代码就有了编译错误。可以得到,在局部内部类中只能访问所在方法的最终变量或参数以及实际上的最终变量或参数。
class Out_1 {

   public void method(final int a) {
       final int b = 1;
       int c = 2;
       c = 3;
       class Inner_1 {
           int d = a;    //编译正确。
           int e = b;    //编译正确。
           int f = c;    //编译错误。
       }
    }

}
接着再来讨论为什么局部内部类中只能访问所在方法的最终变量或实际上的最终变量。这里只讨论方法的变量,对于方法的参数它的道理是一模一样的,因为方法的参数本质上就是方法的变量。要知道局部内部类和外部类是处于同一级别的,局部内部类不会因为定义在方法中就随着方法的执行完毕而销毁。如程序2所示,在外部类Out_2的method1方法中定义了一个局部内部类Inner_2,然后创建了一个线程t并启动它,然后method1方法就执行结束,局部变量m就被销毁。线程t启动之后,会先睡眠1000毫秒,然后创建了局部内部类Inner_2的对象,并通过该对象去调用了method2方法,在method2方法中访问了method1方法定义的变量m,由于method1方法早已执行结束,变量m已经消失。这样就出现了一个矛盾:内部类对象访问了一个不存在的变量。
class Out_2 {

   public void method1() {
       int m = 4;
       class Inner_2 {
           public void method2() {
               System.out.println(m);
           }
       }
       new Thread("t") {
           public void run() {
               try {
                   Thread.sleep(1000);
               } catch (InterruptedException e) {
                   e.printStackTrace();
               }
               new Inner_2().method2();
           }
       }.start();
   }

}
为了解决这个矛盾,如果局部内部类中访问了所在方法的某个变量,就将该方法中的变量复制一份作为内部类的成员变量,当内部类访问所在方法中的变量时,就让它去访问复制出来的成员变量。这样在内部类所在方法中的变量消失的之后,仍然可以访问它,当然这里并不是真正地访问它,而是访问它的复制品。这里需要注意,由于是将局部内部类所在方法的变量复制一份作为局部内部类的成员变量,故在定义局部内部类之前,一定要对局部内部类所在方法的变量进行初始化,没有初始化是无法复制的。在程序3所示的代码中,第7句代码是有编译错误的。
class Out_3 {

   public void method1() {
       int m;
       class Inner_3 {
           public void method2() {
               // 编译错误,m应在定义内部类之前初始化。
               m = 4;
           }
       }
   }

}
但是这时又有一个问题,那就是必须时时刻刻保证复制得到的那一份成员变量的值和原来的局部变量的值相同。如果在外部类中修改了局部变量的值,那就要修改局部内部类中复制得到的那一份成员变量的值;如果在局部内部类中修改了复制得到的那一份成员变量的值,那就要修改外部类中局部变量的值(前提是这个局部变量还存在),这样做是非常困难的。于是Java干脆就不允许局部内部类要访问的局部变量的值发生改变,即局部内部类中只能访问所在方法的最终变量或实际上的最终变量。

相关文章
|
25天前
|
Java 开发工具
【Azure Storage Account】Java Code访问Storage Account File Share的上传和下载代码示例
本文介绍如何使用Java通过azure-storage-file-share SDK实现Azure文件共享的上传下载。包含依赖引入、客户端创建及完整示例代码,助你快速集成Azure File Share功能。
306 4
|
30天前
|
Java
Java语言实现字母大小写转换的方法
Java提供了多种灵活的方法来处理字符串中的字母大小写转换。根据具体需求,可以选择适合的方法来实现。在大多数情况下,使用 String类或 Character类的方法已经足够。但是,在需要更复杂的逻辑或处理非常规字符集时,可以通过字符流或手动遍历字符串来实现更精细的控制。
205 18
|
1月前
|
Java 编译器 Go
【Java】(5)方法的概念、方法的调用、方法重载、构造方法的创建
Java方法是语句的集合,它们在一起执行一个功能。方法是解决一类问题的步骤的有序组合方法包含于类或对象中方法在程序中被创建,在其他地方被引用方法的优点使程序变得更简短而清晰。有利于程序维护。可以提高程序开发的效率。提高了代码的重用性。方法的名字的第一个单词应以小写字母作为开头,后面的单词则用大写字母开头写,不使用连接符。例如:addPerson。这种就属于驼峰写法下划线可能出现在 JUnit 测试方法名称中用以分隔名称的逻辑组件。
173 4
|
2月前
|
算法 安全 Java
除了类,Java中的接口和方法也可以使用泛型吗?
除了类,Java中的接口和方法也可以使用泛型吗?
125 11
|
1月前
|
编解码 Java 开发者
Java String类的关键方法总结
以上总结了Java `String` 类最常见和重要功能性方法。每种操作都对应着日常编程任务,并且理解每种操作如何影响及处理 `Strings` 对于任何使用 Java 的开发者来说都至关重要。
233 5
|
2月前
|
Java 开发者
Java 函数式编程全解析:静态方法引用、实例方法引用、特定类型方法引用与构造器引用实战教程
本文介绍Java 8函数式编程中的四种方法引用:静态、实例、特定类型及构造器引用,通过简洁示例演示其用法,帮助开发者提升代码可读性与简洁性。
|
8月前
|
存储 Java
# 【Java全栈学习笔记-U1-day02】变量+数据类型+运算符
本篇笔记主要围绕Java全栈学习的第二天内容展开,涵盖了变量、数据类型、运算符以及Scanner类的应用。首先介绍了变量的概念与命名规范,以及如何定义和使用变量;接着详细讲解了Java中的基本数据类型,包括整型、浮点型、字符型、布尔型等,并通过实例演示了数据类型的运用。随后,深入探讨了各类运算符(赋值、算术、关系、逻辑)及其优先级,帮助理解表达式的构成。最后,介绍了如何利用Scanner类实现用户输入功能,并通过多个综合示例(如计算圆面积、购物打折、变量交换及银行利息计算)巩固所学知识。完成相关作业将进一步加深对这些基础概念的理解与实践能力。
142 13
|
8月前
|
存储 传感器 缓存
java变量与数据类型:整型、浮点型与字符类型
### Java数据类型全景表简介 本文详细介绍了Java的基本数据类型和引用数据类型,涵盖每种类型的存储空间、默认值、取值范围及使用场景。特别强调了`byte`、`int`、`long`、`float`、`double`等基本类型在不同应用场景中的选择与优化,如文件流处理、金融计算等。引用数据类型部分则解析了`String`、数组、类对象、接口和枚举的内存分配机制。
259 15
|
存储 Java
02 Java基础语法(变量+数据类型+运算符)(下)
02 Java基础语法(变量+数据类型+运算符)
93 5
|
存储 Java
02 Java基础语法(变量+数据类型+运算符)(上)
02 Java基础语法(变量+数据类型+运算符)
107 4