【问题标题】:Java converting from Object to SubclassJava从对象转换为子类
【发布时间】:2016-09-24 20:14:26
【问题描述】:

这是我的 Scene.java 代码。它有不同类型的对象,所有这些都包含在一个名为targets 的常见ArrayList 中。它们都共享一个返回其标识符的toString() 方法。我想使用targets 列表来确定场景中是否有任何对象与给定标识符匹配,无论其类型如何:

ArrayList<NPC> npcs = new ArrayList<NPC>();
ArrayList<Item> items = new ArrayList<Item>();
ArrayList<EnviromentalObject> enviromental_objects = new ArrayList<EnviromentalObject>();

ArrayList<Object> targets;

public Object check_for_target(String target_name){
    targets.addAll(npcs);
    targets.addAll(items);
    targets.addAll(enviromental_objects);
    for (Object target : targets){
        if (target.toString() == target_name){
            return target;
        }
    }
    return null;

这是 Game.java 中的代码,用于检查给定的标识符。如果当前场景有匹配,我想知道对象的类型并将其视为其真实类型。现在,我有以下代码,我知道它不会起作用,但也许它会帮助我理解我的想法。

Object target = current_scene.check_for_target(target_name);
        if (target == null){
            System.out.println(UNRECOGNIZED_TARGET_MESSAGE);
        } else {
            String target_type = target.getClass().getName();
            target = (target_type) target;
        }

获取对象的类型然后能够使用该对象的方法的正确方法是什么?现在,我只得到Object 的方法。我要为NPCItemEnviromentalObject 创建超类吗?

【问题讨论】:

  • 旁白:if (target.toString() == target_name){ --> 那条线会给你带来一些麻烦。对对象使用 .equals()。
  • 您可以使用instanceof关键字来检查对象的类型。
  • 不是您的问题的答案,而是更笼统的...您使用的是ListItems,这是与您选择的ArrayList 的列表实现不同的问题,所以你应该声明List&lt;Item&gt; items = new ArrayList&lt;&gt;();——还要注意你不必在右边重复&lt;Item&gt;。这样,如果您以后决定 LinkedList 效果更好,您就不必重新声明所有内容。
  • 虽然使用instanceof 确实发现了类型,但它是一种非OO 的工作方式——它破坏了封装;它打破了多态性。这是对“Java 从对象到子类的转换” 的正确答案,但这是一种糟糕的方法。学习使用接口。也许 NPC、Item 和 EnvironmentalObject 都是 Targetable,而 NPC 和 Item 是 Moveable 而 EnvironmentalObject 不是。然后findTarget(target_name) 将返回Targetable 而不是Object
  • 定义treat it as its true type。你想用它做什么?

标签: java class oop inheritance types


【解决方案1】:

基本上,您可以检查对象是否是特定类的实例。

可能是这样的:

if( target instanceof NPC) {
    System.out.println("target  is a NPC");
}
else if( Target instanceof Item) {
    System.out.println("target is an Item");
}

if( target  instanceof EnviromentalObject) {

    System.out.println("target is EnviromentalObject"); 
}

编辑:正如我们在 cmets 中所说的,我认为您可以更改代码以获得更好的解决方案。上面的代码仍然有效,但使用 设计模式 是一种很好的做法,这被称为编程中的最佳实践。对于这种情况,请考虑使用 java 接口并定义每个对象可以根据需要实现它们的共享方法。他们以最简单的方式打印他们的标识符。让我们举个例子:

public interface SceneThings() {

    public void printIdentifire();

    public String doSomeOtherThings();

}

每个对象都可以根据需要实现上述接口:

public class Item implements SceneThing {

...

public void printIdentifire(){

//print its identifier here.
System.out.print("ID:ITEM###");

}

public String doSomeOtherThings(){

    //do some other works !!!
}
...
}

其他项目同上。然后您可以使用单个数组来保留它们,而不必担心它们的原始类,如下所示:

ArrayList<SceneThings> targets = new ...

SceneThing  obj = new Item();
targets.add(obj);

我希望这可以帮助您为您的案例定义更好的解决方案。

【讨论】:

  • 谢谢一群朋友
  • 虽然这会起作用,但通常它被认为是代码异味,如果不是反模式的话。您确实应该创建一个所有类都实现的接口,其中包括共享功能。
  • 只有少数情况(例如在equals 实现中)使用instanceof 是一件好事——主要是因为您别无选择。这些都不是。
  • @SeanScott 好吧,假设可以成为目标的类的数量随着时间的推移而增长。然后你将不得不添加越来越多的if(target instanceOf SomeClass) 语句,这使得维护非常困难。使用接口或抽象类,您不必再碰它。
  • 另外,考虑到类的数量可能会在外部增长。使用此实现,只有 you 可以添加新类。未来下游的某些人无法扩展您的代码。这违反了开放/封闭原则。
【解决方案2】:

声明超类或接口Target并使用它来保存目标数组的方法之一,带有抽象类的完整代码示例:

ArrayList<NPC> npcs = new ArrayList<NPC>();
ArrayList<Item> items = new ArrayList<Item>();
ArrayList<EnviromentalObject> enviromental_objects = new ArrayList<EnviromentalObject>();

ArrayList<Target> targets;

public Target check_for_target(String target_name) {
    targets.addAll(npcs);
    targets.addAll(items);
    targets.addAll(enviromental_objects);
    for (Target target : targets) {
        if (target.toString().equals(target_name)) {
            return target;
        }
    }
    return null;
}

private abstract class Target {}
private class NPC extends Target {}
private class Item extends Target {}
private class EnviromentalObject extends Target {}

【讨论】:

  • 我几乎同意(请参阅我对 Q 的评论),但会使用接口而不是超类。无论如何都要支持,因为这比无休止的instanceofs 更好。
  • @StephenP 是的,你的观点是对的,接口可能在这里更适用,但抽象类也是有效的设计。问题中的信息不足以确定这一点,但我会更新答案以提及界面,谢谢
  • 使用接口总是比使用抽象类更好,如果接口能够完成足够的工作,因为在 Java 中你只能扩展 one 类,但你可以实现任意数量的接口。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-09-29
  • 2013-09-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多