Shelter类数组初始化触发ArrayIndexOutOfBoundsException问题咨询
构造器外初始化数组触发ArrayIndexOutOfBoundsException的原因及解决方法
原因分析
问题核心在于Java对象的初始化顺序:
当通过new Shelter("Cemali",10)创建对象时,执行流程是:
- 为Shelter对象分配内存,所有成员变量被设为默认值(
size=0、A=null等) - 执行成员变量的显式初始化代码:
Animal[] A = new Animal[size];,此时size还是默认的0,所以数组A的长度被设置为0 - 执行构造器代码,把
size赋值为10、name赋值为"Cemali"
后续调用addAnimal方法时,虽然i < size(0<10)的判断成立,但数组A的实际长度是0,尝试访问A[0]就会触发ArrayIndexOutOfBoundsException。
而正常写法中,数组仅先声明,直到构造器执行时才完成初始化,此时size已经被赋值为10,数组长度正常,自然不会触发异常。
构造器外初始化数组的可行方案
如果坚持要在构造器外完成数组初始化,可采用以下两种方式:
方案1:懒加载初始化数组
在第一次调用addAnimal方法时才初始化数组,此时构造器已经完成size的赋值:
public class Shelter { String name; int size; Animal[] A; // 仅声明数组 int i = 0; Shelter(String name,int size){ this.name = name; this.size = size; } void addAnimal(Animal animal){ // 第一次调用时初始化数组 if(A == null){ A = new Animal[size]; } if(i < size){ A[i] = animal; i++; } else{ System.out.println("The shelter is full."); } } void showAnimals(){ if(A == null) return; for (Animal animal : A) { if(animal == null){ break; } System.out.println(animal); } } }
方案2:使用静态工厂方法创建对象
通过工厂方法先完成size和name的赋值,再初始化数组,完全避开构造器内初始化的限制:
public class Shelter { String name; int size; Animal[] A; int i = 0; // 私有构造器,避免直接实例化 private Shelter(){} // 静态工厂方法 public static Shelter create(String name, int size){ Shelter shelter = new Shelter(); shelter.name = name; shelter.size = size; shelter.A = new Animal[size]; // 在构造器外初始化数组 return shelter; } void addAnimal(Animal animal){ if(i < size){ A[i] = animal; i++; } else{ System.out.println("The shelter is full."); } } void showAnimals(){ for (Animal animal : A) { if(animal == null){ break; } System.out.println(animal); } } }
使用时改为:
Shelter shelter = Shelter.create("Cemali",10);
内容的提问来源于stack exchange,提问作者hasansabbath71
相关产品推荐
相关产品推荐

