又是把Java基础知识学废的一天,new 一个对象数组,操作时报空指针异常

简介: 又是把Java基础知识学废的一天,new 一个对象数组,操作时报空指针异常

今天的文章素材又是来自我和我的朋友程交流~

也是再次复习到基础知识的一天

又是把基础知识学废的一天

日常开头~

image.png


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

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

image.png

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

发来了有趣的代码

 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]是可以赋值,并且不会报错呢?

一起思考一下~

我的想法

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

然后就有了下面的测试:

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

image.png

只看 new ThirdInfo[6];和 thirdInfos[i].setTitle(vipPaytitle[i]);部分的字节码文件

image.png

圈出来的这三行字节码代码就是ThirdInfo [] thirdInfos = new ThirdInfo[6];的展示

 bipush 6 // 将6压入操作数堆栈。
 anewarray #2 <com/ThirdInfo> //创建一个引用型(如类,接口,数组)的数组,并将其引用值压入栈顶
 astore_1 //把栈顶的值存到第一个变量(thirdInfos )

能不能看懂都没事,我们来看看第二个测试:

直接在方法中 new ThirdInfo(),我们看看它的字节码文件是什么样的。

image.png

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

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

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

image.png

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

我利用反射创建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]);
     }
 }

image.png

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

 ThirdInfo [] thirdInfos = new ThirdInfo[6];
 thirdInfos[0]=new ThirdInfo();
 System.out.println(thirdInfos[0]);

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

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

image.png

之前说到了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]);
 }

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

image.png

不知道大家还记不记得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);
 }

image.png

更详细的可以看看这篇

通过这个文章重新再深入认识认识String吧! 作者:宁在春

后记

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

希望你是满载而归的~


目录
相关文章
|
1天前
|
并行计算 Java API
Java 8中的接口默认方法和静态方法以及并行数组
【5月更文挑战第19天】Java 8引入了许多新特性,其中包括接口的默认方法和静态方法,以及并行数组的能力。这些特性增强了Java的面向对象编程模型和数组处理能力。让我们深入了解它们的概念和实践。
19 2
|
2天前
|
算法 搜索推荐 Java
滚雪球学Java(33):数组算法大揭秘:应用案例实战分享
【5月更文挑战第8天】?本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由?;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
30 8
滚雪球学Java(33):数组算法大揭秘:应用案例实战分享
|
3天前
|
存储 Java 测试技术
滚雪球学Java(32):如何理解和实现稀疏数组
【5月更文挑战第7天】?本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由?;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
14 1
滚雪球学Java(32):如何理解和实现稀疏数组
|
5天前
|
消息中间件 Java RocketMQ
MQ产品使用合集之在同一个 Java 进程内建立三个消费对象并设置三个消费者组订阅同一主题和标签的情况下,是否会发生其中一个消费者组无法接收到消息的现象
消息队列(MQ)是一种用于异步通信和解耦的应用程序间消息传递的服务,广泛应用于分布式系统中。针对不同的MQ产品,如阿里云的RocketMQ、RabbitMQ等,它们在实现上述场景时可能会有不同的特性和优势,比如RocketMQ强调高吞吐量、低延迟和高可用性,适合大规模分布式系统;而RabbitMQ则以其灵活的路由规则和丰富的协议支持受到青睐。下面是一些常见的消息队列MQ产品的使用场景合集,这些场景涵盖了多种行业和业务需求。
11 1
|
5天前
|
Java
Java String 避免空指针的方法
Java String 避免空指针的方法
5 0
|
5天前
|
算法 Java 索引
【Java 刷题记录】双指针(下)
【Java 刷题记录】双指针
26 0
|
5天前
|
算法 Java 容器
【Java 刷题记录】双指针(上)
【Java 刷题记录】双指针
22 0
|
5天前
|
搜索推荐 算法 Java
滚雪球学Java(29):数组长度和排序算法:让你的程序更高效
【5月更文挑战第4天】?本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由?;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
13 0
滚雪球学Java(29):数组长度和排序算法:让你的程序更高效
|
5天前
|
存储 Java
滚雪球学Java(28):轻松掌握数组:访问和遍历技巧
【5月更文挑战第3天】?本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由?;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
13 2
滚雪球学Java(28):轻松掌握数组:访问和遍历技巧
|
5天前
|
存储 Java 索引
【Java开发指南 | 第十六篇】Java数组及Arrays类
【Java开发指南 | 第十六篇】Java数组及Arrays类
10 3
http://www.vxiaotou.com