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

인터뷰 중 하나에서 “추상 수업을 인스턴스화 할 수 있을까요?”라는 질문을 받았습니다.

답장은 “아니요.”라고 대답했습니다. 그러나 면접관은 “잘못, 우리는 할 수있다”고 말했다.

나는 이것에 대해 조금 논쟁했다. 그런 다음 집에서 직접 해보라고했습니다.

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 섹션 12.5 에서 객체 생성 프로세스 에 대해 읽을 수 있습니다 . 여기에서 하나의 진술을 인용하겠습니다 :-

새 클래스 인스턴스가 작성 될 때마다 클래스 유형에 선언 된 모든 인스턴스 변수 및 클래스 유형의 각 수퍼 클래스에 선언 된 모든 인스턴스 변수 (숨겨 질 수있는 모든 인스턴스 변수 포함)를위한 공간이있는 메모리 공간이 할당됩니다.

새로 작성된 오브젝트에 대한 참조가 결과로 리턴되기 직전에 표시된 생성자가 다음 프로 시저를 사용하여 새 오브젝트를 초기화하도록 처리됩니다.

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


실제로 인스턴스화되는 클래스가 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에 대해 얼마나 많이 알고 있는지 관심이있을 수 있습니다.


답변

기술 부분은 다른 답변에서 잘 다루어졌으며 주로
“그는 잘못 되었습니다. 그는 물건을 알지 못하고 그에게 가입하여 모든 것을 지우십시오 :)”

나는 이것이 다른 질문에 언급되었을 것이라는 사실을 강조 하고 싶습니다. 이것은 스트레스 질문 일 수 있으며 많은 면접관이 당신에 대해 더 많이 알 수있는 중요한 도구이며 어렵고 특이한 상황에 어떻게 대처 하는가입니다. 당신에게 잘못된 코드를 제공함으로써, 아마도 당신이 말다툼했는지를 알고 싶었을 것입니다 . 이와 비슷한 상황에서 선배들과 대항 할 자신이 있는지를 알기 위해.

추신 : 이유를 모르겠지만 면접관이이 게시물을 읽은 느낌이 있습니다.


답변

추상 클래스는 인스턴스화 할 수 없지만 서브 클래스화할 수 있습니다. 이 링크를보십시오

가장 좋은 예는

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

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

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