考虑到我有以下给定的类层次结构:
class parent{
void parentMethod(){
System.out.println("inside parent method");
}
}
class child1 extends parent{
void child1Method(){
System.out.println("inside child method");
}
}
class child2 extends parent{}
class grandchild1 extends child1{}
现在,如果我定义一个类似这样的数组:
parent[] p=new child1[4];
然后尝试以这种方式初始化它:
p[0]=new child1(); // works
p[1]=new parent(); //doesn't work
p[2]=new child2(); //doesn't work
p[3]=new grandchild1(); //works
这使我得出结论,我可以将数组中的对象定义为类型为child1或从中继承的类。
然后如果我尝试访问这些方法:
p[i].ParentMethod();//works
p[i].Child1Method(); //doesn't work
这使我得出结论p [i]是父类型的引用。 这里发生了什么?
宣布
parent[] p=new child1[4];
我完全宣布了什么?
我只能将数组的各个元素声明为类型为child1及其子类,并且只能访问类parent的方法。我错过了什么概念?
答案 0 :(得分:1)
parent[] p = new child1[4];
您声明类型p
的数组parent[]
。所以,所有编译器都知道这个数组是一个只能包含父实例的数组。
您使用child1[]
类型的数组初始化此变量。这在Java中是允许的,因为数组是协变的:子数组是父数组。但是,List<Parent>
和List<Child>
等通用类型不允许这样做,因为List<Child>
不是List<Parent>
。
因此,p
的具体,运行时类型为child1[]
。这意味着,在运行时,该数组将只允许child1
的实例存储在此数组中。尝试存储父项(由于声明的类型p
是parent[]
),编译器允许这样做,将产生ArrayStoreException
。
再次注意,这种奇怪的设计并不存在于通用集合中,这通常应该是首选。
答案 1 :(得分:0)
下面:
parent[] p=new child1[4];
您正在创建一个长度为4的数组,该数组可以存储与child1
兼容且具有new child1[4]
部分的类型的对象。然后,您将该数组分配给类型为parent[]
的变量。这在Java编译时是允许的。
然后,您将parent
对象分配给数组中的一个元素。编译器认为这没关系,因为它认为p
是一个parent
的数组。但是在运行时,p
实际上是一个child1
的数组,它不能存储parent
个对象。因此,将抛出ArrayStoreException
。
现在,当您尝试在child1
中的元素上调用p
的方法时,您不能。这是因为编译器认为p
是parent
的数组。在parent
中没有声明这样的方法,因此编译器会抱怨,但事实上,child
对象存储在数组中。