toString() and finalize() method


toString() method

The toString() method is used to create a String representation of an object by using the object´s content. This method should be overridden when writing your class. toString() is called implicitly when an object is concatenated to a string as in "hello " + anObject.

Consider the following:

public class User {
	private String firstName;
	private String lastName;
 
	public User(String firstName, String lastName) {
		this.firstName = firstName;
		this.lastName = lastName;
	}
 
	@Override
	public String toString() {
		return firstName + " " + lastName;
	}
 
	public static void main(String[] args) {
		User user = new User("John", "Doe");
		System.out.println(user.toString()); // Prints "John Doe"
	} 
}

Here toString() from Object class is overridden in the User class to provide meaningful data regarding the object when printing it.

When using println(), the object's toString() method is implicitly called. Therefore, these statements do the same thing:

System.out.println(user); // toString() is implicitly called on `user`
System.out.println(user.toString());

If the toString() is not overridden in the above mentioned User class, System.out.println(user) may return User@659e0bfd or a similar String with almost no useful information except the class name. This will be because the call will use the toString() implementation of the base Java Object class which does not know anything about the User class's structure or business rules. If you want to change this functionality in your class, simply override the method.


finalize() method

This is a protected and non-static method of the Object class. This method is used to perform some final operations or clean up operations on an object before it gets removed from the memory.

  • According to the doc, this method gets called by the garbage collector on an object when garbage collection determines that there are no more references to the object.

But there are no guarantees that finalize() method would gets called if the object is still reachable or no Garbage Collectors run when the object become eligible. That's why it's better not rely on this method.

In Java core libraries some usage examples could be found, for instance in FileInputStream.java:

protected void finalize() throws IOException {
    if ((fd != null) && (fd != FileDescriptor.in)) {
        /* if fd is shared, the references in FileDescriptor
        * will ensure that finalizer is only called when
        * safe to do so. All references using the fd have
        * become unreachable. We can call close()
        */
         close();
    }
}

In this case it's the last chance to close the resource if that resource has not been closed before.

Generally it's considered bad practice to use finalize() method in applications of any kind and should be avoided.

Finalizers are not meant for freeing resources (e.g., closing files). The garbage collector gets called when (if!) the system runs low on heap space. You can't rely on it to be called when the system is running low on file handles or, for any other reason.

The intended use-case for finalizers is for an object that is about to be reclaimed to notify some other object about its impending doom. A better mechanism now exists for that purpose---the java.lang.ref.WeakReference<T> class. If you think you need write a finalize() method, then you should look into whether you can solve the same problem using WeakReference instead. If that won't solve your problem, then you may need to re-think your design on a deeper level

Basic Programs