【问题标题】:Accessing parameters of the same name of different classes in ScalaScala中访问不同类的同名参数
【发布时间】:2025-11-29 22:30:01
【问题描述】:

我有一个非常具体的场景,其中我有一些不同的抽象类,它们的子案例类可以有不同的参数,例如:

abstract class ball() {}

case class football(_name: String, _shape: String) extends ball

case class basketball(_name: String, _size: Int) extends ball

还有一个不同的抽象类:

abstract class food() {}

case class vegetarian(_name: String, calories: Int) extends food

case class meat(_name: String, proteinCount: Int) extends food

现在,我面临的问题是我需要在不知道它是什么类的情况下以某种方式提取所有这些类的名称,我只知道总是,每个类都有一个名为 _name 的参数。

假设我们有一个上述任何类的object,我正在尝试这样做:

object.getClass.getDeclaredField("_name").get(this)

但我得到了错误:

can not access a member of class package.food with modifiers "private"

我尝试将 val 和 var 放在类中的参数之前,但它没有帮助。我还尝试在 get(this) 之前的一行中执行“setAccessible(true)”,这也无济于事。

【问题讨论】:

    标签: scala private public


    【解决方案1】:

    显而易见的干净解决方案是对所有这些类至少具有一个共同特征:

    trait HasName {
      def _name: String
    }
    

    然后你就可以安全地做obj.asInstanceOf[HasName]._name。如果您设法保留objHasName 的静态信息,那就更好了,在这种情况下obj._name 就足够了。

    如果您无法做到这一点,那么反思就是要走的路。在这种情况下,您可以使用结构类型很容易地做到这一点:

    obj.asInstanceOf[{ def _name: String }]._name
    

    请注意,这将比上面的HasName 解决方案慢,并且在编译时完全取消选中。

    【讨论】:

    • 能否请您准确解释第二种解决方案的工作原理?我复制了它,它在我的项目中工作,但我不完全理解它。非常感谢。
    • 还有,同名方法如何实现类似的解决方案?
    • scalac 编译器使用 Java 反射(至少在 JVM 上)实现对结构类型方法的调用。类似obj.getClass.getMethod("_name", classOf[String]).invoke(obj),给出一个简化的想法。