Is there a way to find out whether a Java function (or a constructor) that takes varargs was actually called with varargs or with an array?
Say I have the following:
public class MyCompositeObjects {
MyObject[] objects;
MyCompositeObjects(MyObjects... objects) {
this.objects = Arrays.copyOf(objects,objects.length);
// or just: this.objects = objects; ?
}
// ...
}
The constructor may be called with a single MyObject[]
argument, which may change later, and if I do not copy the array in the constructor those changes will apply to the member variable objects
as well, right? However, if the constructor is called with several MyObject
s, there is no other reference to the array* to change it later outside the class, so I could assign it directly. Can I tell inside the constructor (or, generally, any function that takes varargs) how it was called?
*nb: Is there a specific name for this? Is it simply an anonymous array?
No, you can't. It's meant to be entirely transparent - this code:
new MyCompositeObjects(a, b);
is exactly equivalent to
new MyCompositeObjects(new MyObjects[] { a, b });
If you can trust your callers to do the right thing, you could always create two static methods and make the constructor private:
public static MyCompositeObjects createWithCopy(MyObjects[] values) {
return new MyCompositeObjects(Arrays.copyOf(values, values.length));
}
public static MyCompositeObjects createWithoutCopy(MyObjects... values) {
return new MyCompositeObjects(values);
}
private MyCompositeObjects(MyObjects[] values) {
this.objects = values;
}
Note how the "with copy" version doesn't use varargs, which should help users to use the right version.
The only way to know is to parse the code. This is because varargs is basicaly a compile time feature and doesn't change how the program runs.
If in doubt, I would always copy the array. Unless you know this will be a performance issue.
BTW: You can do the following.
MyCompositeObjects(MyObjects o1, MyObjects... objects) {
MyCompositeObjects(MyObjects[] objects) {
However, this likely to do the opposite of what you want.
Another option is to use a static factory.
private MyCompositeObjects(MyObjects[] objects) {
this.objects = objects;
}
MyCompositeObjects create(MyObjects... objects) {
return new MyCompositeObjects(objects.close());
}
MyCompositeObjects createNotCopied(MyObjects... objects) {
return new MyCompositeObjects(objects, false);
}
Use the more cumbersome method name for the less safe version. This means if a method is chosen without much thought, the safe version is more likely to be used.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With