Java Serialize with Inheritance? - java

Here is the Goals.java
public abstract class Goals {
private String score;
public Goals(String str) {
this.score = str;
}
String getGoals() {
return this.score;
}
void doSomething(score) {
}
}
Here is the Game.java
public class Game implements Serializable {
public String name;
public int game_num;
public int opp;
public int player;
public Goals goal;
public Game(int i, int i2, int i3) {
this.player = i;
this.game_num = i2;
this.opp = i3;
}
public Game(String str, Goals goal) {
this.name = str;
this.goal = goal;
}
}
Can we create a Serialized Object in a way that after it is deserialized and casted to Game , it will set score inside Goals.java ?
Also, can you manipulate / overwrite doSomething method if the serialized data comes from untrusted source?

In the way you are trying to manipulates your objects, I think you can do that Goals implements Serializable, and Game implements Goals:
public abstract class Goals implements Serializable{
private String score;
public Goals(String str) {
this.score = str;
}
String getGoals() {
return this.score;
}
void doSomething(score) {
}
}
for Game
public class Game extends Goals {
public String name;
public int game_num;
public int opp;
public int player;
public Game(int i, int i2, int i3) {
this.player = i;
this.game_num = i2;
this.opp = i3;
}
public Game(String str) {
//create constructor also including the properties of Goals
Super()...
}
}

As mentioned in comments, implement Goals and its implementation with Serializable and also implement default constructor in both the classes .
Working piece of code:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
abstract class Goals implements Serializable{
private String score;
public Goals() {
this(null);
}
public Goals(String str) {
this.score = str;
}
String getGoals() {
return this.score;
}
void doSomething(int score) {
}
}
class Game implements Serializable {
public String name;
public int game_num;
public int opp;
public int player;
public Goals goal;
public Game(int i, int i2, int i3) {
this.player = i;
this.game_num = i2;
this.opp = i3;
}
public Game(String str, Goals goal) {
this.name = str;
this.goal = goal;
}
}
class GoalImpl extends Goals implements Serializable{
public GoalImpl() {
}
public GoalImpl(String str) {
super(str);
}
}
public class Main{
public static void main(String...s) {
Goals goal = new GoalImpl("20");
Game game = new Game("name",goal);
try
{
//Saving of object in a file
FileOutputStream file = new FileOutputStream("gamefile.ser");
ObjectOutputStream out = new ObjectOutputStream(file);
// Method for serialization of object
out.writeObject(game);
out.close();
file.close();
System.out.println("Object has been serialized");
}
catch(IOException ex)
{
ex.printStackTrace();
System.out.println("IOException is caught");
}
Game object1 = null;
// Deserialization
try
{
// Reading the object from a file
FileInputStream file = new FileInputStream("gamefile.ser");
ObjectInputStream in = new ObjectInputStream(file);
// Method for deserialization of object
object1 = (Game)in.readObject();
in.close();
file.close();
System.out.println("Object has been deserialized ");
System.out.println("score = " + object1.goal.getGoals());
}
catch(IOException ex)
{
ex.printStackTrace();
System.out.println("IOException is caught");
}
catch(ClassNotFoundException ex)
{
System.out.println("ClassNotFoundException is caught");
}
}
}
Output:
Object has been serialized
Object has been deserialized
score = 20
PS:
An advice to make score as integer as otherwise you will not be able to do basic operations like increase score or decrease score using inbuilt operators (+ , - )
Always place proper getter setter name like getScore() and setScore int this case.
Do try to make constructors in sync, for example in case of Game constructor with player id, game num and opposition is called, Game name and Goals will never be initialized, better to initialize them with default value or other good option is make another constructor accepting all parameters and then from individual constructos you can call master constructor and pass default values for those which are not passed by the calling method.

Related

My getters and setters aren't wokring correctly

As I'm going though the debugger it looks like it is working at first, however when I try calling getCoordinates() in my shipSunk() method, it returns a null value almost every time. What is wrong here?
public boolean shipSunk(ShipDerived[] s){
ArrayListMultimap<Integer, Integer> temp;
ArrayList<Integer> temp2 = new ArrayList<>();
boolean sunk = false;
for(int i=s.length-1; i>=0;i--){
Ship st = s[i];
temp = s[i].getCoordinates(); //returns null almost every time???
temp2 = s[i].getCoordinatesList();
for (Map.Entry<Integer, Integer> entry : temp.entries()){
//System.out.println(entry.getKey() + ", " + entry.getValue());
if(grid[entry.getKey()][entry.getValue()]=='x'){
sunk = true;
}
else{
sunk = false;
}
}
if(sunk==true){
System.out.println("Ship has been sunk!");
}
temp.clear();
}
return sunk;
}
And here is my Ship class (extended from abstract class) methods:
import java.util.ArrayList;
public class ShipDerived extends Ship{
private String type;
private int length;
private ArrayListMultimap<Integer, Integer> coordinates = ArrayListMultimap.create();
private ArrayList<Integer> c2 = new ArrayList<>();
public ShipDerived(){
this.type = type;
this.length = length;
this.coordinates = getCoordinates();
this.c2 = getCoordinatesList();
}
public ShipDerived(String t, int l){
this.type = t;
this.length = l;
this.coordinates = getCoordinates();
this.c2 = getCoordinatesList();
}
#Override
void setType(String t) {
type = t;
}
#Override
void setLength(int l) {
length = l;
}
#Override
String getType() {
return type;
}
#Override
int getLength() {
return length;
}
#Override
ArrayListMultimap<Integer, Integer> getCoordinates() {
return this.coordinates;
}
ArrayList<Integer> getCoordinatesList() {
return this.c2;
}
#Override
void setCoordinates(int i, int j) {
//coordinates.putAll(i, Collections.singleton(j));
this.coordinates.put(i,j);
this.c2.add(i);
this.c2.add(j);
}
}
Here is my Ship (abstract) class:
public abstract class Ship {
private int length;
private String type;
private ArrayListMultimap<Integer, Integer> coordinates;
Ship(){
this.length = length;
this.type = type;
}
abstract void setType(String t);
abstract void setLength(int l);
abstract String getType();
abstract int getLength();
abstract ArrayListMultimap<Integer, Integer> getCoordinates();
abstract void setCoordinates(int i, int j);
}
And this is what I am passing into my shipSunk() method. I an using getters/setters to create my ships:
p1board.shipSunk(p1.getShips()); //player 1
p2board.shipSunk(p2.getShips()); //player 2
These seem to work but here's some code into these as well:
public class Player {
private String name;
private ShipDerived[] ships = new ShipDerived[5];
public Player(){
this.name = name;
this.ships = ships;
}
public String getName(){
return name;
}
public void setName(String x){
name = x;
}
public void setShips(){
int a = 0;
for(int i=5; i>=1;i--){
ShipDerived s = new ShipDerived("null", 0);
Array.set(ships, a, s);
a++;
}
ships[0].setType("carrier");
ships[0].setLength(5);
ships[1].setType("battleship");
ships[1].setLength(4);
ships[2].setType("destroyer");
ships[2].setLength(3);
ships[3].setType("submarine");
ships[3].setLength(3);
ships[4].setType("patrol boat");
ships[4].setLength(2);
}
public ShipDerived[] getShips(){
return ships;
}
You initialize this.coordinates twice. First as an inline field initializer and second in the constructor. The statement this.coordinates = getCoordinates(); does not make sense because the getter returns this.coordinates, so you effectively get this.coordinates = this.coordinates;
This shouldn't effect your issue, but my recommendation for easier debugging is to just set all fields that you can to final to avoid issues such as this and remove the superfluous call from the constructor.
Then I would investigate the ArrayListMultimap.create(); method, if there is any way that one returns null.
You have #Override annotation on getCoordinates() so I'm guessing your Ship class also have coordinates field. In shipSunk method you cast your object to Ship class so most likely it operate on field Ship.coordintes whis is null because you are initializing only DerivedShip.coordinates.
Check this for simple example of hiding fields: If you overwrite a field in a subclass of a class, the subclass has two fields with the same name(and different type)?
There are so many strange things in your code:
Why has the Ship class private fields if you don't provide access methods for those fields? Without accessor methods nobody can use those fields, so just delete them!
Why do the ShipDerived constructors initialize the coordinates and c2 fields if you already initialize them at the declaration?
Why does Player.setShips() use some obscure Array.set(ships, a, s); when ships[a] = s; would be sufficient?
Why do your constructors (for Ship, ShipDerived and Player) contain nonsense-code like this.type = type; (in ShipDeriveds default constructor) that seems important but does nothing?
Why does the Player.setShips() method create empty ShipDerived instances and only afterwards sets their values?
After some cleanup your classes could look like:
Ship.java:
import com.google.common.collect.ArrayListMultimap;
public abstract class Ship {
Ship(){
}
abstract void setType(String t);
abstract void setLength(int l);
abstract String getType();
abstract int getLength();
abstract ArrayListMultimap<Integer, Integer> getCoordinates();
abstract void setCoordinates(int i, int j);
}
ShipDerived.java:
import java.util.ArrayList;
import com.google.common.collect.ArrayListMultimap;
public class ShipDerived extends Ship{
private String type;
private int length;
private ArrayListMultimap<Integer, Integer> coordinates = ArrayListMultimap.create();
private ArrayList<Integer> c2 = new ArrayList<>();
public ShipDerived(){
}
public ShipDerived(String t, int l){
this.type = t;
this.length = l;
}
#Override
void setType(String t) {
type = t;
}
#Override
void setLength(int l) {
length = l;
}
#Override
String getType() {
return type;
}
#Override
int getLength() {
return length;
}
#Override
ArrayListMultimap<Integer, Integer> getCoordinates() {
return this.coordinates;
}
ArrayList<Integer> getCoordinatesList() {
return this.c2;
}
#Override
void setCoordinates(int i, int j) {
this.coordinates.put(i, j);
this.c2.add(i);
this.c2.add(j);
}
}
Player.java:
public class Player {
private String name;
private ShipDerived[] ships = new ShipDerived[5];
public Player(){
}
public String getName(){
return name;
}
public void setName(String x){
name = x;
}
public void setShips(){
ships[0] = new ShipDerived("carrier", 5);
ships[1] = new ShipDerived("battleship", 4);
ships[2] = new ShipDerived("destroyer", 3);
ships[3] = new ShipDerived("submarine", 3);
ships[4] = new ShipDerived("patrol boat", 2);
}
public ShipDerived[] getShips(){
return ships;
}
}
These changes might not yet solve your issue, but at least make your code easier to read and understand.
Actually, since the Ship class no longer contains any fields and has only abstract methods you could even turn it into an interface (but that would mean that your methods are now public instead of package private, which would mean that you would also need to declare them as public in ShipDerived).
Ship.java, interface version:
import com.google.common.collect.ArrayListMultimap;
public interface Ship {
void setType(String t);
void setLength(int l);
String getType();
int getLength();
ArrayListMultimap<Integer, Integer> getCoordinates();
void setCoordinates(int i, int j);
}

Read and write Parcel when using ArrayList of ArrayList

I'm trying to read and write this ArrayList structured as well: ArrayList<ArrayList<Pair<Float,Float>>> points I've seen that the only way would by using the class inside the external ArrayList, but in this case I haven't it. This is my full class, how do I can implement it?
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Pair;
import java.io.Serializable;
import java.util.ArrayList;
public class Cornice implements Serializable, Parcelable {
private String number;
private ArrayList<ArrayList<Pair<Float,Float>>> points;
public Cornice(String n, ArrayList<ArrayList<Pair<Float,Float>>> p) {
number = n;
if (p!=null) points = new ArrayList<>(p);
else points=new ArrayList<>();
}
protected Cornice(Parcel in) {
number = in.readString();
points = //MISSING
}
public String getNumber () {
return number;
}
public ArrayList<ArrayList<Pair<Float,Float>>> getPoints () {
return points;
}
public static final Creator<Cornice> CREATOR = new Creator<Cornice>() {
#Override
public Cornice createFromParcel(Parcel in) {
return new Cornice(in);
}
#Override
public Cornice[] newArray(int size) {
return new Cornice[size];
}
};
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(number);
//MISSING
}
}
Pair is neither Parcelable, nor Serializable, so what you are trying to do won't work. You will have to change the data structure you use to hold the points to something else. For example you can convert it something like this:
private ArrayList<ArrayList<Float[]>> points;
or even (if you do not want to support null values) to:
private ArrayList<ArrayList<float[]>> points;

List<List<Box>> is not Serialized

I have a class Player that has three variables, one of these is a List<List<Box>> and of course class Box does implement Serializable.
Box has some variables too, all of them are primitive types except for a class Dice which does implement Serializable too.
I have to send this class through the network with a socket and when I send this to the Client side the List<List<Box>> looks ok, and each Box too, the problem is that the Dice class that should be in the Box is always set to null even if the one I sent to the Client from the Server is not and I am absolutely sure that the network part is correct.
Forgot to mention that List<List<Box>> when instantiated becomes an ArrayList<ArrayList<Box>> which should be Serializable.
Dice class:
package ingsw.model;
import java.io.Serializable;
import java.util.Random;
public class Dice implements Serializable {
private int faceUpValue;
private final Color diceColor;
public Dice(Color diceColor) {
this.diceColor = diceColor;
}
public Dice(int faceUpValue, Color diceColor) {
this.faceUpValue = faceUpValue;
this.diceColor = diceColor;
}
/**
* Draft the dice
* get a random number between 1 and 6 and set the faceUpValue
*/
void roll() {
int value = (new Random()).nextInt(6) + 1;
setFaceUpValue(value);
}
public int getFaceUpValue() {
return faceUpValue;
}
public void setFaceUpValue(int faceUpValue) {
this.faceUpValue = faceUpValue;
}
public Color getDiceColor() {
return diceColor;
}
#Override
public String toString() {
if (faceUpValue != 0) {
return diceColor.toString() + String.valueOf(faceUpValue);
} else {
return diceColor.toString();
}
}
}
Card class implements Serializable:
public abstract class PatternCard extends Card {
private int difficulty;
protected List<List<Box>> grid;
public PatternCard(String name, int difficulty) {
super(name);
fillGrid();
this.difficulty = difficulty;
}
#Override
public String toString() {
return "PatternCard{" +
"'" + getName() + "'" +
'}';
}
public int getDifficulty() {
return difficulty;
}
public void setGrid(List<List<Box>> grid) {
this.grid = grid;
}
public List<List<Box>> getGrid() {
return grid;
}
private void fillGrid() {
this.grid = new ArrayList<>(4);
this.grid.add(new ArrayList<>(5));
this.grid.add(new ArrayList<>(5));
this.grid.add(new ArrayList<>(5));
this.grid.add(new ArrayList<>(5));
}
}
Box class:
public class Box implements Serializable {
private Color color;
private Integer value;
private Dice dice;
public Box(Color color) {
this.color = color;
}
public Box(Integer value) {
this.value = value;
}
public Color getColor() {
return color;
}
public Integer getValue() {
return value;
}
public boolean isValueSet() {
return value != null;
}
public void insertDice(Dice dice) {
this.dice = dice;
//TODO the dice at this point must removed from the dice drafted --> dices (set).remove();
}
public void removeDice() {
if (dice != null) dice = null;
//TODO dice must be re-added?
}
public Dice getDice() {
return dice;
}
#Override
public String toString() {
if (isValueSet()) return String.valueOf(value);
else return color.toString();
}
Boolean isDiceSet(){ return dice != null; }
}
I've investigated a bit and thought that I should probably Serialize the object and De-serialize it by myself but I don't know if that could be the real issue here since ArrayLists are Serializable and every object inluded in these ArrayLists are too.
What could possibly be wrong in this?

Java Custom Event Handling

Good Day,
I am writing a custom event handler in Java. I have a class called BoogieCarMain.java that instantiates three instances of a type called BoogieCar. Whenever any of the three instances exceeds a certain speed limit, then an event should be fired off. The code I currently have is working, so here is what I have:
// BoogieCar.java
import java.util.ArrayList;
public class BoogieCar {
private boolean isSpeeding = false;
private int maxSpeed;
private int currentSpeed;
private String color;
BoogieSpeedListener defaultListener;
public BoogieCar(int max, int cur, String color) {
this.maxSpeed = max;
this.currentSpeed = cur;
this.color = color;
}
public synchronized void addSpeedListener(BoogieSpeedListener listener) {
defaultListener = listener;
}
public void speedUp(int increment) {
currentSpeed += increment;
if (currentSpeed > maxSpeed) {
processSpeedEvent(new BoogieSpeedEvent(maxSpeed, currentSpeed, color));
isSpeeding = true;
} else {
isSpeeding = false;
}
}
public boolean getSpeedingStatus() {
return isSpeeding;
}
private void processSpeedEvent(BoogieSpeedEvent speedEvent) {
defaultListener.speedExceeded(speedEvent);
}
}
// BoogieCarMain.java
import java.util.ArrayList;
public class BoogieCarMain {
public static void main(String[] args) {
BoogieCar myCar = new BoogieCar(60, 50, "green");
BoogieCar myCar2 = new BoogieCar(75, 60, "blue");
BoogieCar myCar3 = new BoogieCar(65, 25, "pink");
BoogieSpeedListener listener = new MySpeedListener();
myCar.addSpeedListener(listener);
myCar2.addSpeedListener(listener);
myCar3.addSpeedListener(listener);
myCar.speedUp(50); // fires SpeedEvent
System.out.println(myCar.getSpeedingStatus());
myCar2.speedUp(20);
System.out.println(myCar2.getSpeedingStatus());
myCar3.speedUp(39);
System.out.println(myCar3.getSpeedingStatus());
}
}
// BoogieSpeedListener.java
public interface BoogieSpeedListener { // extends java.util.EventListener
public void speedExceeded(BoogieSpeedEvent e);
}
// MySpeedListener.java
public class MySpeedListener implements BoogieSpeedListener {
#Override
public void speedExceeded(BoogieSpeedEvent e) {
if (e.getCurrentSpeed() > e.getMaxSpeed()) {
System.out.println("Alert! The " + e.getColor() + " car exceeded the max speed: " + e.getMaxSpeed() + " MPH.");
}
}
}
// BoogieSpeedEvent.java
public class BoogieSpeedEvent { // extends java.util.EventObject
private int maxSpeed;
private int currentSpeed;
private String color;
public BoogieSpeedEvent(int maxSpeed, int currentSpeed, String color) {
// public SpeedEvent(Object source, int maxSpeed, int minSpeed, int currentSpeed) {
// super(source);
this.maxSpeed = maxSpeed;
this.currentSpeed = currentSpeed;
this.color = color;
}
public int getMaxSpeed() {
return maxSpeed;
}
public int getCurrentSpeed() {
return currentSpeed;
}
public String getColor() {
return color;
}
}
My question is: While this code works, I would like the BoogieCar type to notify BoogieCarMain directly without me have to "poll" the BoogieCar type by having to invoke the getSpeedingStatus() method.
In other words, perhaps defining a variable in BoogieCarMain.java that changes whenever one of the three cars exceeds its predefined speed limit. Is it possible to have the BoogieCar type set the variable?
Is there a cleaner way to do this?
TIA,
coson
Callbacks are ideal for this scenario.
// BoogieCarMain provides a sink for event-related information
public void handleSpeeding(BoogieCar car) {
System.out.println(car.getSpeedingStatus());
}
// MySpeedListener knows about an object that wants event-related information.
// I've used the constructor but an addEventSink method or similar is probably better.
public MySpeedListener(BoogieCarMain eventSink) {
this.eventSink = eventSink;
}
// MySpeedListener handles events, including informing objects that want related information.
// You decide if the event is an appropriate type for the sink to know about.
// Often it isn't, and instead your listener should pull the relevant info out of the event and pass it to the sink.
public void speedExceeded(BoogieSpeedEvent e) {
if (e.getCurrentSpeed() > e.getMaxSpeed()) {
// I've taken the liberty of adding the event source as a member of the event.
eventSink.handleSpeeding(e.getCar());
}
}

Cannot Find Symbol Method Error

I have an assignment from my Java 1 class (I'm a beginner) and the question instructs us to make some code more object-oriented. I've done what I can for the assignment, but one of my files consistently gives me a Cannot Find Symbol Method error even though the files are in the same project. I know the methods are there, so what's going on? The error only occurs in AlienPack, which doesn't seem to recognize the other files, all of which are in the same project (including AlienPack). The getDamage() method that's being called in AlienPack isn't being found (it's in SnakeAlien, OgreAlien, etc).
EDIT: The new error for the getDamage() methods I'm trying to invoke in AlienPack is that the methods still aren't being found. AlienDriver can't find calculateDamage() either.
Here's the code I've got so far:
Alien:
public class Alien {
// instance variables
private String name;
private int health;
// setters
public void setName(String n) {
name = n; }
public void setHealth(int h) {
if(h>0&&h<=100) {
health = h;
} else {
System.out.println("Error! Invalid health value!");
System.exit(0); } }
// getters
public String getName() {
return name; }
public int getHealth() {
return health; }
// constructors
public Alien() {
setName("No name");
setHealth(100); }
public Alien(String n, int h) {
setName(n);
setHealth(h); }
public Alien(Alien anAlien) {
setName(anAlien.getName());
setHealth(anAlien.getHealth()); }
public Alien clone() {
return new Alien(this);
} }
SnakeAlien:
public class SnakeAlien extends Alien { // new file
// instance variables
private int damage;
// setters
public void setDamage(int d) {
if(d>0) {
damage = d;
} else {
System.out.println("Error! Invalid damage value!");
System.exit(0); } }
// getters
public int getDamage() {
return damage; }
// constructors
public SnakeAlien() {
super();
setDamage(0); }
public SnakeAlien(String n, int h, int d) {
super(n, h);
setDamage(d); }
public SnakeAlien(SnakeAlien anAlien) {
super(anAlien);
setDamage(anAlien.getDamage()); }
public SnakeAlien clone() {
return new SnakeAlien(this);
} }
OgreAlien:
public class OgreAlien extends Alien { // new file
// instance variables
private int damage;
// setters
public void setDamage(int d) {
if(d>0) {
damage = d;
} else {
System.out.println("Error! Invalid damage value!");
System.exit(0); } }
// getters
public int getDamage() {
return damage; }
// constructors
public OgreAlien() {
super();
setDamage(0); }
public OgreAlien(String n, int h, int d) {
super(n, h);
setDamage(d); }
public OgreAlien(OgreAlien anAlien) {
super(anAlien);
setDamage(anAlien.getDamage()); }
public OgreAlien clone() {
return new OgreAlien(this);
} }
MarshmallwManAlien:
public class MarshmallowManAlien extends Alien { // new file
// instance variables
private int damage;
// setters
public void setDamage(int d) {
if(d>0) {
damage = d;
} else {
System.out.println("Error! Invalid damage value!");
System.exit(0); } }
// getters
public int getDamage() {
return damage; }
// constructors
public MarshmallowManAlien() {
super();
setDamage(0); }
public MarshmallowManAlien(String n, int h, int d) {
super(n, h);
setDamage(d); }
public MarshmallowManAlien(MarshmallowManAlien anAlien) {
super(anAlien);
setDamage(anAlien.getDamage()); }
public MarshmallowManAlien clone() {
return new MarshmallowManAlien(this);
} }
AlienPack:
public class AlienPack { // new file, this one isn't recognizing the others
// instance variables
private Alien[] pack;
// setters
public void setPack(Alien[] aliens) {
pack = new Alien[aliens.length];
for(int i = 0; i<aliens.length; i++) {
pack[i]=aliens[i].clone(); } }
// getters
public Alien[] getPack() {
Alien[] temp = new Alien[pack.length];
for(int i = 0; i<pack.length; i++) {
temp[i]=pack[i].clone(); }
return temp; }
// constructors
public AlienPack() {
Alien[] nothing = new Alien[1];
nothing[0]=null;
setPack(nothing); }
public AlienPack(Alien[] aliens) {
setPack(aliens);}
// other methods
public int calculateDamage() {
int damage = 0;
for(int i = 0; i<pack.length; i++) {
if((new SnakeAlien()).getClass()==pack[i].getClass()) {
pack[i].getDamage() +=damage;
} else if((new OgreAlien()).getClass()==pack[i].getClass()) {
pack[i].getDamage() +=damage;
} else if((new MarshmallowManAlien()).getClass()==pack[i].getClass()) {
pack[i].getDamage() +=damage;
} else {
System.out.println("Error! Invalid object!");
System.exit(0); } }
return damage; } }
AlienDriver:
public class AlienDriver { // driver class
public static void main(String[] args) {
Alien[] group = new Alien[5];
group[0]= new SnakeAlien("Bobby", 100, 10);
group[1]= new OgreAlien("Timmy", 100, 6);
group[2]= new MarshmallowManAlien("Tommy", 100, 1);
group[3]= new OgreAlien("Ricky", 100, 6);
group[4]= new SnakeAlien("Mike", 100, 10);
System.out.println(group.calculateDamage());
} }
Two problems:
pack[i].getClass().getDamage() ...
should be just
pack[i].getDamage() ...
You seem to be confused about what the getClass() method does. It returns an object which represents the class (i.e. java.lang.Class) of another object. It is used for reflection. To invoke getDamage() you would just invoke it directly on pack[i] as shown above.
However...
You are attempting to invoke the method getDamage() using a reference of type Alien, which is a base class of all the concrete alien types. If you want to do it that way,
getDamage() needs to be declared abstract in the base class so it can be found and dispatched to the correct subclass when invoking it via an Alien reference.
In Alien:
public abstract class Alien {
...
public abstract int getDamage();
An alternative is to cast to the appropriate subclass at each point since you know what it is:
((SnakeAlien)pack[i]).getDamage() +=damage;
However (again) even that is wrong. You can't apply += to an "rvalue". What you need to do here is either:
Also declare setDamage() abstract in Alien and do pack[i].setDamage(pack[i].getDamage()+damage);
If casting, ((SnakeAlien)pack[i]).setDamage( ((SnakeAlien)pack[i].getDamage()) + damage);
My Recommendation:
In class Alien:
public abstract class Alien {
...
private int damage = 0; // Move damage up to the abstract base class
public int addToDamage(int n) { this.damage += n; }
...
}
In your driver, no need to test the class. Invoke the addToDamage() method on the Alien reference.
I think that at least part of your problem is the getClass() method. You are expecting it to return an object but it does not. Just call directly to the array.
pack[I].getDamage()
should work assuming that the correct type of object is stored in pack()

Categories

Resources