Java中静态变量的适用场景

本文探讨了Java中静态变量的应用场景及注意事项,通过示例对比了使用静态变量前后内存占用的变化,强调了合理利用静态变量的重要性。

【转】http://pengcqu.iteye.com/blog/494576

Java类中的静态变量在程序运行期间,其内存空间对所有该类的对象实例而言是共享的,有些时候可以认为是全局变量。因此在某些时候为了节省系统内存开销、共享资源,可以将类中的一些变量声明为静态变量,通过下面的例子,你可以发现合理应用静态变量带来的好处:

public class WeekA{

       static class Data { 

             private int week;
             private String name;
             Data(int i, String s) {
                   week= i;
                   name = s;
             }
       }

       Data weeks[] = {
             new Data(1, "Monday"),
             new Data(2, "Tuesay"),
             new Data(3, "Wednesday"),
             new Data(4, "Thursday"),
             new Data(5, "Friday"),
             new Data(6, "Saturday"),
             new Data(7, "Sunday")
       };

       public static void main(String args[]) {

             final int N = 10000;
             WeekA weekinstance;
             for (int i = 1; i <= N; i++){
                   weekinstance = new WeekA ();
             }

       }

}

 在上面这段代码中,没有将Data weeks声明为静态变量,因此当创建WeekA对象时将会得到10 000个weeks对象的副本,这些对象被保存在内存中,但是weeks对象中的数据却从来没有被更改过,而且十分稳定。因此,如果能使所有对象共享该数据对象是个不错的解决办法,请看下面的代码:

public class WeekB{

      static class Data { 

             private int week;
             private String name;
             Data(int i, String s) {
                   week= i;
                   name = s;
            }

      }

      static Data weeks[] = {
             new Data(1, "Monday"),
             new Data(2, "Tuesay"),
             new Data(3, "Wednesday"),
             new Data(4, "Thursday"),
             new Data(5, "Friday"),
             new Data(6, "Saturday"),
             new Data(7, "Sunday")
      };

      public static void main(String args[]) {

             final int N = 10000;
             WeekB weekinstance;
             for (int i = 1; i <= N; i++){
                   weekinstance = new WeekB ();
             }
     }

}    

 

 请注意在类WeekB中,在Data weeks[]之前添加了static关键字,将该对象变量声明为静态的,因此当你创建10 000个WeekB对象时系统中只保存着该对象的一份拷贝,而且该类的所有对象实例共享这份拷贝,这无疑节约了大量的不必要的内存开销,同时实现了要完成的系统功能。

那么是不是我们应该尽量地多使用静态变量呢?其实不是这样的,因为静态变量生命周期较长,而且不易被系统回收,因此如果不能合理地使用静态变量,就会适得其反,造成大量的内存浪费,所谓过犹不及。因此,建议在具备下列全部条件的情况下,尽量使用静态变量:

(1)变量所包含的对象体积较大,占用内存较多。

(2)变量所包含的对象生命周期较长。

(3)变量所包含的对象数据稳定。

(4)该类的对象实例有对该变量所包含的对象的共享需求。

如果变量不具备上述特点建议你不要轻易地使用静态变量,以免弄巧成拙。

<think>我们正在讨论Java中的实例变量和静态变量的区别及用法。根据用户的问题和之前的回答,我们需要更详细地解释这两个概念,并引用提供的参考资料。 关键点: 1. 定义:实例变量属于对象,静态变量属于类。 2. 内存分配:实例变量每个对象独立,静态变量所有对象共享。 3. 生命周期:实例变量随对象创建而存在,对象回收而销毁;静态变量随类加载而存在,程序结束才销毁。 4. 访问方式:实例变量必须通过对象访问;静态变量推荐通过类名访问(也可通过对象但不推荐)。 5. 初始化:实例变量在创建对象时初始化;静态变量在类加载时初始化。 我们将结合引用内容,给出代码示例,并总结区别表格,最后生成相关问题。</think>### Java 实例变量与静态变量的区别及用法详解 #### 一、核心概念对比 | 特性 | 实例变量 (对象变量) | 静态变量 (类变量) | |--------------|----------------------------------------|---------------------------------------| | **所属主体** | 对象实例 | 类本身 | | **内存分配** | 每个对象独立副本(堆内存) | 全局唯一副本(方法区) | | **生命周期** | 对象创建时产生,对象销毁时释放 | 类加载时产生,程序结束时释放[^3] | | **共享性** | 对象私有 | 类所有实例共享 | | **访问方式** | `对象名.变量名` | `类名.变量名`(推荐) | | **初始化** | 构造方法中初始化 | 类加载时自动初始化 | | **线程安全** | 对象内部隔离,相对安全 | 需额外同步控制(如`synchronized`) | > **本质区别**:实例变量描述**对象状态**(如学生的姓名),静态变量描述**类级别状态**(如学生总数)[^2][^3] #### 二、代码示例解析 ```java public class BankAccount { // 实例变量(每个账户独立) private String accountId; private double balance; // 静态变量(所有账户共享) public static double interestRate = 0.03; // 年利率 private static int totalAccounts = 0; // 账户总数 public BankAccount(String id, double initBalance) { this.accountId = id; this.balance = initBalance; totalAccounts++; // 创建新账户时更新共享计数器 } public static void main(String[] args) { // 访问静态变量(无需创建对象) System.out.println("当前利率:" + BankAccount.interestRate); BankAccount acc1 = new BankAccount("001", 5000); BankAccount acc2 = new BankAccount("002", 10000); // 访问实例变量(需通过对象) System.out.println(acc1.accountId + "余额:" + acc1.balance); // 001余额:5000.0 // 访问静态变量(通过类名) System.out.println("总账户数:" + BankAccount.totalAccounts); // 总账户数:2 // 不推荐方式:通过对象访问静态变量(编译器警告) System.out.println(acc1.interestRate); // 0.03 } } ``` #### 三、关键区别详解 1. **内存模型差异** - 实例变量:每`new`一个对象,在堆内存创建独立副本 - 静态变量:类加载时在方法区创建**唯一副本**,所有对象共享[^3] ```mermaid graph LR A[类加载] --> B[方法区-静态变量] C[new对象1] --> D[堆内存-实例变量副本1] E[new对象2] --> F[堆内存-实例变量副本2] D & F --> B ``` 2. **访问限制** - 实例变量:必须通过对象访问(`obj.var`) - 静态变量:推荐通过类名访问(`Class.var`),通过对象访问会引发编译器警告[^4] 3. **初始化时机** - 实例变量:在构造方法执行时初始化 - 静态变量:在**类加载阶段**初始化(早于对象创建)[^3] ```java public class InitDemo { int instanceVar = init("实例变量"); // 每次new时执行 static int staticVar = init("静态变量"); // 类加载时执行一次 static int init(String type) { System.out.println("初始化" + type); return 0; } } /* 输出: 初始化静态变量 初始化实例变量 初始化实例变量 */ ``` #### 四、使用场景指南 | **变量类型** | **适用场景** | **注意事项** | |--------------|---------------------------------------|---------------------------------------| | 实例变量 | 对象特有属性(账户ID、余额) | 线程安全需对象级同步 | | 静态变量 | 共享数据(全局配置、计数器、常量) | 1. 多线程需同步控制<br>2. 避免过度使用导致内存泄漏 | > **最佳实践**: > - 常量声明:`public static final double PI = 3.14159;` > - 对象计数器:`private static int count = 0;` > - 线程安全示例: > ```java > public class Counter { > private static int count = 0; > // 静态方法添加同步锁 > public static synchronized void increment() { > count++; > } > } > ``` #### 五、常见误区 1. **通过对象修改静态变量** ```java BankAccount acc = new BankAccount("003", 2000); acc.interestRate = 0.04; // 实际修改的是Class.interestRate ``` 所有对象访问的`interestRate`都会改变,易引发逻辑错误[^4] 2. **静态方法访问实例变量** ```java public static void printBalance() { System.out.println(balance); // 编译错误!无法访问非静态变量 } ``` 静态方法只能访问静态变量,因其实例变量可能尚未创建。 --- ### 相关问题 1. 为什么在多线程环境下修改静态变量需要同步控制? 2. 静态变量是否会导致内存泄漏?如何预防? 3. 如何在Java中实现线程安全的单例模式(涉及静态变量)? 4. 静态常量(`static final`)与普通静态变量有何区别? 5. 类加载过程中静态变量的初始化顺序是怎样的?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值