Firstly, you must understand what subclassing itself is.
If I have an object, let's say Tree, I may give that object a list of methods like plant(), water().
Then I want to define another class, AppleTree. Well an apple tree still needs to be planted and watered, so instead of copying that code from the Tree class, I'll just subclass it. So AppleTree extends Tree.
This means I can now call Tree's methods directly on an AppleTree object. Then maybe I'll add another method to AppleTree called harvest().
Now let's use this in another class. Maybe I have a class called Orchard that contains all my trees. Let's say I have 10 trees, and 2 of them are AppleTrees. In my orchard, I want to water all of my trees.
I can store all of my trees in an ArrayList like so:
ArrayList<Tree> trees = new ArrayList<Tree>();
for(int i = 0; i < 8; i++)
{
    Tree t = new Tree();
    trees.add(t);
}
for(int i = 0; i < 2; i++)
{
    AppleTree a = new AppleTree();
    trees.add(a);
}
I can then iterate through each of my trees in my ArrayList and call water() on each one.
for(int i = 0; i < trees.size(); i++)
{
    trees.get(i).water();
}
However, now I want to harvest all of my trees, but only 2 of them are AppleTrees and know a harvest() method. So I can't do this:
for(int i = 0; i < trees.size(); i++)
{
    trees.get(i).harvest(); //compiler error
}
This is because my ArrayList holds a set of Tree pointers, which don't know a harvest() method. Not all of my Trees are AppleTrees, and the class signature of Tree does not match the class signature of AppleTree.
All AppleTree objects are Tree objects, so this is ok:
Tree t = new AppleTree();
However, not all Trees are AppleTrees, so this doesn't work:
AppleTree a = new Tree(); //error
It's important to note though, that if I define a Tree this way:
Tree t = new AppleTree();
Even though t contains an AppleTree object, I can't call t.harvest() without casting t to an AppleTree, because to the compiler, it's just a Tree and doesn't know the harvest() method.
So this will fail:
Tree t = new AppleTree();
t.harvest(); //error
"Not all Luddites are idiots" (some are) is not the same as "All Luddites are not idiots" (none are). Part of the problem is the ambiguity of English: "Cats are wonderful" can mean "all cats are wonderful" or "some cats are wonderful". When they collide with binary thinking, sparks ensue.
– Alan Jul 01 '21 at 18:37