为什么Java不理解我放在这个多维数组中的对象的类?
我正在做一个小游戏,但为了举例,我将使用来自假设类学生的对象和来自假设类课本的对象 我有一个多维网格,希望由学生对象或书本对象填充。也许它叫为什么Java不理解我放在这个多维数组中的对象的类?,java,arrays,class,multidimensional-array,Java,Arrays,Class,Multidimensional Array,我正在做一个小游戏,但为了举例,我将使用来自假设类学生的对象和来自假设类课本的对象 我有一个多维网格,希望由学生对象或书本对象填充。也许它叫 classroom[][] 有四张桌子: [0][0], [0][1], [1][0], and [1][1]. 我希望能够放置一个学生或一本书,而不是两者都放,并且能够打印 classroom[0][1].someStudentAttribute 如果我知道是个学生或者 classroom[0][1].someBookAttribute
classroom[][]
有四张桌子:
[0][0], [0][1], [1][0], and [1][1].
我希望能够放置一个学生或一本书,而不是两者都放,并且能够打印
classroom[0][1].someStudentAttribute
如果我知道是个学生或者
classroom[0][1].someBookAttribute
如果我知道这是一本书
要明确的是,当它是一个学生或一本书时,它将是显而易见的。我不需要一个万无一失的方法来区分,也就是说,我只会在代码中使用.someStudentAttribute,当它肯定是一个学生在那张桌子上时
我在这里的某个地方读到,我可以创建一个多维数组,通过在名称前声明变量类型Object[]]来接受多种类型的对象
Student alice = new Student("alice", 10);
Student bob = new Student("bob", 11);
Student charlie = new Student("charlie", 10);
Book mathBook = new Book("mathematics", 578);
Object[][] classroom = new Object[2][2];
classroom[0][0] = alice;
classroom[0][1] = bob;
classroom[1][0] = charlie;
classroom[1][1] = mathBook;
这将返回正确的类学生
System.out.println(classroom[0][0].getClass());
这也会返回正确的类目
System.out.println(classroom[1][1].getClass()):
但一旦我尝试打印属性,就会出现错误:
System.out.println(classroom[0][0].age);
错误是:
java: cannot find symbol
symbol: variable age
location: java.lang.Object
看起来Java忘记了这一点
classroom[0][0]
只要我要求属性,它就属于学生类!如果
classroom[0][0]
表示数组插槽中的对象不是正确的方法,是什么
可能与将变量声明为Object[][]有关,但重点还是要能够将来自不同类的对象放入其中。如果我只是叫它Student[][],我就无法把它放进书中。对象教室的类类型是object,正如您所称的教室[0][0]。年龄,对象类不知道您在自定义类中定义的属性。您需要将教室[0][0]强制转换为自定义类,如下所示:
if (classroom[0][0] instanceof Student) { // Although it is a bad practice and against OOP
System.out.println(((Student)classroom[0][0]).age);
}
我建议读一些关于OOP原理的东西,然后设计一个合适的解决方案
编辑:我可能不清楚您必须努力实现什么,但下面是一个示例实现,它可能会给您一些想法。通常避免直接使用on对象访问变量,而是使用getter/setter
查看这个示例实现
public class Classroom {
enum ClassRoomObjectType {
STUDENT,BOOK;
}
static abstract class ClassRoomObject {
private String name;
private int age;
private ClassRoomObjectType classRoomObjectType;
protected ClassRoomObject(ClassRoomObjectType classRoomObjectType, String name, int age) {
this.classRoomObjectType = classRoomObjectType;
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return String.format("Type: %s, Name: %s, Age: %s", classRoomObjectType, name, age);
}
}
static class Student extends ClassRoomObject {
public Student(String name, int age) {
super(ClassRoomObjectType.STUDENT, name, age);
}
}
static class Book extends ClassRoomObject {
public Book(String name, int age) {
super(ClassRoomObjectType.BOOK, name, age);
}
}
public static void main(String[] args) {
Student alice = new Student("alice", 10);
Student bob = new Student("bob", 11);
Student charlie = new Student("charlie", 10);
Book mathBook = new Book("mathematics", 578);
ClassRoomObject[][] classRoomObjects = new ClassRoomObject[2][2];
classRoomObjects[0][0] = alice;
classRoomObjects[0][1] = bob;
classRoomObjects[1][0] = charlie;
classRoomObjects[1][1] = mathBook;
for(int i=0;i<2;i++) {
for(int j=0;j<2;j++) {
System.out.println(classRoomObjects[i][j]); // This is how you can print the object content by overriding toString method
System.out.println(classRoomObjects[i][j].getAge()); // This is how you should access the value of an object attribute by using getters and not directly the variable
}
}
}
}
对象教室的类类型为object,正如您所调用的教室[0][0]。年龄,对象类不知道您在自己的自定义类中定义的属性。您需要将教室[0][0]强制转换为自定义类,如下所示:
if (classroom[0][0] instanceof Student) { // Although it is a bad practice and against OOP
System.out.println(((Student)classroom[0][0]).age);
}
我建议读一些关于OOP原理的东西,然后设计一个合适的解决方案
编辑:我可能不清楚您必须努力实现什么,但下面是一个示例实现,它可能会给您一些想法。通常避免直接使用on对象访问变量,而是使用getter/setter
查看这个示例实现
public class Classroom {
enum ClassRoomObjectType {
STUDENT,BOOK;
}
static abstract class ClassRoomObject {
private String name;
private int age;
private ClassRoomObjectType classRoomObjectType;
protected ClassRoomObject(ClassRoomObjectType classRoomObjectType, String name, int age) {
this.classRoomObjectType = classRoomObjectType;
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return String.format("Type: %s, Name: %s, Age: %s", classRoomObjectType, name, age);
}
}
static class Student extends ClassRoomObject {
public Student(String name, int age) {
super(ClassRoomObjectType.STUDENT, name, age);
}
}
static class Book extends ClassRoomObject {
public Book(String name, int age) {
super(ClassRoomObjectType.BOOK, name, age);
}
}
public static void main(String[] args) {
Student alice = new Student("alice", 10);
Student bob = new Student("bob", 11);
Student charlie = new Student("charlie", 10);
Book mathBook = new Book("mathematics", 578);
ClassRoomObject[][] classRoomObjects = new ClassRoomObject[2][2];
classRoomObjects[0][0] = alice;
classRoomObjects[0][1] = bob;
classRoomObjects[1][0] = charlie;
classRoomObjects[1][1] = mathBook;
for(int i=0;i<2;i++) {
for(int j=0;j<2;j++) {
System.out.println(classRoomObjects[i][j]); // This is how you can print the object content by overriding toString method
System.out.println(classRoomObjects[i][j].getAge()); // This is how you should access the value of an object attribute by using getters and not directly the variable
}
}
}
}
Java被称为静态类型语言,与Javascript(动态类型)形成对比。这意味着,在Java中,每个表达式的类型在编译时都应该是已知的。一旦教室被声明为对象[],表达式教室[0][0]就具有类型对象,而此类型没有年龄字段。您需要将表达式显式强制转换为Student,如下所示:
if (classroom[0][0] instanceof Student)
System.out.println(((Student)classroom[0][0]).age);
或者将教室元素的类型更改为具有年龄属性的类型
如果要将不同类型的对象存储在同一数组中,并且仍然能够访问公共属性而无需显式类型转换,请将公共属性移动到公共超类,例如:
class ClassroomObject {
// Common stuff
public int age;
}
class Book extends ClassroomObject {
// Book-specific stuff
}
class Student extends ClassroomObject {
// Student-specific stuff
}
ClassroomObject [][] classroom;
Java被称为静态类型语言,与Javascript(动态类型)形成对比。这意味着,在Java中,每个表达式的类型在编译时都应该是已知的。一旦教室被声明为对象[],表达式教室[0][0]就具有类型对象,而此类型没有年龄字段。您需要将表达式显式强制转换为Student,如下所示:
if (classroom[0][0] instanceof Student)
System.out.println(((Student)classroom[0][0]).age);
或者将教室元素的类型更改为具有年龄属性的类型
如果要将不同类型的对象存储在同一数组中,并且仍然能够访问公共属性而无需显式类型转换,请将公共属性移动到公共超类,例如:
class ClassroomObject {
// Common stuff
public int age;
}
class Book extends ClassroomObject {
// Book-specific stuff
}
class Student extends ClassroomObject {
// Student-specific stuff
}
ClassroomObject [][] classroom;
就编译器而言,其中所有内容的类型都只是对象。对象没有年龄。如果您知道课堂[1][1]实际上是一本书,那么您必须在代码中表达更多信息;阅读有关铸造的文章。但更广泛的问题似乎是,这并不是如何使用类型化语言。您有一个对象[]。就编译器而言,在每个索引处都有对象。对象肯定没有年龄字段。您是否希望对象student=。。。;要编译的学生年龄?老实说,异类数组很可能不是您想要的。@jonrsharpe我根据错误消息怀疑这一点,但在执行.getClass时被抛出,但仍然收到了正确的类。我的意思是我知道物体是一本书
因为代码实际上是专门将一本书放在教室[1][1],人类读者不应该推断它是一本书。我认为这足以让代码理解一个Book对象被放置在那里。如果没有办法将不同的类对象放入同一个数组中,我将不得不学习更多关于Java的知识,以了解如何做我想做的事情!getClass之所以能够工作,是因为对象确实具有该方法,所以它可以愉快地编译,并且在运行时您确实可以看到相应的类。但是编译器将嵌套数组中的每一项都视为对象,因为这是您告诉它的。数组引用的编译时类型和引用值的运行时类型之间存在差异。就编译器而言,其中的每一项的类型都只是对象。对象没有年龄。如果您知道课堂[1][1]实际上是一本书,那么您必须在代码中表达更多信息;阅读有关铸造的文章。但更广泛的问题似乎是,这并不是如何使用类型化语言。您有一个对象[]。就编译器而言,在每个索引处都有对象。对象肯定没有年龄字段。您是否希望对象student=。。。;要编译的学生年龄?老实说,异类数组很可能不是您想要的。@jonrsharpe我根据错误消息怀疑这一点,但在执行.getClass时被抛出,但仍然收到了正确的类。我所说的“我知道对象是一本书”是因为代码实际上是专门将一本书放在教室[1][1],而不是人类读者应该推断它是一本书。我认为这足以让代码理解一个Book对象被放置在那里。如果没有办法将不同的类对象放入同一个数组中,我将不得不学习更多关于Java的知识,以了解如何做我想做的事情!getClass之所以能够工作,是因为对象确实具有该方法,所以它可以愉快地编译,并且在运行时您确实可以看到相应的类。但是编译器将嵌套数组中的每一项都视为对象,因为这是您告诉它的。数组引用的编译时类型和引用值的运行时类型之间存在差异。谢谢。我一定要确保我的代码没有违反任何法律。我只需要继续学习更多的Java,以了解如何做我想做的事情@Jonathan注意到,您也可以愉快地在教室[0][0]中写书;编译器会接受这一点,但在运行时会得到ClassCastException。然后您的代码开始填充学生{…}的if项实例。谢谢。我一定要确保我的代码没有违反任何法律。我只需要继续学习更多的Java,以了解如何做我想做的事情@Jonathan注意到,您也可以愉快地在教室[0][0]中写书;编译器会接受这一点,但在运行时会得到ClassCastException。然后您的代码开始填充if item instanceof Student{…}。或者接口中的共享接口no字段,不幸的是。啊,这是真的,只有方法。如果这些字段是通过getter和setter访问的,那么它们可能是一个接口。或者是一个共享接口。令人遗憾的是,接口中没有字段。啊,这是真的,只有方法。如果字段是通过getter和setter访问的,那么它们可能是一个接口。