【问题标题】:Is it possible to receive subclass's name in compile time in Java?是否可以在 Java 的编译时接收子类的名称?
【发布时间】:2021-10-16 20:56:20
【问题描述】:

我正在尝试在 java 中创建一个小吃机实现。 我创建了一个名为 Product 的抽象类,它将为每个提供的产品提供基本设计。

我的意思是我们有 abstract class Product,然后是其他类,如 NachosCake 等。它们继承自 Product

Product类不包含太多,它只包含产品的namepriceavailable amount(这些是类中的字段)。

它还有get 方法,用于只返回每个字段的值。

问题是我想将产品的name 设置为static final,因为如果产品的名称是Nachos,它将不会被更改。我的意思是可以创建更多 Nachos 对象,但它们的类的名称仍将是 Nachos

所以没有理由不这样做static final

问题是我不确定如何正确设置。

public abstract class Product {
    
    private static final String productName = getClass().getSimpleName();
    private int price;
    private int amount;

....
Constructor..

Get methods..

我考虑过getClass().getName()getSimpleName(),但它给了我一个IDE 错误,这表明我将该字段也用作static final 并使用getClass 的唯一方法是编写Product.class.getName(); .

问题是,如果我这样做,将返回的名称是 Product 而不是 CakeNachos 或其他子类。

【问题讨论】:

  • 我强烈反对将 getter 返回的值与类名耦合的方法。 --- 为什么不在getter 中写getClass().getSimpleName();?甚至更好:删除字段,使 getter 抽象,让子类实现它们。
  • @Turing85 我明白你的意思,但为什么不把这个字段设为static?我的意思是,该类的每个对象的类名称都是相同的,因此 Nachos 的每个对象都需要运行 getClass().SgetSimpleName(); 而不是已经拥有它。
  • 你想多了。一方面,如果我们将return "Nachos" 写在getter 中,这将始终是完全相同的String"Nachos" == "Nachos" 将始终评估为true)。另一方面,即使我们要编写getClass().getSimpleName(): 足够频繁地调用它,JVM 也会热编译和优化代码。 --- "premature optimization is the root of all evil" -- Donald Ervin Knuth: Computer Programming as an Art (1974), p. 671
  • 感谢您的回答。但是有可能按照我尝试的方式来做吗?以static final 作为字段并对其进行优化,这样每个子类将自动拥有自己的名称,而无需运行getClass()
  • 如果您在Product 类中有一个static final String 字段,它只能引用一个字符串(即一个类的名称)。 Nachos 类不能是“Nachos”,Cake 类不能是“Cake”,因为它只是 Product 及其所有子类的一个字段。

标签: java class inheritance static abstract-class


【解决方案1】:

如果您的 Class 有一些描述该 Class 的属性(例如产品名称),那是该 Class 的一个属性。您不应该编写将类本身的名称与 getClass().getName() 一起使用的代码,这会将您的业务逻辑与实现细节联系起来,并且没有理由(或很少有充分的理由),为什么您的代码需要知道类本身的名称。

相反,在你的类中添加一个像 productName 这样的属性:

public class Product{

    private String productName;

    public Product(String name){
        this.productName = name;
    }

    public String getProductName(){
        return this.productName;
    }
}

【讨论】:

    【解决方案2】:

    您应该只使用“final”并删除“static”。通过将变量声明为 final,您可以分配使用“this”作为参考的“getClass”的值。 “this”不适用于静态。

    abstract class Product {
        private final String productName = this.getClass().getSimpleName();
    
        public String getProductName() {
            return productName;
        }
    }
    

    “this.getClass().getSimpleName()”中的“this”可以省略,只留下“getClass().getSimpleName()”。

    使用“静态”没有意义,因为您将通过类引用直接访问该属性。但这不起作用,因为要获得“getClass”,您需要在某个范围内(构造函数......),因为属性是静态的,不可能在创建时分配属性的值,使得无法使用“Final”。

    【讨论】:

      【解决方案3】:

      静态成员属于定义它的类。在Product 类上将productName 声明为静态意味着每个具体实现都将具有相同的值。这不是你想要的。

      我认为最接近您描述的解决方案是根本没有会员。相反,声明一个访问器如下。

      public abstract class Product {
        public final String getProductName() {
          return getClass().getSimpleName();
        }
      }
      

      因此,给定子类的每个实例(例如Taco)都为其类型引用相同的Class 对象。我们从不复制该值,因为我们正在访问内存空间中的奇异值。我们将此方法声明为最终方法,以便子类无法覆盖它。这强制要求productName 始终是具体实现的simpleName

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-10-09
        • 2010-12-22
        • 1970-01-01
        • 2019-08-05
        • 1970-01-01
        • 2011-01-01
        • 2015-07-18
        相关资源
        最近更新 更多