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
Related
I'm trying to get the first character from the Object after attempting to downcast the object but my code seems to be missing something I don't know what's wrong.
String name = "Mike";
if I try the charAt() method it works fine using the above code.
name.charAt(0);
gives us "M". right?
I tried to downcast(not sure if that's the right term) the object say:
Object obj = (String) name;
obj ==> "Mike"; // is what we get
But if I use the method:
obj.charAt(0);
I'm expecting the same result "M" but it gives me an error instead. Am I missing something?
Your problem is that by assigning String name to Object obj you hide that whatever is obj referencing to, is a String.
Of course you can cast obj to String by using
(String)obj
because underlying reference is an reference to object of type String.
You have to consider that as obj is an Object it might be whatever type your language supports (is it Java?) so that's why you are getting error when executing obj.chatAt(0).
What would you expect it to return if underlying reference was to e.g. Integer?
That's why to use charAt() you have to cast it back to String
String str = (String)obj;
char ch = str.charAt(0);
Or simpler:
char ch = ((String)obj).charAt(0);
keeping in mind, that if obj's reference changed in meantime to e.g. some Integer, you won't succeed at casting probably throwing another error / exception.
P.S. Sample code is assuming, that your language is using char as type that is meant to contain single character.
obj is a Object not a String so that it does not have the charAt() method. If you already know your object is type of String then you can cast it ((String) obj).charAt(0) or you can using: obj.toString().charAt(0)
Well, Casting means taking an Object of one particular type and turning it into another Object type.
Downcast means taking the Object and casting it into a more specific type of Object. For example:
Object obj = "This is an object";
String s = (String)obj;
Now you can invoke the methods in the String Class upon the String s object. But not the opposite. So you cannot invoke Directly the methods that exist in String Class upon an instance of Class Object.
To use the method charAt(int index) in the above example on the Object obj directly, you need to downcast first then you can go ahead:
((String)obj).charAt(0); // it will give "T";
Furthermore, If I do:
obj.charAt(0);
And when I try to compile it, it gives me this error:
The method charAt(int) is undefined for the type Object
Which basically means that method doesn't exist in Object Class.
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.
can we call the toString() method of the Object class for a String
String string = new String("Hello");
System.out.println(string);
for a string the overrided method is called in the String. Are there any way to call the toString() method of the Object class for a String
I want to print out the memory address for the String object
No, you can not call the overridden method. However, you could mimic the output of the Object's toString() (which basically only uses the hashCode) as follows:
string.getClass().getName() + "#" + Integer.toHexString(string.hashCode())
*edit: As noticed by Taemyr in the comments, an even closer mimic, that does not use the hashCode defined by String, would be:
string.getClass().getName() + "#" + Integer.toHexString(System.identityHashCode(string))
Nope.. Why?.. Well because that method is overridden , So based on object type, at run-time, the method from String class is always called
No you can't, once a subclass overrides a parent's member (function or variable), you can't reach them from outside that class. that is the whole principle of encapsulation and inheritance (child classes having different behaviour than parent).
I have a class
class Configuration {
// various stuff
#Override
public String toString() {
// assemble outString
return outString;
}
}
I also have another class
class Log {
public static void d(String format, Object... d) {
// print the format using d
}
}
The Log class works perfectly fine, I use it all the time. Now when I do this:
Configuration config = getConfiguration();
Log.d(config);
I get the compiler error The method d(String, Object...) in the type Log is not applicable for the arguments (Configuration). I can solve this:
Log.d("" + config); // solution 1
Log.d(config.toString()); // solution 2
My problem: How is this different? In the first solution, the compiler notices that it has to concatenate two Strings, but the second one is a Configuration. So Configuration#toString() is called and everything is fine. In the compiler error case the compiler sees that a String is needed, but a Configuration is given. Basically the same problem.
Needed: String
Given: Configuration
How are these cases different and why is toString not called?
While designing the language, someone decided that when a programmer appends an arbitrary object to a string using the + operator, they definitely want a String, so implicitly calling toString() makes sense.
But if you call an arbitrary method that takes a String with something else, that is simply a type error, exactly what all that static typing is supposed to prevent.
The line
"" + config
gets translated to something like
StringBuilder sb = new StringBuilder("");
sb.append(config);
where the second line calls
StringBuilder.append(Object obj);
This method calls obj.toString() to get the String representation of the object.
On the other hand, the first parameter of Log.d must be a String, and Java doesn't automatically call toString() to cast everything to a String in that case.
One of the common use of toString(), is print() and println() methods of PrintStream, as in:
System.out.print(object);
System.out.println(object);
Basically, these two methods will call toString() on the passed object. This is one of the Polymorphism's benefits.
Nice Question...
But,
Compiler does not call a method to match formal parameters. it simply tries to cast the objects if possible.
But when you use the "+" operator the compiler executes the toString() method of its arguments (in case they are objects) by default.
In one case you are passing an object argument to an operator which expects objects.
In the earlier case you are passing an object argument to a function which expects string.
Basically function/operator signature is different.
It is almost incidental [in the context of this question] that .tostring called when + is applied. It takes an object and does something.
For all you know, you might be passing in object when string is required by mistake. So it can't blindly do .tostring()
You are passing Configuration class object argument in case 1 but in the case 2 , you are passing string argument . so no error occures.
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.