3

I am new to Java and I have read threads (here) that it is not possible to instantiate an abstract class. So, I tested it out.

The first test I did is shown below. And it seems like I can actually instantiate an abstract class and in fact, I actually have a new type which refers to the abstract class and the type is actually shared by all subclasses the extends it. This also means polymorhpism applies.

import java.util.*;

abstract class AbstractClass{
    public abstract void printname();
}


class Test1 extends AbstractClass{

    private String name;

    public Test1(String name){
        this.name = name;
    }

    public void printname(){
        System.out.println("My name is " + name);
    }
}

class Test2 extends AbstractClass{
        private String saysomething;

    public Test2(String saysomething){
        this.saysomething = saysomething;
    }

    public void printname(){
        System.out.println(saysomething);
    }
}

class TestingApp{
    public static void main(String[] args){
        AbstractClass[] abstractclass_list = {new Test1("JEFFFFFF") , new Test2("Hey , say something")};
        for(AbstractClass item : abstractclass_list){
            item.printname();
        }
    }
}

Then I did another test but this time, instead of working on abstract class, I decided to create a type which refers to Interface. It seems like I can instantiate an interface as well. I can actually create a type that refers to the interface. This type is shared by all the classes that implements this interface. And polymorphism applies again.

import java.util.*;

interface  AbstractInterface{
    public void printname();
}


class Test4 implements AbstractInterface{

    private String name;

    public Test4(String name){
        this.name = name;
    }

    public void printname(){
        System.out.println("My name is " + name);
    }
}

class Test3 implements AbstractInterface{
    private String saysomething;

    public Test3(String saysomething){
        this.saysomething = saysomething;
    }

    public void printname(){
        System.out.println(saysomething);
    }
}

class TestingAbstractInterfaceApp{
    public static void main(String[] args){
        AbstractInterface[] abstract_list = {new Test4("Helen") , new Test3("Hey , say my name")};
        for(AbstractInterface item : abstract_list){
            item.printname();
        }
    }
}

Question:

I am sensing there is something wrong with what I am doing in my code. But I cannot quite explain how come the code still works when theoretically, it is impossible to instantiate an abstract class and interface. Am I actually instantiating an abstract class and an interface in the examples shown above ? Because this seems like exactly what I have done, as I have a new type for the abstract class and interface. Please correct me, if my logic is wrong or if I am using the wrong words.

Update: SO I guess my misunderstanding is about type. I always thought type can only refer to normal Java classes but not abstract classes and interfaces. How does "type" actually work? Is it creating a reference?

Community
  • 1
  • 1
mynameisJEFF
  • 4,073
  • 9
  • 50
  • 96

5 Answers5

3

Why do you think you are actually instantiating AbstractClass and AbstractInterface?

new Test1("JEFFFFFF") , new Test2("Hey , say something"), new Test4("Helen") , new Test3("Hey , say my name") are all instantiating concrete classes, not abstract ones.

If you refer to AbstractClass[] abstractclass_list = as proof of instantiating abstract classes, that is wrong. Here, you declare an array whose elements are of type AbstractClass, and Test1 and Test2 are (since they extend AbstractClass).

UPDATE

You could have something like this AbstractClass abs = new Test1("hey"); and what it does is it creates a new instance of class Test1, and references that instance from variable abs. abs's concrete type is Test1, but only methods declared in AbstractClass are visible on it. If you want to call methods of Test1, you would have to cast it first.

AbstractClass abs = new Test1("hey");
abs.printname(); // this is ok, and it calls `printname() implemented in Test1
abs.someTest1Method(); // this is NOT ok, someTest1Method() is not visible to abs
((Test1)abs).someTest1Method(); // this is ok, abs is cast to Test1, but would fail if abs was instantiated as 'abs = new Test2("t2")' (would throw ClassCastException)
Predrag Maric
  • 23,938
  • 5
  • 52
  • 68
  • This is the problem with using polymorphism right ? Only the superclass's methods are visible to the subclass, regardless of the superclass is abstract or not. Correct ? – mynameisJEFF Dec 04 '14 at 13:19
  • I wouldn't call it a problem, but that's how it is meant to behave. – Predrag Maric Dec 04 '14 at 13:21
  • I should have said "issue". Thank you very much. I am starting to realize that OOP can become really abstract in the sense that sometimes you can do the same task by creating an abstract class or interface, but deciding which one to use is the hard part. – mynameisJEFF Dec 04 '14 at 13:24
  • That is a big part of Java, take [JPA](http://en.wikipedia.org/wiki/Java_Persistence_API) for example. It is a complex and powerful framework, but it is just a collection of interfaces by itself. It needs an implementation of those interfaces in order to be able to do anything really. – Predrag Maric Dec 04 '14 at 13:28
  • Assume that there is a lot of different geometrical figures. They can be triangles, rectangles,... The only they have in common in that case is that they are geometrical figure. Assume also (a little naive) that all methods that exist for these shapes are declared (or defined) in Shape. This means that they can all be stored in an array of shapes. They can also be used as shapes since all methods are declared in shape. You do not need to bother what kind of shapes they really are. That is possible due to polymorphism. Good, right? – patrik Feb 23 '15 at 23:48
1

You are not instantiating your abstract class or your interface. You are instantiating concrete classes that extend your abstract class (Test1 and Test2) or implement your interface (Test3 and Test4).

It's allowed to assign an instance of a concrete class to a variable whose type is an interface or an abstract class. In fact, it's even encouraged.

Eran
  • 387,369
  • 54
  • 702
  • 768
1

You aren't instantiating either an abstract class, nor an interface. You are just using the inherent upcasting ability from subclasses to superclasses.

Ignoring the array, and using just the first object, this would be equivalent to the implicit upcasts:

AbstractClass myObject = new Test1("JEFFFFFF");

and

AbstractInterface myObject = new Test1("JEFFFFFF");

So, in the code:

  AbstractClass[] abstractclass_list = {
     new Test1("JEFFFFFF") , 
     new Test2("Hey , say something")};

You are instantiating objects of the concrete classes Test1 and Test2 - the Array contains references to the underlying (and common) abstract base class.

Similarly, in the second example, you are obtaining an array of interface references.

StuartLC
  • 104,537
  • 17
  • 209
  • 285
1

In short I would like to say that,
Parent(here, Abstract/Iterface) can refer, it's child(here, concrete class).

So here, reference variable can refer it's child class's instance.

Just note this concept in your brain, it will fix all your problem regarding, Dynamic Dispatcher, Inheritance related....!!!

GitaarLAB
  • 14,536
  • 11
  • 60
  • 80
Vishal Gajera
  • 4,137
  • 5
  • 28
  • 55
0

You are not instantiating an abstract class and an interface,

you are instantiating some specific implementations of that abstract class and of that interface.

If you declare a list of AbstractClass or AbstractInterface you can just calls methods declared on your superclass or interface but not these declared on your specific implementations (Test1, Test2, Test3 and Test4).

Vishal Gajera
  • 4,137
  • 5
  • 28
  • 55
DavidGSola
  • 697
  • 5
  • 17