I'm confused why or when to use downcasting and upcasting and polymorphism.
Am I correct or wrong?
If we say this Gift gift = new Pen(); not only can we leverage the use of polymorphism (if subclass has any overridden methods), but also we will create only one object in the heap. Like if further if we, say, want to access the Pen class methods, we can just say Pen pen = (Pen) gift;. This line can be used to access both superclass methods as well as its own method.
But my point is that here we would not have to create a new object in the heap. Instead, we can just downcast.
So, if we say like Gift gift = new Gift() and then we want to use Pen class methods, we would need to create the object again in heap like Pen pen = new Pen().
Basically, instead of creating two objects in the heap, we can just create one object and downcast it later. This not only helps to write efficient code, but also can leverage the use of polymorphism with well maintained code.
You are addressing two related questions: Which interface to use to access an object (for this, I see
classalso as a kind of interface).If you know in advance that you will need to access
Penmethods, you should type your variable asPenin the first place. But on the other hand, you should refer to objects by their interfaces (from Effective Java by Joshua Bloch) so if you do not need the access toPenmethods, don't access it via that class.Your second question is about creating objects to access the classes methods. But this approach is not what object oriented programming is made for: you create a class so you can access the inside data (in the object) only via the classes' methods. So your idea of first creating a
Giftinstance and then creating aPeninstance again for more methods is less than ideal because the methods ofPenalso need more data, that have to be initialized at some point in time (usually at the construction ofPen). Where do you get that data from if you only have aGiftinstance available?If you have the data in the first place, why did you not create a
Penright away?You could also provide a factory method for
Penthat creates a new instance from aGiftinstance plus all the extra data necessary for aPeninstance.This is not always an ideal solution, so the answer to your question is neither yes or no, but: it depends. Depending on the actual problem you want to solve, the best solution to pick could vary, so if you have an actual problem to solve, you should add it to your question to get more advice, or add another question.
UPDATE: (per OPs request)
As you do not supply any surrounding code, I cannot name the exact reason, but in the link above you find an explanation why you should use the "least specific" interface.
For this we see classes also as interfaces (with an implementation). Also a method is kind of a contract with the implementer of an interface. So if you use the least specific interface, you do not rely on the actual implementation, but on the contract of the methods of that interface. So you can easily change the implementation later if that is necessary.
A good and very commonly used example for this is e.g. the
java.util.Listinterface. You just want to know that (basically) you are operating on an ordered collection. As "user" of the interface you don't care how the list is ordered, or if it is backed by an array or a linked list (or lazy loaded from a database, etc.). If you usedjava.util.ArrayListyou always have to load everything into an array, or at least pretend that you do that - if you inherit from that class and override methods, and that would be super complex to handle for code maintainers.A good use case for this (but probably not the only one) is: Quite often you have existing code that you want to use that expects objects of a certain
classorinterface. But the existing class doesn't fit your needs, so you inherit of or implement what is existing and expected. You create a more specific implementation. But you cannot or don't want to change the existing code, so you downcast your implementation to whatever is needed. Often the inherited classes do not even implement new methods, but just override some existing ones.Polymorphism is not always helpful, the past showed that it also can be a burden, especially for code that is maintained and extended over a longer period of time, but also for new code that is just badly designed. It's hard to give a general advice, but it's good that you try to learn about it.
I would recommend that you read at least the chapter Favor composition over inheritance in the book "Effective Java", but can recommend the whole book. It's not only useful for Java developers, but OOP in general (the examples and specific chapters are Java only).