关于java为什么在Method中局部内部类或者匿名内部类调用Method中定义的变量要用final修饰?

本文详细解释了Java中匿名内部类的工作原理,特别是在方法作用域内的使用方式,并通过实例展示了如何正确使用final修饰符来避免变量作用域问题。

这个问题我碰到过好几次了,也不怎么在意,但是一直不知道真正原因,刚去网上查了下资料,终于知道他的真正原因了。


由于方法中的变量属于当前所在的方法帧,当方法返回的时候方法帧退栈,导致方法中的变量丢失,那么这些匿名的内部类或者局部内部类对该变量的引用就是去了意义,所以通过修饰符final可以把变量变为常量,由于变量和常量的生命周期和存储位置不同,所以常量的值是不会被销毁的,即使方法已经退出,知道结果了吧。

这样干说,可能大家都不知道这样有什么意义,可能会想这样的机制在实战中有什么用呢?

举个例子吧:

package com.example.test;

public class AnonymousInnerClass {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		AnonymousInnerClassInterface anonymousSayHi = getAnonymousClassMethod();
		anonymousSayHi.AnonymousinnerMethod();
		
		AnonymousInnerClassAbstract anonymousSayHi_ = getAnonymousClassMethod_a();
		anonymousSayHi_.AnonymousinnerMethod_0();
		anonymousSayHi_.AnonymousinnerMethod_1();
	}

	public static AnonymousInnerClassAbstract getAnonymousClassMethod_a(){
		final String hi = "Hi,";
		return new AnonymousInnerClassAbstract(){

			void AnonymousinnerMethod_0() {
				// TODO Auto-generated method stub
				System.out.println(hi+"Call AnonymousinnerMethod_0");
			}
			
		};
	}
	
	public static AnonymousInnerClassInterface getAnonymousClassMethod() {

		// String hi = "Hi,";//这个是错的,原因参考刚才阐述。
		final String hi = "Hi,";
		return new AnonymousInnerClassInterface() {

			public void AnonymousinnerMethod() {
				// TODO Auto-generated method stub
				System.out.println(hi + "Call  AnonymousInnerMethod");
			}
		};
	}
}

// 定义局部内部类的上层接口,用于允许返回匿名内部类

//用abstract class的方式
abstract class AnonymousInnerClassAbstract {
	String hi = "Hi,";
	 abstract void AnonymousinnerMethod_0();//这个必须要加abstract,应为默认的不是abstract

	void AnonymousinnerMethod_1() {
		System.out.println(hi + "Call AnonymousinnerMethod_1");
	}
}
//用interface的方式
interface AnonymousInnerClassInterface {
	String hi = "Hi,";//默认的是static final
	void AnonymousinnerMethod();//默认abstract
}

运行结果:

Hi,Call  AnonymousInnerMethod
Hi,Call AnonymousinnerMethod_0
Hi,Call AnonymousinnerMethod_1

看到为什么要这么干了吧,相信大家也经常见到这个所谓的匿名内部类,尤其是Android程序中,就这样了。

<think>好的,我现在需要回答用户的问题:“Java类中定义局部变量和public的属性有什么区别?”首先,我需要回忆Java局部变量和类属性(成员变量)的基本概念,然后从多个维度比较它们的区别。 首先,局部变量是在方法、构造器或代码块内部定义变量,作用域仅限于所在的代码块。而public属性是类的成员变量,属于类或类的实例,作用域更广,可以被类的其他方法或外部类访问(因为是public)。 接下来,我需要从作用域、生命周期、存储位置、初始化要求、访问权限等方面进行比较。例如,作用域方面,局部变量只在定义的方法或代码块内有效,而public属性在整个类内部有效,外部类也可以通过对象实例访问(如果是实例变量)或类名访问(如果是静态变量)。 生命周期方面,局部变量的生命周期与方法或代码块的执行周期一致,方法结束则变量被销毁;而实例属性的生命周期与对象实例一致,对象被创建时存在,被垃圾回收时销毁;静态属性的生命周期则与类的加载和卸载周期一致。 存储位置方面,局部变量存储在栈内存中(基本类型直接存值,引用类型存地址);实例属性存储在堆内存的对象实例中;静态属性存储在方法区(元空间)中。 初始化要求方面,局部变量必须显式初始化后才能使用,否则编译错误;而public属性(成员变量)如果是实例变量,会有默认初始值(如对象默认null,int默认0),静态变量同理。 访问权限方面,局部变量只能在其所在的代码块内访问;public属性则可以被类的所有方法访问,外部类通过对象或类名(静态)访问。 另外,可能还需要提到是否可以被修饰修饰,比如局部变量不能使用访问修饰符(public、private等)和static,而类属性可以使用这些修饰符。 需要确保回答准确,并且覆盖主要区别点。然后,根据回答内容,生成3-5个相关问题。 </think>Java类中的局部变量与`public`属性(成员变量)在定义位置、作用域、生命周期、存储位置等方面有显著区别,具体对比如下: ### 一、定义位置与作用域 - **局部变量**:定义在方法、构造器、代码块(如`if`/`for`块)内部。作用域仅限于其所在的代码块或方法,超出范围无法访问。 ```java public class Example { public void method() { int localVar = 10; // 局部变量,仅在method()方法内有效 System.out.println(localVar); // 正确 } // 此处无法访问localVar } ``` - **public属性**:定义在类内部、方法外部,属于类的成员变量。作用域是整个类(所有成员方法均可访问),且由于是`public`修饰,外部类可通过对象实例(实例属性)或类名(静态属性)直接访问。 ```java public class Example { public String publicField = "Hello"; // public实例属性,类内所有方法可访问 public static int staticField = 20; // public静态属性,类内/外均可访问 public void method() { System.out.println(publicField); // 类内方法访问public属性 } } // 外部类访问public属性 Example obj = new Example(); System.out.println(obj.publicField); // 输出:Hello(实例属性) System.out.println(Example.staticField); // 输出:20(静态属性) ``` ### 二、生命周期 - **局部变量**:生命周期与所在代码块/方法的执行周期绑定。方法调用时创建(压入栈帧),方法执行结束或代码块退出时销毁(弹出栈帧)。 - **public属性**: - **实例属性**:生命周期与对象实例绑定。对象通过`new`创建时,实例属性在堆中分配内存;对象被垃圾回收时,属性内存被释放。 - **静态属性**:生命周期与类的加载/卸载周期绑定。类被加载到JVM时创建(存储在方法区),类被卸载时销毁(仅在JVM关闭或自定义类加载器场景中可能发生)。 ### 三、存储位置 - **局部变量**:存储在Java虚拟机栈(JVM Stack)的栈帧中。基本类型直接存储值,引用类型存储对象在堆中的内存地址。 - **public属性**: - **实例属性**:存储在堆(Heap)中的对象实例内存区域。 - **静态属性**:存储在方法区(Method Area,JDK8后为元空间Metaspace),属于类级别的共享数据。 ### 四、初始化要求 - **局部变量**:必须显式初始化后才能使用,否则编译报错。 ```java public void method() { int localVar; // 未初始化 System.out.println(localVar); // 编译错误:可能尚未初始化变量localVar } ``` - **public属性**:即使未显式初始化,也会有默认初始值(由JVM自动赋值): - 基本类型:`0`(`int`)、`0.0`(`double`)、`false`(`boolean`)等; - 引用类型:`null`; - 静态属性同理(静态变量默认初始值规则与实例变量一致)。 ```java public class Example { public int num; // 默认初始值0 public String str; // 默认初始值null } ``` ### 五、访问修饰符与修饰符限制 - **局部变量**:不能使用访问修饰符(如`public`、`private`)或`static`修饰符,因为其作用域已限定在代码块内。 ```java public void method() { public int localVar = 10; // 编译错误:不能对局部变量使用public static int staticVar = 20; // 编译错误:不能对局部变量使用static } ``` - **public属性**:可以使用`static`、`final`等修饰符(`public`本身是访问修饰符)。例如: ```java public class Example { public static final String CONSTANT = "固定值"; // public静态常量 } ``` ### 总结 局部变量是方法内的临时数据,作用域小、生命周期短;而`public`属性是类的对外数据接口,作用域广、生命周期与类/对象绑定,且有默认初始值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值