记一次空指针异常
来源:互联网 发布:理科生 禅师 知乎 编辑:程序博客网 时间:2024/06/05 14:17
今天跑monkey的时候,出现了一个异常:
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Class java.lang.Object.getClass()' on a null object reference
尝试用一个空的引用去获取类对象,很奇怪的错误!
搜索了整个出错的代码,需要使用对象的时候都进行了判空了呀~
最后看到了这么一个地方:
mLocationListener = sLocationInstance.new LocationListener();这是一个内部类的创建,使用到了外部类的对象,于是猜测是不是因为sLocationInstance这个对象是空的导致的呢?
于是马上写个测试用例:
public class NullTest { public static NullTest test; private boolean isOut; public static class User{ public static void use(){ Inner inner = test.new Inner();// 要创建内部类对象,必须使用外部类的对象+.new的方式。 } } public class Inner{ private boolean isIn; public void test(){ isIn = isOut;// 内部类可以访问外部的所以成员变量和方法 } }}果不其然,执行User.use()方法的时候报错了,也就是文章开头的那个错误。
哦,原来是因为我们要创建内部类,但是创建内部类需要一个外部类对象,但是如果外部类对象为空的话,就出问题了。
我的理解,虚拟机在创建内部类对象的时候,需要一个外部类类型,这个外部类类型是由外部类对象得到的,但是如果这个外部类对象为空的话,那就出现上面的异常了。(字面理解,不知道对不对O(∩_∩)O哈哈~)。
内部类对象的创建条件:
要想使用new 生成一个内部类的实例,需要先指向一个外部类的实例,也就是先生成外部类的实例,因为内部类可以调用外部类的人员成员,当没有外部类实例的时候也就没有这些成员的内存空间,内部类在实例化的时候,调用外部类的成员就会出错,所以需要使用外部类的实例 + 点 + new 的方式实例化一个新的内部类。
在内部类(Inner Class),可以随意的访问外部类的成员,这可让我们更好地组织管理我们的代码,增强代码的可读性。
详细可看内部类的定义:
http://android.blog.51cto.com/268543/384844/
找到了问题,那么还要去想想为什么会出现这个问题?
在我们的代码中sLocationInstance是个Location类的单例对象,该类里面定义了一个内部类:LocationListener,还定义了一个静态内部类:
static class MyHandler extends Handler
在MyHandler的handleMessage方法中,会去执行创建LocationListener对象的过程。
public void handleMessage(Message msg) { case START_LOCATION_MSG: { mLocationListener = sLocationInstance.new LocationListener(); break; } }
在我们的Location类中,定义了MyHandler的静态变量,并进行了初始化(类加载的时候就会去初始化了,这个时候我们的单例对象可能还没创建):
private static MyHandler mHandler = new MyHandler(sLocationThread.getLooper());所以,handler这个对象是优先于sLocationInstance对象创建的,那么就有可能在sLocationInstance还没创建的时候,我们发送了一个msg,于是会执行到hanleMessage方法中,从而去创建内部类LocationListener的对象,这个时候就肯定会出错了。
部分代码如下:
public class Location { private static final HandlerThread sLocationThread = new HandlerThread("location"); static { sLocationThread.start(); } public static Location sLocationInstance; public static final int START_LOCATION_MSG = 10002; private static MyHandler mHandler = new MyHandler(sLocationThread.getLooper()); public static AMapLocationListener mLocationListener; private static Object mLock = new Object(); public static class MyHandler extends Handler { public MyHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { int what = msg.what; switch (what) { case START_LOCATION_MSG: { mLocationListener = sLocationInstance.new LocationListener(); break; } default: break; } } } public synchronized static Location getInstance() { if (sLocationInstance == null) { sLocationInstance = new Location(); } return sLocationInstance; } public synchronized void startLocation() { Log.d(TAG, "startLocation"); mHandler.sendEmptyMessage(START_LOCATION_MSG); } public class LocationListener { }
}
虽然我们mHandler发送一个msg是由sLocationInstance这个对象来调用的,按理说,既然sLocationInstance能调用handler发送一个msg,那必然这个对象是不为空的,也就不可能出现空指针异常了。理想情况当然是这样的,但系统的事情,谁有能说得准呢。或许是我们发送消息后,系统阻塞了这个消息,然后等我们的Location被gc了,而mHandler还健在的时候,收到了这个延迟的消息呢~
就比如说某个app在我们系统中报了这个错误:
Crashjava.lang.NullPointerException09:17:39112:20:35其他未知// at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3128)ActivityThread出错了~~~无论原因怎样,还是在使用对象的时候进行下判空吧~~
以上纯属个人瞎说,不对之处就当笑话看过,勿喷!
- 记一次空指针异常
- 空指针异常
- struts2空指针异常
- Struts2 空指针异常
- hibernate 空指针异常
- NullPointerException空指针异常
- 空指针异常总结
- getServletContext()空指针异常
- 空指针异常
- Hibernate空指针异常
- struts2空指针异常
- 空指针异常
- NullPointerException空指针异常
- 空指针异常
- 空指针异常
- 空指针异常总结
- gethibernatetemplate() 空指针异常
- setAdapter空指针异常
- SQL查询语句
- vuethink 安装流程
- 作业3
- 使用LiquiBase管理数据库的迁移
- 伍蒙的c++作业3
- 记一次空指针异常
- C++第三次上机实验-个人所得税计算器
- Bootstrap 支持的JavaScript插件
- 十四、switch中可以传递的参数类型(Only convertible int values or enum constants are permitted)
- LeetCode算法题——15. 3Sum
- java基础,递归调用的初学总结
- 树莓派Raspberry Pi实战之命令行下实现USB存储设备自动挂载
- 远程连接Ubuntu14.04上的Mysql数据库
- 盒子模型-笔记