解惑 -- static

来源:互联网 发布:centos编译c 编辑:程序博客网 时间:2024/06/06 20:26
static解惑,首先我们先来了解了解要解决的是啥惑,在了解之前,我们先来简单过一下static的应用,static关键字可修饰内部类、方法和变量,被修饰的元素将会独立存储于内存中的静态数据区,不随对象的创建而产生。被static修饰的变量具有了全局的属性,所以使用它便可以很方便在安卓中各种组件中进行数据的交互,然而,大量实例表明使用这种方式进行数据交互是不安全的,被static修饰的变量可能被回收变为空,但是为什么在一些常量和单例的使用中又可以使用static进行修饰而不用担心其值被回收呢?而这就是我们今天要解决的惑。


首先我们说说为什么用静态变量来进行数据交互是不安全的,因为在安卓中,fragment、activity和application都遵循着严格的生命周期,因此当系统资源匮乏的时候,他们是很可能被gc回收的,尤其是优先级较低的进程,即是假如你的应用在后台运行,那么优先级是较低的,系统随时可能杀掉你的程序来获得更多的内存,静态变量也会被随之销毁,当重新打开程序,Android会重新建立一个新的Application实例。这时候的静态变量重新初始化置null或者是其他的默认值,这时候如果再使用它,可想而知,程序则可能会直接crash.


我们来看看静态常量的写法:

    public static final String SD_CARD_PATH = Environment.getExternalStorageDirectory().getAbsolutePath();    public static final String USER_HEAD_IMG_PATH = SD_CARD_PATH  + "UserHeadImg.jpg";    public static final String CAMERA_PATH = SD_CARD_PATH  + "CameraTmp.jpg";    public static final String URL = "http://fcloud.com/api.php/";</span>

和静态内部类饿汉式单例的写法:

publlic class Singleton {    private Singleton() {}    private static class SingletonLoader {        private static final Singleton INSTANCE = new Singleton();    }     public static Singleton getInstance() {        return SingletonLoader.INSTANCE;    }}


为什么以上两种写法是安全的呢,为什么这里的静态变量就不会被回收呢?这就涉及到static元素与java类生命周期的关系了。
java类的生命周期如下:


加载连接(验证,准备,解析)→初始化→卸载


简要介绍一下这几个步骤:
加载:将Java源文件编译成字节码文件(.class),然后在JVM中执行。
验证:验证加载的类是否合法
准备:为静态变量分配内存和默认初值
解析:把常量池中的符号引用转换为直接引用(符号引用可以理解为类名,方法名,变量名等写代码的时候所表示的形式,而直接引用则为jvm中可以直接使用内存地址形式,这个步骤是把这两个形式进行了变换)
初始化:初始化与类相关的静态赋值语句和静态语句
卸载:这里的类被卸载等同于进程被回收


根据以上步骤,静态变量是在classLoader通过以上装载类的步骤(加载、连接和初始化)进行了创建与初始化,所以每次新开进程都会把静态常量和静态代码块进行初始化,然后才执行程序的入口函数,那上面时候才会回收这些静态变量呢,根据java类的生命周期,可以看到只有在类被卸载的时候,这些静态值才会被回收,而类被卸载等同于进程的结束,当进程重新开启,这些定义好的静态量又一次被重新分配内存,赋值,然后被使用。因此可以证明以上的静态常量和单例写法是安全的。至于用静态变量来传值是不安全的也是可以证明的,当我们在程序运行的时候给某个静态变量赋了值,然后程序挂掉了,再回来这个变量被初始化了,即不是原来值了,这时候再进行使用则会出现问题了。明确一点就是,静态变量的值不会在进程运行的时候被回收,只会在类被卸载的时候,既是进程死掉的时候被回收。

所以得出一个结论:静态变量在初始化之后的赋值是不安全的,这里的初始化包括了application,activity,fragment的onCreate中的初始化代码,当然为了保险起见,你也可以在使用的之前做一下判断是否为空。


最后温馨提示:使用静态变量需特别注意内存泄漏,因为大部分内存泄漏的问题都是由于静态变量持有需销毁对象的引用而未及时释放所造成的。

1 0
原创粉丝点击