Lr常量和变量(二)

本节主要学习二者的区别

参数是可以直接在系统函数中应用的,绝大多数情况下都可以直接用参数替换掉函数中双引号内的数据。

变量是属于C语言的,所以无法直接应用在系统函数中(注:可以使用lr_eval_string()函数解决此问题)。

参数和变量的作用域

参数是全局的,在脚本的任何一个Action中都可以使用;变量是局部的,如果跨Action调用会出现未声明的错误

<think>我们正在讨论实例变量常量的区别以及它们在JVM中的回收情况。首先,需要明确两个概念: 1. 实例变量:属于对象实例的成员变量,每个对象实例都有自己的一份拷贝。生命周期对象实例相同。 2. 常量:在Java中,常量通常指用`final`修饰的变量常量可以是类常量(静态常量)或实例常量(属于对象的常量)。此外,还有一种常量是字符串字面量或基本类型的字面量,它们存储在常量池中。 接下来,我们分别讨论它们的区别回收情况。 ### 1. 实例变量(Instance Variables) - **定义**:实例变量是定义在类中,但在任何方法、构造器或块之外,且没有`static`修饰的变量。 - **生命周期**:当创建一个对象时,实例变量被创建;当该对象不再被引用(即不可达)时,实例变量随着对象一起被垃圾回收。 - **存储位置**:实例变量存储在堆内存中(因为对象在堆中)。 ### 2. 常量(Constants) 常量在Java中有多种形式: - **类常量(静态常量)**:使用`static final`修饰,属于类,所有对象共享。 - **实例常量**:使用`final`修饰(但没有`static`),属于对象实例,每个对象有一份,且一旦初始化后不能更改。 - **字面量常量**:如字符串字面量(如`"hello"`)基本类型字面量(如`5`,`3.14`)。字符串字面量存储在字符串常量池(在Java 7之前位于方法区,Java 7及之后位于堆中)。基本类型字面量通常直接嵌入在代码中,但如果是包装类的常量池(如Integer的缓存),则存储在堆中特定区域。 注意:我们通常说的常量更多指`static final`修饰的类常量。 ### 区别总结 | 特性 | 实例变量 | 常量(以`static final`为例) | |--------------|-----------------------------------|------------------------------------------| | 修饰符 | 无特殊要求(可有可无`final`) | 必须用`static final`修饰(类常量) | | 存储位置 | 堆(在对象内部) | 方法区(元空间)或堆(取决于常量类型) | | 生命周期 | 对象实例相同 | 类相同(类卸载时才会回收) | | 是否可修改 | 可以(除非用`final`修饰) | 不可修改(编译期常量)或运行时初始化但只赋值一次 | | 访问方式 | 通过对象实例访问 | 通过类名直接访问 | ### JVM中的回收情况 - **实例变量**:它们作为对象的一部分,当对象不再被任何引用指向时,整个对象(包括其实例变量)会被垃圾回收器标记并回收。注意,如果实例变量是引用类型,那么它引用的对象也可能因此被回收(如果没有其他引用指向它)。 - **常量**: - **实例常量**:属于对象实例,所以回收情况实例变量相同,随对象一起被回收。 - **类常量(静态常量)**:存储在方法区(在Java 8及之后称为元空间)。类常量在类卸载时才会被回收。而类的卸载条件很严格:需要满足该类所有的实例都已被回收,加载该类的ClassLoader已被回收,且该类对应的`java.lang.Class`对象没有任何地方被引用。因此,类常量的回收通常发生在类加载器被回收时(如Web应用卸载时)。 - **字符串常量池中的常量**:字符串字面量存储在字符串常量池中。在Java 7之前,字符串常量池位于方法区(永久代),在Java 7及之后被移到了堆中。因此,字符串常量池中的字符串对象可以被垃圾回收,条件是没有任何引用指向它(包括字面量引用显式引用)。但是,由于字符串字面量通常由类或方法持有,所以回收条件比较严格。 ### 示例说明 ```java public class Example { // 类常量(静态常量) public static final int MAX_VALUE = 100; // 实例常量 public final int minValue; // 实例变量 private String name; public Example(int min) { this.minValue = min; } public void setName(String name) { this.name = name; } } ``` - `MAX_VALUE`是类常量,存储在方法区(元空间)。当加载Example类的类加载器被回收时,它才会被回收。 - `minValue`是实例常量,每个Example对象都有自己的`minValue`,存储在堆中。当对象被回收时,它也被回收。 - `name`是实例变量,存储在堆中,随对象回收而回收。 另外,如果代码中有字符串字面量,如: ```java String s = "hello"; // "hello"在字符串常量池中 ``` 这个字符串`"hello"`在常量池中,当没有任何引用指向它时(包括类卸载、没有代码引用等),它可能被回收。但实际中,由于类可能一直被引用,所以常量池中的字符串回收并不常见。 ### 总结 1. **实例变量**:在堆中,随对象回收而回收。 2. **常量**: - 实例常量:随对象回收而回收。 - 类常量(静态常量):在方法区(元空间),随类卸载而回收(条件严格,较少发生)。 - 字符串常量池中的常量:在堆中(Java7+),当没有任何引用指向它们时,可以被回收。 因此,实例变量常量的主要区别在于它们的声明方式、存储位置生命周期。在垃圾回收方面,实例变量(包括实例常量)的回收依赖于对象实例的回收,而类常量的回收则依赖于类的卸载。 §§相关问题§§ 1. 字符串常量池在JVM中是如何管理的? 2. JVM中类卸载的条件是什么? 3. 如何监控JVM中垃圾回收的情况?</think>### 实例变量常量的区别及JVM回收机制 #### 一、核心区别 | 特性 | 实例变量 | 常量(以`static final`为例) | |--------------|----------------------------------|-----------------------------------| | **定义位置** | 类内部(无`static`修饰) | 类内部(必须用`static final`修饰) | | **存储位置** | 堆内存(对象实例内部) | 方法区(元空间) | | **生命周期** | 随对象创建而创建,随对象回收而销毁 | 类加载时创建,类卸载时销毁 | | **可变性** | 可修改(除非用`final`修饰) | 不可修改(编译期或类加载时初始化) | | **访问方式** | 通过对象实例访问 | 通过类名直接访问 | #### 、JVM回收机制详解 1. **实例变量的回收**: - **回收条件**:当对象实例**不再被任何GC Roots引用**时(如局部变量失效、显式置`null`) - **回收过程**: ```mermaid graph LR A[对象不可达] --> B[标记为垃圾] B --> C[实例变量随对象被回收] C --> D[堆内存空间释放] ``` - **示例**: ```java public class User { private String name; // 实例变量 } void createUser() { User user = new User(); // 对象可达 user = null; // 对象不可达,等待GC回收 } ``` 当`user`被置`null`后,`name`变量随`User`对象被回收[^1][^2]。 2. **常量的回收**: - **回收条件**:需同时满足: - 类的所有实例已被回收 - 加载该类的`ClassLoader`已被回收 - 该类对应的`java.lang.Class`对象无引用 - **特殊类型**: - **字符串常量**:存储在堆内的字符串常量池,当**无任何引用**时可被回收(JDK7+) ```java String s1 = "hello"; // 常量池 s1 = null; // "hello"可能被回收(若无其他引用) ``` - **基本类型常量**:直接嵌入类元数据,不单独回收 #### 三、关键差异总结 1. **内存泄漏风险**: - 实例变量可能因**意外强引用**导致内存泄漏(如集合未清理) - 常量通常无泄漏风险(不可修改+有限生命周期) 2. **回收触发条件**: ```java public class Constants { public static final int MAX_SIZE = 1024; // 类常量 } public class Service { private int count; // 实例变量 } ``` - `count`:随`Service`实例回收 - `MAX_SIZE`:仅当`Constants`类卸载时回收 3. **GC可达性分析**: - 实例变量作为对象一部分参可达性分析 - 常量**不参对象可达性分析**,独立存在于元空间 #### 四、最佳实践 1. **实例变量**: - 及时解除无用引用(`obj = null`) - 避免在长生命周期对象中持有短生命周期对象的引用 2. **常量**: - 优先使用基本类型常量(`static final int`) - 谨慎使用常量引用大对象(可能延迟类卸载) > **关键结论**:实例变量可被GC回收,常量仅在类卸载时回收。实际开发中应特别注意实例变量的生命周期管理,而常量通常无需关注回收问题[^1][^2][^3]。 --- ### 相关问题 1. JVM方法区(元空间)堆内存的垃圾回收策略有何不同? 2. 如何通过强引用、软引用、弱引用控制对象回收时机? 3. 字符串常量池在JDK 7前后的存储位置变化带来了哪些影响? 4. 哪些场景会导致Java类被卸载? 5. 如何检测解决由实例变量引起的内存泄漏问题?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值