I've been looking at a lot of code recently (for my own benefit, as I'm still learning to program), and I've noticed a number of Java projects (from what appear to be well respected programmers) wherein they use some sort of immediate down-casting.
I actually have multiple examples, but here's one that I pulled straight from the code:
public Set<Coordinates> neighboringCoordinates() {
HashSet<Coordinates> neighbors = new HashSet<Coordinates>();
neighbors.add(getNorthWest());
neighbors.add(getNorth());
neighbors.add(getNorthEast());
neighbors.add(getWest());
neighbors.add(getEast());
neighbors.add(getSouthEast());
neighbors.add(getSouth());
neighbors.add(getSouthWest());
return neighbors;
}
And from the same project, here's another (perhaps more concise) example:
private Set<Coordinates> liveCellCoordinates = new HashSet<Coordinates>();
In the first example, you can see that the method has a return type of Set<Coordinates>
- however, that specific method will always only return a HashSet
- and no other type of Set
.
In the second example, liveCellCoordinates
is initially defined as a Set<Coordinates>
, but is immediately turned into a HashSet
.
And it's not just this single, specific project - I've found this to be the case in multiple projects.
I am curious as to what the logic is behind this? Is there some code-conventions that would consider this good practice? Does it make the program faster or more efficient somehow? What benefit would it have?
Upcasting gives us the flexibility to access the parent class members but it is not possible to access all the child class members using this feature. Instead of all the members, we can access some specified members of the child class. For instance, we can access the overridden methods.
Downcasting is useful when the type of the value referenced by the Parent variable is known and often is used when passing a value as a parameter. In the below example, the method objectToString takes an Object parameter which is assumed to be of type String.
In the case of upcasting, people can access the variables and methods of the parent class in the child class but not the other way round. In downcasting, however, the variables and methods of both the classes are easily accessible. Upcasting allows access to only particular child class methods.
Why we need Upcasting and Downcasting? In Java, we rarely use Upcasting. We use it when we need to develop a code that deals with only the parent class. Downcasting is used when we need to develop a code that accesses behaviors of the child class.
When you are designing a method signature, it is usually better to only pin down what needs to be pinned down. In the first example, by specifying only that the method returns a Set
(instead of a HashSet
specifically), the implementer is free to change the implementation if it turns out that a HashSet
is not the right data structure. If the method had been declared to return a HashSet
, then all code that depended on the object being specifically a HashSet
instead of the more general Set
type would also need to be revised.
A realistic example would be if it was decided that neighboringCoordinates()
needed to return a thread-safe Set
object. As written, this would be very simple to do—replace the last line of the method with:
return Collections.synchronizedSet(neighbors);
As it turns out, the Set
object returned by synchronizedSet()
is not assignment-compatible with HashSet
. Good thing the method was declared to return a Set
!
A similar consideration applies to the second case. Code in the class that uses liveCellCoordinates
shouldn't need to know anything more than that it is a Set
. (In fact, in the first example, I would have expected to see:
Set<Coordinates> neighbors = new HashSet<Coordinates>();
at the top of the method.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With