Example, let's say from a game:
public class Enemy {
protected int x, y;
protected int width, height;
protected int hitpoints;
protected int speed;
}
I want to have multiple classes extending this one (one for every enemy type) but I need to make sure (preferably force this) somehow that the extending class assigns values to all of these variables.
I don't want to pass them through a constructor call or set them in it - so currently I'm forced to do this by simply copying the entire decelerations into every class and assigning them values in the same line.
Is there perhaps a more efficient way to do this?
(Sorry if the question is somewhat vague..)
Thanks in advance.
Edit - This is how I would create an extending class:
public class Skeleton extends Enemy {
protected int x, y;
protected int width, height;
protected int hitpoints;
protected int speed;
}
One alternative to Jordão's answer would be to use the builder pattern:
public class SkeletonBuilder
{
private int x, y, width, height...;
public SkeletonBuilder withCoords(int x, int y) { this.x = x; this.y = y; }
public SkeletonBuilder withSize(int width, int height) { this.width = width; this.height = height; }
...
public Skeleton build() { return new Skeleton(x, y, width, height); }
}
public class Skeleton
{
/* package */ Skeleton(int x, int y, int width, int height, ...)
}
// game code
Skeleton skeleton = new SkeletonBuilder().withCoords(1, 4).withSize(2, 30).build();
If some of the params could be defaulted then set them up in the SkeletonBuilder constructor. If the other params are required, then you could either set a boolean flag in the builder, or use boxed objects, and fail in the build() method if they're not set.
To both force the subclasses to set the values in the constructor and to make the constructor call readable, you're going to have to write a lot more code in the superclass. This is one way I could think about it (just showing x and y):
abstract class Enemy {
protected int x, y;
protected Enemy(X x, Y y) {
this.x = x.value;
this.y = y.value;
}
protected static class X {
private final int value;
private X(int value) { this.value = value; }
}
protected static class Y {
private final int value;
private Y(int value) { this.value = value; }
}
protected static X x(int value) { return new X(value); }
protected static Y y(int value) { return new Y(value); }
}
class Skeleton extends Enemy {
public Skeleton() {
super(x(12), y(13));
}
}
UPDATE: if it makes sense to have composite types that encapsulate related values, they can make the code better:
class Skeleton extends Enemy {
public Skeleton() {
super(position(12, 13), size(300, 300), ...);
}
}
Your class Skeleton should not declare the same variables as set in Enemy.
As to your question, the simplest option is to make the variables final, and then set them in a constructor. The compiler will enforce that they are all set.
I think you should create a Type interface
interface Type
{
int getX();
int getY();
int getWidth() ;
int getHeight();
int getHitpoints();
int getSpeed();
}
Then the compiler will do the enforcement work.
Based on the comments (and although I would go with a constructor on the superclass) one way to go at it would be to declare the Enemy class as abstract (which probably should be if you just want to define common behaviour there) and initialize the variables as calls to abstract methods.
This way the extending classes would be forced to implement those methods and in essence initialize the variables.
Here's a simplified example:
public abstract class Enemy {
protected int x = getX();
protected int y = getY();
protected abstract int getX();
protected abstract int getY();
}
public class Skeleton extends Enemy {
#Override
protected int getX() { return 10; }
#Override
protected int getY() { return 10; }
}
Its more verbose, but perhaps it achieves the readability you are looking for.
Related
Today I decided to make a top down based game using Java. I have already made the window and included the Jframe. But I found a problem on creating the GameObject in the Rectagle GetBounds(); . I don't know what really is because I am a beginner and I know the basics of java :( .
If anyone can help me to resolve this problem I give the code example below:
package example;
import java.awt.Graphics;
import java.awt.Rectangle;
public abstract class GameObject {
protected int x, y;
protected float velX = 0, velY = 0;
public GameObject(int x, int y) {
this.x = x;
this.y = y;
}
public abstract void tick();
public abstract void render(Graphics g);
public abstract void Rectangle getBounds();
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public float getVelX() {
return velX;
}
public void setVelX(float velX) {
this.velX = velX;
}
public float getVelY() {
return velY;
}
public void setVelY(float velY) {
this.velY = velY;
}
}
The code causes the following errors:
Illegal modifier for the field Rectangle; only public, protected,
private, static, final, transient & volatile are permitted Return type
for the method is missing Syntax error, insert ";" to complete
FieldDeclaration This method requires a body instead of a semicolon
void is an invalid type for the variable Rectangle
Note: I'm using Java SE-8 and Eclipse Oxigen.
If you want to create an instance of GameObject (like this: new GameObject()) then GameObject class must not be abstract.
You cannot create an instance of abstract class. You can only create a class that inherits from abstract class and implements all or some methods.
Here you can either implement methods tick(), render(Graphics g) and getBounds() or create a new class that inherits from GameObject (public class GameObjectImp extends GameObject) and implement methods there.
Please review the code below:
abstract class Shape {
protected double x;
protected double y;
public Shape(double x, double y) {
this.x = x;
this.y = y;
}
abstract protected void draw();
}
class Circle extends Shape {
public Circle(double x, double y, double r) {
super(x, y);
this.r = r;
}
protected double r;
protected void draw() {
System.out.println(String.format("Draw Circle. %f %f %f", x, y ,r));
}
}
class RenderEngine {
public static void draw1(Shape s) {
s.draw();
}
public static <T extends Shape> void draw2(T t) {
t.draw();
}
}
public class Runner {
#Test
public void run() {
Circle c = new Circle(1,2,3);
RenderEngine.draw1(c);
RenderEngine.draw2(c);
}
}
What's the difference between draw1() and draw2()? Which one is better? Does draw2() have more extensibility? Or does draw2() have better performance?
There is no difference in your scenario, because the type of the object being drawn is consumed internally in the drawX method.
It would make a difference if your method were to use T in some other context, such as returning the original back to the caller:
public static <T extends Shape> T draw2(T t) {
t.draw();
return t;
}
This makes a difference in situations when a subclass defines new methods on top of the base class. For example, if Circle defined
double radius() { return r;}
you could do the following:
double r = RenderEngine.draw1(c).radius();
This would be impossible with an implementation returning Shape.
Note: The above is to demonstrate the differences, not to suggest that the new implementation is more desirable than the original one.
draw2 will do the same thing as draw for things that are already shapes. But when it says T extends Shape, it allows it to take in a parameter that is not a shape. At that point, it will allow it to use the draw method without crashing, whether or not it's a shape, it just might not draw anything.
This title does not express what I mean quite well, I apologize, but it is difficult for me to express it better, because I don't quite understand what's going on due to lack of OOP knowledge and experience.
I am building a basic game, which is going to have the player run around a board with a 'hero' sprite, being chased by a 'badGuy' sprite. Because the two sprites share 5-6 methods, I decided to make a super class 'Sprite' and two classes 'Hero extends Sprite' and 'BadGuy extends Sprite'. Now for all those super methods, including stuff like:
getX(); getY(); getBounds(); render();
to work I need the super class to track the location of 'Hero' and 'badGuy'. So I implemented 'Sprite' like this:
package game.sprites;
import javafx.scene.shape.Rectangle;
import javax.swing.*;
import java.awt.*;
public class Sprite {
public static int x;
public static int y;
private int imageWidth;
private int imageHeight;
public Image image;
public Sprite(int x, int y) {
Sprite.x = x;
Sprite.y = y;
}
public static void render(Graphics g, Image image) {
g.drawImage(image, x, y, null);
}
public Image loadImage(String filePath) {...}
public void getImageDimensions() {...}
public Rectangle getBounds() {
return new Rectangle(x, y, imageWidth, imageHeight);
}
public Image getImage() {
return image;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
The problem kicks in when I want to give different starting coordinates to 'Hero' and 'BadGuy' objects. Currently if I set them different, the second call of 'Sprite' overrides the first and both start at the same spot (which would be very frustrating if your goal is to run from 'badGuy').
'Hero' and 'BadGuy' are currently initialized this way:
public class BadGuy extends Sprite {
public BadGuy() {
super(x, y);
initBadGuy();
}
public void initBadGuy() {
loadImage("resources/craft.gif");
getImageDimensions();
x = 860; // Hero x = 20;
y = 560; // Hero y = 20;
}
So what I tried to do is make the subclasses override Sprite's x and y. But I googled it and I understand that this is very bad idea and thus it is not possible. So my question is something like: How can I make 'Sprite' inherit subclass 'x' and 'y' variables and perform the necessary methods when the certain subclass is called.
Now that I look at it - both the constructor and init<>() are identical for the subclasses, so maybe they can be implemented in 'Sprite' instead? Just a thought, but I'm getting quite confused already, so no idea.
Thanks.
You are getting this problem because x and y are declared as static fields in your Sprite class.
From JLS 8.3.1.1. static Fields
If a field is declared static, there exists exactly one incarnation of the field, no matter how many instances (possibly zero) of the class may eventually be created. A static field, sometimes called a class variable, is incarnated when the class is initialized (§12.4).
Use following code:
Change your Sprite Class like below:
public class Sprite {
public int x;
public int y;
....
}
BadGuy class:
public class BadGuy extends Sprite {
public BadGuy(int x, int y) {
super(x, y);
...
}
....
}
Hero class:
public class Hero extends Sprite {
public Hero(int x, int y) {
super(x, y);
...
}
....
}
From Main class do following: //From where you want to create Object of both classes
public static void main(String[] args){
Hero hero = new Hero(20,20);
BadGuy badGuy= new BadGuy(860,560);
}
I have
class A {
int var;
public A(int x) {
var = x;
}
}
class B extends A {
int var2;
public B(int x, int y) {
super(...);
var2 = y;
x = f(y);
}
}
For the subclass B, I need to calculate the value x that is used in the constructor of A. If I were free to move super below my x=f(y) then I could pass in the result to the constructor of A (super). But super has to be the first line in the constructor of B.
Is there any way to initialize A with the proper value the first time? What if A.var were final and i couldn't go back and change it after construction?
Sure, I could put super(f(y)), but I could imagine cases where this would become difficult.
Assuming var is private and you need to set the value with the constructor (which seems to be the point of the question, otherwise there are many easy solutions), I would just do it with a static factory-like method.
class B extends A {
int var2;
public static B createB(int x, int y) {
x = f(y);
return new B(x, y);
}
public B(x, y) {
super(x);
this.var2 = y;
}
}
something like that. You have no choice, as explicit constructor invocation must happen on the first line of the wrapping constructor.
You can do it like this :
class B extends A {
int var2;
public B(int x, int y) {
super(calculateX(y));
var2 = y;
}
private static int calculateX(int y) {
return y;
}
}
Calling a static method is the only thing you can do before calling the superclass constructor.
Alternative to hvgotcodes, since it looks like you also want to set A's variable...
class B extends A {
int var2;
public B(int x, int y) {
super(x);
var2 = y;
x = f(y);
super.var = ...;
}
}
Another approach could be to add a protected constructor without parameters to A that relies on lazy initialization:
class A {
int var;
public A(int x) {
var = x;
}
/**
* Just use this constructor if you initialize var
*/
protected A(int x) {
}
}
class B extends A {
int var2;
public B(int x, int y) {
super();
var2 = y;
var = f(y);
}
}
But that's hard to document, not very obvious to team members and shouldn't be used for an api.
I have a question similar to In Java, why can't I declare a final member (w/o initializing it) in the parent class and set its value in the subclass? How can I work around? but which requires a different solution. As in the above case, I want to declare a variable to be Final in the superclass, but I want the subclass to give it the value. What makes my problem different though is that I don't want the value passed in to the subclass, I want the subclass to 'know' its value, so the above solution doesn't work for me. Then I tried to do this:
public class Superclass{
public final int x;
public Superclass(int x){
this.x = x;
}
}
public class Subclass extends Superclass{
public Subclass(){
x = 1;
super(x);
}
}
...which didn't work (the call to super() must be on the first line :/ ). But this is basically the behavior that I want. Is there a good way to do this? Thanks!
You could do
super(1);
so instead of setting x, you are passing the value.
An alternative to the one above:
class Superclass{
public final int x;
public Superclass(int x){
this.x = x;
}
public static Superclass createNew(Integer y) {
return new Superclass(y);
}
public void print() {
System.out.println(this.x);
}
}
class Subclass extends Superclass{
public Subclass(int x) {
super(process(x));
}
public static Integer process(Integer y) {
if (y < 100)
y += 100;
return y;
}
}
I don't have a java compiler handy, but you're attempting to set x = 1 twice in this code.
x = 1;
And
super(x); //==> this.x = x
Do as #Kal said and do super(1), as x = 1 won't work.