无法引用对象属性

Unable to reference object attributes

关于 Stack Overflow 的第一个问题! 我觉得这个 has 是 Java 初学者中的一个常见问题。但我已经尝试了好几个小时,却一直无法找到解决方案。我认为可以通过这种方式访问​​对象属性

起初我以为weapon[0]实际上是一个对象数组,所以当我创建对象数组Inventory[] inventory时,我在构造函数中使用了一个对象数组。我立即解决了这个问题,但这个问题仍然存在。

更烦人的是,在调试模式下,我可以从字面上看到 weapon[0]Inventory[] inventory 内部及其属性。 Look at Eclipse mock me.

我目前的理论是,将对象 weapon[0]、class Weapons 的实例放置在对象数组 Inventory[] inventory 中可能是问题所在,并且对象的属性由于该位置,无法以某种方式访问​​。任何帮助将不胜感激,谢谢!而且我是第一次接触数组,所以我绝对是个新手。关于我的格式等的任何提示也将非常有帮助!

package arraytest;

import java.util.Scanner;
import java.util.InputMismatchException;
import java.lang.NumberFormatException;

public class ArrayTest {
    
    static Scanner kb = new Scanner(System.in);
    
    static int i = 0;
    static int choice = 0;
    
    public static void main(String[] args) {
        
        Weapons[] weapon = new Weapons[3];
        weapon[0] = new Weapons(0,"Wooden Sword",1,2);
        weapon[1] = new Weapons(1,"Bronze Sword",2.5,7.5);
        weapon[2] = new Weapons(2,"Iron Sword",5,10);
        
        Armor[] armor = new Armor[3];
        armor[0] = new Armor(3,"Wooden Armor",2,5);
        armor[1] = new Armor(4,"Bronze Armor",3,10);
        armor[2] = new Armor(5,"Iron Armor",5,15);
        
        Enemy[] enemy = new Enemy[3];
        enemy[0] = new Enemy(0,"Skeleton",3,0,10);
        enemy[1] = new Enemy(1,"Goblin",2,1,5);
        enemy[2] = new Enemy(2,"Zombie",4,1,8);
        
        Inventory[] inventory = new Inventory[256];
        
        String chooseweapon = String.format(
                "Choose your weapon:\n"
                + "1. %s\n"
                + "2. %s\n"
                + "3. %s\n"
                ,
                weapon[0].name,
                weapon[1].name,
                weapon[2].name
                );
        System.out.print(chooseweapon);
        
        while (i==0) {
            i++; //1
            
            try {
                choice = Integer.parseInt(kb.nextLine());
            } catch (NumberFormatException e) {
                System.out.println("Error. Try again.");
                i--; //0
                continue;
            }
            if (choice < 1 || choice > 3) {
                System.out.println("Error. Try again.");
                i--; //0
            }
        }
        if (choice == 1) {
            inventory[0] = new Inventory(weapon[0]);
        }
        System.out.println(inventory[0].item); //this is the problem here. i can't put .item.name, error is "name cannot be resolved or is not a field"
    }
}



class Inventory {
    
    public Object item;
    Inventory(Object item) {
        this.item = item;
        
    }
}

class Armor {
    public int id;
    public String name;
    public double defnum;
    public double val;
    
    Armor(int id, String name, double defnum, double val) {
        this.id = id;
        this.name = name;
        this.defnum = defnum;
        this.val = val;
    }
}

class Weapons {
    public int id;
    public String name;
    public double attdmg;
    public double val;
    
    Weapons(int id, String name, double attdmg, double val) {
        this.id = id;
        this.name = name;
        this.attdmg = attdmg;
        this.val = val;
    }
}

class Enemy {
    public int id;
    public String name;
    public double attdmg;
    public double defnum;
    public double health;
    
    Enemy(int id, String name, double attdmg, double defnum, double health) {
        this.id = id;
        this.name = name;
        this.attdmg = attdmg;
        this.defnum = defnum;
        this.health = health;
    }
}

欢迎使用 Whosebug!这是一个措辞良好的问题!

这与 运行 时的类型与编译时的类型之间的差异有关。您将 item 声明为 Object.

类型

Java 允许 多态性 ,当您将 Inventory 中的 item 声明为 Object 类型时,允许您将任何对象分配给 item,其中“是”Object(这意味着您可以将 StringInteger、任何对象分配给 item, 因为它们都继承自 Object class).

但是,当您稍后在程序中访问 item 时,Java 无法 保证 在编译时 item 引用有一个 name 属性! Integer,例如,是一个 Object,但是没有一个name 属性! Java 编译器只是说,“我只知道 item 是一个 Object,我不会让你访问 属性 而不是所有 Object我们有!”。

当你运行程序时,运行时间类型itemWeapon,所以Eclipse 能够向您展示它的属性。但是 Java 旨在在编译时捕获尽可能多的错误,因此如果它不能在编译时保证,它将不允许您访问 name 属性它有一个名字。

这可能看起来很烦人或不必要的限制(你 知道 将要放入 Inventory 的所有内容name!),所以这就是 superclasses 和接口的意义所在!这些功能允许您灵活地创建不同类型的对象,这些对象都共享相似的属性或方法, 仍然允许 Java 预先捕获所有这些潜在问题。

要解决此问题,您可以创建一个 InventoryItem superclass,同时扩展 ArmorWeapon,它有一个 name 属性.然后您可以将 item 声明为 InventoryItem 类型。这样,Java 就会知道,即使 运行 时间类型 可能是 WeaponArmor,它也是保证有名字

我们可以引入一个新的class,比如InventoryItem:

class Inventory {

    public InventoryItem item;
    public int id;

    Inventory(InventoryItem item, int id) {
        this.item = item;
        this.id = id;
    }
}

然后class Inventory可以拿一个InventoryItem(我建议可能是库存包含项目数组)

class Inventory {

    public InventoryItem item;

    Inventory(InventoryItem item) {
        this.item = item;
    }

然后你的classes,比如Armor,可以扩展InventoryItem,例如:

class Armor extends InventoryItem {

    public double defnum;
    public double val;

    Armor(int id, String name, double defnum, double val) {
        super(name, id);
        this.defnum = defnum;
        this.val = val;
    }
}

这样就可以了!

System.out.println(inventory[0].item.name); //Java now knows that inventory[0] is type Inventory, its "item" property is type InventoryItem, and that is *guaranteed* to have a name and id!