Java中使用与不使用this关键字访问实例的差异及调度场景影响
问题1:itemFromMainClass是否需要定义为类成员变量并赋值?
是否需要完全取决于你的业务需求:
- 如果该参数仅在构造方法内部使用,后续类的其他方法、异步逻辑都不需要再访问它,完全不需要定义为类成员变量,直接用完即弃即可。
- 如果后续类的其他方法、内部类、异步任务需要用到该参数的值,就需要将其定义为类成员变量,通过
this.变量名 = 参数名的方式赋值存储。
问题2:带this访问(存储为类成员变量)和不带this访问(直接使用参数)的核心区别
两者本质是两种完全不同的变量存储逻辑,差异主要在3个方面:
- 作用域与生命周期不同:方法参数的作用域仅在当前方法内部,方法执行结束后参数就会被销毁;类成员变量的生命周期和类实例绑定,只要类实例没有被GC回收,成员变量就会一直存在,类内部所有逻辑都可以访问。
- 同名变量优先级不同:当参数名和类成员变量名完全相同时,Java会优先访问作用域更近的参数,只有加了
this才会明确指向类的成员变量。你第一段示例代码中因为刚执行了this.mainClass = mainClass,两个变量指向的是同一个对象,所以直接调用mainClass.ask()和this.mainClass.ask()执行结果没有差异,但如果后续你修改了成员变量的指向,两者的执行结果就会出现区别。 - 内存占用不同:存储为类成员变量会占用类实例的堆内存空间,不过对于普通对象来说该开销可以忽略不计。
问题3:定时重复调度任务场景下两种写法的差异
你给出的两种定时任务写法在功能上都可以正常运行,但底层实现和适用场景有区别:
- 写法2直接将构造方法参数传入lambda使用,属于lambda捕获了方法的局部参数,Java会自动将参数的引用保存在lambda实例中。只要定时任务没有被取消,lambda就会一直持有
MainClass和BukkitScheduler的引用,哪怕AnotherClass的实例被GC回收,只要调度器还在运行,任务就会正常执行。 - 写法1将参数存储为类的final成员变量,lambda中访问
this.mainClass本质是捕获了AnotherClass的实例引用。只要定时任务没有被取消,就会一直持有AnotherClass实例的引用,该实例和它的所有成员变量都不会被GC回收。如果后续你需要在类的其他方法中访问调度器、主类实例,或者需要提供取消定时任务的能力,写法1更合适。 - 注意:由于你两种写法中用到的
mainClass、bukkitScheduler都是实际不可变的(写法1的成员变量加了final修饰,写法2的参数被lambda捕获要求是有效final),所以在这个特定场景下两者的执行效果没有差异。
内容的提问来源于stack exchange,提问作者SQLLearnerMan
相关产品推荐
相关产品推荐

