subclass elements from an arraylist won't use the overriden method in Java -
i have arraylist class (piece) want pick items subclass (miner , bomb). however, when pick items use methods of super class (piece), , not it's subclasses.
since arraylist<pieces>
contain several subclass objects of pieces, not possible define more specific class arraylist. possible pick elements arraylist , still use methods subclasses?
(i found little hard find solution simple problem. searched overriding, arraylist, methods along other things, couldn't find it. if obvious found, i'd know found it.)
class main:
import java.util.arraylist; public class main { public static void main(string[] args) { arraylist<piece> piecelist = new arraylist<>(); piecelist.add(new miner()); piecelist.add(new bomb()); // create new classes test candefeat if (new miner().candefeat(new bomb())) { system.out.println("yes! line printed."); } system.out.println(); // test candefeat pieces piecelist if (piecelist.get(0).candefeat(piecelist.get(1))) { system.out.println("no, line not printed"); } } }
class piece:
public abstract class piece { public boolean candefeat(piece opponent) { return false; } }
class miner:
public class miner extends piece { public boolean candefeat(bomb opponent) { return true; } }
class bomb:
public class bomb extends piece { }
the why of easy:
your
miner
doesn't overridecandefeat(piece)
, adds new method signaturecandefeat(bomb)
.in code
piecelist.get(0).candefeat(piecelist.get(1))
, compiler has work typepiece
, , resolvespiece#candefeat(piece)
.
the what instead more tricky.
i suggest kinds of pieces can defeat other kinds of pieces isn't attribute of each piece; 1 thing, brittle if change rules.
instead, @ alternatives like:
perhaps each piece can have strength level, higher strength means piece can defeat piece lower strength. (example below.)
you have
battlelogic
class can compare types of pieces determine outcome, either work strength per above, or type usinginstanceof
, etc. normally, when reachinstanceof
need stop , think you're doing , whether it's right tool job (it isn't), may right tool this job. advantagebattlelogic
class none of pieces knows other pieces; instead, have 1 thing understands game whole , how pieces rank when fight. (example below.)
if want each piece
know other types of pieces can defeat, can that, think tend lead unmaintainable mess. 2 ways come mind:
having list of types can defeat. (example below.)
using reflection achieve trying originally. (example below.)
here's strength suggestion in code:
import java.util.arraylist; class piece { private int strength; public piece(int strength) { this.strength = strength; } public int getstrength() { return this.strength; } public boolean candefeat(piece opponent) { return this.getstrength() > opponent.getstrength(); } } class miner extends piece { public miner() { super(10); } } class bomb extends piece { public bomb() { super(5); } } public class main { public static void main(string[] args) { arraylist<piece> piecelist = new arraylist<>(); piecelist.add(new miner()); piecelist.add(new bomb()); // create new classes test candefeat if (new miner().candefeat(new bomb())) { system.out.println("yes! line printed."); } system.out.println(); // test candefeat pieces piecelist if (piecelist.get(0).candefeat(piecelist.get(1))) { system.out.println("yes! line printed"); } } }
and battlelogic
suggestion in code:
import java.util.arraylist; abstract class piece { } class miner extends piece { } class bomb extends piece { } class battlelogic { /** * battle between 2 pieces. * * @param first piece * @param b second piece * @return 0 tie, negative number if beats b, or positive number if b beats */ public static int battle(piece a, piece b) { if (a instanceof miner && b instanceof bomb) { return -1; } // ...further tests here... return 0; } } public class main { public static void main(string[] args) { arraylist<piece> piecelist = new arraylist<>(); piecelist.add(new miner()); piecelist.add(new bomb()); // create new classes test candefeat if (battlelogic.battle(new miner(), new bomb()) < 0) { system.out.println("yes! line printed."); } system.out.println(); // test candefeat pieces piecelist if (battlelogic.battle(piecelist.get(0), piecelist.get(1)) < 0) { system.out.println("yes! line printed"); } } }
here's third suggestion, having each type of piece know pieces can defeat, in case. again, though, don't suggest this; think having pieces know each other going maintenance problem:
// not recommended import java.util.list; import java.util.arraylist; abstract class piece { private list<class> idefeat; public piece(class... defeats) { this.idefeat = new arraylist<class>(); (class c : defeats) { this.idefeat.add(c); } } public boolean candefeat(piece piece) { return this.idefeat.contains(piece.getclass()); } } class bomb extends piece { } class miner extends piece { public miner() { super(bomb.class); } } public class main { public static void main(string[] args) { arraylist<piece> piecelist = new arraylist<>(); piecelist.add(new miner()); piecelist.add(new bomb()); // create new classes test candefeat if (new miner().candefeat(new bomb())) { system.out.println("yes! line printed."); } system.out.println(); // test candefeat pieces piecelist if (piecelist.get(0).candefeat(piecelist.get(1))) { system.out.println("yes! line printed"); } } }
or make list static if you're going have millions of pieces , memory issue; sketch.
and finally, way using reflection:
// not reall recommended import java.lang.reflect.method; import java.util.arraylist; class piece { public piece() { } private static method getmethodornull(class cls, string name, class... paramtypes) { try { return cls.getmethod(name, paramtypes); } catch (nosuchmethodexception nsme) { return null; } } public boolean candefeat(piece opponent) { try { class thisclass = this.getclass(); class oppclass = opponent.getclass(); method m = null; while (oppclass != piece.class && (m = getmethodornull(thisclass, "candefeat", oppclass)) == null) { oppclass = oppclass.getsuperclass(); } if (m != null) { return (boolean)m.invoke(this, opponent); } return false; } catch (exception iae) { throw new runtimeexception("can't access method", iae); } } } class miner extends piece { public boolean candefeat(bomb b) { return true; } } class bomb extends piece { } public class main { public static void main(string[] args) { arraylist<piece> piecelist = new arraylist<>(); piecelist.add(new miner()); piecelist.add(new bomb()); // create new classes test candefeat if (new miner().candefeat(new bomb())) { system.out.println("yes! line printed."); } system.out.println(); // test candefeat pieces piecelist if (piecelist.get(0).candefeat(piecelist.get(1))) { system.out.println("yes! line printed"); } } }
Comments
Post a Comment