Hello guys, long time no see!
i've put together a very small simple console base application that takes a date and a few strings and print them off.
Let's look at the code first.
Date.java

/*Date.java
this class represents dates
*/
public class Date{
    private int month;
    private int day;
    private int year;

    //constructor
    public Date(int dayDate, int monthDate, int yearDate){
        day = checkDay(dayDate);
        month = checkMonth(monthDate);
        year = yearDate;//no validation
        System.out.printf(
            "Date is %d-%d-%d\n",getDay(),getMonth(),getYear()
        );

    }

    public int getDay(){//getter
        return day;
    }
    public int getMonth(){
        return month;
    }

    public int getYear(){
        return year;
    }

    private int checkDay(int testDay){//test day
        if((testDay <= 31) || (testDay > 0)){//if between 1 and 31 it's ok
            return testDay;
        }
        else{//if not
            throw new IllegalArgumentException("day must be between 1 and 31");//throw exception
        }
    }

     private int checkMonth(int testMonth){
        if((testMonth <= 12) || testMonth > 0){
            return testMonth;
        }
        else{
            throw new IllegalArgumentException("month must be between 1 and 12");//throw exception
        }
     }

     public String toString(){
        return String.format(
            "Date is %d-%d-%d\n",getDay(),getMonth(),getYear()
        );
     }

}//end of Date

then Patient.java

/*Patient.java
this class represents a patient
*/
public class Patient{
    private String name;
    private String surname;
    private Date dateOfBirth;

    public Patient(String theName, String theSurname, Date birthday){
        name = theName;
        surname = theSurname;
        dateOfBirth = birthday;     
    }
    public String getName(){
        return name;
    }

    public String getSurname(){
        return surname;
    }

    /* public String getBirth(){
        return dateOfBirth;
    } */
    public String toString(){
        return String.format("Name: %s, Surname: %s, Date of birth: %s ",
            getName(), getSurname(), dateOfBirth
        );
    }

}//end of class

and the testing class, PatientTest.java

/*PatientTest.java
testing the Date and Patient classes
*/
public class PatientTest{
    public static void main(String[] args){
        Date birth = new Date(10, 02, 1912);//create a date object with that date
        Patient patient = new Patient("John", "Dye", birth);

        System.out.println(patient);
    }
}//end of PatientTest

OK, so here are the questions:
in PatientTest.java I have System.out.println(patient);
This implies that the toString() of the the patient object is called implicitly from what I remember. Class Patient has a toString() method there, so that's fine, but when in class Date I remove the toString() (even though I have this

System.out.printf(
            "Date is %d-%d-%d\n",getDay(),getMonth(),getYear()
        );

) I don't get a properly formatted date but rubbish values:

antobbo@antobbo-linux-Dell-System-XPS-L702X:/media/KINGSTON/JAVA/health_basic$ java PatientTest
Date is 10-2-1912
Name: John, Surname: Dye, Date of birth: Date@65c0035b 

Is ther eason for this that, since Date is "part" of the patient object created int he test class, the Date class must also have a toString() method? I'm not entirely clear on this.
Second question: in Patient.java I have some getters methods to return the instance variables of type String. I wanted to have a getter to return an instance variable (or is that an object?) of type Date, so I included this

/* public String getBirth(){
        return dateOfBirth;
    } */

trouble is that if I then call it from, say, the toString() method like so:

public String toString(){
        return String.format("Name: %s, Surname: %s, Date of birth: %s ",
            getName(), getSurname(), getBirth()
        );
    }

I get the following error:

antobbo@antobbo-linux-Dell-System-XPS-L702X:/media/KINGSTON/JAVA/health_basic$ javac *.java
Patient.java:23: incompatible types
found   : Date
required: java.lang.String
        return dateOfBirth;
               ^
1 error

Does it mean that I can't use a getter with reference types?
thanks

Recommended Answers

All 10 Replies

Every class in Java has a toString method. It's defined in the Object class so everyone inherits it if they don't override it. It returns the name of the class followed by the instance's hash (that's the garbage you referred to). You are right, print always calls the toString method of anything you print. But when you use format you have to ensure that the values you provide match the format spec.
Using a reference type, which includes String remember!, is perfectly OK and normal for.a getter

Public Date getDateOfBirth() ...

I thought toString() was only called if you attempt to print an object, like if you do something like System.out.println(patient);. I think I'm getting confused because I used return String.format() rather than something like return "Date is %d-%d-%d\n",getDay(),getMonth(),getYear(). what's the difference between these two then?

public String toString(){
        return String.format(
            "Date is %d-%d-%d\n",getDay(),getMonth(),getYear()
        );
     }


public String toString(){
        return  "Date is %d-%d-%d\n",getDay(),getMonth(),getYear();
     }

Also, please bear with me as I haven't done Java for quite a long time. Let's quickly look at this scenario: Say that in my Date class I remove the toString() method completely. When I run the app and create a Date object, the date information prints OK because in Date.java I have this

System.out.printf(
            "Date is %d-%d-%d\n",getDay(),getMonth(),getYear()
        );

then, control returns to PatientTest.java. I then create a patient object and then control returns back again to PatientTest: here this statement System.out.println(patient);calls the toString() methods of patient first and then attempts to call the toString of Date, which I have removed, hence I get the "rubbish" data. Is that a fairly accurate representation?
thanks

Yes, toString is called when you print or println.
If you override the 'garbage' Object toString then you have to return a String. How you construct that String is entirely up to you - string concatenation, format or whatever.
When you print a Patient object, print calls its toString. Now if that toString includes a Date its up to that toString method to ensure that the Date is converted to a suitable String.

toString() gives you a string representation of your object.
But you have to define that string representation if you want it to be anything meaningful and human readable.
The default implementation just gives you a hashcode for the object in memory, useful to distinguish between 2 instances but no more.

String.format() otoh will format the arguments into the template you provide as the first argument, and return the result. It's handy to fill in wildcards in a date string like you found out for example.
Mainly it's a bit of shorthand for String.replaceAll()

Thanks guys, maybe I begin to remember : -). Just one last thing then: all this is because the test class is attempting to print an object, but, say that I instead replace System.out.println(patient); with something like

System.out.println("name: " + patient.getName() + " surname: " + patient.getSurname() + " date: " + birth.getDay() + "/" + birth.getMonth() + "/" + birth.getYear() );

where I don't use objects, then I can remove all my toString()methods and replace them with normal System.out.println.... Is that correct?
thanks

Yes, that's possible, but it's a really bad idea. For a start you are replacing one simple short safe piece of code with two lines of detailed fragile code. Duh!
The whole idea is that each object is in the best position to know about all its own fields etc, so it's uniquely best placed to provide a printable version of itself. It's a universal Java idea that you can just print any object without having to know about its details.
Suppose one day someone enhances the Patient class to include (eg) gender. That same person is responsible for updating toString to match. Any code that prints a Patient will continue to work, and will display all the latest data.

Cool, I understand, thanks a lot for the explanation!

and remember that for anything in that string you're building its toString() method is called under the hood...

Are you sure that's generally true? For example StringBuilder append will call toString implicitly, but I don't think format will.

format would try to convert anything in the arguments to a String, which AFAIK is done by calling toString() on any object reference in the argument list (of course the rules for primitives are different).

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.