Java only calling method with parent as its function parameter - java

In my project I came across this problem, where I have an abstract class of Entity, and it's children are Player, Shot and Enemy. I want to check for collision between them. A separate Physics class is doing the collision evaluation with the following code:
public class Physics {
private static int height = 32;
private static int width = 32;
public static void collision(Entity entity, LinkedList<Entity> eList) {
for (int i = 0; i<eList.size(); i++) {
if (entity.getBounds(width, height).intersects(eList.get(i).getBounds(width, height))) {
entity.collidesWith(eList.get(i));
}
}
}
}
The linkedList contains both Shots and Enemies, and yet for some reason, the collision only calls the collidesWith(Entity entity) method, instead of the collidesWith(Shot b) or collidesWith(Enemy e).
edit: The mentioned classes (with only the code that I think would matter from them in this case)
Entity:
public abstract class Entity {
protected double x;
protected double y;
public Entity (double x, double y) {
this.x = x;
this.y = y;
}
public abstract void tick();
public double getX() { return x; }
public double getY() { return y; }
public Rectangle getBounds(int width, int height) {
return new Rectangle((int)x, (int)y, width, height);
}
public abstract void collidesWith(Entity e);
public abstract void collidesWith(Enemy e);
public abstract void collidesWith(Shot s);
Player:
public class Player extends Entity {
private boolean alive;
private int gameWidth, gameHeight;
private GameController gCont;
private Textures textures;
public Player( String name, int x, int y, int gameWidth, int gameHeight, Textures textures, GameController gCont) {
super(x,y);
this.name = name;
this.score = 0;
this.gameWidth = gameWidth;
this.gameHeight = gameHeight;
this.gCont = gCont;
this.textures = textures;
this.alive = true;
}
public void tick() {
gCont.collisionCheck(this);
}
public void collidesWith(Enemy e) {
System.out.println("Player collides with enemy");
this.alive = false;
}
public void collidesWith(Shot s) {
return;
}
public void collidesWith(Entity e) {
System.out.println("collided with entity");
return;
}
Shot
public class Shot extends Entity {
private Textures textures;
private GameController gCont;
public Shot(double x, double y, Textures textures, GameController gCont) {
super(x, y);
this.textures = textures;
this.gCont = gCont;
}
public void tick() {
x+=10;
gCont.collisionCheck(this);
}
public void collidesWith(Entity e) {
return;
}
public void collidesWith(Enemy e) {
gCont.removeEntity(e);
gCont.removeEntity(this);
gCont.addScore();
}
#Override
public void collidesWith(Shot s) {
return;
}
Enemy
public class Enemy extends Entity {
private int speed;
public Enemy(double x, double y) {
super(x, y);
Random random = new Random();
speed = random.nextInt(3)+1;
}
public void tick() {
x-=speed;
}
public void collidesWith(Entity e) {
return;
}
#Override
public void collidesWith(Enemy e) {
return;
}
#Override
public void collidesWith(Shot s) {
return;
}
How can I get it to call to the correct functions?

Look into Java's Generics. I think you could use something like this:
public abstract class Entity<T> {
protected double x;
protected double y;
public Entity (double x, double y) {
this.x = x;
this.y = y;
}
public abstract void tick();
public double getX() { return x; }
public double getY() { return y; }
public Rectangle getBounds(int width, int height) {
return new Rectangle((int)x, (int)y, width, height);
}
public abstract void collidesWith(T e);
}

Might be wrong, I am new to answering questions on stackoverflow.
Hope this gives you some clarity:
entity.collidesWith(eList.get(i));
eList.get(i) in that line, in your Physics class Entity returns an an object of type Entity.
This is because it is defined like that:
LinkedList<Entity> eList
That means that if you have an overload that takes that Entity it would just call that method. This is exactly what I see in your code. You have a method overload for "collidesWith" with Argument: Entity.
In all of the children classes of Entity.
I think you should read more about "Java Polymorphism".

For me the Entity class knowing about Enemy and Shot is wrong.
Why don't you remove these two methods from Entity and subclasses:
public abstract void collidesWith(Enemy e);
public abstract void collidesWith(Shot s);
And keep and implement only:
public abstract void collidesWith(Entity e);
If you need to know the type of Entity e passed as argument, you can use reflection, but this is bad design. It is better to implement collidesWith in such way that it doesn't need to know the exact type of the passed argument.

I think a solution other than Generic type as specified by Jamie Bisotti, is to use an interface and a switch to check which class is what.
This is the interface that declares a method that all entities that can collide must have:
public interface Collidable {
public boolean collidesWith(Collidable entity);
}
Then each class that you want to be able to collide has to implement that:
public class Enemy extends Entity implements Collidable {
private int speed;
public Enemy(double x, double y) {
super(x, y);
Random random = new Random();
speed = random.nextInt(3)+1;
}
public void tick() {
x-=speed;
}
#Override
public void collidesWith(Collidable e) {
if (e.getClass().equals(Shot.class)) {
// DO SOMETHING, I am colliding with a shot
} else if(e.getClass().equals(Enemy.class)) {
// I am colliding with an Enemy
}
. . . etc
}
I prefer to use Interfaces so I can specify each behaviour. At the moment it seems to be all simple and everything can be extended from the Entity abstract class, but there will be a moment when you will differentiate each entity by many other feature.
For example a flying enemy, a walking enemy, ecc ecc and you can specify each feature with an interface.
In this case, the interface is also very simple. But you could specify many methods that you want to be implemented such as
public boolean canCollide();
public boolean isAlive(); //if the entity is already dead you might want not to stop a bullet
public boolean isAnimatingDeath(); //if the entity is animating death could collide with another antity because of its exploding animation, maybe you want to avoid that.
You can implement som method in the abstract Entity class, but that abstract entity shouldn't know about its children. This is the reason to implement some methods using the generic "Collidable" type as input, directly in the children.

Related

Java - Return different classes from method and use specific functions of the classes

I have 2 classes.For example ; Rectangle and Circle
public class Rectangle {
private int width;
private int height;
public Rectangle(int width,int height) {
this.width = width;
this.height = height;
}
public int getArea() {
return width * height;
}
}
public class Circle {
private int radius;
public Circle(int radius) {
this.radius = radius;
}
public int getArea() {
return radius * radius * 3;
}
}
and I have this method out of classes;
public void PrintArea(Object object) {
if(object instanceof Circle)
System.out.print(((Circle)object).getArea());
else if(object instanceof Rectangle)
System.out.print(((Rectangle)object).getArea());
}
but I want to do it on one line without class cast, For example:
public void PrintArea(Object object) {
System.out.print(object.getArea());
}
is it possible? Thank you... (Circle and Rectangle are only examples.I have different and detailed classes in big project.And I cannot change this class structure)
You can use Polymorphism to invoke the method of the correct instance at runtime. To do this you can make a interface Shape which has the printArea() method. This method would be implemented by the concrete classes Rectangle and Circle which would define their specific behaviour:
interface Shape {
void printArea();
}
class Rectangle implements Shape {
private int width;
private int height;
public Rectangle(int width, int height) {
this.width = width;
this.height = height;
}
public int getArea() {
return width * height;
}
public void printArea() {
System.out.println(this.getArea());
}
}
class Circle implements Shape {
private int radius;
public Circle(int radius) {
this.radius = radius;
}
public int getArea() {
return radius * radius * 3;
}
public void printArea() {
System.out.println(this.getArea());
}
}
Then there would a dispatcher class like Printer which takes a shape object and calls the printArea() method on it:
class Printer {
public void printArea(Shape shape) {
shape.printArea();
}
}
Then you could do something like this to use the dynamic method dispatch concept in Java:
public static void main(String[] args) {
Shape rectangle = new Rectangle(10, 20);
rectangle.printArea();
Shape circle = new Circle(20);
circle.printArea();
Printer printer = new Printer();
printer.printArea(circle);
printer.printArea(rectangle);
}
EDIT
If you can't add new methods in the classes then you can go for default methods in the Shape interface introduced from Java 8:
interface Shape {
int getArea();
default void printArea(){
System.out.println(this.getArea());
}
}
Now lets say if you need a Square implementation, and have the getArea defined then you no longer have to define a printArea() method in the class Square:
class Square implements Shape{
private int side;
public Square(int side) {
this.side = side;
}
public int getArea() {
return side * side;
}
}
This way you don't break the existing implementations when you implement the new Shape interface in existing classes.
You need to write an interface with getArea () method. And you should make Rectangle and Circle implement the interface.
public interface Shape {
int getArea();
}
public class Rectangle implements Shape {
private int width;
private int height;
public Rectangle(int width,int height) {
this.width = width;
this.height = height;
}
#Override
public int getArea() {
return width * height;
}
}
public class Circle implements Shape {
private int radius;
public Circle(int radius) {
this.radius = radius;
}
#Override
public int getArea() {
return radius * radius * 3;
}
}
and..
public void PrintArea(Object object) {
if(object instanceof Shape)
System.out.print((Shape)object.getArea());
}
//or..
public void PrintArea(Shape object) {
object.getArea();
}
You can use reflections inside the printArea method but it is not recommended way of doing it. Use either interface or extend from an abstract base class
One way of doing it is below.
public void PrintArea(Object object) throws Exception {
Method method = object.getClass().getMethod("getArea");
System.out.println(method.invoke(object));
}
Let's say you have your two classes, Rectangle and Circle.
These two classes, you can't alter, so you can't make them implement an interface.
You can, however, locally extend them, and have those subclasses implement an interface.
public interface Shape {
int getArea();
}
And, you create two new classes:
public class MyRectangle extends Rectangle implements Shape {
}
public class MyCircle extends Rectangle implements Shape {
}
Since these classes inherit the members of their parent classes, and those already provide an implementation for getArea(), that is all you need to do.
then, change your printArea method to:
public void printArea(Shape myShape) {
System.out.println(myShape.getArea());
}
In order for this to work, you'll need to either use instantiate your new classes instead of the old ones, or you need to add a mapper, this can be something like:
public static Shape createMyShapes(Object o) throws TechnicalException {
if ( !(o instanceof Circle || o instanceof Rectangle) )
throw new TechnicalException("Wrong type");
if ( o instanceof Circle )
return new MyCircle(o);
return new MyRectangle(o);
}
and use that where necessary.

Java varargs constructor gives error in subclass constructor

I have 2 classes: FinishButton and ChangeSpeedButton.
FinishButton is the parent class, but it is from a different package and it is a subclass of another class.
It has 2 constructors:
public class FinishButton extends Button {
public FinishButton(Point...points) {
super(Response.SLOW,Type.HOLD,points);
}
public FinishButton() {
this(new Point(width-75,height-75),
new Point(width-75,height-15),
new Point(width-15,height-15),
new Point(width-15,height-75));
}
public void function() {
nextPanel();
}
public void draw(Graphics g) {
super.draw(g);
this.xpoints[0] = 0;
g.setColor(Defaults.GRAPHIC_COLOR);
int[] xPoints = {
width-45-(int)((20*Math.sqrt(3))/2),
width-45-(int)((20*Math.sqrt(3))/2),
width-45+(int)((20*Math.sqrt(3))/2)
},
yPoints = {
height-65,height-25,height-45
};
int nPoints = 3;
g.fillPolygon(xPoints, yPoints, nPoints);
}
}
These classes are works in progress but ChangeSpeedButton looks like this:
public class ChangeSpeedButton extends FinishButton {
public ChangeSpeedButton() {
super(new Point(width/2-30,height-75),
new Point(width/2-30,height-15),
new Point(width/2+30,height-15),
new Point(width/2+30,height-75));
}
}
The weird thing is that FinishButton handles the varargs perfectly when overloading its own constructor, but for some reason on ChangeSpeedButton's constructor, Eclipse is telling me to
either "remove arguments to match 'FinishButton()'" or "Change
constructor 'FinishButton()': Add parameters
'Point,Point,Point,Point'".
Does anyone know why it's giving me an error on ChangeSpeedButton?
Edit: I added the full classes. And as requested, here is the Point class:
public class Point {
private double x,y;
public double getX() { return x; }
public double getY() { return y; }
public Point() {
this(0,0);
}
public Point(double x,double y) {
this.x = x;
this.y = y;
}
public String toString() {
return "Point: ("+x+", "+y+")";
}
}
Maybe it has to do with the fact that the Button classes are nested classes?
Oh my goodness. I'm so dumb. I had 2 FinishButton files open and even though I saved one of them with the correct changes, the ChangeSpeedButton only looked at the outdated file.

Abstracting the functionality of enum

I have 2 enums which look similar:
public enum enum1{
A(1,1),
B(2,2);
private final int x,y;
enum1(int x,int y){
this.x=x;
this.y=y;
}
int func(){ return this.x+this.y; }
}
public enum enum2{
C(3,3),
D(4,4);
private final int x,y;
enum2(int x,int y){
this.x=x;
this.y=y;
}
int func(){ return this.x+this.y;}
}
public class test{
void method(enum1 e){ /*something using func*/ }
void method(enum2 e){ /*something using func*/ }
}
How do I abstract the functionality of these enums in an interface and use only one method in the test class instead of two by passing the interface.
Edit: I don't want the enums to be merged. I need separate enums.
One thing is for sure: as long as x and y are private and there's no way to read them from outside the class - you would have to implement the same method for each enum. If you allow the reasonable change to add accessors to these fields in the enums, then you can use an interface's default method to implement the umbrella behavior:
interface Addable {
int getX();
int getY();
default int add() {
return getX() + getY();
}
}
enum Enum1 implements Addable {
A(1, 1), B(2, 2);
private final int x, y;
Enum1(int x, int y) {
this.x = x;
this.y = y;
}
#Override
public int getX() {
return x;
}
#Override
public int getY() {
return y;
}
}
Then you can make a call like Enum1.B.add() which will give 4. As for your test class:
public class Test {
void method(Addable e) { e.add(); }
}
is now valid for anything that implements Addable.
If you're worried about bloating the code, I recommend using Lombok:
#RequiredArgsConstructor
enum Enum1 implements Addable {
A(1, 1), B(2, 2);
#Getter
private final int x, y;
}
Note: type names should start with an uppercase. enum1 and test shoud be Enum1 and Test.
Create an interface that is implemented by each enum, only 'problem' the method must be public:
public interface Inter {
public void func();
}
public enum Enum1 implements Inter {
A(1,1),
B(2,2);
private final int x,y;
Enum1(int x,int y) {
this.x=x;
this.y=y;
}
#Overwrite
public int func() { return this.x+this.y; }
}
public enum Enum2 implements Inter {
...
#Overwrite
public int func() { ... }
}
public class Test {
void method(Inter e) {
// something using func
int sum = e.func();
}
}

Return a class to be created later

Currently, I'm migrating a game from Python to Java. In it, I created a Generator that returns a "class" that will be created with arguments its caller would have, like so:
package me.mathmaniac.smallworlds.world.generation;
import me.mathmaniac.smallworlds.block.Block;
import me.mathmaniac.smallworlds.block.NullBlock;
import me.mathmaniac.smallworlds.world.LayerType;
public class FlatGenerator implements Generator {
#Override
public Block generateBlock(LayerType ltype, int x, int y) {
switch (ltype) {
case Liquid:
return HoleBlock;
case Solid:
return GrassBlock;
case Air:
return AirBlock;
default:
throw new RuntimeException();
}
}
}
Called from here:
package me.mathmaniac.smallworlds.world;
import me.mathmaniac.smallworlds.block.Block;
import me.mathmaniac.smallworlds.world.generation.Generator;
public class World {
Generator generator = ...;
// ...
private void generateBlocks(int x, int y) {
for (LayerType ltype : LayerType.values())
setblock(generator.generateBlock(ltype, x, y).new(x, y, ltype), //.new() is as an example
x, y, ltype);
}
}
How would I accomplish this in Java?
You want to use the Factory Pattern
You would have a few classes: an abstract class Block (or an interface) and the factory class BlockFactory (or as you called it, FlatGenerator).
If there are a number of functions that can have the same implementation across all Block types, then make the base class Block be an abstract class and put those methods in there. Otherwise, you can use an interface.
One approach could be to give all your layer classes the same interface and a no-argument constructor, and return Class<T> object from the method that returns the class to be instantiated later:
interface Layer {
void init(LayerType ltype, int x, int y);
}
class Liquid implements Layer {
public Liquid() {
...
}
public void init(LayerType ltype, int x, int y) {
...
}
}
class Solid implements Layer {
public Solid() {
...
}
public void init(LayerType ltype, int x, int y) {
...
}
}
With this setup in place you could do this:
public Class generateBlock(LayerType ltype, int x, int y) {
if (...) return Liquid.class;
if (...) return Solid.class;
...
}
The caller would initialize the layer as follows:
Layer layer = (Layer)generator
.generateBlock(ltype, x, y)
.newInstance();
layer.init(ltype, x, y);
I would just do it in the traditional OOP style.
First define an interface for a factory class
public interface BlockFactory {
Block createInstance(int x, int y, LayerType ltype);
}
And then define corresponding factories
public class HoleBlockFactory implements BlockFactory {
public Block createInstance(int x, int y, LayerType ltype) {
return new HoleBlock(x, y);
}
}
public class GrassBlockFactory implements BlockFactory {
public Block createInstance(int x, int y, LayerType ltype) {
return new GrassBlock(x, y);
}
}
Finally in your generator first you get a factory in your switch statement and the use the factory to create objects when you need:
public class FlatGenerator implements Generator {
#Override
public BlockFactory generateBlock(LayerType ltype, int x, int y) {
switch (ltype) {
case Liquid:
return new HoleBlockFactory();
case Solid:
return new GrassBlockFactory();
default:
throw new RuntimeException();
}
}
}
}
public class World {
Generator generator = ...;
// ...
private void generateBlocks(int x, int y) {
for (LayerType ltype : LayerType.values())
setblock(generator.generateBlock(ltype, x, y).createInstance(x, y, ltype), //.new() is as an example
x, y, ltype);
}
}

Java class inheritance and blocking superclass methods

Im currently making a simple pluginable program. My problem is that I don't want to let plugin access all base-plugin fields/methods. For example:
public abstract class BasePlugin {
private int x; //Mysterious x
public abstract void update(); //update func that may need x, but can't change it
protected final int getX() {return x;} //x accessor
}
And that would work unless you realize that there is no way to set x.
What can I do? I want to make subclass (plugin) unable to change x, but let it read the value. Value should be accesible at least once when creating (that would be enough).
EDIT: Constructor works in most cases, but what if I have for example:
public abstract class BasePlugin {
private List<int> x; //Mysterious x
public abstract void update(); //update func that may need x, but can't change it
protected final List<int> getX() {return x;} //x accessor
public BasePlugin(List<int> y) {x = y;}
}
public class Plugin {
public Plugin(List<int> y)
{
super(y);
y.remove(0); //Will it work?
}
}
An abstract class is permitted to have a constructor, so you can create a parameterless constructor for BasePlugin:
public abstract class BasePlugin {
private int x; //Mysterious x
public BasePlugin() {
x = 42;
}
public abstract void update(); //update func that may need x, but can't change it
protected final int getX() {return x;} //x accessor
}
And now when a plugin is created, x is set to 42. You don't even need to make any code changes to the plugins to make them use this constructor.
To answer the edited question: If x is a List and you don't want the plugins to modify it, your constructor should be copying it and wrapping it in an unmodifiable list. Otherwise, any plugin can call getX().add(myObject).
public BasePlugin(List<int> y) {
List<int> temp = new ArrayList<int>();
Collections.copy(temp, y); // shallow copy of the list
this.x = Collections.unmodifiableList(temp);
}
Now if the plugin's constructor is
public Plugin(List<int> y)
{
super(y);
y.remove(0); //Will it work?
}
It will have no effect on the BasePlugin's list.
You can add a constructor to get your property initialized by the subclasses:
public abstract class BasePlugin {
private int x; //Mysterious x
public BasePlugin(int x) {
this.x = x;
}
public abstract void update(); //update func that may need x, but can't change it
protected final int getX() {return x;} //x accessor
}
You can use Constructor Injection.
public abstract class BasePlugin{
private int x;
public BasePlugin(int x){
this.x=x;
}
public abstract void update(); //update func that may need x, but can't change it
protected final int getX() {return x;} //x accessor
}
And in your childs
public class Plugin extends BasePlugin{
public Plugin(int x){
super(x);
}
}

Categories

Resources