How toString() is automatically call inside println() - java

I just started learning Java. What I've learned about constructor is that :
It will automatically run when an object is initialized.
The name of the constructor has be the same as the class name.
Now, below is where I'm starting to get confused.
class Frog{
public String toString() {
return "Hello";
}
}
public class App {
public static void main(String[] args) {
Frog frog1 = new Frog();
System.out.println(frog1);
}
}
My question :
Since public String toString () is not a constructor, then why can it behave like constructor when I run the program. I thought It can only be run when I call it from the App class.

Short answer: public frog1.toString() method call is used inside System.out.println(Object x) call stack.
But how? Let's find it out together :)
Take a look at the PrintStream class (which instance is used as System.out field value by default) source code and its println implementation that accepts Object argument:
public void println(Object x) {
String s = String.valueOf(x);
synchronized (this) {
print(s);
newLine();
}
}
And the String's valueOf method for argument with Object type is:
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
obj is frog1 in your case, its toString() method is called and returns "Hello" String instance for the console output)

The "toString" is not behaving like a constructor; the reason why it is being called is the second line in your main method:
System.out.println(frog1);
This invokes toString on frog1.

When you call PrintStream class print(obj) / println(obj) method then internally it called write method with arguement as String.valueOf(obj) shown below :
public void print(Object obj) {
write(String.valueOf(obj));
}
Now String.valueOf(obj) does the task of calling to String method as shown below :
/**
* Returns the string representation of the <code>Object</code> argument.
*
* #param obj an <code>Object</code>.
* #return if the argument is <code>null</code>, then a string equal to
* <code>"null"</code>; otherwise, the value of
* <code>obj.toString()</code> is returned.
* #see java.lang.Object#toString()
*/
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}

public String toString(){..} is method of class Object , here overridden specifically for Frog class. This method returns object value representation. It's a method not a constructor. Please remember constructor cannot return value.
Valid constructor would be something like below:
public Frog(){}

The usage of toString is to give some meaningful representation for your class. Something like description about the object or class can go inside toString method.
Whenever the object is used with any String referenced operations like System.out.print or String s="abcd"+frog1;" the content of toString will be returned.
If toString is not overridden it would return the object class and its hash code. Please check here
From your code,
Frog frog1 = new Frog(); => creates object frog1 of type Frog.
System.out.println(frog1); => outputs the String representation
of the object frog1.
Hope it explains.

The toString method overrides Object.toString
public String toString() {
return "Hello";
}
So when call
System.out.println(frog1);
It toString's the object to "hello"

I'm not sure you understand what "behaving like a constructor" means. The Frog constructor (the default one, because you haven't written one) is called when you do new Frog(). The call to .toString() is done automatically inside the call to .println(), which is in the line after the call to the constructor.
You may be getting confused because toString() is the only method you have declared. However, you are missing the knowledge that there is an implicit default constructor automatically in your class. If you were to type it out it would look like this:
public Frog() {
// default constructor does nothing
}
It is that default constructor that is "behaving like a constructor". toString() is just behaving like a method that is being called by another method (the key thing being that println(Object o) is definitely certain that Object has a toString() method because it is part of the class definition).

Related

Invoking the default constructor (in Java) in a class that only has a defined constructor that requires parameters

Please tell me if I have the proper understanding of the following code:
public class Test {
public static void main(String[] args) {
A a = new A();
a.print();
}
}
class A {
String s;
A(String s) {
this.s = s;
}
void print() {
System.out.println(s);
}
}
The line “A a = new A();” invokes the class/constructor to create a new object with reference variable “a”. Class A has a defined constructor that requires a string argument, thus it does not have the default constructor. This means that the instantiation without any string arguments causes a compiler error.
If I were to add a string argument into the instantiation, e.g. A a = new A("goldfish"); the program would compile and run.
I am not sure if I have used the right vocabulary for this, so feel free to correct anything that is inaccurate/confusing. Thanks!
Your understanding is pretty much correct. The one thing that I would change is "create a new object" to "create a new instance of A" with a reference to a java.lang.String in parameter s. In this case the constructor assigns that parameter to a field, but it can do something else with it entirely (such as use it to calculate a different value for some field).
What you wrote is roughly correct.
To be more precise: "invokes the class/constructor" is not entirely correct. A a = new A(); intends to invoke the constructor (invoking a class doesn't mean anything).
Though constructors are not methods, you can think of them a bit like methods: if your class has defined a method like so :
public void myMethod(String s) { ... }
Then trying to call myMethod() without any argument would fail. It's the same here.

Failing to override the default methods

I am basically trying to override the default valueOf(Object obj). So why is this still calling the default method and not the overridden one?
class Method {
public static String valueOf(Object obj) {
return "hey!!";
}
public static void main(String[] args)
{
Method m1 = new Method();
System.out.println(m1);
}
}
o/p : Method#1de3f2d
Why am I getting this output? Why is the obj.toString() method being called without me defining it in the overridden method body?
You aren't overriding the toString method, you are attempting to override the valueOf method. Which isn't a method in Object according to the javadoc.
Do this.
#Override
public String toString() {
return "Hey!";
}
instead of your valueOf method.
Object isn't an interface, it's just a class. It has default implementations that will be used, unless you override them. That way you always know that toString will return a string (even if you don't specifically implement it).
Now, the valueOf doesn't get called because you never try to call it?
class Method {
#Override
public static String toString() {
return "hey!!";
}
public static void main(String[] args)
{
Method m1 = new Method();
System.out.println(m1);
}
}
Should print "hey".
EDIT: DISREGARD THIS:I think I see your problem. You are thinking about the Strings toString method, which quite correctly calls the valueOf method to determine what to print. But since Method doesn't extend String
I do not know why you think it will call the value of method. It will instead use Objects toString method. Which uses the class name and hashcode to make the string.

Can void be used in toString method

I am creating a program but i want to print the string from toString method directly with using System.our.println(ClassName.toString()),
Instead i want just to write the ClassName.toString(); and it print the output.
No, because if you want to call toString method like ClassName.toString(), that means you want to create a static toString() method in your ClassName class, means you are hiding toString instance method of Object class with static method of your class, but Java rule says you cannot hide instance methods with static method.
Java Specification reference: jls 8.4.8.2. Hiding (by Class Methods)
It is a compile-time error if a static method hides an instance method.
toString() method is a method available in Object class.
any class in java if its not extending any parent class then it will have internally Object class as parent.
and toString() method is non final in Object class
so it means we can override the toString() method in any of the subclass.
and return type of overridden methods should be same if its built in type and it should be same or parent if its custom object.
so in our case of toString() its return type is String so nobody can replace String for return type.
hence changing it will give compile time error.
so to achieve your scenario you can do as below in the worst case
#Override
public String toString() {
System.out.println("your string");
return super.toString();
}
and call this method using object of this class, if class name is A
then
A a = new A();
a.toString();
will automatically print the content on console using its body.
I feel like the other answers have covered “don’t do that”, but this is my “try this instead”. But if you are simply trying to accomplish a more terse way of printing the toString() output you could do something like this instead:
public class PrintMe {
private String data = "Just an example";
#Override
public String toString() {
return data;
}
public void print() {
System.out.println(toString());
}
public static void main(String[] args) {
PrintMe p = new PrintMe();
p.print();
}
}
Output: Just an example

How do overloaded methods work?

public class Test1 {
public static void main(String[] args) {
Test1 test1 = new Test1();
test1.testMethod(null);
}
public void testMethod(String s){
System.out.println("Inside String Method");
}
public void testMethod(Object o){
System.out.println("Inside Object Method");
}
}
When I try to run the given code, I get the following output:
Inside String Method
Can anyone explain why the method with the String type parameter is getting called?
most specific method argument is chosen for overloaded methods
In this case, String is subclass of Object. Hence String becomes more specific than Object. Hence Inside String method is printed.
Directly from JLS-15.12.2.5
If more than one member method is both accessible and applicable to a method invocation, it is necessary to choose one to provide the descriptor for the run-time method dispatch. The Java programming language uses the rule that the most specific method is chosen.
As BMT and LastFreeNickName have correctly suggested, (Object)null will cause overloaded method with Object type method to be called.
Adding on to an existing reply, I'm not sure if this is because of a newer Java version since the question, but when I tried to compile the code with a method taking an Integer as a parameter instead of an Object, the code still did compile. However, the call with null as the parameter still invoked the String parameter method at run-time.
For example,
public void testMethod(int i){
System.out.println("Inside int Method");
}
public void testMethod(String s){
System.out.println("Inside String Method");
}
will still give the output:
Inside String Method
when called as:
test1.testMethod(null);
The main reason for this is because String does accept null as a value and int doesn't. So null is classified as a String Object.
Coming back to the question asked, The type Object is encounter only when a new object is created. This is done by either type casting null as an Object by
test1.testMethod((Object) null);
or using any type of object for a primitive data type such as
test1.testMethod((Integer) null);
or
test1.testMethod((Boolean) null);
or by simply creating a new object by
test1.testMethod(new Test1());
It should be noted that
test1.testMethod((String) null);
will again invoke the String method as this would create an object of type String.
Also,
test1.testMethod((int) null);
and
test1.testMethod((boolean) null);
will give a compile time error since boolean and int do not accept null as a valid value and as int!=Integer and boolean!=Boolean.
Integer and Boolean type cast to Objects of type int and boolean.

I have two methods that need to be tested using the JUnit test. Here are the codes

public class Manager extends Employee
{
/**
* Manager Constructor takes in arguements and calls superclass
* #param id
* #param weeklyPay
*/
public Manager(int id, double weeklyPay) // Constructor
{
super(id);
super.weeklyPay=weeklyPay;
}
public String toString() // returns a String
{
return "Manager "+super.toString();
}
public double calculateWeeklyPay() // calculates weeklypay
{
return super.weeklyPay;
}
I have to test the toString method and the calculateWeeklyPay method. How do i do it?
Not sure you want to test this class as it looks like a lot fo the logic is in your super class. But here goes...
assertEquals(42d, new Manager(1, 42d).calculateWeeklyPay,0.001);
and to test the string equals (assuming super.toString returns MyString
assertEquals("ManagerMyString", new Manager(1, 42d));
the toString on the right hand side is called automatically or if you want to be explicit
assertEquals("ManagerMyString", new Manager(1, 42d).toString());
All of these methods are part of JUnit and can be statically imported via the Assert class to your java file.

Categories