The root of the problem for me is that Java does not allow references.
The problem can be summarized succinctly. Imagine you have a List of Blob objects:
class Blob {
public int xpos;
public int ypos;
public int mass;
public boolean dead;
private List<Object> giganticData;
public void blobMerge(Blob aBlob) {
. . .
if (. . .) {
this.dead = true;
} else {
aBlob.dead = true;
}
}
}
If two blobs are close enough, they should be merged, meaning one of the two blobs being compared should take on the attributes of the other (in this case, adding the mass and merging the giganticData sets) and the other should be marked for deletion from the list.
Setting aside the problem of how to optimally identify adjacent blobs, a stackoverflow question in its own right, how do you keep the blobMerge() logic in the Blob class? In C or C++ this would be straightforward, as you could just pass one Blob a pointer to the other and the "host" could do anything it likes to the "guest".
However, blobMerge() as implemented above in Java will operate on a copy of the "guest" Blob, which has two problems. 1) There is no need to incur the heavy cost of copying giganticData, and 2) the original copy of the "guest" Blob will remain unaffected in the containing list.
I can only see two ways to do this:
1) Pass the copies in, doing everything twice. In other words, Blob A hosts Blob B and Blob B hosts Blob A. You end up with the right answer, but have done way more work than necessary.
2) Put the blobMerge() logic in the Class that contains the containing List. However, this approach scales very poorly when you start subclassing Blob (BlueBlob, RedBlob, GreenBlob, etc.) such that the merge logic is different for every permutation. You end up with most of the subclass-specific code in the generic container that holds the list.
I've seen something about adding References to Java with a library, but the idea that you have to use a library to use a Reference put me off that idea.
Why would it operate on a copy? Java passes references to objects. And references are very much like C++ pointers.
Um... a reference is passed not a copy of the entire object. The original object will be modified and no data is actually moved around.
Related
Consider the following JNA structure:
public class VkDeviceQueueCreateInfo extends VulkanStructure {
public VkStructureType sType = VkStructureType.VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
public Pointer pNext;
public int flags;
public int queueFamilyIndex;
public int queueCount;
public Pointer pQueuePriorities;
}
The sType field is a constant value used by the native layer to identify the type of structure. This works fine for a single instance of this class created using new.
However if we allocate an array of this structure using toArray() the sType is reset to the default value after the constructor has been invoked for each array element. i.e. it clears the field!
Alternatives that didn't work:
Setting the field explicitly in the constructor has no effect (it still gets reset).
Ditto making the field final.
Doesn't seem to matter whether we try the default constructor or one with a JNA Pointer argument.
The only thing that seems to work is to turn off auto-read for the structure:
public class VkDeviceQueueCreateInfo extends VulkanStructure {
...
public VkDeviceQueueCreateInfo() {
setAutoRead(false);
}
}
(Note that this structure is only used to write to the native layer, not read anything back).
This works but what is it actually doing? Why is JNA resetting the structure to the native values when there aren't any yet? Is there a way to switch off the auto-read for this field globally?
This is not a big deal for a single structure, but in this project there are several hundred that were code generated from the native layer, most of which (but not all) with the sType pre-populated as the above example. Clearly pre-populating the field was not was the way to go, but what is the alternative? Will every structure need to be re-generated with the above fiddle?
EDIT: Another related question that comes to mind after brooding on this - what about array types in a structure? Are they reset to null by the auto-read thingy? The code-generated structures initialise any arrays to size the structure, e.g. public float[] colour = new float[4];
You are on the right track pointing out that the auto-read() is part of the problem here. When you invoke toArray() you are (usually) changing the memory backing for the array to a new native memory allocation (the auto-allocation zeroes out the memory). So all those 0's are loaded into your array.
The internal Structure toArray() keeps the values for the first element for your convenience, but does nothing for the remainder, which are instantiated using newInstance() inside the loop. Here are the two lines causing your problem:
array[i] = newInstance(getClass(), memory.share(i*size, size));
array[i].conditionalAutoRead();
My recommendation would be for you to override toArray() in your own VulkanStructure structure that the others inherit from. You could copy over the existing code and modify it as you see fit (e.g., remove the autoRead).
Or you could overload a toArray() that gets passed a collection of Structures and copies over the backing memory from the old collection before reading it to the new one. Alternately, if the original memory backing is large enough when toArray() is called, the memory isn't cleared. So you could allocate your own large enough memory, use useMemory() on the first element to change its backing, and copy over the backing memory bytes; and they would be auto-read into the new array version.
I am trying to make a copy of an ObjectA, which has another ObjectB in it, which also has 6 other ObjectC's, but I dont want to have a copy of ANY of their memory addresses, so if I updated any of the original objects later on, it will not update the copy's values (which consists of all three objects). I have tried implementing the clone() but that still doesnt work for what I am trying to do.
Here is what I am trying to do (yes I know this looks ridiculous...):
void rotateEntireCubeClockwise(){
System.out.println("Changing view of cube...rotating entire cube clockwise...");
CubeAlgorithms a2 = clone();
cube.left = a2.clone().cube.clone().front.clone();
cube.front = a2.clone().cube.clone().right.clone();
a2.clone().rotateTopClockwise(1);
cube.top = a2.clone().cube.clone().top.clone();
a2.clone().rotateTopCounterClockwise(1);//undo
a2.clone().rotateLeftClockwise(2);
cube.back = a2.clone().cube.clone().left.clone();
a2.clone().rotateLeftCounterClockwise(2);//undo
a2.clone().rotateBackClockwise(2);
cube.right = a2.clone().clone().cube.clone().back.clone();
a2.clone().rotateBackCounterClockwise(2);//undo
a2.clone().rotateBottomClockwise(1);
cube.bottom = a2.clone().cube.clone().bottom.clone();
}
public CubeAlgorithms clone() {
try {
return (CubeAlgorithms) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
throw new RuntimeException();
}
}
CubeAlgorithms contains a Cube object, and the Cube object contains 6 CubeSide objects(front, left, back, right, bottom, and top)
Both Cube and CubeSides also contain a clone method similar to the one you see above.
My problem with this code is that I want it to rotate a cube clockwise, however the only rotation that it does is the very last one.
This is generally called a "deep copy." There's not a single way to do it; all of the classes being deeply copied have to help out in one form or another.
One approach is to have a copy constructor (that is, a constructor CubeAlgorithms(CubeAlgorithms)) that does a deep copy on all of the incoming object's fields. Of course, to do a deep copy of those, you need to do something similar to them -- and so on.
Another approach, if your classes are all serializable and performance isn't a huge concern, is to serialize and deserialize your objects. In this, I don't necessarily mean java's built-in serialization: you could use Jackson to JSON-ify them and then read that JSON string back out, etc.
I think your code looks complex because in that method you are trying to clone the object and modify it (rotate it) at the same time.
Also, you are invoking the "clone" method of all the objects several times, so each time you would be creating a new copy. That could explain why only the last operation is applied.
I'd suggest you separate the operations and first clone the entire cube (with all the sub-objects it has inside) and then once you have the new Cube object, then rotate that one (the original one will not be rotated since the second object is a separate one).
To clone the object, you should write a "clone" method in all the classes. The "clone" method should create a new instance of the class, and then populate the attributes by cloning them as well.
For example, in the "Cube" class:
public Cube clone() {
Cube newCube = new Cube();
newCube.front = this.front.clone();
newCube.back = this.back.clone();
newCube.left = this.left.clone();
newCube.right = this.right.clone();
newCube.top = this.top.clone();
newCube.bottom = this.bottom.clone();
return newCube ;
}
You should then implement the other classes' "clone" method in a similar fashion (create a new instance, then populate the attributes with clones of the attributes in the "this" instance).
Once you have successfully cloned the object, then do whatever operation you need to rotate it (and you don't need to call "clone" several times, just clone the cube once).
Cube rotateEntireCubeClockwise(Cube originalCube) {
Cube newCube = originalCube.clone;
// now manipulate the "newCube" to make sure it rotates
// ...
return newCube;
}
I'm having an odd problem that I haven't encountered before with copying objects in Java.
So, I've written a class in my code called "State". This contains a few ints, a 2d array, a string and such...
So, for an instance of State called S, I want to make a copy of it called X (I do this simply by writing State X = S; ). Then I want to make changes to X, do some evaluations based on those changes and then just throw away X and keep using S. However, the problem I'm getting is that S seems to be getting the changes that I make to X.
This seems odd to me, since I feel quite certain that I've done things like this before but never had this problem.
Any thoughts?
(Thanks in advance)
I want to make a copy of it called X (I do this simply by writing State X = S; ).
That does not make a copy of the object.
Variables (of non-primitive types) in Java are references - they are not the objects themselves. By doing
State X = S;
you are not copying an object, you are just copying the reference - the result is that you now have two variables that are referring to the same object. If you modify the object through one reference, you'll see the changes also through the other reference.
One way to copy objects is by using the clone() method. For this to work, the class of the object that you are trying to copy must implement interface Cloneable. Another (and probably better) way is to create a copy constructor, and use it to copy the object:
public class State {
public State(State other) {
// initialize this object by copying content from other
}
}
// Make a copy
State X = new State(S);
Your code is not creating a copy of the object. What you are doing there is creating a new reference and pointing it to the same object.
Search for "how to clone an object in Java". Read up on the Cloneable interface.
Lets say I have list of Scenarios in a Game, and lists of Players. Each player plays some scenario from the Scenario list in Game. I don't want to have copy of Scenario in Player, I want to have something like pointer to the list in Game object, so that if any scenario is edited, it is also edited in Player list.
Game
Scenarios : list
Player
Scenarios : list -> each scenario here is a reference to scenario in Game
Now It would be simple in language supporting pointers, but Java is supposedly pass-by-value. At the same time, I know there are hacks using passing values inside tables etc. Is it possible to do this or not?
What have you tried? If you would have tried putting the reference into separate lists you would have known that they are the same reference. The term "pass-by-value" is tricky here because you will get a reference to the same object in your methods for example but java passes around copies of references. So basically java passes around values of references.
If you put the same reference in all your lists the changes to the original will be reflected in them.
SomeObject o = new SomeObject();
list0.add(o);
list1.add(o);
list2.add(o);
o.setSomeValue(true);
// all lists will "see" the changes
list0.get(0).equals(o); // assuming list0 only contains o -> this is true
As a rule of thumb: if you don't mess (swap, assign, etc.) with references and only call methods on the objects the references point to you'll be fine.
In your case, if Player object has a Scenario object, not the whole scenario will be copied (or cloned), only the reference of Scenario will be copied. And you can modify the Scenario either through reference by Player or through the List; as it is one object many references.
1st way
I would use interface in your case. Something like:
public class Scenario implements ScenarioItf{/**/}
And the Player will store only ScenarioItf.
2nd way
To store Scenarios list into Factory class:
public class ScenariosFactory {
private static List<Scenarios> mScenarios = null;
public static void create(List<Scenarios> scenarios) {
mScenarios = scenarios;
}
public static List<Scenarios> getFactory(){
if ( mScenarios == null )
throw new NullPointerException( "...null..." );
return mScenarios;
}
}
So both classes Player and Game can use the same source.
Java is pass-by-reference, so if you have a Scenario object in the list AND in the Player object, they will both be a pointer to the actual Scenario object in memory.
Edit: Apparently, it's sort of by-reference but technically not really. As long as you don't go scenario = new Scenario() at either end, it will be the same object.
I need help with something. my code is of the following template.
Assume customObject has multiple property1, property2, ..property100.
List<CustomObject> customObjectList = /*<method call to external API that returns the said list >*/
if(customObjectList != null && customObjectList.size() > 0){
//*** point A ***<clone the Object>
resultList = <some method that process the above list>(customObjectList)
if(resultList.size() > 0){
for(Iterator<Map.Entry<CustomObject, ExternalResponse>> itr = resultList.entrySet().iterator(); itr.hasNext();) {
//code that modifies the properties in the CustomObjects
//*** point B ***resetAProperty(<Object clone>)
}
}
}
At point B, I need the one unmodified specific property of original object to use in the method. I have two strategies for this:
Clone the object at point A, and use the cloned copy to get the
property as shown in above code. At point A, Use a for loop and a
Map to form an associate array of object names, property original
values and traverse them to get the property initial value at point
B
Avoid Cloning because it always requires Deep Cloning
.clone() especially on a List will almost always end in tears because you would have to deep clone all the objects in the list, all their referenced objects, and so on.
Deep Cloning means you have to make a binary copy of every last object in the Object graph. Just copying a reference will give you a shallow copy and you will see any changes that are made to the referenced object. Just miss one property and you will have a hell of a time finding that bug.
Solution
What you should do is make all your CustomObject instances Immutable and then you don't need to worry about versioning, they can never change, mutation would involve creating a new instance that is also Immutable and a complete different object. Then you never had to worry about versions.
Of course all the instance variables that point to other objects will need to be Immutable as well. This is the same problem as the deep clone but taking from another angle. A much more manageable angle.