arraylist中的子类元素赢得';不要在Java中使用重写的方法
我有一个带有特定类(片段)的ArrayList,我想从中挑选带有子类(Miner和Bomb)的项。然而,当我选择一些项目时,它将使用超类(Piece)的方法,而不是它的子类 由于arraylist中的子类元素赢得';不要在Java中使用重写的方法,java,methods,arraylist,subclass,overriding,Java,Methods,Arraylist,Subclass,Overriding,我有一个带有特定类(片段)的ArrayList,我想从中挑选带有子类(Miner和Bomb)的项。然而,当我选择一些项目时,它将使用超类(Piece)的方法,而不是它的子类 由于ArrayList将包含多个片段的子类对象,因此无法为ArrayList定义更具体的类。是否可以从ArrayList中选择一些元素,并且仍然使用子类中的方法 (我发现要找到这个简单问题的解决方案有点困难。我搜索了overriding、arrayList和其他一些方法,但找不到它。如果它太明显而找不到,我想知道您是在哪里找
ArrayList
将包含多个片段的子类对象,因此无法为ArrayList定义更具体的类。是否可以从ArrayList中选择一些元素,并且仍然使用子类中的方法
(我发现要找到这个简单问题的解决方案有点困难。我搜索了overriding、arrayList和其他一些方法,但找不到它。如果它太明显而找不到,我想知道您是在哪里找到的。)
班长:
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 to test canDefeat
if (new Miner().canDefeat(new Bomb())) {
System.out.println("Yes! This line will be printed.");
}
System.out.println();
// test canDefeat with pieces from the pieceList
if (pieceList.get(0).canDefeat(pieceList.get(1))) {
System.out.println("No, this line will not be printed");
}
}
}
职业矿工:
public class Miner extends Piece {
public boolean canDefeat(Bomb opponent) {
return true;
}
}
类炸弹:
public class Bomb extends Piece {
}
Miner
不会覆盖工件的canDefeat
-方法,因为参数类型已缩小。您可以通过添加
@Override
到您认为要重写的方法,以在编译时验证它
此外,在抽象超类中提供默认行为并不是好的OO风格,而是在可能的情况下将行为移动到具体的子类中,因为否则您可能会不自觉地继承您想要覆盖的行为。在您的情况下,将canDefeat
抽象化,并让Bomb
使用Piece
中当前存在的行为来实现它,您只需更改canDefeat
的签名以接受泛型类型,并确保以正确的方式进行重写,两个签名始终相同
件类
public abstract class Piece {
public boolean canDefeat(Piece opponent) {
return false;
}
}
public class Miner extends Piece {
@Override
public boolean canDefeat(Piece opponent) { // Piece not Bomb
return true;
}
}
public abstract class Piece<T> {
public boolean canDefeat(T opponent) {
return false;
}
}
public class Miner extends Piece<Bomb> {
@Override
public boolean canDefeat(Bomb opponent) { // Defeats Bomb
return true;
}
}
矿工职业
public abstract class Piece {
public boolean canDefeat(Piece opponent) {
return false;
}
}
public class Miner extends Piece {
@Override
public boolean canDefeat(Piece opponent) { // Piece not Bomb
return true;
}
}
public abstract class Piece<T> {
public boolean canDefeat(T opponent) {
return false;
}
}
public class Miner extends Piece<Bomb> {
@Override
public boolean canDefeat(Bomb opponent) { // Defeats Bomb
return true;
}
}
更新为让矿工只击败炸弹
件类
public abstract class Piece {
public boolean canDefeat(Piece opponent) {
return false;
}
}
public class Miner extends Piece {
@Override
public boolean canDefeat(Piece opponent) { // Piece not Bomb
return true;
}
}
public abstract class Piece<T> {
public boolean canDefeat(T opponent) {
return false;
}
}
public class Miner extends Piece<Bomb> {
@Override
public boolean canDefeat(Bomb opponent) { // Defeats Bomb
return true;
}
}
公共抽象类片段{
公共布尔canDefeat(T对手){
返回false;
}
}
矿工职业
public abstract class Piece {
public boolean canDefeat(Piece opponent) {
return false;
}
}
public class Miner extends Piece {
@Override
public boolean canDefeat(Piece opponent) { // Piece not Bomb
return true;
}
}
public abstract class Piece<T> {
public boolean canDefeat(T opponent) {
return false;
}
}
public class Miner extends Piece<Bomb> {
@Override
public boolean canDefeat(Bomb opponent) { // Defeats Bomb
return true;
}
}
公共类Miner扩展块{
@凌驾
公共布尔canDefeat(炸弹对手){//击败炸弹
返回true;
}
}
为什么这样做很容易:
您的Miner
不会覆盖canDefeat(工件)
,它会添加一个带有签名canDefeat(炸弹)
的新方法
在代码piecelest.get(0).canDefeat(piecelest.get(1))
中,编译器需要处理的只是类型Piece
,因此它将其解析为Piece\canDefeat(Piece)
取而代之的是更棘手的问题
我想说的是,什么样的棋子可以击败其他类型的棋子并不是每一个棋子的属性;首先,如果你改变规则,这会很快变得脆弱
相反,我会考虑以下替代方案:
- 也许每个棋子都有一个强度等级,其中较高的强度意味着该棋子可以击败较低强度的棋子。(以下示例。)
- 您可以拥有一个
BattleLogic
类,该类可以比较不同类型的碎片以确定结果,该类可以根据上述要求使用强度,也可以使用instanceof
按类型进行操作。通常,当你接触到instanceof
时,你需要停下来想想你在做什么,以及它是否真的是适合这份工作的工具(通常不是),但它很可能是适合这份工作的工具。BattleLogic
类的优点是,没有一个片段知道其他片段的任何信息;取而代之的是,你有一件事可以理解整个游戏,以及棋子在战斗时的排名。(以下示例。)
如果你想让每件作品
知道它能击败哪些其他类型的作品,你可以这么做,但我认为这会导致无法维护的混乱。我想到两种方法:
- 列出它可以击败的类型。(以下示例。)
- 使用反射来实现您最初尝试做的事情。(以下示例。)
以下是代码中的强度建议:
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 to test canDefeat
if (new Miner().canDefeat(new Bomb())) {
System.out.println("Yes! This line will be printed.");
}
System.out.println();
// test canDefeat with pieces from the pieceList
if (pieceList.get(0).canDefeat(pieceList.get(1))) {
System.out.println("Yes! This line will also be printed");
}
}
}
import java.util.ArrayList;
abstract class Piece {
}
class Miner extends Piece {
}
class Bomb extends Piece {
}
class BattleLogic {
/**
* Does a battle between the two pieces.
*
* @param a The first piece
* @param b The second piece
* @return 0 for a tie, a negative number if a beats b, or a positive number if b beats a
*/
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 to test canDefeat
if (BattleLogic.battle(new Miner(), new Bomb()) < 0) {
System.out.println("Yes! This line will be printed.");
}
System.out.println();
// test canDefeat with pieces from the pieceList
if (BattleLogic.battle(pieceList.get(0), pieceList.get(1)) < 0) {
System.out.println("Yes! This line will also be printed");
}
}
}
这是第三个建议,让每种类型的棋子都知道它能击败什么棋子,以防万一。不过,我也不建议这样做;我认为让这些部件彼此了解这么多将是一个维护问题:
// Not really 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>();
for (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 to test canDefeat
if (new Miner().canDefeat(new Bomb())) {
System.out.println("Yes! This line will be printed.");
}
System.out.println();
// test canDefeat with pieces from the pieceList
if (pieceList.get(0).canDefeat(pieceList.get(1))) {
System.out.println("Yes! This line will also be printed");
}
}
}
//不太推荐
导入java.util.List;
导入java.util.ArrayList;
抽象类文章{
私人名单;
公开片(类…失败){
this.iDefeat=新的ArrayList();
对于(c类:失败){
本.iDefeat.add(c);
}
}
公共布尔烛台(件){
返回此.iDefeat.contains(piece.getClass());
}
}
类炸弹扩展件{
}
类矿工延伸件{
公共矿工(){
超级(炸弹级);
}
}
公共班机{
公共静态void main(字符串[]args){
ArrayList pieceList=新的ArrayList();
添加(new Miner());
添加(新炸弹());
//创建新类以测试canDefeat
如果(新矿工().canDefeat(新炸弹())){
System.out.println(“是的!这一行将被打印”);
}
System.out.println();
//使用计件表中的部件测试canDefeat
if(pieceList.get(0).canDefeat(pieceList.get(1))){
System.out.println(“是的!此行也将被打印”);
}
}
}
或者,如果你将拥有数百万块,并且内存是一个问题,那么你可以将列表设置为静态;这只是个草图
最后,使用反射的方法:
// 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 to test canDefeat
if (new Miner().canDefeat(new Bomb())) {
System.out.println("Yes! This line will be printed.");
}
System.out.println();
// test canDefeat with pieces from the pieceList
if (pieceList.get(0).canDefeat(pieceList.get(1))) {
System.out.println("Yes! This line will also be printed");
}
}
}
//不建议使用reall
导入java.lang.reflect.Method;
导入java.util.ArrayList;
班级作品{
公共物品(){
}
私有静态方法getMethodOrNull(类cls、字符串名称、类…paramTypes){
试一试{
返回cls.getMethod(名称,pa