【问题标题】:How to create a new type of object based on a String?如何基于字符串创建新类型的对象?
【发布时间】:2017-05-06 18:23:33
【问题描述】:

第一次在这里发帖。刚开始学习Java和一般的编码,所以请耐心等待!

所以我在这里有几节课。一个水果类,有 2 个子类 - 橙子和西瓜。

public class Fruit {
    String name;
    String size;

    public Fruit() {
        this.name = "Fruit";
        this.size = "";
    }

    public String getName() {
        return this.name;
    }

    public String getSize() {
        return this.size;
    }
}

class Orange extends Fruit {
    public Orange() {
        this.name = "Orange";
        this.size = "Small";
    }
}

class Watermelon extends Fruit {
    public Watermelon() {
        this.name = "Watermelon";
        this.size = "Large";
    }
}

我还有一个 Crate 类,我想存储水果对象。但是,我希望它根据传递给构造函数的 String 来存储特定对象。

public class Crate {
    Fruit f = new Fruit();

    public Crate(String fruitType) {
        if (fruitType == "Orange") {
            f = (Orange)f;
        } else {
            f = (Watermelon)f;
        }
    }

    public String getFruitName() {
        String s = f.getName();
        return s;
    }
}

试图像这样沮丧会给我一个错误。我的问题是如何根据传递给构造函数的内容向 Crate 对象添加某个 Fruit 子类?

编辑:谢谢大家的建议。进行了建议的更改,效果很好!

【问题讨论】:

  • 字符串应该像 if(fruitType.equals("Orange")) 这样比较,尽管像 JavascriptC# 这样的其他语言接受与 == 比较的字符串,Java 不会以同样的方式工作。
  • 你的“工厂”在我看来是错误的,演员不是某种可以转化物体的巫师
  • == 测试引用相等性(它们是否是同一个对象)。

标签: java class oop casting


【解决方案1】:

最简单的方法是查看String 中的内容并使用new

if ("Orange".equals(fruitType)) {
    f = new Orange();
} else if ("Watermelon".equals(fruitType)) {
    f = new Watermelon();
}

(您也可以使用switch 代替if...else if。)

您还可以将Fruit 传递给构造函数,这会使事情变得更简单:

class Crate {
    Fruit fruit;

    Crate(Fruit fruitToHold) {
        this.fruit = fruitToHold;
    }
}

有些人会告诉你,你可以使用反射来创建Fruit,这是真的,但如果你是初学者,这并不是你应该做的。

【讨论】:

  • 你得到了我对清晰准确的措辞的投票;虽然我的回答有点不同……欢迎反馈。
  • @GhostCat 这是一个很好的答案。我想你只是迟到了。我想我得到的赞成票和我建议将Fruit 作为论据一样多,因为它是一种很好的风格。 OP 对String 的使用让我觉得他们可能正在从System.in 获取输入,所以也许真正的答案是使用您建议的工厂方法以及将Fruit 传递给构造函数。跨度>
【解决方案2】:

你不能把一个类转换成它不是的东西。由于你调用了new Fruit(),它只是一个水果,所以你不能转换为OrangeWatermelon

相反,您必须创建适当类型的对象。

此外,您永远不应该使用== 来比较String 的值。始终使用equals()

public class Crate {
    Fruit f;

    public Crate(String fruitType) {
        if (fruitType.equals("Orange")) {
            f = new Orange();
        } else {
            f = new Watermelon();
        }
    }
}

【讨论】:

    【解决方案3】:

    投射不会改变对象的类型!

    您只能将变量强制转换为被引用对象已经是的类型。

    在您的示例中,变量fruitType 中的对象是String 类型。 它与Fruit OrangeWatermellon 没有任何关系。因此演员阵容失败。

    您可以做的是创建所需类型的 new 对象:

    public Crate(String fruitType) {
        if (fruitType == "Orange") {
            f = new Orange();
        }
            else {
                f = new Watermelon();
        }
    }
    

    问题是:你不应该在构造函数中做这样的事情。此外,将 Strings== 进行比较也是一个坏主意,正如其他答案和 cmets 所建议的那样。

    【讨论】:

    • 谢谢。更合适的路径(而不是在构造函数中这样做)是创建一个添加水果的方法吗?
    • @BrynM。安装应在工厂中完成。这要么是静态方法,要么是它自己的类(取决于复杂性)。在您的情况下,静态工厂方法是合适的,它的结果应该作为参数传递给构造函数。
    【解决方案4】:

    这么多答案,都漏掉了一个核心点:

    Java 是一种静态类型的语言。在 string 基础上做所有事情是 不是 在 Java 中要走的路。你尽量避免这样的代码!

    换句话说:您的第一个错误是创建这些不同的类并携带“名称”字符串。你可以这样做:

    abstract class Fruit {
      @Override
      public final String toString() {
        return getClass().getSimpleName() + getSize();
      }
    
      abstract String getSize();
    

    相反。这将确保 any 水果的字符串表示只给出(短)类名(没有包信息)以及getSize() 的子类实现返回的任何内容。

    你可以这样使用:

    class Orange extends Fruit {
      private String size;
      Orange(String size) { this.size = size; };
      String getSize() { return size; }
    

    对于橙子,可以有不同的大小;还有

    class Apple extends Fruit {
      String getSize() { return "always the same"; }
    

    在我的示例中使用相同的大小!

    对于创建对象,您宁愿使用工厂方法,例如:

    Fruit createByName(String fruitName) {
      switch (fruitName) {
        case "Orange": return new Orange();
        case ...
        default: throw new IllegalArgumentException("unknown fruit: " + fruitName);
      }
    }
    

    【讨论】:

    • 感谢您的回复。这为我清除了一些东西。我之前唯一的其他编程经验是 Python,所以我仍然习惯于静态类型语言。很好的解释!
    • 很高兴我的想法对您有所帮助。
    【解决方案5】:

    == 测试引用相等性(它们是否是同一个对象)。

    String s1="Orange";
    String s2="Orange";
    if(s1==s2) ===> true
    

    (s1==s2) ===> 真

                       String Pool
    s1 -----------------> "Orange" <-----------------s2
    

    if(s1==s3) ===> 错误。

                String Pool
    "Orange" <-------------------- s1
    
                   Heap
    "Orange" <-------------------- s3
    

    你需要使用Stringequals方法

    if ("Orange".equals(fruitType)) {
        f = new Orange();
    } else if ("Watermelon".equals(fruitType)) {
        f = new Watermelon();
    }
    

    【讨论】:

      【解决方案6】:

      == 运算符不适用于比较字符串,因为它基本上是比较整个对象,包括它的内存位置。这基本上意味着只有当被比较的两个字符串基本上是相同的实例时,它才会返回 tru。要比较 Java 中的 2 个字符串,您可以使用 .equals(string2) 方法。

      str1.equals(str2); 
      

      这仅比较 2 个字符串的值

      【讨论】:

        【解决方案7】:

        "Orange" == "Orange" 如果两个字符串都指向相同的内存位置,则此表达式给出true。这意味着两者都引用相同的 String 对象。

        但是equal()方法会在比较给定对象的后返回。

        参考以下示例,

        "ss"=="ss"                       //true 
        "ss" == new String("ss")         //false
        "ss".equals("ss")                //true
        "ss".equals(new String("ss"))    //true
        

        【讨论】:

          猜你喜欢
          • 2011-05-20
          • 1970-01-01
          • 1970-01-01
          • 2011-06-23
          • 2011-01-13
          • 2015-06-20
          • 2019-06-05
          • 1970-01-01
          • 2011-05-24
          相关资源
          最近更新 更多