Downcasting while calling super.clone() method - java

Consider the following program
class A implements Cloneable {
String str = null;
public void set(String str)
{
this.str = str;
}
#Override
public A clone()
{
A a = null;
try {
a = (A) super.clone();
if(a.str!=null) {
System.out.println(a.str);
}
else {
System.out.println("null");
}
}
catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return a;
}
public static void main (String args[])
{
A a = new A();
a.set("1234");
A b = a.clone();
}
}
Why output of above program is 1234 and not null.
I was expecting null, because of following understanding of mine.
super.clone() method will create a new object of parent type (Object in this case) in which attributes of parent class will be shallow copied.
When we do downcasting in our clone() method, then attributes defined in child class will get initialised with their default values, since this is a new object.
But after looking at the output, it seems like attribute values of current instance of child class (this) are getting copied to newly contructed object (after calling clone of parent class and downcasting).
Can someone please tell what is going on when we are downcasting?

1234 is the correct result... Let's see why:
Create a new A instance:
A a = new A();
Set value to A.str
a.set("1234");
Clone a
A b = a.clone();
First of all, note, we're using clone() method from instance a, so let's go there:
#Override
public A clone()
{
// create a NEW instance, it does not set a to null!!!
// to reference the caller (a.clone in main)
// you must use this keyword i.e: this.str = null
A a = null;
try {
// call Cloneable::clone() method
a = (A) super.clone();
// now a is filled with data of this instance so print 1234
if(a.str!=null) {
System.out.println(a.str);
}
// unused code in this case
else {
System.out.println("null");
}
}
catch (CloneNotSupportedException e) {
e.printStackTrace();
}
// return cloned instance
return a;
}

From the Object#clone documentation.
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.
As you can see, the typical case is that X.equals(XClone) == true.
This wont be the case for you, as A didn´t override the equals method.
Additonally:
The method clone for class Object performs a specific cloning operation.
[...]
this method creates a new instance of the class of this object and initializes all its fields with exactly the contents of the corresponding fields of this object, as if by assignment; the contents of the fields are not themselves cloned. Thus, this method performs a "shallow copy" of this object, not a "deep copy" operation.
As this documentation states, the native implementation just creates a shallow copy of the object you are trying to clone. Due to that behaviour the correct output is 1234 and not null, as the fields in the class are just assigned to the cloned instance.

super.clone() method will create a new object of parent type (Object
in this case)
No. This is where you are going wrong. Object.clone() will create a new instance of the same runtime class as the runtime class of the object it is called on, which is A, not Object. And it will shallow-copy all of the fields of A in the object it is called on into the new object.
When we do downcasting in our clone() method, then attributes defined
in child class will get initialised with their default values, since
this is a new object.
That doesn't make any sense because casting references will never affect the state of the object that is pointed to. If the object that the reference points to was not already an instance of A, then the cast will throw a ClassCastException. If the cast succeeds then that means the object that the reference points to was already an instance of A, and you are simply pointing to that same object with a different type of reference. You will never get a "new object" with a cast.

Related

Is it possible to get the type of an uninstantiated variable in Java?

Is it possible to get the type of a variable that is declared (but not instantiated) in Java?
for example:
public class Foo {
FooTwo foo2;
FooTwo foo3;
FooThree foo4;
public static void main(String[] args) {
if (foo2.getClass() == foo3.getClass()) {
System.out.println("foo2 is the same type as foo3");
}
if (foo3.getClass() == foo4.getClass()) {
System.out.println("foo3 is the same class as foo4");
}
}
}
With output:
foo2 is the same type as foo3
obviously the method getClass() does not work on an uninstantiated variable, so this code does not function. I am assuming that the information I am looking for is stored somewhere in the variable (pointer?) for type safety, and that it may be accessible. Is it possible to Achieve this comparison?
the reason:
I have a class with several declared variables. These variables are supposed to point to objects stored in an ArrayList in another class. I am trying to create a method that will take an initialized (but uninstantiated) variable as a parameter, scan the arraylist for an object matching the type of the initialized variable, and set the variable to the object (Make the variable point to the object).
ALSO: The point of the system is to remove coupling in the constructor of the class. The objects cannot be instantiated immediately or in the constructor.
To start with, you need to be aware of the difference between the type of an expression and the runtime-type of a value. Consider, for example, the following code:
List<String> list = new ArrayList<String>();
System.out.println(list.getClass());
The above code prints class java.util.ArrayList, not java.util.List<java.lang.String>, because getClass() returns the runtime-type of the object that list refers to, not the type of list itself.
So it doesn't make sense to call getClass() on an uninitialized variable, because there's no value for it to return the runtime-type of.
I am trying to create a method that will that will take an initialized (but uninstantiated) variable as a parameter, […] and set the variable to the object (Make the variable point to the object).
Since Java is a pass-by-value language, it doesn't expose a way to modify a variable that is passed in as a parameter. For example, consider this method:
public void doNothing(Object obj) {
obj = "obj";
}
The above method does absolutely nothing. It has a local variable obj, which originally contains whatever reference is passed in, and then is changed to refer to the string "obj" instead; but this change has no effect, because nothing actually uses the local variable obj after that point. In particular, this method does not have any effect on whatever reference was passed in.
The closest you can get is to use reflection; if your method takes an instance of type Field, it can both examine the declared type of the field, and set the field to a value of its choosing.
You can do something similar using reflection. Here is an example code snippet. But may be there is a better way to solve your problem if you explain your use case in a bit more in detail.
import java.lang.reflect.Field;
public class Foo {
static FooTwo foo2;
static FooTwo foo3;
static FooThree foo4;
public static void main(String[] args) {
try {
Field foo2Field = Foo.class.getDeclaredField("foo2");
Field foo3Field = Foo.class.getDeclaredField("foo3");
Field foo4Field = Foo.class.getDeclaredField("foo4");
if (foo2Field.getType().equals(foo2Field.getType())) {
System.out.println("foo2 is the same type as foo3");
}
if (foo3Field.getType().equals(foo4Field.getType())) {
System.out.println("foo3 is the same class as foo4");
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
// TODO handle this if this can happen
} catch (SecurityException e) {
e.printStackTrace();
// TODO handle this appropriately
}
}
}
class FooTwo {
}
class FooThree {
}

Understanding Object.clone() in Java

I know that using this cloning mechanism is not a good idea (since it is 'broken' as some authors suggest), although I need help understanding how it works. We're given the following class hierarchy:
class N implements Cloneable{
protected int num;
public N clone() throws CloneNotSupportedException{
return (N)super.clone();
}
}
class M extends N{
protected String str;
public M clone() throws CloneNotSupportedException{
M obj = (M)super.clone();
obj.setString(new String(this.str));
return obj;
}
void setString(String str){
this.str = str;
}
}
Since N extends Object, how does the super.clone() return an instance of N? super.clone() is actually Object.clone() which returns a reference to an object of class Object. Why are we then able to cast it to N? N has a member num that is not in the class Object. How does the default behavior actually manage to automatically clone this variable (since it has no record of it in class Object)?
Also, the same goes for M. In M.clone() we're casting an object from class N (returned by super.clone()) to an object of class M. I know that all of this is valid, yet I do not understand why.
Object#clone is a native method that makes a low-level binary copy of your object, thus producing another instance of the same class. Therefore it is safe to downcast.
Note that this is the only way to have a polymorphic cloning method.
Technically, Object.clone() is a native method:
protected native Object clone() throws CloneNotSupportedException;
And the JVM internally knows how big the current object is, and what the type of the object is. So, it can create the appropriate object as a bit-wise copy and return a reference to it.
Since N extends Object, how does the super.clone() return an
instance of N?
super.clone() is actually Object.clone() which returns a reference
to an object of class Object. Why are we then able to cast it to N?
N has a member num that is not in the class Object. How does the
default behavior actually manage to automatically clone this
variable (since it has no record of it in class Object)?
Answers :
At runtime, you are inside an instance of N class calling its parent clone method. Consider it the exact same thing as if you had overrided it in your N class. The Object class is a native, and abstract object. When you call N.toString() in fact you call the first toString method the JVM finds in N's hierarchy.
Same here, remember you are in an instance of N class.
it does not : How do I copy an object in Java?
You can also use the XStream object to clone your objects, like this :
public static <T> T cloneObject(
T object) {
XStream xstream = new XStream();
return (T) xstream.fromXML(xstream.toXML(object));
}

Changing the value of an object in a method changes it globally?

Here's my Code
Class A
public class A {
private int a;
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
}
Class Change
public class Change {
public void changeSomething(A a){
a.setA(13);
}
}
Class Learn
public class Learn {
public static void main(String[] args) {
A a = new A();
Change change = new Change();
change.changeSomething(a);
System.out.println(a.getA());
}
}
The output is 13. Now when i am passing an object to the changeSomething method, internally the value of Object A has been changed but why do i see this effect outside that function?
Is not this equivalent to passing by value in C where unless you return that variable/Object you dont get the updated value.
i.e. dont i need to do a=changeSomething(a); and set the return type of this method to be as A?
Thanks
You're passing a reference to the original object around. When you write a method
void someMethod(A param) { ... }
param is a reference to the original object. The original object isn't being copied. Consequently when you change this object, the change is visible wherever that object is observed.
When you write:
private A a = new A();
it's important to realise that the variable is a reference to object type A, not an actual object type A. It's a fine distinction, granted.
The above behaviour can cause unexpected effects across your system, and it's an argument for immutability, especially in threaded environments where changes can be triggered from multiple threads.
Short:
changeSomething() will update the value for object so if you refer to same instance you will get the same value back
Bit long explanation:
//an Object of A created and its reference is set to a
A a = new A();
//instance of Change is created and its reference is set to change
Change change = new Change();
//it passes reference's (a) 's value to the changeSomething method
//which invokes `setA()` on instance referred by a (which is the same instance that waas crated in line 1
change.changeSomething(a);
//so you will get the changed value here
System.out.println(a.getA());
Well the code you provided works directly on an instance of A. This instance is changed, no matter if you return it or not. Its still the same instance of your object. And this instances variable reflects the new value.
This is because you pass the Object, and objects in Java are always passed by reference. Only primitive (int, double, char, long...) are passed by value.
In C it could be:
public void changeSomething(A& a){
a.setA(13);
}

Java Implementing copy completely from superclass when classes do not differ by data

I have several subclasses of a class "A", say B, C, and D. I store several of these in a generic
ArrayList<A> stuff;
B, C, and D have absolutely no different data members than A. The only way they differ is by different overridden methods. I would LIKE to be able to copy any instance of class A to another instance of class A (while retaining the true subclass)
Something like:
A obj1 = (A)new B(...)
A obj2 = (A)new C(...)
A obj3 = obj1.copy();
// (obj3 instanceof B) == true
Normally this would require B, C, and D to implement custom copy methods. However, this seems like a waste since the data members are exactly the same, and they would only exist so that the class is preserved.
Is there any way I could get away with only implementing copy in class A, and still preserving the underlying classes of the objects?
EDIT:
If I'm thinking correctly, the problem I would run into if just the superclass had a copy method:
class A {
int dataMember;
public A copy() {
A ret = new A(); // !!
ret.dataMember = dataMember;
return ret;
}
}
When calling "new" I couldn't generically determine what subclass of A the class is, and furthermore explicitly instantiate an instance of that. Or is there a way to do this?
You could give A a copy constructor:
class A {
public A(A other) {
//copy other's fields to this instance
}
}
Subclasses of A could also expose a constructor that took an A instance and passed it to the super constructor:
class B extends A {
public B(A other) {
super(other);
}
}
Are you familiar with clone? It will copy all your fields and mantain the derived class. Be careful that it won't do a clone of each field's object, but they will point to the same reference.
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {} // Will never happen if your object implements the Cloneable interface
}

How do I create a constant object in Java?

How do I create a reference to a constant object?
final Myclass obj = new Myclass();
does not work, it says obj(the reference) should not be re-assigned but we can still change the object referred. I want to ensure that the object itself does not change once constructed.
Just make it immutable (like String is). Or wrap it in another object which restricts access to mutators of the object in question (like Collections.unmodifiableList() and consorts do).
You are mixing two things: final and immutable.
A variable can be final, so you can't change it's a value (or object reference) after it is initialized (but of course you can change the reference's objects attributes)
An object can be immutable (not a keyword but a property), so you can't change it's value after it is created. The string is a good example - you can not change the backing char[] inside a String object.
What you want is an Immutable Object. There are no keywords in Java that can instantly make an object immutable. You have to design the object's logic, so that its state cannot be changed. As BalusC put, you can wrap it in another object which restricts access to its mutators.
I don't think there's any built in keyword to make that possible in Java. Even if the reference is constant/final, the internals of the object could still be changed.
Your best options is to have a ReadOnly implementation version of your class.
You can read more about this here: http://en.wikipedia.org/wiki/Const-correctness#final_in_Java
In Java, an immutable class is generally means that it doesn't have "setters" and any field that can be accessed with a "getter" should also be immutable. In order to get your data into the class to start, you'll need to have a constructor that takes the values as arguments:
public class MyClass {
String something;
int somethingElse;
// The class can only be modified by the constructor
public MyClass(String something, int somethingElse) {
this.something = something;
this.somethingElse = somethingElse;
}
// Access "something". Note that it is a String, which is immutable.
public String getSomething() {
return something;
}
// Access "somethingElse". Note that it is an int, which is immutable.
public int getSomethingElse() {
return somethingElse;
}
}
Yes it does you seem to have forgotten to set the type.
final MyClass obj = new Myclass();
That means that obj can only be assigned once. Java does not have a const keyword like C++ does. If MyClass is not declared final (final class MyClass { ... }) it can still change.
final variables should be assigned in the moment of declaration.
final MyClass obj = new MyClass();
In java object constant means you cannot change its reference but you can change the values of its state variables untill they are not final. if all the member variables are final then its a perfect constant, where you cannot change anything.
Here is a way to wrap any object to make it "roughly" immutable.
All method calls that are not 'getters' will throw an Exception. This code defines a getter as a method that meets these criteria:
name of the method starts with get or is
it takes no arguments
it returns a value (not void return type)
Yes, getter methods could mutate an object. But if your code (or code you are using) is doing that, you have some bigger problems, please go get some help :)
the code:
class ImmutableWrapper
public static <T> T wrap(T thing) {
return (T) Proxy.newProxyInstance(thing.getClass().getClassLoader(), new Class[]{thing.getClass()}, OnlyGettersInvocationHandler.instance);
}
private static class OnlyGettersInvocationHandler implements InvocationHandler {
public static InvocationHandler instance;
#Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
final String name = method.getName();
if ((args == null || args.length == 0)
&& (name.startsWith("get") || name.startsWith("is")
&& !method.getReturnType().equals(Void.class))) {
return method.invoke(proxy, args);
} else {
throw new UnsupportedOperationException("immutable object: " + proxy + ", cannot call " + name);
}
}
}
}
SomeClass myThing = ... create and populate some object ...
SomeClass myImmutableThing = ImmutableWrapper.wrap(myThing);
myImmutableThing.setValue('foo'); // throws Exception
myImmutableThing.whatever(); // throws Exception
myImmutableThing.getSomething(); // returns something
myImmutableThing.isHappy(); // returns something
Mayby you can create class with final attributes. So, you can't change it: object == const.
At least "String" immutable because of it:
public final class String implements Serializable, Comparable<String>, CharSequence {
private final char[] value;
//...
}

Categories

Resources