toString() behavior of object when not overridden - java

If the toString() method of a class is not overridden (or overloaded), and another method that returns a string is defined in the class, then what happens when I pass an instance of the class where a String is expected?

If your class extends Object, you will get the result of Object#toString(), which is what will be called. If your class extends something else, it will get the first #toString in the inheritance path.

Fun fact: It takes less time to test this than asking a question on Stack Overflow and getting an answer.
As you may know, every single class you create directly or indirectly inherits from the almighty Object class! If you don't override toString, calling toString will result in a call to the toString method of the nearest ancestor.
Suppose A inherits from B which inherits from C which inherits from D. Only C has overridden toString.
Calling toString on an object of... will result in calling the toString of...
A C
B C
C C
D Object
I hope you understand that.
Actually, not only does the toString behave like this. Every method does this as well!
Now that you know Object.toString will be called. What does it do actually?
From this answer, we know that Object.toString outputs something like this:
FullyQualifiedNameOfYourClass#12345
FullyQualifiedNameOfYourClass basically means your class name, followed by the package that it is in e.g. com.example.MyClass.
12345 is the hashcode of the object, returned by hashCode() on the object.
So will Object.toString call one of your class' methods that returns a string, if you ever declared one?
Nope. Because it just doesn't. The documentation of toString clearly says that it just returns something like FullyQualifiedNameOfYourClass#12345 and nothing else.
Even if it did, it makes no sense. What if you declared two methods that return a string? Which one should it choose? Also, reflection takes time and will slow down the whole thing.

Using the name of the class where a String is expected is not allowed. Consider the following:
class Foo {}
class Bar {
public void baz(String a) {
// Do something
}
public void binky() {
baz(Foo); // Compiler error
}
}
However, you could do the following:
class Foo {}
class Bar {
public void baz(String a) {
}
public void binky() {
Foo b = new Foo();
baz(b.toString());
}
}
Because the .toString() method of class Foo is not overridden, you will inherit the default .toString() from the Object class. This default behavior will print a string consisting of the name of the class of which the object is an instance, the at-sign character #', and the unsigned hexadecimal representation of the hash code of the object. (Thanks Kevin!)

Related

Calling equals(""); by itself compiles and runs

I've noticed that calling equals(""); in a method of a class is not generating any error within Eclipse. I've never seen .equals called without something like string1.equals(string2);.
package voodoo;
public class Equals {
public void method(){
equals("");
}
}
What's going on here and when would calling equals() by itself ever be used?
If I put that into a JUnit to test, it runs and passes.
equals that you are calling is Object's equals method, which can be called on this reference without specifying it explicitly. In other words, your call is equivalent to
this.equals("");
This is perfectly valid, although a well-behaved implementation must always return false. Note that the return value is ignored, which is legal as well.
You can see what's going on by overriding equals with something that prints a message, as a matter of an experiment:
public class Equals {
public void method(){
equals("");
}
#Override
public boolean equals(Object other) {
System.out.println("I am being compared to '"+other+"'");
return super.equals(other);
}
}
equals is non-static and it is calling equals of Object which is similar like calling any other method of the class. Moreover, our class is child of Object. Method call is something like thisObject.equals(emptyString) note here String is also an Object. So, ultimately we are invoking currntObject.equals(object) method from child of the Object.
It is similar to,
class A {
public boolean ok(Object str) {
return false;
}
}
class B extends A {
public void method(){
ok("");
}
}
Here child has not overriden the equals so, it will call the method of it's parent and it will refer to the current instance.
Since everything is subclass of Object class, here you are calling super class (Object) equals method. And it receives Object as a parameter where "" is a string object, it compiles fine.
And it returns boolean actually, but you are ignoring it to receive. That's legal to ignore the result.
If you receive it and check, that returns false since your Equals class is not equals to an empty string.
equals(...) without explicit object calls the method on this. In your example you are comparing the instance of Equals to an empty string.
The equals() public method at Object class. All class by default a direct/indirect child class of Object class. Your Equals class doesn't inherit any class explicitly. So it is an direct subclass of Object.
And in Object class the method equals() is declared like this -
public boolean equals(Object obj){}
So your code is completely valid. You are actually calling Equals.equals() at method().

Why does Java call the overridden method even when object is upcasted?

I have the following classes :
public abstract class Animal
{
private String species;
public Animal(String ll)
{
species = ll;
}
public abstract void speak();
public String toString()
{
return "Species: " + species;
}
}
The 2nd class:
public class Raven extends Animal
{
String name;
public Raven(String emri)
{
super("Raven");
name = emri;
}
public void speak()
{
System.out.println("krra krra");
}
public String toString()
{
return super.toString() + "\nName : "+ name ;
}
}
and the test class :
public class TestAnimals
{
public static void main(String args[])
{
Raven blabla = new Raven("Ziosh");
Animal a = blabla;
System.out.println(a.toString());
}
}
When I execute the test class, I get :
Species: Raven
Name: Ziosh
What I don't understand is why does Java use the "new" toString() method, even after we "upcast" the Raven object to Animal ?
Thanks.
Because that's what polymorphism is all about: you can call a method of an object without knowing the actual concrete type of the object, and the appropriate method, defined in this concrete type, will be called.
This works exactly like real objects: if I give you a car, even if you don't know it's actually a hybrid car, the car will behave like a hybrid car when you drive it.
In your example, a and blabla are two references to the same object, which is a Raven instance. So this object *speak*s and *toString*s like a Raven.
When you call a method in java, even if it's cast to the super type, it always looks for the most overridden method to call.
From http://docs.oracle.com/javase/tutorial/java/IandI/override.html
The distinction between hiding a static method and overriding an instance method has important implications:
The version of the overridden instance method that gets invoked is the one in the subclass.
The version of the hidden static method that gets invoked depends on whether it is invoked from the superclass or the subclass.
Raven blabla = new Raven("Ziosh");
Animal a = blabla;
Here, a and blabla reference the exact same object, as you can confirm with:
System.out.println(a == blabla);
// prints "true"
As such, a is really a Raven, so naturally it will talk like a Raven, even if you label it an Animal.
Consider another explanation in human terms. Letting the implementation to be executed on an object of a subclass could be actually very dangerous. Imagine a Bicycle class, and its more specialized BicycleWithLittleWheels. The thing about the latter, the little wheels are quite fragile, and if you try to ride it too fast, they could break. If you let somebody ride that bicycle as if was a regular bicycle, completely obvious of the little wheels, he may break it. By similar logic, you probably shouldn't use a high-precision dental drill the same way as a sledgehammer.
This is why, intuitively, you shouldn't let a specialized object be treated as its more general form. Sure, in some cases, it may make sense to use a specialized object as if it was something more general, but not always. How could the compiler distinguish the safe cases from the unsafe cases? That would be too difficult. So to stay on the safe side, the language won't let you do this.
Java always uses the method of the instance as describe in this post:
java override method invocation

different signatures for accessing class methods

I really am a little confused here. Normal signature to call accessible class method or variable is (Class/Object).(method/variable). Then how do we give System.out.println()? Since System.out only gives the return type but does not belong to same class. Also in servlets, "this.getServletConfig().getInitParameter("defaultUser")" is not making sense to me, since getServletConfig() and getInitParameter are both member functions of same class, so signature becomes something like, class.method1().method2(), where method1 and method2 are member functions of same class. Can someone please explain..
Example:
Class CascMethodClassB()
{
public CascMethodClassA methodTest()
{
CascMethodClassA obj1 = new CascMethodClassA();
return obj1;
}
} /*Class CascMethodClassB ends*/
Class CascMethodClassA()
{
public int varTest;
public CascMethodClassA()
{
varTest = 7;
}
} /*Class CascMethodClassA ends*/
Class CascMethodClassC()
{
CascMethodClassB obj2 = new CascMethodClassB();
int varTestC = obj2.methodTest().varTest
public static void main(String[] args)
{
System.out.println("varTest in CascMethodClassA is: "+ varTestC);
} /*Class CascMethodClassC ends*/
}
Thankyou,
Fraggy.
Both are different cases.
In the first case, outis a public static member in the System class. The member out is of type PrintStream, so the call
System.out.println()
will call the method println() from the PrintStream object (out).
The second case, is something called method chaining. What happens is that class.method1() will return an object instance, according to Java docs it will return a ServetConfig object. So, you can again call a method from that returned object. Another way of seeing that call is (brackets are redundant, just there so you can visualize the order of the calls):
(ClassName.someMethod1()).someMethod2();
System.out is a public class variable of type PrintStream, not a
method. Therefore you can invoke the println method on it, which returns void.
this.getServletConfig().getInitParameter("defaultUser") makes
perfect sense once you understand chaining method invocations. In
this case, you are:
calling the present instance of Servlet
getting its instance field's value of type ServletConfig
getting whichever String value is returned by invoking the getInitParameter method on the ServletConfig object
Finally, a method's signature is made of the method's name and parameter types
Each non-void method returns a type, which may be a different type to the declaring class, so the chained method/field will have the methods of the returned type (not the class it's called from or the class that the first method is defined in).
For example, to break down System.out.printkln():
System.out // out is a public field of type PrintStream
.println() // println() is a method of PrintStream, not System

Why does sysout(upper class) invoke toString of lower class after assigning lower class to upper class?

I have two classes A and B while B is a subtype of A:
public class A {
private String stringVar;
public A() {
stringVar = "";
}
public String getStringVar() {
return stringVar;
}
public void setStringVar(String str) {
this.stringVar = str;
}
#Override
public String toString() {
return getStringVar();
}
}
Class B:
public class B extends A {
private int intVar;
public B() {
intVar = 0;
}
public int getIntVar() {
return intVar;
}
public void setIntVar(int intVar) {
this.intVar = intVar;
}
#Override
public String toString() {
return super.toString() + " " + getIntVar();
}
}
As you can see in the following main method I assign the b to a. Now "a" can't invoke b's methods which is clear, because I'm using an instance of type A now. But it behaves like a B when toString is invoked. Curious, I would have expected toString of a. Why is this so?
public class Main {
public static void main(String[] args) {
A a = new A();
B b = new B();
b.setIntVar(200);
b.setStringVar("foo");
a = b;
System.out.println(a);
}
}
Because a points to the implementation of B.
And is declared as A.
So behavior of B. And methods visible of A.
To use B methods do like this
((B) a).getIntVar();
Think of it like this
Object o = new FancyObject();
When compiling this only Objects methods will be accepted even though it's a FancyObjcet with lots of methods.
To use the methods of FancyObject on o do like this.
Object o = new FancyObject();
(FancyObject o).fancyMethod();
Quote "because I'm using an instance of type A now" you are still using an instance of type B. You can see it like you have upcasted b but it's the same instance.
Picture cross linked from another site with credits in the picture, if this is against the rules then somebody is free to edit this part of my answer.
This is nature of inheritance / polymorphism and overriding methods.
Overrided methods will be determined in runtime based on objects real type and not based on reference type.
Therefore a.toString() is actually b.toString() because it is determined in runtime.
http://download.oracle.com/javase/tutorial/java/IandI/override.html
The concept you need to understand is the difference between References and Objects.
a is a reference (a local variable in this case) that points first to an Object of type A and then to an Object of type B.
The compiler knows that it must be of type A (or a subtype thereof), so it can safely call all methods A defines, but they will be called on the actual Object, not on the original Type of a.
This is polymorphism: The object that a holds has static type A, but it is still an Object of dynamic type B. Dynamic dispatch therefore chooses the overridden toString() defined in B.
That's exactly how Java's runtime polymorphism works. All that matters is the actual type at runtime. What you have done is take a reference to an A and point it at an instance of B. You have changed the type of the thing that a points to.
Try
a = (A)b;
No, B Overrides the toString method of A, so if an object is an instance of B, when you call its toString method, you get whatever method that instance has. In general, if you have an object and call its methods, the method called is the one that is in the instance, not in the variable type. The only exception is static methods.
In C++, this is not the case. The method called is the one of the variable type, if one exists, unless you explicitly select the above described behavior by making a method virtual.
That is called runtime polymorphism in OOP.

Overriding or overloading?

Guys I know this question is silly but just to make sure:
Having in my class method:
boolean equals(Document d)
{
//do something
}
I'm overloading this method nor overriding right? I know that this or similiar question will be on upcoming egzam and would be stupid to not get points for such a simple mistake;
Based on the code provided, we can't tell for sure whether you're overloading or overriding it.
You are most likely overloading the equals(Object o) method.
class A {
void method() {..}
}
class B extends A {
// this is overriding
void method() {..}
}
And
// this is overloading
class A {
void method(boolean b) {..}
void method(String arg) {..}
void method(int arg) {..}
}
P.S. you are using a bracket convention that is not widely accepted on the java world. In Java it is more common to place opening the curly bracket on the same.
You are not even overloading, since the other method is called equals. But if you add that s, you will be overloading equals. Although, to be precise, we talk about overloading if two (or more) methods with the same name but different signature are defined in the same class. In your case, it is trickier, since your equals with its different signature partly hides the original equals. Which is usually a bad thing, because this almost always leads to hard to understand behaviour, thus subtle bugs. Whenever someone calls equals on an instance of your class, depending on the parameter type the call may go to a different implementation of the method.
class Document {
public boolean equals(Document d)
{
//do something
}
}
Document doc1 = new Document();
Document doc2 = new Document();
String string = new String();
doc1.equals(doc2); // calls Document.equals
doc1.equals(string); // calls Object.equals!
You would be overriding Object.equals if you defined your method with the exact same signature as the original, i.e.
public boolean equals(Object obj) ...
In this case, both of the above calls to equals correctly execute Document.equals.
From the code you posted it could be either. If equal is defined in a superclass with the same parameter declarations then you are overriding it. If there is already a method called equal, but with different parameter types, you are overloading it.
On a related note, if you are using Java 5 and above and your intent is to override then it is highly recommended to use the #Override annotation before the method definition to indicate your intention. The wrong usage of this annotation (i.e. when you want to override and are not doing so) would flag a compile error.
As of Java 6 you can use the #Override annotation while defining methods that are
declared in an interface the class in implementing.
Overloading: same method name, same parameter list, different classes
Overriding: same method name, different parameter list, same or different classes.
Class A {
bool Equals(Document d) {...}
bool Equals(A a) {...} // overloaded method
}
Class B extends A {
bool Equals(Document d) {...} // overridden method
bool Equals(B b) {...} // overloaded method
}
One thing to note, the return type does not matter, it's the name of the method and the parameter list that make all the difference.

Categories

Resources