MartinElvar
MartinElvar

Reputation: 5804

Can't call methods in class

I'm currently working on some school project; we are developing a simple RPG, but I seem to be questioning some of my Java code.

I have an Abstract class called Item, then I have Armor and Weapon classes which both inherit from Item. Both Armor and Weapon have some attributes that Item doesn't have.

So in my database wrapper, I have a loaditem method, which gets the stats and creates an instance of my class (read comments in code):

public Item loadItem(int itemID)
{
    // Setting item, as a Item, as it can be both Weapon or Armor 
    Item item;

    try {

        // Build prepared statement
        PreparedStatement stmt = con.prepareStatement("SELECT * FROM item WHERE iid = ?");

        // Set Parameter
        stmt.setInt(1, itemID);

        // Execute the query
        ResultSet rs = stmt.executeQuery();

        // Get row
        rs.first();

        // Set all values and keys


        if(rs.getString("type").equals("weapon")) { 
            item = new Weapon();
            // SetDamage is unique to Weapon, and setDefense to armor  
            item.setDamage();
        }else {
            item = new Armor();
            item.setDefense()
        }

        item.setIid(rs.getInt("iid"));
        item.setName(rs.getString("name"));
        item.setDescription(rs.getString("description"));
        item.setSellValue(rs.getInt("sellvalue"));
        item.setBuyValue(rs.getInt("buyvalue"));
        item.setStrength(rs.getInt("strength"));
        item.setAgility(rs.getInt("agility"));
        item.setEndurance(rs.getInt("endurance"));

I have no problem setting a instance of Weapon or Armor to item, but it can't find the methods in the classes.

Do I really need to create both a weapon and an armor object, and return after type?

Upvotes: 2

Views: 4182

Answers (5)

emin
emin

Reputation: 752

You should distinguish the instance type and reference type;

Item myItem = new Weapon();

Instance type: Weapon Reference type: Item

So if you call a method on myItem it can be only method of Item class. Because your reference type is Item.

In your case you want to call a method of Weapon so your reference type has to be Weapon too.

Weapon myWeapon = new Weapon();
item.setDamage(); // method of Weapon class, it's ok

Pay attention to reference type and instance type!

I think This answer is best: (thanks to Jon Skeet)

// I'd still declare `item` as late as possible, i.e. here rather than
// outside the `try` block, unless you *also* need it outside the try block...
Item item;
if (rs.getString("type").equals("weapon")) { 
    Weapon weapon = new Weapon();
    weapon.setDamage();
    item = weapon;
} else {
    Armor armor = new Armor();
    armor.setDefense();
    item = armor;
}
// Other code using `item` here

Upvotes: 0

mprabhat
mprabhat

Reputation: 20323

item = new Weapon() will make item refer to a Weapon instance but item will not become Weapon, in order to refer to Weapon of Armor methods you can do one of the following:

if (rs.getString("type").equals("weapon")) { 
   Weapon weapon = new Weapon();
   weapon.setDamage();
   return weapon;
} else {
   Armor armor = new Armor();
   armor.setDefense();
   return armor;

}

or

if (rs.getString("type").equals("weapon")) { 
item = new Weapon();
((Weapon)item).setDamage();
} else {
item = new Armor();
((Armor)item).setDefense();
}

return item

Upvotes: 0

Mat
Mat

Reputation: 206909

You can do it like this:

    if (...) {
      Weapon w = new Weapon();
      // SetDamage is unique to Weapon, and setDefense to armor  
      w.setDamage();
      item = w;
    } else {
      ...
    }

After that if block/sequence, you can use item before you return. But you can only call methods of the Item class on it. Similarly, the callers of your loadItem method can only use the methods from the Item class on the value you return, unless they carefully use a cast.

Upvotes: 3

Jon Skeet
Jon Skeet

Reputation: 1503839

Yes, if you're going to call an instance method, the "target" expression of the method call must have a compile-time type which is known to have the appropriate method. The compiler needs to resolve the method calls at compile time. (Any overload resolution is done at compile-time; the actual implementation is decided at execution time based on polymorphism of course.)

It's unclear why you'd want the item variable in the first place. It sounds like you should just have:

if (rs.getString("type").equals("weapon")) { 
    Weapon weapon = new Weapon();
    weapon.setDamage();
    return weapon;
} else {
    Armor armor = new Armor();
    armor.setDefense();
    return armor;
}

That's assuming you want to return immediately - your code was truncated, so it's not clear. If you really do need the item variable, you can just assign weapon or armor to item where I have the return statements above.

EDIT: It sounds like that's the case, so you'd have:

// I'd still declare `item` as late as possible, i.e. here rather than
// outside the `try` block, unless you *also* need it outside the try block...
Item item;
if (rs.getString("type").equals("weapon")) { 
    Weapon weapon = new Weapon();
    weapon.setDamage();
    item = weapon;
} else {
    Armor armor = new Armor();
    armor.setDefense();
    item = armor;
}
// Other code using `item` here

In fact, you may well want to put the code to initialize the weapon into a separate method. Then you could use:

String type = rs.getString("type");
Item item = type.equals("weapon")) ? createWeapon() : createArmor();

Upvotes: 3

Hot Licks
Hot Licks

Reputation: 47759

In order to call a method unique to "Weapon" you must cast the item pointer to Weapon, thus:

Weapon weaponPointer = (Weapon)item;
weaponPointer.setDamage();

Upvotes: 0

Related Questions