当前位置: 首页 > 知识库问答 >
问题:

无法引用对象属性

宰父德馨
2023-03-14

关于堆栈溢出的第一个问题!我觉得这一定是Java初学者的一个常见问题。但我已经尝试了几个小时,一直没有找到解决办法。我认为可以通过这种方式访问对象属性。

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

它甚至更烦人,因为在调试模式下,我可以看到inventory[]inventory及其属性中的武器[0]。看着Eclipse嘲笑我。

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;
    }
}

共有1个答案

汪跃
2023-03-14

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

这与运行时的类型和编译时的类型之间的差异有关。您将声明为对象类型。

Java允许多态性,当您将清单中的声明为类型object时,允许您为分配任何“是”对象的内容(这意味着您可以为分配一个字符串、一个整数、任何对象,因为它们都继承自object类)。

但是,当您稍后在程序中访问item时,Java不能保证编译时引用的item都有name属性!例如,integer对象,但没有name属性!Java编译器只是说,“我只知道对象,我不会让您访问并非所有对象都有的属性!”

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

这可能看起来很烦人或不必要的限制(您知道要放入目录中的所有内容都有一个名称!),所以这就是超类和接口的意义所在!这些特性允许您灵活地创建不同类型的对象,这些对象都共享相似的属性或方法,并且仍然允许Java预先捕捉所有这些潜在的问题。

要解决这个问题,可以创建一个InventoryItem超类,ArmorArmare都扩展该超类,该超类具有Name属性。然后可以将Item声明为InventoryItem类型。这样,Java就会知道,即使运行时类型可能是武器盔甲,它也保证有一个名称。

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

class Inventory {

    public InventoryItem item;
    public int id;

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

然后类inventory可以接受inventoryItem(我建议inventory可能包含项数组)

class Inventory {

    public InventoryItem item;

    Inventory(InventoryItem item) {
        this.item = item;
    }
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!
 类似资料:
  • 问题内容: 我想要进行属性调用,例如返回某种方法的结果。我怎样才能做到这一点? 编辑:我很快问:看起来我可以用 这样行吗? 问题答案: 使用属性装饰器 使用__dict__进行处理很脏,尤其是在@property可用时。

  • 问题内容: 因此,我在回答这个问题的同时一直在使用Python,但发现这是无效的: 由于 。但是,对于从对象继承的任何类,它都是有效的: 打印将按预期显示“ hello”。为什么会这样呢?在Python语言规范中,有哪些规定不能将属性分配给香草对象? 问题答案: 为了支持任意属性分配,对象需要一个:与对象关联的字典,可以在其中存储任意属性。否则,就无处放置新属性。 的实例object并没有随身携带

  • 问题内容: 我要返回一个Mongoose文档,并希望在发送之前向其中添加一些元数据。但是,我无法添加任何属性,我不确定为什么。我检查了它是否可以使用Object.isExtensible(doc)扩展。 可能是什么问题? 问题答案: 啊..我的对象是一个Mongoose文档,不允许添加属性。解决方案是将返回的文档转换为普通对象,或者在查询中调用lean()。

  • 在Swagger中,在定义子对象的哪些属性是时,是否可以引用父对象的属性? 例如,给定以下基类: 我希望有两个子类:一个用于创建Pet(有效负载中需要所有属性),另一个用于更新Pet(不需要任何属性)。我试图通过以下方式实现这一目标: 然而,这是行不通的。相反,会引发一个异常: 我怎样才能做到这一点?Swagger甚至可能吗?

  • 根据Mapstruct文档,通过为被引用的对象(对象B)定义映射方法,可以将一个对象(对象A)映射到D,该对象包含另一个对象(对象B)。但是如果我只需要映射那个对象(对象B)的属性而不是整个对象呢? 但是如何用Java和MapStruct来实现呢?

  • 问题内容: 我在node.js上运行此代码 1)第一个console.log返回完整文档 2)第二个console.log返回未定义 我不明白为什么。 我需要执行类似 我该如何实现?我想念什么? 问题答案: 我怀疑您要获取的值不在您的中,而是存储在数据库中。 您有两种解决方案。您可以将其添加到您的文档中,然后Mongo可以将其绑定到您收到的对象。这是推荐的方法。 或者,您可以绕过猫鼬,并使用访问存