I am receiving input from my Ext JS application on the front end and I want to compare two records on the java side, the record prior to a form update on the UI side and the record after setting all the new values. I have made two references to the same type of object, one before setting new values (oldRecord) and one after (newRecord) and compare these but when I try to use oldRecord.getClass() on the old record it will show the new field values. Is there any way to have access to the old values? I also tried making two field arrays and passing those into my method.
private static Map<String, List<String>> changes;
public static <T> Map<String, List<String>> getChanges (T oldRecord, T newRecord) {
changes = new HashMap<String, List<String>>();
try {
if(oldRecord instanceof UserInfo && oldRecord.getClass().equals(newRecord.getClass())) {
Field field = oldRecord.getClass().getDeclaredField("name");
field.setAccessible(true);
System.out.println(field.get(oldRecord));
field = newRecord.getClass().getDeclaredField("name");
field.setAccessible(true);
System.out.println(field.get(newRecord));
// will loop through all fields in both records and compare
}
} catch (Exception e) {
System.err.println("Exception");
}
return changes;
}
I think you are using the same object. This is the case if you have done something like this:
Object oldRecord = new Object();
Object newRecord = oldRecord;
newRecord.doSomethingThatModifyIt();
getChanges(oldRecord, newRecord);
If you have done something like this, then keep in mind that Object newRecord = oldRecord; does not create any new object, but just sets the 2 variables to point to the same object.
You should instead create a new object based on the old one, with some method like clone() that you would have to implement. Or just by manually setting the fields of the newly created object.
Note: I have used Object but it could be any type of course.
If oldRecord and newRecord reference the same object like
T oldRecord = new T();
T newRecord = oldRecord;
they will "hold" the same instance variable values as well.
To save in oldRecord the old values you must do a deep copy of the object, that means create a new object and copy the instance variable values.
SEarch for deep copy or cloning, maybe start here: How do you make a deep copy of an object in Java?
Related
I am creating a lot of objects called: Obj1, Obj2.... ObjX
Object Obj1 = new Object();
Object Obj2 = new Object();
Object ObjX = new Object();
Now I am having a function where I want to get access to one of this objects.
public void useObject(int objectNumber) {
String objectName = "Obj" + objectNumber;
objectName.doAnythingWithThisObject();
}
Is something like that possible in C# or Java? I don't want to use something like:
switch(objectNumber) {
case 1:
Obj1.doThis();
break;
case 2:
Obj2.doThis();
break;
If I would use switch/if-else then I have to repeat a lot of code which make this thing less readable, because I have to call the same function with different objects.
The actual answer is: you shouldn't, generally speaking, access your variables, using strings at runtime. Cases where this is actually appropriate are few and far between and your example, simplified though it may be for illustration purposes, is not a good match for it.
Instead, why don't you simply use a collection or an array to store your objects? #T.R.Rohith gives an example in their answer.
Still, the direct answer to your question, as it applies to Java, is given below. While the code would be different for C#, the language feature, which can be used for this purpose, namely, reflection, is available in C# as well.
If Obj1, Obj2 etc. are declared as static or instance fields in a class, you can get their values by their names using reflection (see relevant docs for Java). If they are local to a method, there is no simple way to do so (see these questions: for Java, for C#).
Static fields
class Something {
static Object obj1 = new Object();
static Object obj2 = new Object();
// etc.
}
(I've taken the liberty of starting field names with lowercase letters, as it the accepted practice in Java.)
In this case you can get the value of the variable by its name using the following code (you need to import java.lang.reflect.Field):
// Get field, named obj1, from class Something.
Field f = Something.class.getDeclaredField("obj1");
// This line allows you access the value of an inaccessible (non-public) field.
f.setAccessible(true);
// Assigning the value of the field, named obj1, to obj.
// You may want to cast to a more concrete type, if you know exactly what is stored in obj1.
// The parameter for get() is ignored for static fields, so simply pass null.
Object obj = f.get(null);
// Now you can do whatever you want with obj,
// which refers to the same object as static field obj1 of Something.
System.out.println(obj);
Instance fields
class Something {
Object obj1 = new Object();
Object obj2 = new Object();
// etc.
}
You can do it in almost exactly the same way for instance fields, you just need an instance of the class to pass to f.get(). So, for the sake of example, let's assume we have an instance of class Something, called sth.
// Let's say this is an instance of our class
Something sth = new Something();
// ...
// Get field, named obj1, from class Something.
Field f = Something.class.getDeclaredField("obj1");
// This line allows you access the value of an inaccessible (non-public) field.
f.setAccessible(true);
// Assigning the value of the field, named obj1, to obj.
// You may want to cast to a more concrete type, if you know exactly what is stored in obj1.
// The parameter for get() is the instance of Something,
// for which you want to retrieve the value of an instance field, named obj1.
Object obj = f.get(sth);
// Now you can do whatever you want with obj,
// which refers to the same object as instance field obj1 of sth.
System.out.println(obj);
Local variables
You are probably out of luck in this case. Again, see the following links: Java, C#.
This sounds like a classic Strategy pattern problem Strategy Design Pattern
Here's the code:
//Declare this in the class so that it can be called by any method
static Object[] array = new Object[4];
public static void main()
{
//Use this to initialize it
Object[] array = new Object[4];
for(int i=0;i<4;i++)
{
array[i] = new Object();
}
//You can now easily call it
useObject(0);
useObject(1);
useObject(2);
useObject(3);
}
//Your numbers may be off by 1 because we are using an array but that is easily adjusted
public static void useObject(int objectNumber)
{
array[objectNumber].doAnythingWithThisObject();
}
The answer is... don't. Use an array instead. This is exactly what they're for.
ObjectType[] objectArray = new ObjectType[10]; // Or as many as required.
for (int i = 0; i < objectArray.length; i++) {
objectArray[i] = new ObjectType(); // Or whatever constructor you need.
}
// Then access an individual object like this...
ObjectType obj = objectArray[4];
// Or...
objectArray[5].someMethod();
I know how to add an object:
ArrayList<Object> ob = new ArrayList<Object>();
ob.add (index, some_object);
But let say the object has a field called 'name', how can I change that single field only?
For example:
ob.setName(name);
(I know this does not work.)
There's no special treatment here:
ArrayList<SomeObjectType> ob = new ArrayList<SomeObjectType>();
//...
ob.add(index, some_object);
some_object.setName(name);
The object you wanted to set name for is some_object, not ob.
If you are asking about a situation where you have a List which contains the object you want to update, but you don't yet have a reference to that object, then you will need to first find the object within the list, and then update its name field.
If you do have the reference to the object, then the fact that it is contained in a list is irrelevant: call some_object.setName(name) and the object will have the new name whether it is fetched from the list or directly.
I think maybe you want to see
public void stuff(List<? extends Foo> list, int indexToAlter){
// Get the item in the list at the index and call the appropriate method
list.get(indexToAlter).methodOnFoo();
}
You seem to be confusing the list you are storing your object in and the object itself. Try something like:
Object temp = ob.get(index);
temp.name = new_name;
I have a question regarding I guess the scope of objects and whether or not the values the object holds would be changed under certain conditions.
For example, I have made a class in which I need to contruct more than 1 instance of the object, but these instances need to be used and modified throughout the programm and no new instances should be made after the first are made (I don't know what design pattern this would be following if any). The way I have designed the object is something similar to the following:
//basic constructor class
public class MyObject {
private String var1;
private int var2;
private boolean vr3
public MyObject(String param1, int param2, boolean param3) {
var1 = param1;
var2 = param2;
var3 = param3;
}
//getter and setter methods
}
//in main class
Map<String, MyObject> myObjects = new HashMap<String, MyObject>();
on the start of my program, I search through some files to construct new MyObject objects then put them in the HashMap and that is the only time a new MyObject should be created. So throughout the program, I get the objects in the HashMap by getting the value that matches the String key, and once I have that object, I may do things to it using the different setter methods like below:
MyObject object1 = MyObjects.get("anObject");
object1.setVar1("This is the objects new var1 string value");
And that code above should change the string value in the object that is in the HashMap under the key "anObject". But I am wondering that should this also work for things like Lists? like say I had a list as one of the values in the object, and if I got that object from the HashMap, and called something like:
object1.getList().add("new value in the object1 list");
would that add the value to the object in the hashMap? I am wondering this because since I called:
MyObject object1 = MyObjects.get("anObject");
it seems like it could be creating a new instance of that class or just copying it over and that any changes to that object1 object wont be made to the object in the HashMap.
Am I correct that the changes made to any values to the object gotten form the HashMap will be put back to the object in the HashMap?
Sorry for this stupid question.
Java is pass by value, however MyObject is a reference and this is passed by value.
This means every copy of a reference to your Object is the same object and wherever you attempt to change it, the same object will be changed.
The object itself will only be copied when you copy it, not implicitly.
You are correct: any changes made to the internals of the object that you retrieve from the HashMap will be changed in the HashMap, as when you retrieve an object from any data structure, you are actually getting a pointer to an object, so the HashMap and the pointer you get back both point to the same object data. The only times when this is different is if you are storing primitives (like int, double, float, etc.) or if you reconstruct the object you have received from the HashMap.
I using type object and I fill it with data inside loop and at the end I want to clear the data inside ,I don't see any option to clear it (with .+CTRL SPACE) and I don't want to create new instance for it because I want to create object type just once ,is there a workaround to clear it?
I want to do the following just once for specObject, i.e. create instance type list or object and than I have loop that I fill the data inside this object ,when i finish and want to create new instance in specObject I want to clear it before ,how should I do that?
List<Object> itemObject = null;
Object specObject = null;
// Check instance type whether is list or specific object instance
if (multiplicity.equals(MULTI_N)) {
itemObject = new ArrayList<Object>();
return itemObject;
} else if (multiplicity.equals(MULTI_1)) {
return specObject;
} else {
return specObject;
}
You can call the clear method on the List object. That will remove all elements without the need to create a new instance. The documentation is here.
Just to note on object references
when i finish and want to create new instance in specObject I want to clear it before ,how should I do that?
Let's say you have a list:
ArrayList<String> strings = new ArrayList<String>();
If you add some string objects to this list:
strings.add("Hello");
strings.add("There");
strings.add("StackOverflow");
Then you nullify the strings object.
strings = null;
You have effectively removed all of the elements inside the list? Why? Well when you declare ArrayList<String> strings;, you're not creating a new object. You're creating a new reference (pointer) to an object. To illustrate this:
String s = "Hello";
String s2 = s; // s2 points to the same object that s points to.
String s3 = "Another String"; // S3 points to a different object.
The one exception to this rule is if you declare:
String s = "Hello";
String s2 = "Hello"; // s2 will point to the same object as s.
When an object isn't pointed to by anything, it is removed by the Garbage Collector. So effectively, if you declare:
strings = null;
You're removing all of the String child objects that you added to.
Basically I have a variable, zlort = one;
I want to concatenate the value of zlort into a variable (object reference) name.
Like
BankAccount Accountzlort = new BankAccount;
I want the zlort in Account.zlort to actually be the replaced with value of zlort (one--meaning I want the value to be Accountone), and not zlort itself.
Is it possible to do this?
Thanks!
No you can't, but you might put the instance in a map:
Map<String,BankAccount> map = new HashMap<String,BankAccount>();
map.put("Account" + zlort, new BankAccount());
If you mean dynamically choosing the name to assign a variable to, then no.
You could use a HashMap to achieve the same effect.
It is not possible to change the name of a variable at runtime. That would lead to extreme security and stability problems when dealing with any real-world application.
However, as the two answers here have mentioned, a HashMap might acheive what you are looking for. (See the javadoc!!)
A HashMap (or any other map, for that matter) maps a Key to a Value. The concept is similar to a variable, which is a name -> value mapping. The only difference is that variables are part of the actual program code, which is effectively unmodifiable after compiling. A Map is a data structure that can be modified by the running program. This allows you to freely add key-value pairings to it.
Note that in Java, type-safety is encouraged through the use of Generics. Basically this ensures that the key can only be of one type (e.g. String) and the value can be of only one type (BankAccount). A thorough coverage of Generics can be found here.
You would declare this as follows:
Map<String, BankAccount> accounts = new HashMap<String, BankAccount>();
And then to add a key-value pair to the map, you would use the put() method (which 'puts' a value into the map, associated with a key)
String key = "Key"
BankAccount value = new BankAccount();
accounts.put(key, value);
To retrieve it, you would use the get() method.
BankAccount retrievedValue;
retrievedValue = accounts.get(key);
After reading the explanations in your comments, the fact that you can't use an array but can use an `ArrayList'...
Rather than creating a new variable name (or array element, or map value) for each BankAccount, you can probably use scope to your advantage.
Scope is the concept that a reference to a variable only has meaning within a certain part of code. If you declare a variable inside a method, that variable can only be seen within that method. A variable declared within a block (a loop, if statement, etc ) can only be seen from within that block.
Class fields have a different kind of scoping that can be adjusted with keywords (see here).
For example:
public class ScopeExample
int classInt = 10;
public void method() {
int methodInt = 0; // This integer can only be seen by code in
// this method
}
public void method2() {
//doSomething(methodInt) // This line won't compile because i is
// declared in a different method!
doSomething(classInt); // This line will compile and work
// because x is declared in the class that
// contains this method.
int index = 0;
while (index < 3) {
int whileInt = index; // This integer can only be seen from within
// this while loop! It is created each
// loop iteration.
doSomething(whileInt);
}
doSomething(whileInt); //This line won't work, whileInt is out of scope!
}
public doSomething(int a) {
System.out.println(a);
}
}
SO! If you create a BankAccount object within the loop, you don't have to worry about creating a new name for the next one. Each time the loop iterates it will become a new object (when you create it).
If you have to store it, you definitely will need to use an array or other data structure (ArrayList!).
Building on the idea of scope, you -can- have the same variable name for each new BankAccount. A variable reference name isn't guaranteed to be paired with the object that it refers to. That is a convenience to the programmer, so you don't have to know the exact memory address it is being stored in.
For example:
public static void main(String[] args) {
Object o;
int i = 0;
while (i < 5) {
Object reference = new Object(); // Create a new Object and store
// it in 'reference'
o = obj; // The Object 'o' now refers to the object in 'reference'
i++;
}
System.out.println(o); // This should print information about the
// LAST object created.
}
The new Object created in the loop does not belong to 'obj'. You as a programmer use 'obj' to point to the Object. The program doesn't really know what obj means, other than the fact that it points to the Object you just created.
Finally, you can use this along with an ArrayList to make your life easier.
public static void main(String[] args) {
// Our new ArrayList to hold our objects!
ArrayList<Object> stuff = new ArrayList<Object>();
int i = 0;
while (i < 5) {
Object obj = new Object(); // Create an object and make obj point to it.
stuff.add(obj); // Put "the object that 'obj' points to" in 'stuff'.
i++;
}
// This loop goes through all of the Objects in the ArrayList and prints them
for (int index = 0; index < stuff.size(); index++) {
System.out.println(stuff.get(i)); // This will print a single
// object in the ArrayList each time.
}
}