1

I've been recently reading a book on Java design patterns and have come across classes inheriting from other classes and being instantiated by putting

Superclass s = new Subclass()

as opposed to

Subclass s = new Subclass()

My initial thoughts were that it's more from a design point of view and due to abstraction or information hiding. However, I'm still unsure and haven't been able to find a clear explanation.

Why would someone instantiate by using Superclass s = new Subclass(), and is it ever acceptable to use Subclass s = new Subclass()?

I'd greatly appreciate any help from someone who can help shed some light on this for me.

khelwood
  • 55,782
  • 14
  • 81
  • 108
joe Wilson
  • 11
  • 1
  • format your question and code! – flyingfox Jun 13 '18 at 11:31
  • 4
    See [What does it mean to program to an interface?](https://stackoverflow.com/questions/383947/what-does-it-mean-to-program-to-an-interface) – khelwood Jun 13 '18 at 11:31
  • Is it ever acceptable to use `Scanner sc = new Scanner(System.in);` instead `Object sc = new Scanner(System.in);`? Yes. Why do you even ask? – Johannes Kuhn Jun 13 '18 at 11:32
  • @JohannesKuhn Although it's acceptable, OP asks why you would ever use something like that since it can seem confusing. The answer given by Ben, as well as the top two answers in the question linked by _khelwood_ above answer that question. – Kevin Cruijssen Jun 13 '18 at 11:35

2 Answers2

3

Imagine a class Animal with subclasses Dog and Cat. You now want to create an animal management system. To keep it simple you want to have all your animals in one list. You can now write:

List<Animal> managementList = new ArrayList<>();

and add Dogs and Cats in there, just like this:

managementList.add(new Dog());
managementList.add(new Cat());

This is easy to maintain as both Dogs and Cats are Animals.

When you now retrieve an animal from the list you can do:

Animal theFirstAnimal = managementList.get(0);

As you are a clever manager you know the first animal is a Dog. So you could also just write:

Dog theFirstAnimal = (Dog) managementList.get(0);

If you are not sure anymore if the first animal was a dog but you really want to do something with it only if it is a dog you can use instanceof to check if that is actually a Dog.

if(managementList.get(0) instanceof Dog)
{
    doSomething();
} 

And to answer your final question if it is fine to simply instantiate the subclass: Sure it is. If you don't like cats and only want to work with dogs noone is holding you back to simply do:

List<Dog> dogManagementList = new ArrayList<>();
Ben
  • 1,665
  • 1
  • 11
  • 22
  • 3
    All that magic is called _polymorphism_. – Peteef Jun 13 '18 at 11:35
  • 1
    The `List managementList = new ArrayList<>();` itself is also a great example. If you every decide to change the `ArrayList` to another implementation of List (if you of course haven't used any ArrayList-specific method-calls), you only have to change those instantiations. If it would have been `ArrayList managementList = new ArrayList<>();` you'd have to change it at more than one place. – Kevin Cruijssen Jun 13 '18 at 11:39
  • @KevinCruijssen Yes, that is indeed one actual example where this is a super useful mechanism. Decide to use a `LinkedList` now? You only need to change one line of code as both `LinkedList` and `ArrayList` are a `List`. Didn't even notice this small part :) – Ben Jun 13 '18 at 11:40
  • Thank you very much for your response, it has helped greatly. So therefore could you say that this is abstraction? You only need to know the key details of the animals so therefore anything extra in the subclasses isn't relevent to the task at hand? – joe Wilson Jun 13 '18 at 11:48
  • In this example `Animal` is an abstraction, yes. – Ben Jun 13 '18 at 11:50
  • Okay okay i'm understanding this more. So you technically could instanciate it by putting Subclass s = new Subclass, however this would provide proporties not relevent to the task at hand? – joe Wilson Jun 13 '18 at 11:52
  • No, I think your getting something wrong. If I type `Animal dog = new Dog()` this does not magically strip all additional properties of a `Dog` from this object. It still is a dog. It still behaves like a dog. If I call a method on it the `Dog`s implementation is called. It's just saved as an `Animal`. It's called polymorphism. I would recommend you to read up on it a bit :D – Ben Jun 13 '18 at 11:55
  • @joeWilson is partially correct however. If you only need fields and methods from Animal (or put animals in a list like you did), it's fine to use `Animal dog = new Dog()`. However, if you want to use a method of a specific animal, you do need that field-type instead of `Animal`. For example: `Animal bird = new Bird()` and the Bird would have a method `fly()` (which Dog does not have), you cannot do `bird.fly()` in this case. If `Animal bird = new Bird()` would have been `Bird bird = new Bird();` you _can_ use `bird.fly()`. – Kevin Cruijssen Jun 13 '18 at 12:04
  • It does not mean though that `Animal bird = new Bird()` does not have the method anymore. Simply using `((Bird) bird).fly()` would work just as well ;) – Ben Jun 13 '18 at 12:05
  • @Ben But you're right `bird` is still a `Bird` when you use `Animal bird = new Bird()`. To use the method `fly()` however, you'd need a cast: `((Bird)bird).fly()`. EDIT: You beat me to it by 5 sec.. Previous comment didn't had any space anymore. ;) – Kevin Cruijssen Jun 13 '18 at 12:05
0

Talking about Upcasting, it is also helpful in the form of function argument:

public class Music {
 public static void tune(Instrument i) {
     // ...
     i.play(Note.MIDDLE_C);
 }
 public static void main(String[] args) {
    Wind flute = new Wind();  //Wind extends Instrument
    tune(flute); // Upcasting
 }
}

The method Music.tune( ) accepts an Instrument reference, but also anything derived from Instrument.

Upcasting from Wind to Instrument may “narrow” that interface, but it cannot make it anything less than the full interface to Instrument.

Saurav Sahu
  • 13,038
  • 6
  • 64
  • 79