Development Tip

추상 클래스를 인스턴스화 할 수 있습니까?

yourdevel 2020. 10. 3. 12:07
반응형

추상 클래스를 인스턴스화 할 수 있습니까?


인터뷰 중에 "추상 클래스를 인스턴스화 할 수 있는지"라는 질문을 받았습니다.

내 대답은 "아니요. 우리는 할 수 없습니다"였습니다. 하지만 면접관이 "그렇습니다. 할 수 있습니다."라고 말했습니다.

나는 이것에 대해 약간 논쟁했다. 그런 다음 그는 집에서 직접 시도하라고 말했습니다.

abstract class my {
    public void mymethod() {
        System.out.print("Abstract");
    }
}

class poly {
    public static void main(String a[]) {
        my m = new my() {};
        m.mymethod();
    }
}

여기에서는 내 클래스의 인스턴스를 만들고 추상 클래스의 메서드를 호출합니다. 누구든지 나에게 이것을 설명해 주시겠습니까? 인터뷰 중에 내가 정말 틀렸나 요?


여기, 내 클래스의 인스턴스를 만들고 있습니다.

아니요, 여기서 추상 클래스의 인스턴스를 만드는 것이 아닙니다. 오히려 추상 클래스 익명 하위 클래스 인스턴스를 만듭니다 . 그런 다음 하위 클래스 개체를 가리키는 추상 클래스 참조 에서 메서드를 호출 합니다 .

이 동작은 JLS-섹션 # 15.9.1 에 명시되어 있습니다 .

클래스 인스턴스 생성 표현식이 클래스 본문으로 끝나면 인스턴스화되는 클래스는 익명 클래스입니다. 그때:

  • T가 클래스를 나타내는 경우 T로 명명 ​​된 클래스의 익명 직접 하위 클래스가 선언됩니다. T로 표시된 클래스가 최종 클래스 인 경우 컴파일 타임 오류입니다.
  • T가 인터페이스를 나타내는 경우 T로 명명 ​​된 인터페이스를 구현하는 Object의 익명 직접 하위 클래스가 선언됩니다.
  • 두 경우 모두 하위 클래스의 본문은 클래스 인스턴스 생성 표현식에 제공된 ClassBody입니다.
  • 인스턴스화되는 클래스는 익명의 하위 클래스입니다.

내 강조.

또한 JLS-Section # 12.5 에서 Object Creation Process 에 대해 읽을 수 있습니다 . 여기에서 한 가지 진술을 인용하겠습니다.-

새 클래스 인스턴스가 생성 될 때마다 클래스 유형에 선언 된 모든 인스턴스 변수와 숨길 수있는 모든 인스턴스 변수를 포함하여 클래스 유형의 각 수퍼 클래스에서 선언 된 모든 인스턴스 변수를위한 공간이있는 메모리 공간이 할당됩니다.

새로 생성 된 객체에 대한 참조가 결과로 반환되기 직전에 표시된 생성자는 다음 절차를 사용하여 새 객체를 초기화하도록 처리됩니다.

내가 제공 한 링크에서 전체 절차에 대해 읽을 수 있습니다.


인스턴스화되는 클래스가 Anonymous SubClass 인지 실제로 확인하려면 두 클래스를 모두 컴파일하면됩니다. 이러한 클래스를 두 개의 다른 파일에 넣었다고 가정합니다.

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();
    }
}

이제 두 소스 파일을 모두 컴파일하십시오.

javac My.java Poly.java

이제 소스 코드를 컴파일 한 디렉토리에서 다음 클래스 파일을 볼 수 있습니다.

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

그 클래스를 참조하십시오- Poly$1.class. 아래 코드를 사용하여 인스턴스화 한 익명 하위 클래스에 해당하는 컴파일러에서 만든 클래스 파일입니다.

new My() {};

따라서 인스턴스화되는 다른 클래스가 있음이 분명합니다. 그 클래스는 컴파일러에 의해 컴파일 된 후에 만 ​​이름이 부여됩니다.

일반적으로 클래스의 모든 익명 하위 클래스는 다음과 같은 방식으로 이름이 지정됩니다.

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

이러한 숫자는 해당 익명 클래스가 둘러싸는 클래스에 나타나는 순서를 나타냅니다.


위는 my추상 클래스 의 하위 클래스 인 익명 내부 클래스를 인스턴스화합니다 . 추상 클래스 자체를 인스턴스화하는 것과는 완전히 동일하지 않습니다. OTOH, 모든 하위 클래스 인스턴스는 모든 수퍼 클래스 및 인터페이스의 인스턴스이므로 대부분의 추상 클래스는 실제로 구체적인 하위 클래스 중 하나를 인스턴스화하여 인스턴스화됩니다.

면접관이 "틀렸다!" 설명도하지 않고이 예를 들어 보면 독특한 반례로 그가 무슨 말을하는지 모르는 것 같아요.


= my() {};객체의 단순한 인스턴스화가 아닌 익명 구현이 있음을 의미합니다 = my(). 추상 클래스를 인스턴스화 할 수 없습니다.


당신이 할 수있는 관찰 :

  1. poly확장 my합니까? 이건 쓸모 없어 ...
  2. 컴파일 결과는 무엇입니까? 세 파일 : my.class, poly.classpoly$1.class
  3. 그런 추상 클래스를 인스턴스화 할 수 있다면 인터페이스도 인스턴스화 할 수 있습니다 ... 이상합니다 ...


추상 클래스를 인스턴스화 할 수 있습니까?

아니요, 할 수 없습니다. 우리가 할 수있는 일은 익명의 클래스 (세 번째 파일)를 만들고 인스턴스화하는 것입니다.


수퍼 클래스 인스턴스화는 어떻습니까?

추상 슈퍼 클래스는 우리가 아니라 자바에 의해 인스턴스화됩니다 .

편집 :이 테스트를 요청

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());

}

출력은 다음과 같습니다.

false
class my$1
class my$2

한 줄로 간단히 대답 할 수 있습니다.

아니요 , 추상 클래스를 인스턴스화 할 수 없습니다.

그러나 면접관이 여전히 동의하지 않습니다.

할 수있는 것은 익명 클래스를 만드는 것입니다.

그리고 Anonymous 클래스에 따르면 클래스가 선언되고 동일한 위치 / 줄에서 인스턴스화됩니다.

따라서 면접관이 귀하의 신뢰 수준과 OOP에 대해 얼마나 알고 있는지 확인하는 데 관심이있을 수 있습니다.


기술적 인 부분은 다른 답변에서 잘 다루어졌으며 주로
"그는 틀렸어요. 그는 물건을 모릅니다. SO 가입을 요청하고 모든 문제를 해결했습니다. :)"로 끝납니다.

나는 이것이 스트레스 질문 일 수 있으며 많은 면접관이 당신에 대해 더 많이 알고 어렵고 비정상적인 상황에 어떻게 반응 하는지를 알 수있는 중요한 도구 라는 사실 (다른 답변에서 언급 했음)을 언급 하고 싶습니다. 잘못된 코드를 제공함으로써 그는 아마도 당신이 반박하는지보고 싶어 했을 것입니다 . 이와 비슷한 상황에서 선배들과 맞설 자신감이 있는지 알아보기.

PS : 이유는 모르겠지만 면접관이이 게시물을 읽은 것 같습니다.


추상 클래스는 인스턴스화 할 수 없지만 하위 클래스화할 수 있습니다. 이 링크보기

가장 좋은 예는

하지만 캘린더 클래스) (추상 메소드의 getInstance를 가지고 ,하지만 당신은 때를 말한다Calendar calc=Calendar.getInstance();

calc는 GregorianCalendar 클래스의 클래스 인스턴스를 "GregorianCalendar extends Calendar "로 참조합니다.

Infact 익명 내부 유형을 사용하면 추상 클래스의 이름없는 하위 클래스 와 이것의 인스턴스 를 만들 수 있습니다 .


기술 답변

추상 클래스는 인스턴스화 할 수 없습니다. 이것은 정의와 디자인에 의한 것입니다.

JLS에서 8 장. 클래스 :

명명 된 클래스는 추상 (§8.1.1.1)으로 선언 될 수 있으며 불완전하게 구현 된 경우 추상으로 선언되어야합니다. 이러한 클래스는 인스턴스화 할 수 없지만 하위 클래스에 의해 확장 될 수 있습니다.

Classes.newInstance ()에 대한 JSE 6 Java 문서에서 :

InstantiationException-이 Class가 추상 클래스, 인터페이스, 배열 클래스, 원시 형 또는 void를 나타내는 경우 또는 클래스에 nullary 생성자가없는 경우; 또는 다른 이유로 인스턴스화가 실패한 경우.

물론 추상 클래스 (익명 하위 클래스 포함)의 구체적인 하위 클래스를 인스턴스화 할 수 있으며 추상 유형에 대한 개체 참조의 유형 변환을 수행 할 수도 있습니다.

이것에 대한 다른 각도-팀 플레이 및 소셜 인텔리전스 :

이러한 종류의 기술적 오해는 복잡한 기술과 법적 사양을 다룰 때 현실 세계에서 자주 발생합니다.

"People Skills" can be more important here than "Technical Skills". If competitively and aggressively trying to prove your side of the argument, then you could be theoretically right, but you could also do more damage in having a fight / damaging "face" / creating an enemy than it is worth. Be reconciliatory and understanding in resolving your differences. Who knows - maybe you're "both right" but working off slightly different meanings for terms??

누가 압니까-가능성은 아니지만 면접관이 고의적으로 작은 갈등 / 오해를 도입하여 어려운 상황에 처하게하고 당신이 감정적으로 사회적으로 어떻게 행동하는지 볼 수 있습니다. 동료들에게 은혜 롭고 건설적으로 대하고 선배들의 조언을 따르고 인터뷰 후 문제 / 오해를 해결하기 위해 이메일이나 전화를 통해 진행하십시오. 동기 부여와 세부 사항 지향적임을 보여줍니다.


모든 사람이 대답 한대로 인스턴스화 abstract class할 수 없는 것은 확고한 사실입니다 .

프로그램이 익명 클래스를 정의 할 때, 컴파일러는 실제로 다른 이름으로 새 클래스 (패턴이 만들어 익명 클래스 번호입니다)EnclosedClassName$nn

따라서이 Java 클래스를 디 컴파일하면 아래와 같은 코드를 찾을 수 있습니다.

내 수업

abstract class my { 
    public void mymethod() 
    { 
        System.out.print("Abstract"); 
    }
} 

poly $ 1.class ( "익명 클래스"의 생성 된 클래스)

class poly$1 extends my 
{
} 

ploly.cass

public class poly extends my
{
    public static void main(String[] a)
    {
        my m = new poly.1(); // instance of poly.1 class NOT the abstract my class

        m.mymethod();
    }
}

아니요, 추상 클래스는 인스턴스화 할 수 없습니다. 익명 클래스 만 인스턴스화합니다. 추상 클래스에서는 추상 메서드를 선언하고 구체적인 메서드 만 정의합니다.


추상 클래스 정보

  • 추상 클래스의 개체를 만들 수 없습니다.
  • 변수 생성 가능 (데이터 유형처럼 동작 할 수 있음)
  • 자식이 부모의 하나 이상의 추상 메서드를 재정의 할 수없는 경우 자식도 추상이됩니다.
  • 추상 클래스는 자식 클래스 없이는 쓸모가 없습니다.

추상 클래스의 목적은베이스처럼 동작하는 것입니다. 상속 계층 구조에서는 맨 위에 추상 클래스가 표시됩니다.


다음과
같이 말할 수 있습니다. 추상 클래스를 인스턴스화 할 수는 없지만, 추상 클래스 끝에 구현 본문을 new추가하는 것만으로 키워드를 사용하여 익명 클래스 인스턴스를 만들 수 있습니다 {}.


클래스를 확장한다고해서 클래스를 인스턴스화한다는 의미는 아닙니다. 실제로 귀하의 경우에는 하위 클래스의 인스턴스를 만들고 있습니다.

추상 클래스가 시작을 허용하지 않는다고 확신합니다. 그래서 저는 아니오라고 말하고 싶습니다. 추상 클래스를 인스턴스화 할 수 없습니다. 그러나 확장 / 상속 할 수 있습니다.

추상 클래스를 직접 인스턴스화 할 수 없습니다. 그러나 이것이 클래스의 인스턴스 (실제로 원래 추상 클래스의 인스턴스가 아님)를 간접적으로 얻을 수 없다는 것을 의미하지는 않습니다. 원래 추상 클래스를 인스턴스화 할 수는 없지만 다음과 같이 할 수 있습니다.

  1. 빈 클래스 만들기
  2. 추상 클래스에서 상속
  3. Instantiate the dervied class

So you get access to all the methods and properties in an abstract class via the derived class instance.


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.


No, we can't create the object of abstract class, but create the reference variable of the abstract class. The reference variable is used to refer to the objects of derived classes (Sub classes of Abstract class)

Here is the example that illustrates this concept

abstract class Figure { 

    double dim1; 

    double dim2; 

    Figure(double a, double b) { 

        dim1 = a; 

        dim2 = b; 

    } 

    // area is now an abstract method 

    abstract double area(); 

    }


    class Rectangle extends Figure { 
        Rectangle(double a, double b) { 
        super(a, b); 
    } 
    // override area for rectangle 
    double area() { 
        System.out.println("Inside Area for Rectangle."); 
        return dim1 * dim2; 
    } 
}

class Triangle extends Figure { 
    Triangle(double a, double b) { 
        super(a, b); 
    } 
    // override area for right triangle 
    double area() { 
        System.out.println("Inside Area for Triangle."); 
        return dim1 * dim2 / 2; 
    } 
}

class AbstractAreas { 
    public static void main(String args[]) { 
        // Figure f = new Figure(10, 10); // illegal now 
        Rectangle r = new Rectangle(9, 5); 
        Triangle t = new Triangle(10, 8); 
        Figure figref; // this is OK, no object is created 
        figref = r; 
        System.out.println("Area is " + figref.area()); 
        figref = t; 
        System.out.println("Area is " + figref.area()); 
    } 
}

Here we see that we cannot create the object of type Figure but we can create a reference variable of type Figure. Here we created a reference variable of type Figure and Figure Class reference variable is used to refer to the objects of Class Rectangle and Triangle.

참고URL : https://stackoverflow.com/questions/13670991/can-we-instantiate-an-abstract-class

반응형