【问题标题】:Adding Getters/Setters to one Base class将 Getter/Setter 添加到一个基类
【发布时间】:2013-05-05 03:55:06
【问题描述】:

我有一个想法,但无法弄清楚如何实现。

public class BaseDomain<T>{

//Generic methods goes here

}

public class Domain1 extends BaseDomain<Domain1>{

private int id;

private String name;

//only properties should be present here

}

public class Domain2 extends BaseDomain<Domain2>{

private int id;

private String name;

//only properties should be present here

}

在上述场景中,我可以轻松地在基类中定义所有泛型方法,并且可以通过使用泛型在我的所有域类中使用。但是我的问题是我想设计一个机制,开发人员必须通过它只定义域类中的属性(没有 getter/setter)但是 BaseDomain 应该以某种方式提供 动态获取每个域的 getter/setter。

任何建议都非常感谢!

【问题讨论】:

  • 查看依赖注入框架
  • “属性”是指“字段”吗?
  • @Joh....是的,我的意思是字段
  • 另一种方法呢:提供方法Object get(String name)void set(String name, Object value)。对于开发人员:get("id")get("name")set("id", 5)set("name", "john")。如果你愿意,我会给你一个实现。
  • 开发人员必须记住这种方法中的所有字段名称,并且只能在运行时捕获任何错误。

标签: java generics


【解决方案1】:

您无法使用 Java 的正常功能来做到这一点。

您可以使用Lombok 之类的工具。

我个人不喜欢这种方法,因为它在您的项目中引入了“魔法”,在某些时候会造成麻烦,并且只会节省一点样板代码。

【讨论】:

  • 对于应用程序来说,魔法不是必需的,但对于框架来说,这种功能真的很有帮助..将检查 Lombok
  • 支持关于魔法的评论。我在一个项目中使用了 Lombok,并在一段时间后对其进行了重构,因为它实际上产生的问题比我一开始节省的时间要多。
  • Lombok 现在(2017 年)稳定并用于许多项目。它应该集成到标准 Java 库中,因为它增强了语言本身。
【解决方案2】:

这听起来像是你应该使用接口。使用接口定义必须提供的功能,实现它的类必须提供它们。在您的代码中,您永远不会只引用特定的类,就像一个类一样。

例子:

public interface MyInterface
{
     public String getName();
}

public MyClass implements MyInterface
{
    public String getName { return " test"; }
}

public OtherClass
{
    private MyInterface = new MyClass();
}

如果你不希望程序员实现你的接口,这只能通过反射来完成。你可以使用一个代理对象来实现 getter 和 setter,并通过这个对象访问它们,就像这里讨论的那样:@987654321 @

【讨论】:

  • 创建代理对象是一种方法,但我希望 IDE 代码完成不会起作用,因为这是一个运行时过程。想要实现……开发者不应该觉得缺少什么
  • 我似乎记得 Hibernate 使用了类似的东西,但我不确定这一点以及他们是如何做到的。当您创建一行时,该对象并不真正存在,并且仅在运行时透明地填充,但在您对其进行编程时您不会注意到它。 IDE 将其视为任何其他类。所以也许你可以看看他们是如何做到这一点的,因为这听起来和你想要的很相似。
  • 使用 reflection,这就是 Hibernate(以及许多其他框架,例如 Velocity/Freemarker)的工作方式。有关示例代码,请参阅我的答案。
【解决方案3】:

如果您的代码没有某种预处理器,您将无法做到这一点。预处理器会在编译 Java 文件之前对其进行解析,添加所需的方法,然后才将生成的预处理文件推送到编译器。无论如何,看到 Java 是一种静态类型语言 - 这是一个非常糟糕的主意。

如果您希望它是动态的,您可以使用 Groovy 代替 Java。 Groovy 是一门独立的语言,它与 Java 有很多共同点,并且可以编译为 JVM 字节码。但是,它允许您非常轻松地制作这些“动态”方法。

【讨论】:

    【解决方案4】:

    使用 Reflection 你可以做到这一点。

    public class BaseDomain<T>{
    
    
        public String getName() {
            return this.getClass().getField("name").get(this);
        }
    
        public void setName(String value) {
            this.getClass().getField("name").set(this, value);
        }
    
    }
    

    注意this.getClass() 将引用该对象的运行时类,例如Domain1。因此,您可以访问那里的字段、获取/设置值等。

    如果您将属性声明为privateprotected,您可能需要设置访问权限。他们是public,它应该可以工作。

    正如 OP 所述,使用 getDeclaredFields() 不会强制您声明公共字段,不幸的是,您必须遍历(或使用 Map)才能访问具有特定名称的 Field

    如果您的对象实例中不存在该字段,则会出现异常。

    【讨论】:

    • Thnx @GaborSch....解决方案看起来不错。使用 this.getClass().getFields() 我可以从实现类中获取所有字段,并可以通过反射将 setter/getter 添加到基类.....似乎它在编译时不起作用??
    • @TapasKumarJena public void setName(String value) { this.getClass().getField("name").set(this, value); }
    • @johnchen902 谢谢,已更正。复制粘贴魔鬼跟我玩 :)
    • @TapasKumarJena 是的,如果你在BaseDomain 中声明它们应该可以工作。如果它有效,您可以投票并接受;)
    • 我对 AspectJ 不太熟悉,但您可以尝试一下 execution(* get*(..)) 构造。但最好使用一些动态代理
    【解决方案5】:

    如果访问级别修饰符允许使用,则基类中定义的任何变量、getter 和 setter 都可以在扩展基类的类中使用。

    这是一个例子:

    public class BaseClass {
    
        private int id;
    
        private String name;
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
    }
    
    class AnotherClass extends BaseClass {
    
        public String getIdString() {
            return Integer.toString(getId());
        }
    }
    

    由于 id 在基类中被定义为私有,扩展类获取 id 的唯一方法是使用公共 getId 方法。通过使用 getId 和 setId 方法。扩展类可以使用 Id 字段而无需定义它。

    如果您希望扩展类能够访问字段本身,则必须保护这些字段,而不是私有。

    扩展类只需要定义它们自己需要的 getter 和 setter。他们可以使用已经在基类中定义的 getter 和 setter,再次假设访问级别修饰符允许使用。

    【讨论】:

      猜你喜欢
      • 2018-04-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-14
      • 2010-09-26
      • 2017-08-05
      • 1970-01-01
      • 2015-01-20
      相关资源
      最近更新 更多