Can we instantiate an abstract class?

后端 未结 16 1179
长情又很酷
长情又很酷 2020-11-22 07:43

During one of my interview, I was asked \"If we can instantiate an abstract class?\"

My reply was \"No. we can\'t\". But, interviewer told me \"Wrong, we can.\"

相关标签:
16条回答
  • 2020-11-22 08:10

    Just observations you could make:

    1. Why poly extends my? This is useless...
    2. What is the result of the compilation? Three files: my.class, poly.class and poly$1.class
    3. If we can instantiate an abstract class like that, we can instantiate an interface too... weird...


    Can we instantiate an abstract class?

    No, we can't. What we can do is, create an anonymous class (that's the third file) and instantiate it.


    What about a super class instantiation?

    The abstract super class is not instantiated by us but by java.

    EDIT: Ask him to test this

    public static final void main(final String[] args) {
        final my m1 = new my() {
        };
        final my m2 = new my() {
        };
        System.out.println(m1 == m2);
    
        System.out.println(m1.getClass().toString());
        System.out.println(m2.getClass().toString());
    
    }
    

    output is:

    false
    class my$1
    class my$2
    
    0 讨论(0)
  • 2020-11-22 08:11

    You can simply answers, in just one line

    No, you can never instance Abstract Class

    But, interviewer still not agree, then you can tell him/her

    all you can do is, you can create an Anonymous Class.

    And, according to Anonymous class, class declared and instantiate at the same place/line

    So, it might be possible that, interviewer would be interested to check your confidence level and how much you know about the OOPs .

    0 讨论(0)
  • 2020-11-22 08:11

    Abstract classes cannot be instantiated, but they can be subclassed. See This Link

    The best example is

    Although Calender class has a abstract method getInstance(), but when you say Calendar calc=Calendar.getInstance();

    calc is referring to the class instance of class GregorianCalendar as "GregorianCalendar extends Calendar "

    Infact annonymous inner type allows you to create a no-name subclass of the abstract class and an instance of this.

    0 讨论(0)
  • 2020-11-22 08:14

    Here, i'm creating instance of my class

    No, you are not creating the instance of your abstract class here. Rather you are creating an instance of an anonymous subclass of your abstract class. And then you are invoking the method on your abstract class reference pointing to subclass object.

    This behaviour is clearly listed in JLS - Section # 15.9.1: -

    If the class instance creation expression ends in a class body, then the class being instantiated is an anonymous class. Then:

    • If T denotes a class, then an anonymous direct subclass of the class named by T is declared. It is a compile-time error if the class denoted by T is a final class.
    • If T denotes an interface, then an anonymous direct subclass of Object that implements the interface named by T is declared.
    • In either case, the body of the subclass is the ClassBody given in the class instance creation expression.
    • The class being instantiated is the anonymous subclass.

    Emphasis mine.

    Also, in JLS - Section # 12.5, you can read about the Object Creation Process. I'll quote one statement from that here: -

    Whenever a new class instance is created, memory space is allocated for it with room for all the instance variables declared in the class type and all the instance variables declared in each superclass of the class type, including all the instance variables that may be hidden.

    Just before a reference to the newly created object is returned as the result, the indicated constructor is processed to initialize the new object using the following procedure:

    You can read about the complete procedure on the link I provided.


    To practically see that the class being instantiated is an Anonymous SubClass, you just need to compile both your classes. Suppose you put those classes in two different files:

    My.java:

    abstract class My {
        public void myMethod() {
            System.out.print("Abstract");
        }
    }
    

    Poly.java:

    class Poly extends My {
        public static void main(String a[]) {
            My m = new My() {};
            m.myMethod();
        }
    }
    

    Now, compile both your source files:

    javac My.java Poly.java
    

    Now in the directory where you compiled the source code, you will see the following class files:

    My.class
    Poly$1.class  // Class file corresponding to anonymous subclass
    Poly.class
    

    See that class - Poly$1.class. It's the class file created by the compiler corresponding to the anonymous subclass you instantiated using the below code:

    new My() {};
    

    So, it's clear that there is a different class being instantiated. It's just that, that class is given a name only after compilation by the compiler.

    In general, all the anonymous subclasses in your class will be named in this fashion:

    Poly$1.class, Poly$2.class, Poly$3.class, ... so on
    

    Those numbers denote the order in which those anonymous classes appear in the enclosing class.

    0 讨论(0)
  • 2020-11-22 08:14

    It's impossible to instantiate an abstract class. What you really can do, has implement some common methods in an abstract class and let others unimplemented (declaring them abstract) and let the concrete descender implement them depending on their needs. Then you can make a factory, which returns an instance of this abstract class (actually his implementer). In the factory you then decide, which implementer to choose. This is known as a factory design pattern:

       public abstract class AbstractGridManager {
            private LifecicleAlgorithmIntrface lifecicleAlgorithm;
            // ... more private fields
    
            //Method implemented in concrete Manager implementors 
            abstract public Grid initGrid();
    
            //Methods common to all implementors
            public Grid calculateNextLifecicle(Grid grid){
                return this.getLifecicleAlgorithm().calculateNextLifecicle(grid);
            }
    
            public LifecicleAlgorithmIntrface getLifecicleAlgorithm() {
                return lifecicleAlgorithm;
            }
            public void setLifecicleAlgorithm(LifecicleAlgorithmIntrface lifecicleAlgorithm) {
                this.lifecicleAlgorithm = lifecicleAlgorithm;
            }
            // ... more common logic and getters-setters pairs
        }
    

    The concrete implementer only needs to implement the methods declared as abstract, but will have access to the logic implemented in those classes in an abstract class, which are not declared abstract:

    public class FileInputGridManager extends AbstractGridManager {
    
    private String filePath;
    
    //Method implemented in concrete Manager implementors 
    abstract public Grid initGrid();
    
    public class FileInputGridManager extends AbstractGridManager {
    
        private String filePath;
    
        //Method implemented in concrete Manager implementors 
        abstract public Grid initGrid();
    
        public Grid initGrid(String filePath) {
            List<Cell> cells = new ArrayList<>();
            char[] chars;
            File file = new File(filePath); // for example foo.txt
            // ... more logic
            return grid;
        }
    }
    

    Then finally the factory looks something like this:

    public class GridManagerFactory {
        public static AbstractGridManager getGridManager(LifecicleAlgorithmIntrface lifecicleAlgorithm, String... args){
            AbstractGridManager manager = null;
    
            // input from the command line
            if(args.length == 2){
                CommandLineGridManager clManager = new CommandLineGridManager();
                clManager.setWidth(Integer.parseInt(args[0]));
                clManager.setHeight(Integer.parseInt(args[1]));
                // possibly more configuration logic
                ...
                manager = clManager;
            } 
            // input from the file
            else if(args.length == 1){
                FileInputGridManager fiManager = new FileInputGridManager();
                fiManager.setFilePath(args[0]);
                // possibly more method calls from abstract class
                ...
                manager = fiManager ;
            }
            //... more possible concrete implementors
            else{
                manager = new CommandLineGridManager();
            }
            manager.setLifecicleAlgorithm(lifecicleAlgorithm);
            return manager;
        }
    }
    

    The receiver of AbstractGridManager would call the methods on him and get the logic, implemented in the concrete descender (and partially in the abstract class methods) without knowing what is the concrete implementation he got. This is also known as inversion of control or dependency injection.

    0 讨论(0)
  • 2020-11-22 08:15

    The above instantiates an anonymous inner class which is a subclass of the my abstract class. It's not strictly equivalent to instantiating the abstract class itself. OTOH, every subclass instance is an instance of all its super classes and interfaces, so most abstract classes are indeed instantiated by instantiating one of their concrete subclasses.

    If the interviewer just said "wrong!" without explaining, and gave this example, as a unique counterexample, I think he doesn't know what he's talking about, though.

    0 讨论(0)
提交回复
热议问题