How do i change multiple references at once in Java?
I have an array holding references for objects. I want to change some of those references in开发者_运维问答 the array to another object. At the moment I use a for loop like the one below:
for (int i = region2.getStartPos(); i <= curPos; i++) {
if (regions[i] == region2) {
regions[i] = region1;
}
}
I want to avoid the for loop though, because it increases the computational complexity.
Is there a way to make the object referenced by region2
equal to the one of region1
directly?
For example, I have tried writing a method in the Region
class like the one below, but it gives me a "cannot assign a value to final variable this" error.
public void mergeRegions(Region region){
this = region;
}
Is something like this possible?
Each reference in Java is simply an address to some object in memory, so the kind of "automatic updates" you're asking for require aren't possible without some extra code.
Imagine that region1
references the address 0x1001
in memory, and region2
references 0x2001
. These two memory locations hold the actual region data:
0x1001
:x = 0, y = 5, width = 20, height = 30
0x2001
:x = 100, y = 200, width = 50, height = 20
If you could somehow tell the object at 0x2001
to be equal to 0x1001
, using your mergeRegions
method, would Java try to do something like this?
0x1001
:x = 0, y = 5, width = 20, height = 30
0x2001
:0x1001
This wouldn't work though, because the Java objects are both supposed to be Region
objects, each with the same fields and methods. If we wipe out the the Java object at 0x2001
, and just put in a plain address, none of the existing references to 0x2001
would work, because they're all expecting a Region
object at that address. That's why you cannot "directly assign" one Java reference to another.
Here are three hints to help you redesign your algorithm:
- Instead of copying the address
0x1001
into0x2001
, you can copy all of the data from0x1001
into the object at0x2001
. This would make both objects equivalent, but separate. - You can introduce one level of indirection. If you know C, think "pointers to pointers". Your
regions
array would hold a references toIndirectRegion
objects, which would in turn hold references to the actualRegion
objects. When you want to updateregion2
toregion1
, you only need to ask one of theIndirectRegion
objects to update its internal reference. - Wait until the end of your algorithm before you merge the regions. If you're able to collect up all the merge operations, you may be able to execute all of them in a single O(n) loop.
You cannot do this because it will break the contract of how that object might behave to other callers. Your first for-loop is the best you can do. A better solution might be to not use an array and instead use something that has O(1) access. For example, a Set<T>
. You could something like
set.remove(region2);
set.add(region1);
Which will be really fast if you have written, .equals()
and .hashcode()
Another solution is to copy everything from one class to another. I am not sure how I feel about this and if it is even safe. But you can do something like.
public void mergeRegions(Region region){
this.a=region.a;
this.b=region.b;
this.c=region.c;
this.d=region.d;
}
What are you using the array for? Amir's and Dan's suggestions about swapping the contents or using an indirection came to my mind, too. But I have the feeling that maybe you should change your data structure. So could you please elaborate on the usage of your array?
For instance, if you just have a few regions, n, then maybe instead of using an array of region-objects, you could use n sets of integers and use set operations like union, intersection and complement, or swapping sets. Or you don't even need the integers any more, but could use EnumSets or EnumMaps.
If you happen to have Josh Bloch's book "Effective Java", take a look at Item 25 about arrays and Item 32/33 about EnumSets/EnumMaps.
精彩评论