내 키 지 않 는 구조 기
3444 단어 java puzzle
비록 하나의 방법 성명 에서 throws 자 구 를 보 는 것 은 매우 흔 하지만, 구조 기의 성명 에서 throws 자 구 를 보 는 것 은 매우 드물다.다음 절 차 는 이러한 성명 이 있다.그렇다면 그것 은 무엇 을 인쇄 할 것 인가?
public class Reluctant {
private Reluctant internalInstance = new Reluctant();
public Reluctant() throws Exception {
throw new Exception("I'm not coming out");
}
public static void main(String[] args) {
try {
Reluctant b = new Reluctant();
System.out.println("Surprise!");
} catch (Exception ex) {
System.out.println("I told you so");
}
}
}
main 방법 은 Reluctant 구조 기 를 호출 하여 이상 을 던 집 니 다.catch 자구 가 이 이상 을 포착 하고 I told you so 를 인쇄 하 기 를 기대 할 수 있 습 니 다.가까이 가서 이 프로그램 을 자세히 보면 Reluctant 인 스 턴 스 는 두 번 째 내부 인 스 턴 스 도 포함 되 어 있 고 구조 기 에 도 이상 이 있 음 을 알 수 있다.어떤 이상 을 던 져 도 main 의 catch 자 구 는 잡 아야 할 것 같 습 니 다. 따라서 이 프로그램 이 I told you 를 인쇄 할 것 이 라 고 예측 하 는 것 은 안전 한 내기 일 것 입 니 다.그러나 그것 을 실행 하려 고 시도 할 때, 그것 은 전혀 이런 일 을 하지 않 았 다 는 것 을 알 게 될 것 이다. 그것 은 Stack Overflow Error 이상 을 던 졌 다. 왜 일 까?
StackOverflow Error 이상 을 던 지 는 대부분의 프로그램 과 마찬가지 로 이 프로그램 도 무한 재 귀 를 포함 하고 있 습 니 다.구조 기 를 호출 할 때 인 스 턴 스 변수의 초기 화 작업 은 구조 기의 프로그램 보다 먼저 실 행 됩 니 다 [JLS 12.5].이 수수께끼 에서 internalInstance 변수의 초기 화 작업 은 재 귀적 으로 구조 기 를 호출 했 고 이 구조 기 는 Reluctant 구조 기 를 재 호출 하여 이 변 수 를 자신의 internalInstance 도 메 인 으로 초기 화 시 켜 무한 재 귀 했다.이 재 귀적 호출 은 구조 체 가 실행 기 회 를 얻 기 전에 StackOverflow Error 이상 을 던 집 니 다. StackOverflow Error 는 Exception 의 하위 형식 이 아 닌 Error 의 하위 형식 이기 때문에 catch 자 구 는 잡 을 수 없습니다.
한 대상 이 자신의 유형 과 같은 인 스 턴 스 를 포함 하 는 경우 가 적지 않다.예 를 들 어 링크 목록 노드, 트 리 노드 와 그림 노드 는 모두 이런 상황 에 속한다.StackOverflow Error 이상 을 피하 기 위해 서 는 이러한 인 스 턴 스 를 매우 조심스럽게 초기 화 해 야 합 니 다.
이 수수께끼 의 이름 에 있 는 문제: 성명 은 이상 한 구조 기 를 던 질 것 입 니 다. 구조 기 는 인 스 턴 스 초기 화 작업 이 던 질 모든 검사 이상 을 밝 혀 야 합 니 다.다음은 흔히 볼 수 있 는 '서비스 제공 자' 모델 을 보 여 주 는 프로그램 입 니 다. 이 규칙 을 위반 하기 때문에 컴 파일 할 수 없습니다.
public class Car {
private static Class engineClass = ...;
private Engine engine = (Engine)enginClass.newInstance();
public Car(){ }
}
구조 기 는 프로그램 체 가 없 음 에 도 불구 하고 검사 이상 두 개 를 던 집 니 다. InstantiationException 과 IllegalAccessException.Class. Instance 에서 던 진 것 입 니 다. 이 방법 은 engin e 도 메 인 을 초기 화 할 때 호출 됩 니 다.이 프로그램 을 수정 하 는 가장 좋 은 방법 은 개인 적 이 고 정적 인 조수 방법 을 만 드 는 것 입 니 다. 도 메 인의 초기 값 을 계산 하고 이상 을 적절하게 처리 하 는 것 입 니 다.이 안건 에서 우 리 는 engineClass 가 인용 한 Class 대상 을 선택 하여 방문 가능 하고 실례 화 될 수 있 도록 한다 고 가정 합 니 다.
다음 Car 버 전 은 오류 없 이 컴 파일 할 수 있 습 니 다.
//Fixed - instance initializers don’t throw checked exceptions
public class Car {
private static Class engineClass = ...;
private Engine engine = newEngine;
private static Engine newEngine() {
try {
return (Engine)engineClass.newInstance();
} catch (IllegalAccessException e) {
throw new AssertionError(e);
} catch (InstantiationException e) {
throw new AssertionError(e);
}
}
public Car(){ }
한 마디 로 하면 인 스 턴 스 초기 화 작업 은 구조 기의 프로그램 체 보다 먼저 실 행 됩 니 다.인 스 턴 스 초기 화 작업 에서 던 진 모든 이상 은 구조 기 에 전 파 됩 니 다.초기 화 작업 이 검사 이상 을 던 졌 다 면 구조 기 는 이러한 이상 을 던 졌 다 고 밝 혀 야 하지만 이 를 피해 야 합 니 다. 혼 란 스 러 울 수 있 기 때 문 입 니 다.마지막 으로 우리 가 디자인 한 클래스 에 대해 만약 에 그 실례 가 같은 클래스 에 속 하 는 다른 실례 를 포함한다 면 이런 무한 귀속 에 대해 각별히 주의해 야 한다.