Java基础知识学fei了!new 一个对象数组,操作时报空指针异常!

今天的文章素材来自和朋友交流~ 也是再次复习到基础知识的一天又是把基础知识学fei的一天

开头~

​别慌,懵就懂了,因为没有上下文啊~

然后开始告诉我错误是什么~

​一开始看到数组对象时,我是有想法的,包括他这个错误,我隐隐约约感觉我学过这部分的知识,有点久远的感觉~

发来了有趣的代码

public class ThirdInfo { private String title; private int number; private String pay; private String count; ​ @Override public String toString() { return "ThirdInfo{" + "title='" + title + ''' + ", number=" + number + ", pay='" + pay + ''' + ", count='" + count + ''' + '}'; } ​ 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[]{ "3笔", "¥1000.00", "¥100.00", "100积分", "¥10.00", "100积分" }; String vipPaytitle[] = new String[]{ "会员消费笔数","储值余额消费","赠送余额消费","积分抵线变动","积分抵扣金额","积分赠送变动" }; ​ 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); } } } 复制代码

如果不事先说他会报错,你顺着看下来,甚至还会觉得是对的。

因为就算没见过上面这样的代码,也可能见过下面这样的代码

String[] str = new String[6]; String vipPaytitle[] = new String[]{ "会员消费笔数", "储值余额消费", "赠送余额消费", "积分抵线变动", "积分抵扣金额", "积分赠送变动" }; 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]是可以赋值,并且不会报错呢?

一起思考一下~

我的想法

我自己在测了之后,光从代码逻辑层面看不出什么问题,我就想去看一下底层的字节码文件是怎么样的。(我当时只是隐约记得这是实例化的一个问题,但是我知道逻辑层面看不出,但是在字节码中肯定有所不同)

然后就有了下面的测试:

首先看的是原来测试代码的字节码文件

只看 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 #2 <com/ThirdInfo> // 创建一个对象 dup // 复制栈顶数值(数值不能是long或double类型的)并将复制值压入栈顶 invokespecial #3 <com/ThirdInfo.<init> : ()V> // 调用超类构造方法,实例初始化方法,私有方法 pop // 出栈 复制代码

其实看到这里,就能够大致知道是什么原因了。

就是因为没有实例化,所以看起来ThirdInfo [] thirdInfos = new ThirdInfo[6];好像是创建了6个ThirdInfo对象的这段代码,实际上,只是分配了内存空间。

​还可以换个更简单的方式来证实这个情况:

我利用反射创建ThirdInfo对象进行输出,和输出ThirdInfo [] thirdInfos = new ThirdInfo[6];第一个对象,看看他们的结果是什么~

public class Test { ​ public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException { Class<?> aClass = Class.forName("com.ThirdInfo"); ThirdInfo o =(ThirdInfo) aClass.newInstance(); System.out.println(o); ​ ThirdInfo [] thirdInfos = new ThirdInfo[6]; System.out.println(thirdInfos[0]); } } 复制代码

可以看到,实际上 thirdInfos[0] 实际上就是null

ThirdInfo [] thirdInfos = new ThirdInfo[6]; thirdInfos[0]=new ThirdInfo(); System.out.println(thirdInfos[0]); 复制代码

只有进行实例化之后,才能正确使用。

反射他本质上也是进行了类的实例化的,这点从字节码中依然可以看出。

之前说到了invokespecial是调用超类构造方法,实例初始化方法,私有方法

invokevirtual 的意思是调用实例方法.

更详细的很难说,学过但我忘了

阅读字节码文件,也没你想的那么难,反正不会去查就好了,很多中文版手册的~

所以在使用前肯定都会去进行实例化的。

聊完这个,又回到了之前的问题上。

为什么new String[6]可以?

String也是个对象~

说到这个,又回到了以前学JVM的知识上来了.

写了一小段代码,这是可以正确执行的

String[] str = new String[6]; for (int i = 0; i < 6; i++) { str[i] = ""+i; } for (int i = 0; i < 6; i++) { System.out.println(str[i]); } 复制代码

我们来看看他的字节码文件:

​不知道大家还记不记得String不可变性,当我们使用当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值。

因为String它的不可变性,看似只是改变str[0]=null的值,实际上将一个新的字符串("abc")赋值给str[0]时,真正改变的是str[0]的指向。

看个简单的例子吧:

public static void main(String[] args) { String str1 = "hello"; String str2 = "hello"; str1="abc,hao"; // 判断地址, 它由true -->false System.out.println(str1 == str2); } 复制代码

今天就写到了这里啦~ 感觉自己还好菜啊~ 一起努力哦~

希望你是满载而归的~

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值