又是把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 索引
Java快速入门之数组、方法
### Java快速入门之数组与方法简介 #### 一、数组 数组是一种容器,用于存储同种数据类型的多个值。定义数组时需指定数据类型,如`int[]`只能存储整数。数组的初始化分为静态和动态两种: - **静态初始化**:直接指定元素,系统自动计算长度,如`int[] arr = {1, 2, 3};` - **动态初始化**:手动指定长度,系统给定默认值,如`int[] arr = new int[3];` 数组访问通过索引完成,索引从0开始,最大索引为`数组.length - 1`。遍历数组常用`for`循环。常见操作包括求和、找最值、统计特定条件元素等。
|
1天前
|
存储 Java 索引
Java基础(六):数组
Java基础(六):数组
Java基础(六):数组
|
3月前
|
存储 缓存 算法
Java 数组
【10月更文挑战第19天】Java 数组是一种非常实用的数据结构,它为我们提供了一种简单而有效的方式来存储和管理数据。通过合理地使用数组,我们能够提高程序的运行效率和代码的可读性。更加深入地了解和掌握 Java 数组的特性和应用,为我们的编程之旅增添更多的精彩。
42 4
|
3月前
|
存储 缓存 算法
提高 Java 数组性能的方法
【10月更文挑战第19天】深入探讨了提高 Java 数组性能的多种方法。通过合理运用这些策略,我们可以在处理数组时获得更好的性能表现,提升程序的运行效率。
52 2
|
3月前
|
存储 Java
Java“(array) <X> Not Initialized” (数组未初始化)错误解决
在Java中,遇到“(array) &lt;X&gt; Not Initialized”(数组未初始化)错误时,表示数组变量已被声明但尚未初始化。解决方法是在使用数组之前,通过指定数组的大小和类型来初始化数组,例如:`int[] arr = new int[5];` 或 `String[] strArr = new String[10];`。
115 2
|
3月前
|
Java
Java数组动态扩容和动态缩减
Java数组动态扩容和动态缩减
32 3
|
3月前
|
存储 算法 Java
带你学习java的数组军队列
带你学习java的数组军队列
45 0
|
4月前
|
存储 Java
Java编程中的对象和类
【8月更文挑战第55天】在Java的世界中,“对象”与“类”是构建一切的基础。就像乐高积木一样,类定义了形状和结构,而对象则是根据这些设计拼装出来的具体作品。本篇文章将通过一个简单的例子,展示如何从零开始创建一个类,并利用它来制作我们的第一个Java对象。准备好让你的编程之旅起飞了吗?让我们一起来探索这个神奇的过程!
41 10
|
4月前
|
存储 Java
Java的对象和类的相同之处和不同之处
在 Java 中,对象和类是面向对象编程的核心。
73 18
|
4月前
|
Java
Java 对象和类
在Java中,**类**(Class)和**对象**(Object)是面向对象编程的基础。类是创建对象的模板,定义了属性和方法;对象是类的实例,通过`new`关键字创建,具有类定义的属性和行为。例如,`Animal`类定义了`name`和`age`属性及`eat()`、`sleep()`方法;通过`new Animal()`创建的`myAnimal`对象即可调用这些方法。面向对象编程通过类和对象模拟现实世界的实体及其关系,实现问题的结构化解决。
37 4