Java 动态创建字段和方法

Java 动态创建字段和方法,java,Java,我想为给定类添加新字段(变量)和封装方法。例如:一个班名学生没有任何如下字段: public class Student implements Serializable{ } 然后在我的应用程序中创建一个实例 Student s=new Student(); 我想添加在运行时学生类不存在的新方法。例如:我想添加一个名为studentName的字段,以及getStudentName()和setStudentName()方法 然后在运行时,student对象将如下所示: public clas

我想为给定类添加新字段(变量)和封装方法。例如:一个班名学生没有任何如下字段:

public class Student implements Serializable{

}
然后在我的应用程序中创建一个实例

Student s=new Student();
我想添加在运行时学生类不存在的新方法。例如:我想添加一个名为
studentName
的字段,以及
getStudentName()
setStudentName()
方法

然后在运行时,student对象将如下所示:

public class Student implements Serializable{

    private String studentName;

    public void setStudentName(..){}
    public String getStudentName(){return ...;}
}

在我的应用程序中,对象被写入一个文本文件,并且同一类型的所有对象并不具有所有变量。因此,我只想添加所需的字段以节省内存

有什么办法可以做到这一点吗?有没有示例代码或链接

编辑:或者我们可以创建一个类并创建不存在的实例吗?


编辑2:谢谢你们所有人的回答,并得到了许多信息和想法。并从您的建议中选择了更好的路径

实际上,不是用Java。在Javascript等其他语言中,这是可能的

我不相信这在java中是可能的,但我确信这只会增加内存,因为如果动态添加它们,它们必须事先设置好+动态添加它们的代码

虽然字节码操作是可能的,但这样做并不明智,尤其是如果您打算这样做是为了“节省内存”。您不太可能拥有如此多的数据,以至于会产生影响,如果您拥有了,您会将它们存储在数据库中。

为什么不创建一个值的
HashMap
?效率更高,并且具有您所期望的所有灵活性

public class Student
{
      private HashMap<String, String> values;

      public Student()
      {
          this.values = new HashMap<String, String>();
      }

      public void addValue(String name, String value)
      {
          values.put(name, value);
      }

      public String getValue(String name)
      {
          return values.get(name);
      }
}

目前,您的
HashMap
中只有一个值。你唯一要面对的是
HashMap
对象本身和两个方法,坦白说,这是一个更整洁的解决方案的公平权衡。

你可以使用字节码插装库,比如或为此目的。通过使用Javassist添加字段或方法

Java不是一种动态编程语言,因此我不建议您遵循这条路线,即使某些高级方法可能允许您这样做

该场景的Java习惯用法是将字段值存储在(哈希)映射中。因此,您将有两个公共访问器来设置或获取所有属性值,并且在访问器中,您需要指示要更改的属性的名称

但是,除非属性的最大数量相当大,并且大多数对象只有少量此类属性的值,否则此解决方案不会节省内存

   public class Entity {
   
      // 5 is an estimate for the number attrs.
      private Map<String,Object> attrs = new HashMap<>(5); 

      public Object getAttribute(String name) { return attrs.get(name); }

      public void setAttribute(String name, Object obj) { attrs.put(name,obj); } 

   }
公共类实体{
//5是属性数的估计值。
私有映射attrs=新HashMap(5);
公共对象getAttribute(字符串名称){return attrs.get(名称);}
public void setAttribute(字符串名称,对象对象){attrs.put(名称,对象);}
}

如果您管理有关可能属性及其值类型的元数据,则可以执行一些运行时类型检查。

您可以使用基于
哈希映射的解决方案,而不是编写自己的解决方案:不仅支持简单属性,还支持索引(数组)和映射(映射)。
DynaBean可以进行内省以获取属性和值,这样您就可以转储到文件,但 使用此解决方案,您只是“模拟”一个bean,您的
Student
类实际上并不包含字段和访问器(您调用
Student.getClass().getDeclaredField()
将得到一个空数组)。


如果您需要编写一个“真正的”java
java.lang.Class
Javassist(我的首选,我用来解决与您的问题类似的解决方案),最好选择ASM(或CGLIB)

部分重复:听起来你可能正在为一个毫无根据的问题想出一个解决方案,而这个解决方案可以通过对数据模型(可能还有更多类型)进行更多的前期思考来更好地解决。看在上帝的份上,不要走那条路!说真的,你不需要,只是别这么做。询问如何以这种方式实现您想要实现的东西“在我的应用程序中,对象被写入一个文本文件,并且相同类型的所有对象并不都有所有变量”。。这意味着什么??反射不能添加字段。为此,您需要字节码操作。您可以使用诸如ASM或Javassist之类的字节码插装库来实现。我认为OP应该像Jon Skeet在其评论中建议的那样重新考虑数据模型,而不是创建一些可以容纳任意属性集的类。请担心HashMap的内存消耗,也许你想给它一个初步的能力估计在建设。我认为这些细节是更多的OP工作。我不喜欢把一切都交给他们。Griffey也同意,但如果我们能够实现他们想要的功能,那么发布它是有意义的。如果有什么区别的话,那么未来的读者知道该怎么做才是这种类型的类是正确的选择。。。无论如何,如果需要将它们作为特定类型进行检索,则有必要创建解析器,其可能会对性能产生影响。是的,但我认为,特别是对于一开始就对Java提出这样一个基本问题的人来说,遵循这条路线不是一个好主意。是的。同意。这只是另一个选项。它是
HashMap
而不是
HasMap
一个小的输入错误thereIDEA在这里报告了一个错误:
attrs.put(name,obj),因为?是未知类型。@K.Symbol谢谢,我想现在已修复。
   public class Entity {
   
      // 5 is an estimate for the number attrs.
      private Map<String,Object> attrs = new HashMap<>(5); 

      public Object getAttribute(String name) { return attrs.get(name); }

      public void setAttribute(String name, Object obj) { attrs.put(name,obj); } 

   }