1

I was reviewing my OOP and I have a little question about objects. Well I have a super class Ship which is also an abstract class. Ship has some subclasses namely Submarine, Destroyer and so on.

I know I cannot create an object of the Ship class because it's abstract. But why does the following still work?

Ship s1 = new Submarine("ship 1");
Bongs
  • 5,502
  • 4
  • 30
  • 50
John
  • 728
  • 2
  • 15
  • 37
  • 2
    Just because you can't instantiate an abstract class, doesn't mean you can't have an object of that type. You can also have objects of a certain interface, like `List strings = new ArrayList<>();` – Davio Sep 19 '14 at 13:10
  • 2
    Because in this line you're creating an object of type `Submarine` and then casting it to type `Ship`. `Submarine` IS-A `Ship` – Alex Sep 19 '14 at 13:11
  • 2
    Read this one: http://stackoverflow.com/questions/4321386/create-object-of-abstract-class-and-interface – Dr. Debasish Jana Sep 19 '14 at 13:11
  • 1
    It's polymorphysm - you have Submarine object but you see it as Ship. – MGorgon Sep 19 '14 at 13:12
  • It works, because you are instantiating a subclass of Ship, not Ship itself. You declare abstract method to make sure, that every class that extends abstract class will implement this method. – Kamil Kłys Sep 19 '14 at 13:13

6 Answers6

2

The line : Ship s1 = new Submarine("ship 1");

You are not creating Object of Abstract class Ship, its mere a reference which points to Object of Child class Submarine. What you are actaully doing is creating object of child class.

Snehal Masne
  • 3,403
  • 3
  • 31
  • 51
1

It is due to the polymorphism.

Reference of parent class can hold the child class object.But using this reference you can call methods those are correctly overridden in the child class.

AsSiDe
  • 1,826
  • 2
  • 15
  • 24
1

You should distinguish between runtime-type and compile-time type.

Let's say you have the following statement:

Ship s1 = new Submarine("ship 1");
  • The compile-time type of s1 is the type on the left-hand side of the assignment statment, e.g. the compile-time type is Ship. You can assign s1 to any type that inherits Ship.

  • The runtime type of s1 is the right-hand side of the assignment statement, e.g. the runtime type of s1 is a concrete implementation of Ship (in your case - Submarine).

More info:

Konstantin Yovkov
  • 62,134
  • 8
  • 100
  • 147
1

To be simple, an abstract class means you cannot create a new instance of this class.
However, it's still possible to declare an object as a Ship (compile-time type vs runtime type) to use the polymorphism, allows you to do some funny stuff like an array of Ship which contains both Submarine and Destroyer (and many more).

Ship[] army = new Ship[2];
army[0] = new Submarine("0");
army[1] = new Destroyer("1");

for( Ship s : army ) {
  s.fire();
}

In this sample, we can invoke fire() on the two object because fire() is a method of Ship. As the ship's attack depends on the ship's type (a submarine will not fire like a destroyer), you set the fire() method of Ship abstract and implements it in Submarine and Destroyer.

These tricks are essential in OOP, and allows you to implement powerful design patterns. If you're a beginner, looks at the strategy pattern and the template method pattern, they changed my vision of OOP few years ago ;)

Hope this little sample helps you :)

NiziL
  • 5,068
  • 23
  • 33
0

Just because you can't instantiate an abstract class, doesn't mean you can't have an object of that type. You can also have objects of a certain interface, like List<String> strings = new ArrayList<>()

You declare a method abstract because a default implementation doesn't make sense.

Consider a class called shape with subclasses circle and square. A shape has an area, but a circle's area is calculated differently from that of a square.

You can create an abstract method called getArea in the abstract shape class and let circle and square provide their implementation.

Davio
  • 4,609
  • 2
  • 31
  • 58
0

s1 is a ship and you can use all methods defined in your abstract class, but only those. If you have additional methods in your Submarine class (like for example; dive, periscopeUp, ...) they cannot be called because they are not defined in your abstract Ship class.

Using this is mainly handy for Collections, for example you can now store different types of Ship's in a List.

List<Ship> ships = new ArrayList<Ship>();
ships.add(new Submarine("sub 1"));
ships.add(new Destroyer("des 1"));

If you would define a 'List<Submarine> subs' you can only store Submarine classes in that list.

dirk
  • 101
  • 2