In a book on Core Java, I found this excerpt :
Think about the way in which the
Object class can implement clone. It
knows nothing about the object at all,
so it can make only a field-by-field
copy. If all data fields in the object
are numbers or other basic types,
copying the fields is just fine. But
if the object contains references to
subobjects, then copying the field
gives you another reference to the
subobject, so the original and the
cloned objects still share some
information.
After reading this I was wondering, that How is the clone method originally implemented in Object Class?
What bothers me is that: how can a method in Object class make a field by field clone of a sub-class object, when it knows nothing about that class?
Actually, clone() is implemented in native code, so I assume it just does a memory copy (copy all the bytes) without knowing the contents.
Besides that, there is the Reflection API to gain knowlegde about a class (which would be slower, however).
Read this from the Javadoc:
protected Object clone() -
Creates and returns a copy of this
object. The precise meaning of "copy"
may depend on the class of the object.
The general intent is that, for any
object x, the expression:
x.clone() != x
will be true, and that the expression:
x.clone().getClass() == x.getClass()
will be true, but these are not
absolute requirements. While it is
typically the case that:
x.clone().equals(x) will be true, this
is not an absolute requirement. By
convention, the returned object should
be obtained by calling super.clone. If
a class and all of its superclasses
(except Object) obey this convention,
it will be the case that
x.clone().getClass() == x.getClass().
By convention, the object returned by
this method should be independent of
this object (which is being cloned).
To achieve this independence, it
may be necessary to modify one or more
fields of the object returned by
super.clone before returning it.
Typically, this means copying any
mutable objects that comprise the
internal "deep structure" of the
object being cloned and replacing the
references to these objects with
references to the copies. If a class
contains only primitive fields or
references to immutable objects, then
it is usually the case that no fields
in the object returned by super.clone
need to be modified.
Means when you have a subobject in your object you shouldnt just clone/copy its reference but the internal structure of this object (in order to create a new instance of it), if each object has its clean clone() methode you will be able to clone it like the parent object otherwise you will have to create a new instance of it and copy its internal premitive fields one by one.
Related
I want to make a getter that doesn't allow the caller to edit the returned object.
Using a List as an example (though I would like the answer to apply to any other type as well), this is the usual approach for returning and for editing an attribute:
class MyClass {
private List<String> strings;
// to get the whole object
public List<String> getStrings() {
return this.strings;
}
// to alter the object
public void addString(String newStr) {
this.strings.add(newStr);
}
//...
}
However, this doesn't prevent that some other class from doing this
myClassInstance.getStrings().add("that's a dumb implementation, bro");
and that would be kind of rude since I created addString() for that specific purpose.
I would rather if other classes would only use the getStrings() method for reading, because there might be a similar case where I don't want to implement the addString() method. In that situation, other classes are able to edit strings anyway through the getter, but I still want to be able to edit the object privately in the C class.
I know this wouldn't be a problem if the attribute was a primitive type since those are saved directly in the instance, but objects are references to memory, so any class that's able to get its hands on those references can edit it if the object type allows that.
Can I just trust that other classes won't try to edit my object through the getter?
There's the option of cloning it (some classes may override the clone() method), but is this a good use for clone()? What are the best practices of cloning an object?
Is it worth it to create a custom class (called ReadOnlyList, for this example) that is only writeable in the constructor (like this), then copy my strings to a new ReadOnlyList, and return that?
Also, should objects provide a method that returns a non-writeable clone of the object to solve this?
You can have getStrings return an unmodifiable list.
public List<String> getStrings() {
return Collections.unmodifiableList(this.strings);
}
https://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#unmodifiableList(java.util.List)
Can I just trust that other classes won't try to edit my object through the getter?
No.
There's the option of cloning it (some classes may override the clone() method), but is this a good use for clone()? What are the best practices of cloning an object?
The oracle docs provide a proposed strategy:
Don't share references to the mutable objects. Never store references to external, mutable objects passed to the constructor; if necessary, create copies, and store references to the copies. Similarly, create copies of your internal mutable objects when necessary to avoid returning the originals in your methods. (https://docs.oracle.com/javase/tutorial/essential/concurrency/imstrat.html)
Is it worth it to create a custom class (called ReadOnlyList, for this example) that is only writeable in the constructor (like this), then copy my strings to a new ReadOnlyList, and return that?
In this case not (see Micky Loo's answer). However in a more special case yes (if you have to guarantee immutableness and can not copy the object).
Also, should objects provide a method that returns a non-writable clone of the object to solve this?
You can not create a const return value in Java. see: Const return values in Java
As I understood from what I've read there are basically two ways to create completely new objects in Java: 1) by using new operator and 2) by means of serialization (for deep copying, for example). All other object manipulations (like assigning, for instance) deal with references to existing objects. But what is the difference between the two above mentioned ways in terms of inner logic? It seems that one difference is that serialization somehow doesn't use constructor methods. Am I right? Are there other differences?
By 'inner logic' I mean how the compiler (or whoever deals with it) creates object step-by-step, what algorithm it uses, what methods are used for that and so on. More like what Margaret Bloom was writing about in her answer but in more detail.
FURTHER CONFUSION CLARIFICATION:
So do I get it right that during deserialization the copy of the object:
class Class1 {
static ARRAY_LENGTH = 10;
public class1() {
int[] anArray = new int[ARRAY_LENGTH];
anArray[0] = 5;
...
anArray[9] = -2;
}
}
will include a copy of the array created elsehow (how? since no constructor has been called)? And furthermore, though the original array (before serialization) has been created by using static field (which is lost during serialization) its deserialized copy will nevetheless be identical to the original array?
Serialization and the new operator are completely different things, though they both result in a reference to a newly allocated object.
You can find detailed information about the new operator in chapter 15.9.4 Run-Time Evaluation of Class Instance Creation Expressions of the Java Language Specification.
At run time, evaluation of a class instance creation expression is as follows.
[...]
Next, space is allocated for the new class instance.
[...]
The new object contains new instances of all the fields declared in the specified
class type and all its superclasses.
[...]
Next, the actual arguments to the constructor are evaluated, left-to-right. [...]
Next, the selected constructor of the specified class type is invoked. This results in
invoking at least one constructor for each superclass of the class type.
The value of a class instance creation expression is a reference to the newly created
object of the specified class. Every time the expression is evaluated, a fresh object
is created.
Editing mine
So long story short, new allocates space for a new object (specifically space for its fields), initialize its fields with their default values and invokes the chosen constructor.
Java Serialization is another matter entirely.
The ability to store and retrieve JavaTM objects is essential to building all but the most transient applications. The key to storing and retrieving objects in a serialized form is representing the state of objects sufficient to reconstruct the object(s).
Emphasis mine
Which means that serialization was designed to allow the programmer to save objects states into a persistent medium (abstracted into stream within Java) and read them back.
As such, deserializiation does not invoke constructors since the object state is restored automatically by reading it out the stream. You can override the default behavior though.
Reading an object from the ObjectInputStream is analogous to creating a new object. Just as a new object's constructors are invoked in the order from the superclass to the subclass, an object being read from a stream is deserialized from superclass to subclass. The readObject or readObjectNoData method is called instead of the constructor for each Serializable subclass during deserialization.
Emphasis mine
Said that, I would like to stress out how using new and serialization are totally unrelated things from a conceptual point of view.
In the first case you are creating your own new object, in the latter you are reading a previously saved object (possibly by someone else).
Even though they can be thought as similar for their final result, you should have, in your mind, a really clear distinction between the twos.
New operator is use to create object in memory whereas serialization is the concept belongs to data persistence and it could also be used for creating a new object in memory.
If an object implements java.io.Serializable it will be marked as Serializable Object and data in object could be converted to byte stream (serialize) and we could use this byte stream data to create a new object in memory (desrialize). Java supports 2 objects for serialize and deserialize, they are ObjectInputStream and ObjectOutputStream
Disagree with deserializiation does not invoke constructors:
In fact, Deserializiation just does not invoke the constructors defined in the class body. As depends on java.reflect, it of course need to invoke constructors to produce a Object from a Class. It just invoke the custom constructors created by sun.reflect.ReflectionFactory.newConstructorForSerialization(Class<?> var1, Constructor var2).
Whenever I'm doing shallow cloning then if my class consists of any user-defined reference type then there reference value will copied but not values, but if I'm writing String s="something", then even though s is an object but it is directly copied into the cloned object, why so? Does it mean pre-defined object will be copied but user-defined object reference will be copied?
If you want an object of the same state, then you can use clone(). If there's no difference between the two I would say use a constructor. Cloning requires an object to already have been made in order to make another instance, not to mention the implementation of Cloneable is already fairly messy.
Also note, the object you attempt to use clone() on must actually implement Cloneable and override the method in order to actually work.
It is not that "predefined" object types are deep copied and "user defined" object types are shallow copied.
Your cited example is this :
String s = "something";
Yes, a string literal is an "object" but strings are immutable objects, and more importantly they are special down to the level that they are built into the design of the language itself. REALLY what you are doing here is nothing different from saying YourClass varName = new YourClass(); Here, you create a new String object with value "something" (if the literal does not exist in the string constant pool) and store a reference to that object to your variable s of type String.
You can shallow copy a string just like you can shallow copy a user defined object:
String s = "something"; //in this example this would be the same as saying new String("something")
String imAShallowCopyOfS = s;
System.out.println(imAShallowCopyOfS == s); //true
You are still just copying the reference that s points to into imAShallowCopyOfS. I would suggest you shy away from using Strings to learn the behavior of references in java, though, as they are rather special objects that receive some special treatment by the compiler/vm.
I don't fully understand when Java passes a copy/value and when it passes a "reference" (the pointer).
I'm trying to assign a copy of a static object I have, but I'm not sure how to go about it.
I have this:
static ArrayList<MyObject> myObjects;
I want to get a copy of myObjects so that I can play around with the values without affecting the original. Does it pass a reference or a copy/value when I use a getter like so:
public static ArrayList<MyObject> getMyObject()
{
return ThisClass.myObjects;
}
What does that return? If it's a reference, how can I get a copy?
I've seen these:
(How do I copy an object in Java?)
(Java: getter method vs. public instance variable: performance and memory)
(Is Java "pass-by-reference" or "pass-by-value"?)
(How can Java assignment be made to point to an object instead of making a copy?)
But I still don't quite understand what I'll get back.
Java will always return a reference and not a copy as long as it's not a primitive type (aka long,int,short,etc or one of the primitive wrappers Long,Integer, Short.
To get a copy you will need to either copy the data, use a copy constructor, or use the method clone which will create a new object with the appropriate values.
Example of a copy constructor with a list, by default this is a "shallow copy" meaning the objects inside are the same.
List<MyObject> myNewCopiedList = new ArrayList<MyObject>(oldList);
For a "deep copy", meaning the objects inside can be mutated without affecting the originals you will need to make a new List then add copies/clones of the object and add.
Example, assuming MyObject has a copy constructor or a clone method.
List<MyObject> myNewCopiedList = new ArrayList<MyObject>();
for (MyObject myo : oldList){
myNewCopiedList.add(new MyObject(myo)); // if there is a copy constructor
myNewCopiedList.add(myo.clone()); // if there is clone method
}
Think of it this way. Java is always pass by value.
For primitives, it is pass by value(actual value).
For objects, it is pass by value-of-reference.
public int square(int a) { //The parameter a is copy of actual int itself.
//So now there are 2 ints
a=a*a; //Only local copy a is actually modified.
//The integer variable passed(in caller function) is not modified.
return a;
}
If you call doSomething(d) where d is an object, a copy of reference pointing to this object is assigned to parameter a but there is only one object.
public void doSomething(Object a) {
// Here the parameter is a reference which points to an
// object, not the object itself
a.doMore(); //But doMore() does things using a different ref but on the same object.
//The object can be modified!
Object b = new Object();
a = b; //Object referenced by passed parameter does not change but
//copy of reference now points to different object.
// Now there is no reference of original object passed in this method.
}
Technically, Java is always pass-by-value. However, for a beginner's thinking, it's easier to think about it this way:
If it's a primitive type, it's pass-by-value.
If it's an object, it's pass-by-reference.
So in your example, you are returning a reference to the same static object in ThisClass. The reason I say this is technically pass-by-value is because your variable myObjects actually stores the memory address of the ArrayList<MyObject> which you declared, and it's this which is passed.
In order to properly make a copy of an object, one must know which non-primitive fields encapsulate
Mutable aspects of the object's state, but not its identity
The identity of an object and other immutable aspects, but no mutable aspects.
Aspects of the object which are expected never to be exposed to any code which might mutate them (and not identity)
Mutable aspects of the object's state, as well as its identity
Based upon what a field encapsulates, a correct copy of Foo
If one of Foo's field which encapsulates mutable state, a the corresponding field in a copy of Foo should hold a reference to a different object with the same state.
If a field encapsulates object identity, that field in the copy must hold a reference to the same object as in Foo--not a copy.
If a field encapsulates only immutable aspects other than identity, then a copy of Foo may either hold a reference to the same object as in Foo, or any object which has the same immutable state, as convenient.
If a field encapsulates both mutable state and identity, because the first two requirements will conflict, it will not be possible to copy the object in isolation.
In some cases, it may be possible to copy a set of mutable objects which use references to each other to encapsulate both state and identity. Such a copy must be performed on the set as a whole; for each object within the set, any field which in the original object encapsulates both the mutable state and identity of another object in the original set must in the copy refer to the corresponding object in the copied set.
To make a class immutable what I can do is:
1)Make class final
2)do not provide setters
3)mark all variables as final
But if my class has another object of some other class then , somone can change value of that object
class MyClass{
final int a;
final OtherClass other
MyClass(int a ,OtherClass other){
this.a = a;
this.other = other;
}
int getA(){
return a;
}
OtherClass getOther(){
return other;
}
public static void main(String ags[]){
MyClass m = new Myclass(1,new OtherClass);
Other o = m.getOther();
o.setSomething(xyz) ; //This is the problem ,How to prevent this?
}
}
A) Make the OtherClass immutable as well
or
B) Don't allow direct access to the OtherClass object, instead providing only getters to act as a proxy.
Edit to add: You could make a deep copy of OtherClass and return a copy rather than the original, but that generally isn't the type of behavior you would expect in Java.
Immutability is best considered from the perspective of the API user. So your object API needs to satisfy the following two conditions:
No way for an external user to change the value of the object
A guarantee that any time the user reads or makes use of the object's value in the future, it will get the same result
Important note: It is in fact OK to have mutable data inside an immutable object as long as it behaves as an immutable object from the perspective of the API user. Consider java.lang.String for example: although it is generally considered as the definitive immutable class, it does in fact have a mutable internal field for caching the hashCode (not many people know this!).
So to address your question, if you wish to contain another (mutable) object inside an immutable object then you typically need to do one or more of the following:
Guarantee that nobody else can change the value of the mutable object. Typically this means ensuring that no-one else can have a reference to the mutable object, so this is only usually possible if you create the object yourself rather than accept a reference from outside.
Take a defensive deep copy of the mutable object, and don't hand out references to the new copy. Only allow operations that read the new copy in the public API. If you need to hand out a reference to this object, then you need to take another defensive copy (to avoid handing out a reference to the internal copy).
Use an immutable wrapper for the mutable object. Something like Collections.unmodifiableList. This is useful if you want to hand out a reference to the internal mutable object but don't want to run the risk of it being modified.
All of these solutions are a bit hacky - a better solution overall is to avoid the use of mutable objects within immutable objects. In the long run it's asking for trouble because sooner or later a mutable reference will leak out and you will have an extremely hard to find bug. You are better moving towards a full hierarchy of immutable objects (the approach taken by languages like Scala and Clojure)
I assume OtherClass (by the way you say Other once) is meant to be a class you don't control, or which has to have a setter.
If you can't remove getOther, change it to getOtherView and return a read-only view of other. There will be wrappers for all the get methods, but no set ones.
Return deep clones from your getters. You may find this to be no easy task.
All the objects referenced in the immutable class should be immutable, or at least be encapsulated as private and making sure that they are not modified (not inside the methods of your class and definitely not from the outside). For instance, if you have this situation:
public class MyImmutable {
private MutableClass mutableObject;
}
... You can not provide the getMutableObject() method, because doing so will open the door for outside modifications, like this:
myImmutable.getMutableObject().setSomeAttribute(newValue);
As a special case of the above, all collections and/or maps should be made immutable, with the ummodifiableXXX() methods in the Collections class.
you cannot (reasonably) stop that in java. if you don't have control over the other class, there are ways to effectively get immutable behavior, but it can be very expensive in practice. basically, you must always return a copy of that class in any public method return values. (the jdk actually has this problem with the TimeZone class).
But If my class has another object of some other class then , somone
can change value of that object...
Java objects are not primitive. If you mark a primitive as final, then its value cannot be changed once it is assigned. However, object contents cannot be final, only object references can be final. So you cannot make an object in this way.
One solution might be abandoning all setter/mutator methods those could change the particular fields of the object and encapsulating them in a way that you can only access them, not change them.
It is possible to create the immutable class in java by following ways
1.Don't Provide setter methods.
2.Make all fields are as final and private.
3.Make Class as final.