首页 > 解决方案 > 无法引用对象属性

问题描述

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

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

更烦人的是,在调试模式下,我可以从字面上看到 weapon[0]Inventory[] inventory的属性。 看看 Eclipse 嘲笑我。

我目前的理论是在对象数组中放置 object weapon[0], class 的实例可能是问题,并且由于该放置,对象的属性无法以某种方式访问​​。任何帮助将不胜感激,谢谢!这是我第一次搞乱数组,所以我绝对是个新手。关于我的格式等的任何提示也将非常有帮助!WeaponsInventory[] 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;
    }
}

标签: javaarraysobjectattributes

解决方案


欢迎来到 StackOverflow!这是一个措辞得当的问题!

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

Java 允许多态性,当您将itemin声明Inventory为 typeObject时,它​​允许您分配任何item“is-a”的对象Object(这意味着您可以将 a String、 an Integer、任何对象分配给item,因为它们都继承自Object该类)。

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

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

这可能看起来很烦人或不必要的限制(你知道要放入的所有东西Inventory都会有一个名字!),所以这就是超类和接口的重点!这些特性允许您灵活地创建共享相似属性或方法的不同类型的对象,并且仍然允许 Java 提前捕获所有这些潜在问题。

要解决此问题,您可以创建一个InventoryItem既可扩展ArmorWeapon具有name属性的超类。然后,您可以声明item为 type InventoryItem。这样,Java 就会知道,即使运行时类型可能是 aWeaponArmor,它也保证有一个名称。

我们可以引入一个新的类,例如InventoryItem

class Inventory {

    public InventoryItem item;
    public int id;

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

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

class Inventory {

    public InventoryItem item;

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

然后你的类,例如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!

推荐阅读