今天的文章素材是来自和我的朋友的交流~
也是再次复习到基础知识的一天
又是把基础知识学废的一天
日常开头~
别慌,懵就懂了,因为没有上下文啊~
然后开始告诉我错误是什么~
一开始看到数组对象时,我是有想法的,包括他这个错误,我隐隐约约感觉我学过这部分的知识,有点久远的感觉~
空指针的解决办法:重点关注报错发生的所在行,通过空指针异常产生的两条主要原因诊断具体的错误。同时为了避免空指针的发生,最好在做判断处理时将“null”或者空值放于设定的值之前。
发来了有趣的代码
public class ThirdInfo { private String title; private int number; private String pay; private String count; @Override public String toString() { return &34; + &39;&39;&39; + &34; + number + &39;&39;&39; + &39;&39;&39; + &39;; } public ThirdInfo(String title,String count,String pay) { this.title = title; this.pay = pay; this.count = count; } public ThirdInfo(String title,int number,String pay) { this.title = title; this.number = number; this.pay = pay; } public ThirdInfo(String title,String pay) { this.title = title; this.pay = pay; } public String getTitle() { return title;} public void setTitle(String title) { this.title = title; } public int getNumber() { return number;} public void setNumber(int number) { this.number = number; } public String getPay() { return pay;} public void setPay(String pay) { this.pay = pay;} public String getCount() { return count; } public void setCount(String count) {this.count = count;} } class testal{ public static void main(String[] args) { ThirdInfo [] thirdInfos = new ThirdInfo[6]; String vipPay[] = new String[]{ &34;,&34;,&34;,&34;,&34;,&34; }; String vipPaytitle[] = new String[]{ &34;,&34;,&34;,&34;,&34;,&34; }; for (int i = 0;i<vipPay.length;i++){ thirdInfos[i].setTitle(vipPaytitle[i]); thirdInfos[i].setPay(vipPay[i]); } for (ThirdInfo info : thirdInfos) { System.out.println(info); } } }
如果不事先说他会报错,你顺着看下来,甚至还会觉得是对的。
因为就算没见过上面这样的代码,也可能见过下面这样的代码
1、字符串变量未初始化,接口类型的对象没有用具体的类初始化,比如List lt;会报错,List lt = new ArrayList(),则不会报错。2、当一个对象的值为空时,没有判断为空的情况,可以试着把下面的代码前加一行代码。3。
String[] str = new String[6]; String vipPaytitle[] = new String[]{ &34;,&34;,&34;,&34;,&34;,&34; }; for (int i=0;i<vipPaytitle.length;i++){ str[i]=vipPaytitle[i]; } for (int i=0;i<vipPaytitle.length;i++){ System.out.println(str[i]); }
说 String是对象没人会骂我吧,那接着说new String[6] 创建了一个对象数组也没人反对吧。
那再说,为什么new ThirdInfo[6]是不可以操作的,但是我new String[6]是可以赋值,手机app空指针异常怎么解决,并且不会报错呢?,
一起思考一下~
在以上这些方案中,我比较推荐使用注解来预防空指针异常,因为这种方式十分有效,对代码的侵入性也较小。所有的公共 API 都应该使用 @Nullable 和 @NonNull 进行注解,这样就能强制调用方对空指针异常进行预防,让我们的程序更为健壮。 已赞。
我的想法
我自己在测了之后,光从代码逻辑层面看不出什么问题,我就想去看一下底层的字节码文件是怎么样的。(我当时只是隐约记得这是实例化的一个问题,但是我知道逻辑层面看不出,但是在字节码中肯定有所不同)
然后就有了下面的测试:
首先看的是原来测试代码的字节码文件
FlatformAgentController.findAllFlatformAgent方法的第81行,变量或者参数为空,设置个断点看看,是不是哪块忘了初始化了,或者传递的参数没有赋值。
只看 new ThirdInfo[6];和 thirdInfos[i].setTitle(vipPaytitle[i]);部分的字节码文件
圈出来的这三行字节码代码就是ThirdInfo [] thirdInfos = new ThirdInfo[6];的展示
bipush 6 // 将6压入操作数堆栈。 anewarray #2 <com/ThirdInfo> //创建一个引用型(如类,接口,数组)的数组,并将其引用值压入栈顶 astore_1 //把栈顶的值存到第一个变量(thirdInfos )
能不能看懂都没事,我们来看看第二个测试:
直接在方法中 new ThirdInfo(),我们看看它的字节码文件是什么样的。
new 3 <com/ThirdInfo.<init> : ()V> // 调用超类构造方法,实例初始化方法,私有方法 pop // 出栈
空指针异常: 可以直接在可能出现空指针的代码处 try catch一下,你也可以这样做:在用到可能出现空指针的 变量或者对象处,先增加一个判空处理(比如:if(textutil.isempty(str) { })对于ThreadException:对于线程的。
其实看到这里,就能够大致知道是什么原因了。
就是因为没有实例化,所以看起来ThirdInfo [] thirdInfos = new ThirdInfo[6];好像是创建了6个ThirdInfo对象的这段代码,实际上,只是分配了内存空间。
还可以换个更简单的方式来证实这个情况:
我利用反射创建ThirdInfo对象进行输出,和输出ThirdInfo [] thirdInfos = new ThirdInfo[6];第一个对象,看看他们的结果是什么~
可以看到,实际上 thirdInfos[0] 实际上就是null
只有进行实例化之后,才能正确使用。
反射他本质上也是进行了类的实例化的,这点从字节码中依然可以看出。
之前说到了invokespecial是调用超类构造方法,实例初始化方法,私有方法
invokevirtual 的意思是调用实例方法.
更详细的很难说,学过但我忘了
阅读字节码文件,也没你想的那么难,反正不会去查就好了,很多中文版手册的~
所以在使用前肯定都会去进行实例化的。
聊完这个,又回到了之前的问题上。
为什么 new String[6]可以?
String也是个对象~
说到这个,又回到了以前学JVM的知识上来了.
写了一小段代码,这是可以正确执行的
我们来看看他的字节码文件:
不知道大家还记不记得String不可变性,当我们使用当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值。
看个简单的例子吧,是我以前文章里面的。
public static void main(String[] args) { String str1 = &34;; String str2 = &34;; str1=&34;; // 判断地址, 它由true -->false System.out.println(str1 == str2); }
后记
今天就写到这里啦~ 感觉自己好菜啊~ 一起努力哦~