11

I want to add new fields(variables) and encapsulating methods for a given class. For example: A class name Student has no any fields like below:

public class Student implements Serializable{

}

then in my application an instance is created;

Student s=new Student();

I want to add new methods which do not exist for student class at the run time.for example: I want to add a field called studentName, and getStudentName() and setStudentName() methods.

Then at the run time the student object will be like this;

public class Student implements Serializable{

    private String studentName;

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

In my application objects are written to a text file and all objects of same type do not have all variables. Therefore, I want to add only the required fields to save memory.

Any way is there a way to do this? Any sample code or link?

EDIT: or else can we create a class either and create instances which does not exists ?

EDIT 2: Thanks all of you answered and got many info and ideas. And changed the way to a better path from your suggestions as well

Borda
  • 3
  • 3
Débora
  • 5,816
  • 28
  • 99
  • 171
  • 2
    Partial Duplicate: http://stackoverflow.com/questions/6680674/can-a-java-class-add-a-method-to-itself-at-runtime – christopher Aug 16 '13 at 14:13
  • 4
    It sounds like you may be coming up with a solution to an unfounded concern, and one which could be better addressed with more upfront thought about the data model (and possibly more types). – Jon Skeet Aug 16 '13 at 14:15
  • Don't follow that road, for God's sake ! – Tulains Córdova Aug 16 '13 at 14:15
  • You don't need that, seriously, just don't do it. Ask about how to implement the thing that you want to implement this way – SpongeBobFan Aug 16 '13 at 14:17
  • "In my application objects are written to a text file and all objects of same type do not have all variables" .. what this means?? – nachokk Aug 16 '13 at 14:17
  • it's not possible with pure java but with bytecode manipulation. Nevertheless, I see absolutely no reason from your given post to do so and I wouldn't recommend it either! As other people already said: DON'T DO THIS – u6f6o Aug 16 '13 at 14:19
  • @AashMaharoon, just imagine how you will load those objects from a file without knowing what was stored there. Just save all, and when you'll run out of disk space buy another disk, they're cheap enough – SpongeBobFan Aug 16 '13 at 14:25
  • If your gut keeps telling you to modify classes at runtime, you may want to check out python. – MatrixManAtYrService Nov 02 '18 at 14:25

7 Answers7

7

Why not just create a HashMap of values? Much more efficient, and has all the flexibility you're looking for.

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);
      }
}

Why a HashMap?

You said that all objects may have differing values, and you'll be defining those new methods and attributes by a String. Well.. this will achieve that functionality without any horrible bytecode manipulation. For example:

String attrName = "name";
String attrValue = "jim";
Student stu = new Student();
stu.addValue(attrName, attrValue);

At the moment, you've only got the one value in your HashMap. The only overheard you have to face is the HashMap object itself, and two methods, which frankly is a fair trade off for a far tidier solution.

christopher
  • 26,815
  • 5
  • 55
  • 89
  • I think the OP should rather rethink the data model as Jon Skeet suggested in his comments, rather than creating some class that can hold any arbitrary set of attributes. – GriffeyDog Aug 16 '13 at 14:34
  • 1
    Be worry of the memory consumption of the HashMap, perhaps you want to give it a initial capacity estimate at construction. – Valentin Ruano Aug 16 '13 at 14:35
  • I think these details are more for OP to work out. I don't like handing them everything. And agreed Griffey, but if we can achieve their desired functionality, then it makes sense to post it. If anything, so future readers know what to do is this type of class *is* the correct choice. – christopher Aug 16 '13 at 14:41
  • You are assuming values are stored as String... anyways if they are needed to be retrieved as a specific type it would be necessary to create parsers with its probably consequent impact in performance. – gabriel garcia May 11 '20 at 15:49
3

You can use bytecode instrumentation libraries like Javassist or ASM for this purpose. Here is an example of adding a field or method by using Javassist.

Santosh
  • 17,667
  • 4
  • 54
  • 79
1

While it is possible with bytecode manipulation and such it wouldn't be wise, especially if you intend to do this to "save memory". It's unlikely that you would have so much data that it would make a difference, and if you did, you would store them in a database anyways.

Kayaman
  • 72,141
  • 5
  • 83
  • 121
1

Instead of writing your own HashMap based solution you can use DynaBean and DynaClass: support not only simple properties but also indexed (Array) and mapped (Map).
DynaBean can be introspected to get properties and values so you can dump to file BUT with this solution you are only "simulating" a bean, your Student class doesn't really contains fields and accessors (you you call Student.getClass().getDeclaredField() you will get an empty array).

If you need to compose a "real" java java.lang.Class Javassist (my preferred choice, I used to resolve a solution similar to your question) or ASM (or CGLIB) are the best choiches.

Luca Basso Ricci
  • 17,829
  • 2
  • 47
  • 69
0

Practically speaking, not in Java. In other languages like Javascript, this is possible.

Brad
  • 6,106
  • 4
  • 31
  • 43
0

I dont believe if this is possible in java but I'm sure it will only add to the memory because if you add them dynamically they must be set up beforehand + the code to add them dynamically.

Mihai Bratulescu
  • 1,915
  • 3
  • 27
  • 43
0

Java is not a dynamic programming language and so I would not advice to follow that route even if some advance approaches may allow you to do so.

The Java idiom for that scenario would be to store the field values in a (hash) map instead. So you would have a couple of common accessors to set or get all attribute values and in the accessor you would need to indicate the name of the attribute you want to change.

However this solution won't save memory unless the maximum number of attributes is rather large and most object just have values for a small number of such attributes.

   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); } 

   }

You could implement some runtime type-checking if you manage meta-data about possible attributes and their value types.

Valentin Ruano
  • 2,726
  • 19
  • 29