Java subclass with different method parameters - java

I am trying to make a simulation that simulates simple creatures and carnivorous creatures.
I have a class called creature and a subclass called carnCreature. I have a method in creature called eat, that takes in a one type of object, but I need the eat method in the carnCreature class to take in a list of creatures. I tried naming the method the same as it is named in the creature class, but when I try to call it, java doesn't accept the updated parameters.
package simulationObjects;
import java.awt.Color;
import java.util.List;
import java.util.Random;
import java.lang.Math.*;
public class Creature {
public int x;
public int y;
public int maxTilesX;
public int maxTilesY;
public Color color;
public float health = 50;
public int life = 0;
public Creature (int x, int y, Color color, int maxTilesX, int maxTilesY) {
this.x = x;
this.y = y;
this.color = color;
this.maxTilesX = maxTilesX;
this.maxTilesY = maxTilesY;
}
public void update(Tile tile) {
eat(tile);
life++;
health-=1;
}
public void eat(Tile currentTile) {
if (currentTile.color == this.color) {
health += 3;
currentTile.color = Color.GRAY;
}
}
public boolean isCarnivore() {
return false;
}
}
package simulationObjects;
import java.awt.Color;
import java.util.List;
public class CarnCreature extends Creature{
private static final boolean CANABOLIC = false;
public CarnCreature(int x, int y, Color color, int maxTilesX, int maxTilesY) {
super(x, y, color, maxTilesX, maxTilesY);
// TODO Auto-generated constructor stub
}
public void update(List<Creature> creatures) {
eat(creatures);
life++;
health-=1;
}
public void eat(List<Creature> creatures) {
for (Creature creature : creatures) {
if (CANABOLIC) {
if (creature.color == this.color) {
health += 3;
creature.health = 0;
}
} else {
if (creature.color == this.color && creature.isCarnivore() == false) {
health += 3;
creature.health = 0;
}
}
}
}
public boolean isCarnivore() {
return true;
}
}
The eat function is being called later like this:
for (Creature creature : creatures) {
if (creature.isCarnivore()) {
creature.upadte(creatures);
} else {
creature.update(tiles.get(creature.x).get(creature.y));
}
}
I am trying to store the creatures and the carnCreatures in the same list, "creatures." Is this the problem, and do I need to store them in separate lists?
Thanks

You have a two options:
Once you know if the creature is carnivore cast it and access the method
Create a method with the same "signature", that is, same name AND arguments.
The second option is the more elegant. Using the "magic" of polymorphism each class will have its method called and you won't need to check the class with the isCarnivore() method. But you will need to get the list of creatures from the tile.

The isCarnivore() test will not spare you to cast to the subclass type as you manipulate as declared type the Creature the base class :
for (Creature creature : creatures) {
if (creature.isCarnivore()) {
((CarnCreature)creature).update(creatures);
} else {
creature.update(tiles.get(creature.x).get(creature.y));
}
}
So the isCarnivore() appear helpless as if (instanceof CarnCreature) would have the same effect and consequences.
Is this the problem, and do I need to store them in separate lists?
It would be better as you don't want manipulate them in an uniform way.
Using the base class to group them in a unique List make your task harder.
But in fact you have a deeper issue. Here eat() is not a overrided method but an overloaded method in the subclass. Same thing for update().
It means that in both cases the two methods are defined in the subclass.
Such a design will not allow to benefit from a polymorphism feature because you want to invoke the first method on the base class instance and invoke the overloaded method on the subclass instance.
In terms of concept, a carnivore creature IS not a creature. Their type of behavior is very different : one consumes a thing (a tile) and the other consumes a very different thing (a list of creature).
To benefit from polymorphism you should re-design the base class and the subclass to override the methods and not overload them. But as you pass really different types in the parameters, you are stuck.
So in your case I think that I would not even create a inheritancy relation between theses classes.

Related

Method is undefined for a class

I am trying to run a code in eclipse that uses a method called getArea(an object). I am currently getting an error saying
The method getArea(ComparableRectangle) is undefined for the type RectangleTest
This is the code for RectangleTest-
package geometry;
import java.awt.Rectangle;
public class RectangleTest extends Rectangle {
/**
*
*/
private static final long serialVersionUID = -3282103336310735942L;
public static void main(String args[]) {
ComparableRectangle rect01 = new ComparableRectangle(5, 4);
ComparableRectangle rect02 = new ComparableRectangle(6, 8);
System.out.println("Area: " + getArea(rect01));
}
}
And this is the code for ComparableRectangle.
package geometry;
import java.awt.Rectangle;
public class ComparableRectangle extends Rectangle implements Comparable {
private int width;
private int height;
public ComparableRectangle(int w, int h) {
width = w;
height = h;
}
public double getArea(ComparableRectangle rect) {
return width*height;
}
public boolean compareTo(ComparableRectangle rect1, ComparableRectangle rect2) {
if(rect1.width == rect2.width && rect1.height == rect2.height) {
return true;
}
else {
return false;
}
}
#Override
public int compareTo(Object o) {
// TODO Auto-generated method stub
return 0;
}
}
How do I clarify that rect01 is a ComparableRectangle?
In object oriented language like Java or C++ to call a class method you need a instance of that class, which we call also an object instantiated from that class. So you have to call your method like below:-
rect02.getArea(rect01);
rect01.getArea(rect02);
Because getArea(ComparableRectangle rect) is a member function or method of class ComparableRectangle hence you need its instance to call it. Here are two instances of that class rect01 and rect02.
Good luck!
You misunderstood how methods and their parameters work.
You need some way to combine the method with some object it should be called on. Currently you do so by using the object as parameter, but this is not correct.
You should combine object and method by writing
obj.method();
Therefore, you should call the method like
rect01.getArea();
and remove the parameter from the method
public double getArea() { ... }
Parameters can be used to give the method additional information on the way. A good example is the compareTo method which is supposed to compare the current instance with the given instance. A call would look like
rect01.compareTo(rect02);
and the methods signature is
public int compareTo(Object o)
Note that it only has one parameter as the current instance is implicitly known to the method (this keyword).
Notes
There is no need for the additional custom compareTo method, which by the way should be named compare and should be static since it's not bound to any instance.
Also note that your custom compareTomethod is not comparing. It just returns same or not same. But for an order you need less than, greater than and equals. Your method thus does not define an order.

A variable that could take different types in?

TLDR: I need a variable that can take in an object from either of 2 classes.
I'm working on a Java 2D game, still getting the basics to work and here I have a problem: in the class Actor, in the constructor, the actor generates its hitbox (4 XY coordinates object) and then adds that hitbox to a list of things that need to check for collisions.
But now that I got all this working, I made a new class, Platform, so that my character can walk on something else than the defiled corpses of it's enemies. But in the Rect constructor, I have a variable (Parent) that sets itself to the object that called the constructor (with itself in parameter) so I would get hitbox.parent() = player for example.
But since the Platform objects are from another class (that I don't really want to inherit from the Actor class) how can I make it so that Rect and give itself a parent of different type ?
Edit
The class as it is now
package misc;
import item.Platform;
import npc.Actor;
public class Rect {
int x,y,wdt,hgt;
public Rect(Actor a){
x = a.x;
y = a.y;
wdt = a.wdt;
hgt = a.hgt;
}
public Rect(Platform p){
parent = p;
x =p.x;
y =p.y;
wdt =p.wdt;
hgt =p.hgt;
}
}
And here is the place where I have trouble calling it
private static void collision(Rect r1,Rect r2){
if (r1.y -r2.y <= r2.hgt && r1.y -r2.y >= -r2.hgt){
r1.parent.yCol = true;
}else{
r1.parent.yCol = false;
}
if (r1.x -r2.x <= r2.wdt && r1.x -r2.x >= -r2.wdt){
r1.parent.xCol = true;
}else{
r1.parent.xCol = false;
}
}
In addition to inheritance, you could also use an interface based approach.
public interface GameRect {
int getX();
int getY();
int getHeight();
int getWidth();
}
public class Actor implements GameRect {
// implementation
}
public class Platform implements GameRect {
// implementation
}
public class Rect {
// implementation
private GameRect parent;
// constructor works for all classes that implement GameRect interface
public Rect(GameRect gr) {
parent = gr;
x = gr.getX();
y = gr.getY();
// etc
}
}
The problem with a solution like this is that you need to cast back to the original type (Actor, and Platform respectively) every time you want to call class methods on the parent objects that are not GameRect interface methods.
You need to use Inheritance, which is one of the most important aspects of Object Oriented Programming. You need to do some reading on it so you understand how it works and how to use it: https://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html

Using attributes in a class that implements an interface in another class

Hi everyone i am trying to use the attributes in my Fish class which implements an an interface called Catchable , in my Fisher class , is this possible, or is there some part of interfaces that I am not understanding. Because i thought we were allowed to use the attributes in a class that has been implemented by an interface, in another class, however i keep errors saying:
Error: cannot find symbol
symbol: variable weight
location: variable item of type Catchable
Error: cannot find symbol
symbol: variable size
location: variable item of type Catchable
Error: cannot find symbol
symbol: variable weight
location: variable item of type Catchable .
Any help or advice on this is appreciated!
If needed, here is my Catchable interface:
public interface Catchable
{
public float getWeight();
public boolean isDesirableTo(Fisher f);
}
my Fish class which implements the Catchable interface
public abstract class Fish implements Catchable
{
// Any fish below this size must be thrown back into the lake
public static int THROW_BACK_SIZE = 18;
public static float WEIGHT_LIMIT = 10;
protected float weight;
protected int size;
public Fish(int aSize, float aWeight)
{
size = aSize;
weight = aWeight;
}
public boolean isDesirableTo(Fisher f)
{
if(canKeep() && f.numThingsCaught < f.LIMIT && this.weight + f.sumOfWeight < WEIGHT_LIMIT)
{
return true;
}
else
{
return false;
}
}
public abstract boolean canKeep();
public int getSize() { return size; }
public float getWeight() { return weight; }
public String toString ()
{
return ("A " + size + "cm " + weight + "kg " + this.getClass().getSimpleName());
}
}
and lastly my Fisher class
import java.util.*;
public class Fisher
{
private String name;
private Catchable [] thingCaught;
public int numThingsCaught;
private int keepSize;
public float sumOfWeight;
public static int LIMIT = 10;
public String getName()
{
return this.name;
}
public int getNumThingsCaught()
{
return this.numThingsCaught;
}
public int getKeepSize()
{
return this.keepSize;
}
public Fisher(String n, int k)
{
name = n;
keepSize = k;
}
public String toString()
{
return(this.name + " with " + this.numThingsCaught + " fish");
}
private ArrayList<Catchable> thingsCaught = new ArrayList<Catchable>();
public void keep(Catchable item)
{
if(this.numThingsCaught < LIMIT)
{
thingsCaught.add(item);
numThingsCaught++;
sumOfWeight += item.weight;
}
}
public boolean likes(Catchable item)
{
if(item.size >= this.keepSize)
{
return true;
}
else
{
return false;
}
}
public void listThingsCaught()
{
System.out.println(this.toString());
for(Catchable item : thingsCaught)
{
System.out.println(item.toString());
}
}
public void goFishingIn(Lake lake)
{
Catchable item = lake.catchSomething();
if(likes(item))
{
this.keep(item);
}
else
{
lake.add(item);
}
}
public void giveAwayFish(Fisher fisher, Lake lake)
{
for(Catchable item : thingsCaught)
{
if(fisher.likes(item))
{
fisher.keep(item);
}
else
{
lake.add(item);
}
sumOfWeight -= item.weight;
}
thingsCaught.clear();
this.numThingsCaught = 0;
}
}
The problem are the following lines:
keep():
sumOfWeight += item.weight;
likes():
if(item.size >= this.keepSize)
giveAwayFish():
sumOfWeight -= item.weight;
In every case, item is of type Catchable, and Catchable doesn't have size or weightfields. What you have to do is call item.getWeight() instead of item.weight and add a getSize() method to Catchable, and call item.getSize() instead of item.size:
Catchable:
public interface Catchable
{
public float getWeight();
public int getSize();
public boolean isDesirableTo(Fisher f);
}
keep():
sumOfWeight += item.getWeight();
likes():
if(item.getSize() >= this.keepSize)
giveAwayFish():
sumOfWeight -= item.getWeight();
You don't have to modify Fish, as it already implements getSize().
And you should really use an IDE like Eclipse, because it can show you where your errors are in real time.
Not every Catchable is a Fish, so, for example
public boolean likes(Catchable item)
{
if(item.size >= this.keepSize)
...
will fail, because Catchable doesn't have a size member (it also can't have member variables because it's an interface). item is Catchable here, it's not fish.
When you're using an interface, you should only interact with the instance through the methods defined in the interface (or in interfaces that it extends).
In Java we usually call them "fields" not "attributes".
Anyways, there are a couple of issue. First, you declare weight (for example) as protected in Fish. This is the right thing to do here, but it means that weight is not accessible outside of Fish. So you would have to do this from a class outside of Fish:
void example (Fish fish) {
// System.out.println(fish.weight); // <- not allowed, weight is protected
System.out.println(fish.getWeight()); // <- ok, getWeight() is public
}
That's the point of providing a public getter like getWeight() in the Catchable interface in the first place (that and the fact that interfaces can't have non-static non-final member fields). The underlying implementation is hidden -- an object that implements Catchable might not have a weight field at all and might calculate a return value based on some completely different set of rules. But it doesn't matter, because you access it through getWeight().
Secondly, the above doesn't make sense for a general Catchable anyways even if Fish.weight was public; Catchable does not have a field named weight. Fish does. So if you are accessing it through a reference of type Catchable, there's no weight anyways.
You do provide Catchable.getWeight(), however. That method is present in all Catchable types. So you would have to use that to access weight. So in your Fisher you could do:
void example (Catchable catchable) {
// System.out.println(catchable.weight); // <- not allowed, Catchable has no weight
System.out.println(catchable.getWeight()); // <- ok, getWeight() is public and is in Catchable
}
I highly suggest working through the official Interfaces and Inheritance tutorial. It may familiarize you with a few of the concepts you are asking about.
Added:
It seems like you have a background in C# or another language with a similar concept of "attributes" - where you provide a getter/setter but syntactically you still refer to it directly by the attribute name (e.g. fish.weight = 3 calls fish.setWeight(3) automatically).
This construct does not exist in Java. You can write getters/setters as member methods, and you call them, and that's all you get. There is no automatic calling of getters/setters on direct field access. You can have this:
class Example {
public int field;
public void setSomething (int x) { ... }
public int getSomething () { ... }
}
And that's what you get. From that you can do this:
Example x = ...;
x.field = ...;
... = x.field;
x.setSomething(...);
... = x.getSomething();
But you cannot automatically do anything like this:
x.setField(...);
... = x.getField();
x.something = ...;
... = x.something;
So if you have a background in a language like that, that could be the source of your confusion. You will need to adjust. In Java you have to explicit; the language is noteworthy for its low amount of ambiguity and redundancy.
I see this dotted about in your code:
sumOfWeight += item.weight;
Slow down a moment here - you're not using a concrete instance of a class; you're referring to the interface instead. You'll observe that the interface doesn't have a field for weight, hence your compilation failure.
If you want to adhere to using the interface, then you need to change a few things.
Add a method getWeight() to your interface.
public float getWeight();
Remove the abstract declaration from your Fish class (that will only serve to hurt and confuse you).
Then, when you want to perform that summation operation, you can:
sumOfWeight += item.getWeight();

OO - Creating object using a method of no argument

I am experience some problems in understanding how the OO pattern works, My lecturer gave me the following question but I cannot solve it after thinking whole day
Scenario for my problems.
There is a class named "ShapeManager" which manages the Shape object. A class named "Shape" has two subclasses named "Circle" and "Rectangle"
The implementation of Shape class as follow
abstract public class Shape {
private String id;
private double length;
public Shape() {
}
public Shape(String id , double length) {
this.id = id;
this.length = length;
}
public void setID(String id) {
this.id = id;
}
public String getID() {
return id;
}
public void setLength(double length) {
this.length = length;
}
public double getLength() {
return length;
}
public abstract String getDetails();
}
The subclass Square as follow
public class Square extends Shape{
public Square() {
super();
}
public Square(String id , double side) {
super(id, side);
}
#Override
public String getDetails() {
return "Square => Id : "+getID() +", Side : "+ getLength() + ",Area : "+(getLength() * getLength());
}
}
The subclass Circle as follow
public class Circle extends Shape{
public Circle(){
super();
}
public Circle (String id, double radius) {
super(id, radius);
}
#Override
public String details() {
return "Circle => Id : "+getID() + ", Radius : "+ getLength() + ",Area: "+(3.14*(getLength() * getLength()));
}
}
The ShapeManager class as follow, this is not a completed class
public class ShapeManager {
public Shape createShape() {
}
public void updateLength(String id ){
}
public void deleteShape(String id) {
}
public void listShapes() {
}
}
ShapeManager have an association with Shape
ShapeManager --1------0..*--> Shape
The design of this package (All the classes above) can not be changed, implementation must be following OCP (Open-Closed Principle).
My question is: How am I suppose to complete createShape method? Without parameter, it is seemingly impossible to create an object either a Rectangle or Circle.
ShapeManager cannot create a shape if not knowing what this shape is (Square, Circle or something else). And it really doesn't know because you say the method createShare has no parameters. Either you misunderstood the question or the lecturer didn't explain it well. You should ask him/her for clarifications. If you look at the libraries of Java or any other OO language, I am pretty sure you won't find such scenario and implementation pattern as the one you gave in your example.
#croraf
You should find some other reading I think e.g. the classic book http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612. The main idea of a factory is that it returns something whose type the caller doesn't know, and doesn't care about. For example, if you have a method createSocket() in some SocketFactory, this method is usually defined to return an interface or an abstract class Socket. But actually it returns new SocketImpl1() and new SocketImpl2() which are concrete classes. What the factory returns may depend on many things - a system property, the underlying OS, anything you can think of. The main idea is that the factory centralizes the creation of Socket objects at one single place. This way, if you need to make a change, you can make it just in the factory. I think this book also has some decent Java counterparts too, you may look around. Other free good sources are referenced here.
Real world examples of Factory Method pattern
I think you should have something like this, similar to how BorderFactory from java API works.
public class ShapeManager {
public Shape createCircle() {
...
return Circle;
}
public Shape createSquare() {
....
return Square;
}
...
public void updateLength(String id ){
}
public void deleteShape(String id) {
}
public void listShapes() {
}
}
You can't create shape without knowing type which shape would You like to create. You can define enumeration for types and pass the type value to the createShape(). And there You can switch between types and create the concrette shape You want.
For me, Its classic Factory pattern.
public class ShapeFactory {
public abstract Shape getShape(int shapeId);
}
public interface Const {
public static final int SHAPE_CIRCLE =1;
public static final int SHAPE_SQUARE =2;
}
public class SimpleShapeFactory extends ShapeFactory throws BadShapeException {
public Shape getShape(int shapeTypeId){
Shape shape = null;
if(shapeTypeId == Const.SHAPE_CIRCLE) {
//in future can reuse or cache objects.
shape = new Circle();
}
else if(shapeTypeId == Const.SHAPE_SQUARE) {
//in future can reuse or cache objects
shape = new Square();
}
else throw new BadShapeException("ShapeTypeId="+ shapeTypeId);
return shape;
}
}
Calling:
ShapeFactory factory = new SimpleShapeFactory();
//returns a Shape but whether it is a Circle or a
//Square is not known to the caller.
Shape s = factory.getShape(1);
s.getDetails(); // circle details called
//returns a Shape but whether it is a Circle or a
//Square is not known to the caller.
s = factory.getShape(2);
s.getDetails(); //Square details called
References:
The Open Close Principle states that the design and writing of the code should be done in a way that new functionality should be added with minimum changes in the existing code. The design should be done in a way to allow the adding of new functionality as new classes, keeping as much as possible existing code unchanged.

Creating multiple subclass objects

I'm trying to achieve a 'wave' of enemies through a for loop. Basically when a wave object is called it accepts an int that sets the number of enemies in the wave. Each enemy has it's own class that is a subclass of 'Enemy'. What I'm stuck on is how I can go about passing in a second parameter in the wave constructor to set which enemy subclass is created eg 25 'Orcs' created or 13 'Trolls' in one method. Any help will be greatly appreciated.
It sounds like you want to create a static factory method of the Enemy class that creates new Enemy objects based on parameter. Something like:
// EnemyType is an enum
public static Enemy createEnemy(EnemyType enemyType) {
switch (enemyType) {
case BASIC_MONSTER:
return new BasicMonster();
case ORC:
return new Orc();
case TROLL:
return new Troll();
case ..... // etc...
}
}
Note, I would use something cleaner for the parameter such as an enum, not an int so as to be sure that the parameter passed in is correct. Otherwise you risk having a nonsense int such as -24232 being passed in.
You can use an Enum
public enum EnemyType {
ORC{
#override
public Enemy create() {
return new Orc();
}
},
TROLL{
#override
public Enemy create() {
return new Troll();
}
}...etc;
public abstract Enemy create();
}
Then pass the relevant enum into your wave method:
public Collection<Enemy> createWave(final int num, final EnemyType enemyType) {
final Collection<Enemy> enemies = new ArrayList<>(num);
for(int i=0;i<num;i++) {
enemies.put(enemyType.create());
}
return enemies;
}
If you have lots of differenet enemy types consider a generic factory
public interface EmemyFactory<E extends Enemy> {
E create();
}
Then create an implementation for each enemy type and store them in the enum instead
public enum EnemyType {
ORC(new OrcFactory()),
TROLL(new TrollFactory()),
...etc;
private final EnemyFactory enemyFactory;
public EnemyType(final EnemyFactory enemyFactory) {
this.enemyFactory = enemyFactory;
}
public Enemy create() {
return enemyFactory.create();
}
}
And last and least you could use a little reflection, assuming your Enemies have a noargs constructor:
public Collection<Enemy> createWave(final int num, final Class<? extends Enemy> enemyClass) {
final Collection<Enemy> enemies = new ArrayList<>(num);
for(int i=0;i<num;i++) {
enemies.put(enemyClass.newInstance());
}
return enemies;
}
This is messy and prone to runtime errors however...

Categories