I have a method sleep() which sets int hp of the instance to final int MAX_HP. I have placed this method inside the Warrior and Mage classes, which are the child classes of Character. The problem here is that I define MAX_HP individually within each child class as Warrior's and Mage's would have different Max_HP's, so it seems like I have to also declare sleep() within each class instead of just once in the parent class - inefficient. Is there a way I can declare the sleep method in the parent class and somehow retrieve the MAX_HP's from within the child classes? Or is there a better way to do this?
//Warrior Class
public class Warrior extends Adventurer{
private final int MAX_HP = 150;
public void sleep(){
setHp(MAX_HP);
System.out.println(getName() + "fully restored HP!");
}
}
//Mage Class
public class Mage extends Adventurer{
private final int MAX_HP = 100;
public void sleep(){
setHp(MAX_HP);
System.out.println(getName() + "fully restored HP!");
}
}
//Adventurer Class
public abstract class Adventurer{
private int hp;
public Adventurer(int hp){
this.hp = hp;
}
public int getHp(){
return this.hp;
}
public void setHp(int hp){
this.hp = hp;
}
Yes, you can.
Inside the abstract class Adventurer add an abstract method:
public abstract int getChildHP();
and have Warrior and Mage implement it:
public int getChildHP() { return MAX_HP };
(MAX_HP is different for each one of them of course).
Move the sleep() method (delete it from the children) to the abstract class and implement it:
public void sleep() {
setHp(getChildHP());
System.out.println(getName() + "fully restored HP!");
}
When this method is called, the relevant getChildHP() will be called according to the instance.
Now sleep() exists only once in the parent class ==> no code duplication.
Hope it helps.
Related
When setting a value of a parent class, which way is more preferable:
Set a field
public abstract class Weapon {
final Integer damage;
}
public class Knive extends Weapon {
public Knive(){
damage = 100;
}
}
Override a method
public abstract class Weapon {
public abstract int getDamage();
}
public class Knive extends Weapon {
#Override
public int getDamage(){
return 100;
}
}
Or is it just personal taste?
I think it depend on the situation. Both examples correct.
Your fist approach is more preferably when you have inheritance, and the're general logic for number of child classes. BUT, do make your property protected.
Second approach, is more suitable when you use light classes, like strategies without default implementation. In this case you can change your parent class to interface.
public abstract class Weapon {
protected final Integer damage;
protected Weapon(Integer damage) {
this.damage = damage;
}
// more logic here
}
public class Knive extends Weapon {
public Knive(){
super(100);
}
}
OR
public interface Weapon {
Integer getDamage();
}
public class Knive implements Weapon {
// light-weight strategy
public Integer getDamage() {
return 100;
}
}
The two ways are not opposed. You could use the one, the second or both.
But these don't have the same intention.
A constructor with parameter allows to value the created instance with this parameter : it sets the instance state.
While specifying a method as abstract allows to define a contract that subclasses have to respect. In this way the base class or any other class can rely on this method to perform some logic. The template method uses this idea.
Suppose you have a class Warrior that has a Weapon as field, you could compute the damage performed by a Weapon thanks to this method that each subclass will have to implement :
public class Warrior{
private Weapon weapon;
// ...
public void attack(Warrior otherWarrior){
otherWarrior.receiveAttack(weapon.getDamage());
}
}
Now nothing prevents you to store the damage information that you received in Weapon subclass :
public class Knive extends Weapon {
private int damage;
public Knive(int damage){
this.damage = damage;
}
#Override
public int getDamage(){
return damage;
}
}
As explained earlier the two approaches are not opposed at all.
I don't think this is about personal taste but about the reusability, correctness, and uniformity across extending classes.
public abstract class Weapon {
protected Integer damage;
public void setDamage(Integer damage){
this.damage = damage;
}
public Integer getDamage(){
return this.damage;
}
}
public class Knive extends Weapon {
public Knive(){
setdamage(100);//or damage = 100;
}
}
The setter and getter would be the same for all of the extending classes. In case if you want to explicitly override the setter and getter for some specific result, you could override it.
It depends a lot on when and where do you want to set the value, but note that an abstract class can have field, methods and even constructors, it just can't be instantiated. so for the example you provided I prefer using this:
abstract class Weapon{
private int damage;
public Weapon(int damage) {
this.damage = damage;
}
public int getDamage() {
return damage;
}
}
class Knife extends weapon{
//damage as a parameter
public Knife(int damage) {
super(damage);
}
//damage as a default value
public Knife(){
super(100);
}
}
then you can use it this way:
Weapon knife = new Knife(100);
Weapon defaultKnife = new Knife();
System.out.print(knife.getDamage()); --->100
You can also have getter and setter methods in the parent class and you don't even have to override anything in the child class.
I've been trying my best with some basic code, and I am completely stuck...
I have an abstract class "Piece":
public abstract class Piece {
private static int type;
public int getType() {
return type;
}
}
The "Pawn" is the Child:
public class Pawn extends Piece {
private static final int type = 1;
}
And now for the problem: When creating the Pawn with Pawn p = new Pawn();, p.getType() returns 0, not 1...
How can I fix this?
The problem is that you already have a variable declared in your abstract class. You shouldn't redeclare it in your subclass. Instead, set the abstract class's variable like this:
public class Pawn extends Piece {
public Pawn() {
type = 1;
}
}
You should also declare the variable as protected so that subclasses can access it and refrain from making it static, since that will allow only one value for all subclasses:
public abstract class Piece {
protected int type;
public int getType() {
return type;
}
}
This code you write relies on an instance and not on a static context:
Pawn p = new Pawn();
p.getType();
A static final field is not designed to be inherited by child classes.
And creating a static final field in the child class with the same name as in the parent class doesn't allow to override it either.
1) So you should use an instance field and not a static field for the type field.
2) If you want to override the behavior of getType() in the child class, in fact you don't even need to use a field. Using a method should be enough.
In the base class :
public abstract class Piece {
public int getType() {
return 0;
}
}
In the child class :
public class Pawn extends Piece {
#Override
public int getType() {
return 1;
}
}
Here is one way. But you really need to read up on classes and abstract classes.
public abstract class Piece {
public int getType() {
return 0;
}
}
public class Pawn extends Piece {
public int getType() {
return 1;
}
}
Having a static variable in a class means that all instances of that class share the same value. I don't think that's what you intended.
Also, you can use the hierarchy of inheritance to your advantage by not redefining the getType() method.
Here is one of many ways to solve it:
public abstract class Piece {
protected int type;
public int getType() {
return type;
}
}
public class Pawn extends Piece {
public Pawn() {
type = 1;
}
}
There are two problems with your approach.
The first is that Java does not support inheritance of static methods. Not that it couldn't have supported this - it's just a design choice. What this means is that any method of class Piece, which calls getType() - calls the Piece class' implementation of getType(), not a polymorphic call to getType() of whatever the actual subclass is.
The second problem is that you're sort of reinventing the wheel. Java has rich reflection facilities: You can use getClass() and instanceof for your check:
if(myObject instanceof Piece && myObject.getClass() != Piece.class) {
// do stuff
}
and of course you can make this a method of the piece class (no need to override it).
I am a little confused on how to set up the TestHomework method so that it prints properly when using the toString() method. Right now when I run the main method it prints "null - 0" but what I would like it to say is "Math - 6". This program is supposed to extend an abstract class. It is supposed to say how many pages there are for homework and for what subject.
public abstract class Homework {
private int pagesToRead;
private String typeHomework;
{
// initialise instance variables
pagesToRead = 0;
typeHomework = "none";
}
public Homework(int pages, String hw) {
this.pagesToRead = pages;
this.typeHomework = hw;
}
public abstract void createAssignment(int p);
public int getPages() {
return pagesToRead;
}
public void setPagesToRead(int p) {
pagesToRead = p;
}
public String getTypeHomework() {
return typeHomework;
}
public void setTypeHomework(String hw) {
typeHomework = hw;
}
}
public class MyMath extends Homework {
private int pagesRead;
private String typeHomework;
public MyMath(int pages, String hw) {
super(pages,hw);
}
public void createAssignment(int p) {
setTypeHomework("Math");
setPagesToRead(p);
}
public String toString() {
return typeHomework + " - " + pagesRead;
}
}
public class TestHomework {
public static void main(String[] args) {
MyMath one = new MyMath(6, "Math");
one.createAssignment(6);
System.out.println(one);
}
}
That's because you are defining the 2 properties (that one of them happen to have the same name as one of the abstract class's) but you are not initializing them, you are initializing those of the abstract class. (So their values is always set to their type's default)
You need to drop those from the MyMath class, & define the toString method in your abstract class: it's the one to be used by default by its inheriting classes.
public abstract class Homework {
private int pagesToRead;
private String typeHomework;
// Same code
// Define the toString here
#Override
public String toString() {
return typeHomework + " - " + pagesToRead;
}
}
public class MyMath extends Homework {
// You don't need to define any extra attributes
public MyMath(int pages, String hw) {
super(pages,hw);
}
public void createAssignment(int p) {
setTypeHomework("Math");
setPagesToRead(p);
}
}
public static void main(String[] args) {
// Calls the constructor of the MyMath class, which in turn
// invokes the constructor of its superclass, the 'Homework' class
MyMath one = new MyMath(6, "Math");
one.createAssignment(6);
// Invokes the toString of the MyMath class. Since it does not have one,
// The toString method of its superclass (Homework) is called.
System.out.println(one);
}
Your derived class has its own typeHomework and pagesRead fields, which are never set (even though the base class happens to have fields with the same names). Therefore, they stay null and 0.
You should delete those fields and use the data from the base class, via the public getter methods.
Why it doesn't work:
Be careful you redeclared the attribute typeHomework of you parent class. Attributes are automatically added to your extending class so you don't have to write them again.
By redeclaring it you confused the compiler, viewing your code in debug shows, that your one object contains your typeHomework twice:
typeHomework = null // The one from the super class
typeHomework = "Math" // The one from your child class
Your method now uses the typeHomework from your super-class therefor the output is null!
pagesRead is 0 because you are setting the pagesToRead of your super-class to 6(not pagesRead!) when calling setPagesToRead(p);.
Some style tips
Use the #Override annotation when overriding methods like this:
#Override
public void createAssignment(int p) {
setTypeHomework("Math");
setPagesToRead(p);
}
It's not really needed but it's good practice (readers of your code know that it overrides something).
When referring to attributes of your class it's also good practice to use the this statement so it's clear, that you're referring to an attribute and not a local variable:
#Override
public String toString() {
return this.typeHomework + " - " + this.pagesRead;
}
I'm making a game with different types of building. I'm making an interface for each type. Some buildings have more than 1 type.
I have this code:
public interface DefenseBuilding {
int range;
int damage;
public void shoot ();
}
It gives me an error on the 2 variable declarations (range & damage). The error being something along the lines of "Final variable may not be initialised"
It works if I assign the variable in the interface, but I don't want to do that.
I can't just extend a class, because - as said earlier - some buildings need more than 1 type. Classes can only extend 1 other class so I need to use interfaces.
What I'm asking is, is there a way to have variables in an interface without having to initialise the variable inside the interface?
The whole point of interfaces is to specify as interface - i.e. how will your classes interface with client classes. Instance variables are clearly not part of any interface at all.
Instead, try this:
public interface DefenseBuilding {
public void shoot ();
}
and this:
public abstract class AbstractDefenseBuilding implements DefenceBuilding {
protected int range;
protected int damage;
}
edit:
Your classes should now extend AbstractDefenseBuilding, so they will inherit the variables. They also indirectly implement DefenceBuilding so they'll still be forced to implement the shoot() method (unless they are also abstract)
You can use a property method aproach.
public interface DefenseBuilding {
public void setRange(int range);
public int getRange();
public void setDamage(int damage);
public int getDamage();
public void shoot ();
}
Then in your class
public MyClass implements DefenseBuilding{
int range;
int damage;
public int getRange() {
return range;
}
public void setRange(int range) {
this.range = range;
}
public int getDamage() {
return damage;
}
public void setDamage(int damage) {
this.damage = damage;
}
public void shoot (){...}
}
All variables in Interface are static and final. Hence, unless initialized, compiler will keep giving an error that it is not initialized. This is enforced because interface cannot be instantiated and therefore any variable should be of static in nature and cannot be changed.
If your intention is to define class variables, do as NickJ suggested.
Interfaces define behavior but not state (other than constants). Protected variables are a potential danger to proper encapsulation of data (an object should hide its data and provide access through methods unless there is a very compelling reason not to). An alternative would be the following:
public interface DefenseBuilding {
public void shoot();
public int getRange();
public int getDamage();
}
It's also VERY common to provide an abstract class that partially implements the interface:
public abstract class AbstractDefenseBuilding implements DefensBuilding {
private int range;
private int damage;
public AbstractDefenseBuilding(int range, int damage) {
this.range = range;
this.damage = damage;
}
public int getRange() {
return range;
}
public int getDamage() {
return damage;
}
}
Given the folowing, in pseudocode
abstract public class Bug {
private static int BREEDTIME;
public void breed() {
if (this.age % this.BREEDTIME) {
world.setAt(new this.class(newX, newY, this.world);
}
}
}
public class Ant extends Bug {
private static int BREEDTIME = 3;
}
public class Doodlebug extends Bug {
private static int BREEDTIME = 8;
}
Is there a way to define the breed() method such that it depends on the BREEDTIME of whatever subclass is calling it? Each subclass of bug is guaranteed to have BREEDTIME initialized.
Also, Ants should breed other Ants, so the constructor called inside breed() has to be the constructor of the type of the subclass that is calling breed().
Am I barking up the wrong tree here?
I would use an abstract method to do this. Define getBreedTime() as abstract in your superclass and then implemented it in each subclass to return the appropriate constant.
You can't really do what you want using static fields like this.
It can not be done like this. Static fields are also inherited. Just remove static keyword. If you don't want to double ints then you could create abstract method to getTime or create enum:
abstract class Bug {
private int age;
public void breed() {
if (this.age % BREEDTIME.valueOf(this.getClass().getName()).getTime() == 0) {
}
}
}
class Ant extends Bug {
}
class Doodlebug extends Bug {
}
enum BREEDTIME {
Ant(3),
Doodlebug(8);
private BREEDTIME(int time) {
this.time = time;
}
public int getTime() {
return time;
}
private int time;
}