android中的类加载和静态成员变量的初始化

本文探讨了Java中静态成员变量的初始化时机,并通过实例分析了如何避免Runtime异常,同时解释了Java与C++静态成员变量初始化的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前几日做项目的时候使用了静态的成员变量Handler,如下所示:

public class MyUtility
{
    private static final int MSG_ADD = 0;
    private static final int MSG_DECREASE = 1;
    private static int cnt = 0;
    
    public static Handler handler = new Handler()
    {
        @Override
        public void handleMessage(Message msg)
        {
            switch(msg.what)
            {
            case MSG_ADD:
                cnt++;
                break;
            case MSG_DECREASE:
                cnt--;
                break;
            default:
                break;
            }
        }
    };
    
    public static void bench()
    {
        Message msg = handler.obtainMessage(MSG_ADD);
        handler.sendMessage(msg);
        new Thread(){
            @Override
            public void run()
            {
                Message msg = handler.obtainMessage(MSG_DECREASE);
                handler.sendMessage(msg);
            }
        }.start();
    }
}


并在主线程中一个按钮的onClick事件中调用这个类中的静态函数:

public void onClick(View vw)
    {
        new Thread(){
            @Override
            public void run()
            {
                MyUtility.bench();
            }
        }.start();
    }

注意是在子线程中调用的MyUtility中的函数,结果运行中出错,调试发现如下错误:
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

意思是说handler是在子线程中创建的,而子线程没有调用Looper.perpare()。


原先以为static成员变量是在程序加载的时候初始化,怎么会在子线程中创建呢?网上搜索也没发现有价值的线索,最后只有自己总结了。网上说静态变量是在类加载的时候初始化,难道是MyUtility是在第一次使用的时候才加载?如果程序运行过程中没有使用这个类,那么这个类是不会被程序加载的?带着这样的疑问,进行了下面的调试:

如果类第一次使用是在子线程中,那么类加载是在子线程中进行的,static变量的初始化也是在子线程中进行。把Handler改成如下声明方式(这样可以打断点进行调试):

public static Handler handler = null;

static{

handler = new Handler()
    {
        @Override
        public void handleMessage(Message msg)
        {
            switch(msg.what)
            {
            case MSG_ADD:
                cnt++;
                break;
            case MSG_DECREASE:
                cnt--;
                break;
            default:
                break;
            }
        }
    };

}

经调试发现,果然如我总结的一样。看来java中static成员变量初始化时机和c++中static成员变量不一样啊。

发现问题的原因就好解决问题了,第一次使用MyUtility类要在主线程中(比如先在主线程中随便调用一个MyUtility函数或者变量),那么就不会出现java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()异常了。


后续:在一篇文章中看到,Java和C#语言都支持类的动态加载,而C++不支持!


### 如何在 Android初始化互斥锁 (Mutex) 在 Android 的 C/C++ 编程环境中,可以利用 POSIX 提供的标准库来实现线程间的同步机制。对于互斥锁(`pthread_mutex_t`),其初始化可以通过两种方式完成:静态初始化动态初始化。 #### 静态初始化 如果希望在编译时就定义好互斥量而不需要运行期间调用任何函数,则可以直接使用宏 `PTHREAD_MUTEX_INITIALIZER` 来进行初始化: ```cpp #include <pthread.h> // 定义并立即初始化互斥锁为未锁定状态 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; ``` 这种方式适用于全局变量或具有静态存储期的对象,在程序加载时自动完成初始化工作[^1]。 #### 动态初始化 当需要更灵活地控制何时以及如何初始化互斥锁时,可以选择通过调用 `pthread_mutex_init()` 函数来进行动态初始化。这允许设置额外属性,并且可以在任意时刻执行此操作而不必局限于声明阶段。 ```cpp #include <pthread.h> #include <stdio.h> int main() { pthread_mutex_t mutex; // 初始化互斥锁,默认属性 int result = pthread_mutex_init(&mutex, NULL); if(result != 0){ printf("Failed to initialize mutex\n"); return -1; } // 使用完毕后销毁互斥锁释放资源 pthread_mutex_destroy(&mutex); return 0; } ``` 上述代码展示了如何安全地创建一个互斥锁实例,并检查返回值以确保成功初始化。最后记得要适时调用 `pthread_mutex_destroy()` 方法清理不再使用的互斥锁所占用的资源。 为了在线程间共享这个互斥锁,通常会把它作为成员变量放在某个类里面或者作为一个外部作用域内的全局/静态变量处理。这样不同线程就可以访问同一个互斥锁对象从而达到保护临界区的目的。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值