Recommended: Sing it, brah! 5 fabulous songs for developers
JW's Top 5
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
I would like to clarify my understanding of abstract classes.
As I understand it, a class declared abstract is an incomplete class, not meant to be instantiated. Java would complain if an abstract class were created using a class instance creation expression.
The javadoc for DateFormat provides two examples:
myString = DateFormat.getDateInstance().format(myDate);
DateFormat df = DateFormat.getDateInstance();
for (int i = 0; i < a.length; ++i)
{ output.println(df.format(myDate[i]) + "; "); }
With that in mind, since DateFormat is an abstract class, how can an instance of it be created by the final static method DateFormat.getDateInstance()?
Welcome to the wonderful world of polymorphism! Polymorphism allows a type to have many behaviors. Remember this definition,
as we'll come back to it.
It is absolutely true that you cannot instantiate an abstract class. You are correct in pointing out that DateFormat::getDateInstance() can not return an instance of DateFormat by calling new DateFormat(). Something else is going on here.
getDateInstance() is a factory method. Factory methods hide the implementation of the object that they create. Internally, they create a concrete extension of an
abstract class (or interface), but cast it down to the interface or abstract class before it returns the instance.
Consider the following implementations of DateFormat:
AmericanDateFormat extends DateFormat. AmericanDateFormat formats dates in the following format: mm/dd/yyyy
EuropeanDateFormat extends DateFormat. EuropeanDateFormat formats dates in the following format: yyyy/mm/dd
StarDateFormat extends DateFormat. StarDateFormat formats dates in the following format: XXXXXX.XX
Since getDateInstance() cannot instantiate DateFormat, it must instantiate one of its nonabstract implementations -- either AmericanDateFormat, EuropeanDateFormat, or StarDateFormat.
When we call getDateInstance(), we do not know which particular implementation of DateFormat is returned. That detail remains hidden from you. Instead, we simply treat the instance as the abstraction DateFormat. Once we have an instance, we use the behavior without worrying about the specific implementation and move on.
This is polymorphism in its purest form. By creating different implementations of DateFormat but treating each of them as the superclass, we have a type that displays many different behaviors. By taking such an approach,
we can program very generically.
Say we didn't use polymorphism but wanted to have different DateFormats in the same program. We would need to treat every implementation very specifically. We would need if statements or case
statements for each specific implementation that we wish to use. Whenever we wanted to add new implementations, we would need
to update all of our code.
With polymorphism, however, if we want to switch implementations, we need only to override the instance factory method so that it creates an instance of the implementation we want. We can make this change and use the new implementation without having to change any of the code that uses the instance. This allows us to plug new implementation types into our system at any time.