I have a question regarding the following code:
Object o;
o = "Some string";
System.out.println(o.toString()); //Some string
o = 666;
System.out.println(o.toString()); //666
How come that the content of the Object can be printed without any casts? Is it really so universal container?
It's just due to polymorphism. Object defines the method toString(), and it is overridden in String and Integer.
Object o;
o = "Some string"; // o is now a String.
System.out.println(o.toString()); // so calls String::toString().
o = 666; // o is now an Integer.
System.out.println(o.toString()); // so calls Integer::toString().
If the method toString() had not been defined in Object, the cast would have been necessary.
The toString() method is defined on the Object class so, in a sense, yes it really is such a 'universal' container.
However, much of the useful functionality associated with any particular object is in the references of the object's subtype. Once you've assigned a String to an Object you can't access things like substring(). The functionality you can access with an Object reference is limited.
From the doc:
Class Object is the root of the class hierarchy. Every class has Object as a superclass. All objects, including arrays, implement the methods of this class.
Its not a universal container so to speak. Primitive types are not Object.
In your example, you are storing String and Integer which inherit from Object. Since Object has toString() method, you don't need to cast it.
Related
This question already has answers here:
What is polymorphism, what is it for, and how is it used?
(29 answers)
Closed 5 years ago.
Here is my example code:
String str = "hello";
Object obj = (Object)str;
System.out.println(obj.toString());
I found the source code of Object, and the toString() method is:
public String toString() {
return getClass().getName() + "#" + Integer.toHexString(hashCode());
}
I thought the result of the example shound be the address of this Object, like [B#15db9742 , after I convert str to Object , but it still print hello. Why? Shoundn't obj use the method of Object? Can Anyone explain the principle of it to me?
This is polymorphism (specifically, runtime polymorphism). It doesn't matter what the type of your reference to the object is (Object or String), as long as that type has toString (so your code compiles), the toString that will be used is the one the object itself actually has, not necessarily the one provided by the type of your reference. In this case, the object is a String no matter what the type of your reference to it is, so String#toString is used.
Because the underlying object is a String object and the String class has overridden the toString() method in it.
Though you have the type Object on left hand, the methods from implemented Class gets execute and the overall phenomenon called as Polymorphism. You are Just changing the Form of String to Object.
When you do
Object obj = (Object)str;
That doesn't change String to Object class. You are just changing the type of the Object not the actual behaviour of it.
Virtual method invocation implies the method override will be executed given the actual implementation, as opposed to the implementation in the reference type.
In other words, your String instance will still invoke overrides of Object's methods implemented in String, even if cast as Object.
Object obj is the result of an (unnecessary) cast, but is still a String....
the String class has an implemented overide of toString method:
public String toString() {
return this;
}
verify that obj is a String by doing:
System.out.println(str.getClass());
System.out.println(obj.getClass());
you will get
class java.lang.String
class java.lang.String
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 cannot figure out the difference between accessing a method of a subclass that is accessed and overwritten using the base class(Object) for the static type of the object versus using the subclass(Point).
For example:
public class Point {
int x, y;
...
public boolean equals(Object o){
...
}
public boolean equals(Point p){
...
}
}
Object o = new Object();
Point p = new Point(3,4);
Object op = new Point(3,4);
// here the static type is Point and the dynamic type is point, in this case
// the equals() method that we choose and gets overwrriten depends on the
// parameter type that is passed.
p.equals(o);
p.equals(p);
p.equals(op);
// here however the static type is Object so we initially look at the equals()
// method in our Object class during compile time and check its parameter type
// which is Object, thus if we overwrite
// the equals() method we will pick the one that has a type Object parameter.
// Since the dynamic type of our object is Point, when we are at run time
// we will look for the equals() method in Point that matches with the
// method type Object parameter.
op.equals(o);
op.equals(op);
op.equals(p);
What i am not seeing is why would i want to use the later rather than the former to specify what method i would like to overwrite? The former depends on the type parameter while the later depends on the type parameter of the static type of our object. I just dont see the benefit of using Basetype obj = new Subclasstype() to access and overwritten method in my subclass. It looks more complicated and the object can only be used to access instances of methods in the subclass that were in the base class, not any other methods in the subclass.
public boolean equals(Point p){
...
}
The above method has nothing to do with equals(Object) except sharing the name equals. It does not override it, it cannot be invoked from an Object-typed variable, there is no contract for it defined by Object.
When you write
op.equals(p);
you are invoking a method on the Object type. The only method called equals in that type is equals(Object) and this choice is permanent. The runtime can only provide a different override of equals(Object), but it will never route the call to equals(Point).
Similarly, when you write
p.equals(op);
the compiler will again see that you are invoking equals with an argument whose static type is Object, selecting equals(Object).
I think you are messing up some concepts, so let me explain them:
Object op = new Point(3,4);
The behavior of variables o and p are clear, so I'll focus on op: it's a variable whose type is Object, which means you can use all methods declared in that class. You cannot use equals(Point p) method because it does not exist for Object. But, at the same time, the behavior of a method is given by the instance it self, not by the variable which is pointing at it, so op is pointing to a Point instance and the equals(Object) method has been overwritten, so the behavior of that method is given by the class Point.
I'm preparing for a java exam. I came across the following question
String s = new String ("hello");
Object o = (object) s;
Since o and s are both references that point to the same object, is there any difference in accessing the object through the reference s over the reference o?
Would I be right in saying that all objects (like the one being reference by s) are subclasses of Object in Java and as such using the reference s you will be able to call the methods known by the superclass Object like clone() and the methods known by String like length(). Whereas, the superclass object reference o will only be able to call it's own methods and not those of the subclass? Thanks.
The difference is that by using o you will not be able to call string specific methods unless you cast it back to String.
However, any method that you call on o that is defined on the String class will call the later version of the method. For example, o.toString() will return "hello", and not the descriptor that the Object.toString() normally returns. This is called polymorphism.
im trying to do some reflection on a applet.
things i found are some arrays of ints, strings, objects etc.
for example, if there was a field with an object[] and object[0].toString() = [I#7593c366
then i know its an integer array. but what if it says aa#98324ca33 is it's class then aa?
im using a classloader, so my first guess when i see this i need to load the aa class (part before the #, and use the object in it. but im not sure the part befor the # is the class. can somebody say me this is right? or got other ideas?
thnx!
You shouldn't use toString() for this - for one thing, it can have been overridden. As a straightforward example:
Object x = "aa#98324ca33";
String bogusClassName = x.toString();
You would clearly be wrong to think that x refers to an object of type aa here - it refers to a string.
You can find out the class of any object just by calling getClass() on it:
Object x = new SomeType();
Class<?> clazz = x.getClass();
It's not really clear what you're trying to do or where you're getting information from in the first place, but you definitely shouldn't be using toString to determine the class involved.
Yes, the part before # is the class fqn, but you should not rely on that. Object can override toString() and then your logic will fail.
Use obj.getClass() instead.
Take a look at the class java.lang.Class. Just call getClass on an object to retrieve its class instead of using the toString method
Object anObject = ... ;
Class<?> clazz = anObject.getClass();
If you want to check whether it is an array, you can use to Class#isArray() method
clazz.isArray()
The other way around is also possible. If you have a Class instance, you can determine whether an object belongs to this class by using the Class#isInstance( Object ) method
clazz.isInstance( anObject );