Reputation: 5804
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
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
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
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
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
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