Java에서 객체 초기화 순서에 대한 자세한 설명

3894 단어 java대상초기화
앞말
자바에서 하나의 대상은 사용할 수 있기 전에 반드시 정확하게 초기화되어야 한다는 점은 자바 규범에 규정된 것이다.최근에 나는 재미있는 문제를 발견했는데, 이 문제의 답안은 언뜻 보니 나의 눈을 속였다.이 세 가지 종류를 살펴보자.

package com.ds.test;

public class Upper {
 String upperString;

 public Upper() {
 Initializer.initialize(this);
 }
}

package com.ds.test;

public class Lower extends Upper {

 String lowerString = null;

 public Lower() {
 super();
 System.out.println("Upper: " + upperString);
 System.out.println("Lower: " + lowerString);
 }

 public static void main(final String[] args) {
 new Lower();
 }
}

package com.ds.test;
public class Initializer {
 static void initialize(final Upper anUpper) {
 if (anUpper instanceof Lower) {
 Lower lower = (Lower) anUpper;
 lower.lowerString = "lowerInited";
 }
 anUpper.upperString = "upperInited";
 }
}
이 클래스를 실행하면 어떤 출력을 얻을 수 있습니까?이 간단한 예에서 전체 형세를 더욱 쉽게 볼 수 있지만, 이 상황은 현실에서 발생하면 매우 많은 코드가 한 사람의 주의력을 분산시킬 수 있다.
어쨌든 출력은 다음과 같다.

Upper: upperInited
Lower: null;
작은 예시에서 Lower 유형을 사용했지만 String 류의 실제 코드 중 등록에 사용되는 위탁 대상이 있는데 Initializer 류의 기능과 같다. 적어도 Lower 류는 이런 의도이다.그러나 일부 원인으로 인해 프로그램을 실행할 때 작동하지 않습니다.대신 기본 경로를 사용했습니다. 의뢰 대상이 설정되지 않았습니다 (null).
이제 코드를 살짝 변경합니다Lower .

package com.ds.test;

public class Lower extends Upper {

 String lowerString;

 public Lower() {
 super();
 System.out.println("Upper: " + upperString);
 System.out.println("Lower: " + lowerString);
 }

 public static void main(final String[] args) {
 new Lower();
 }
}
현재 출력은 다음과 같습니다.

Upper: upperInited
Lower: lowerInited
코드의 차이를 발견했습니까?
예, 이 필드는 더 이상 명확하게 비어 있지 않습니다.왜 그랬는지는 달라.어쨌든 참조 형식 필드 (예를 들어 여기 Lower 의 기본값은 비어 있지 않습니까?당연히 비어있지.이런 미세한 변화는 분명히 어떤 방식으로도 코드 행위를 바꾸지 않겠지만 결과를 다르게 만든다는 사실이 증명된다.
그럼 도대체 무슨 일이 일어난 거야?초기화 순서를 보면 모든 것이 뚜렷해진다.
1. lowerString 함수는 String 구조기를 호출했다.
2.main() 의 실례 하나가 준비되었다.모든 필드가 생성되고 기본값이 채워졌다는 것을 의미합니다. 예를 들어 인용 형식의 기본값은 비어 있고 부울 형식의 기본값은 Lower 입니다.이때 필드에 대한 내연부치는 발생하지 않았다.
3. 부류 구조기가 호출되었다.이것은 언어의 특성에 의해 강제적으로 집행된 것이다.그래서 다른 어떤 일이 발생하기 전에 어퍼의 구조기가 호출되었다.
4. Upper 이 구조기가 실행되고 Lower 방법으로 새로 만든 실례를 가리키는 인용을 지정합니다.
5. false 클래스는 두 필드 Initializer.initialize() Initializer 에 새 문자열을 첨부합니다.좀 더러운 upperString 실례 검사를 통해 그 두 필드에 값을 부여하는 것은 특별히 좋은 디자인 모델이 아니지만 그렇게 많은 것을 상관하지 않아도 된다.일단 발생하면lowerString instanceof 의 인용은 더 이상 비어 있지 않습니다.
6. upperString 의 호출이 완료되었고 lowerString 구조기도 마찬가지로 완성되었다.
7. 이제 재미있어졌다: Initializer.initialize() 실례의 구조가 계속되고 있다.Upper 필드의 성명에 명확하게 Lower 값을 부여하지 않았다고 가정하면, lowerString 구조기는 필드에 연결된 두 문자열을 다시 실행하고 출력합니다.
그러나 만약에 명확한 값을 부여하는 작업이 있다면 실행 절차는 약간 다르다. 부류 구조기가 완성되면 나머지 구조기가 실행되기 전에 모든 변수를 초기화할 것이다(java언어규범 12.5절 참조).이 경우, 이전에 =null 에 부여된 문자열 인용은 다시 null이 부여되지 않습니다.그리고 나머지 함수 구조를 계속 실행합니다. 현재 인쇄 Lower 의 값은:null입니다.
이것은 우리가 창설 대상의 세부 사항(또는 자바 인코딩 규범, 인쇄된 것, 온라인을 어디로 보는지 알 수 있을 뿐만 아니라, 왜 이렇게 초기화를 쓰는 것이 엉망인지 보여주는 좋은 예이다.우리는 어퍼의 하위 클래스에 조금도 관심을 가져서는 안 된다.반대로, 일부 이유로 일부 필드에 대한 초기화가 하위 클래스 자체에서 이루어지지 않으면, 그 자체의 일부 초기화 도움말 클래스의 변체만 필요합니다.이런 상황에서 만약 당신이 lowerString 또는 lowerString 을 사용한다면 그것은 정말 아무런 차이가 없을 것이다.
총결산
이상은 이 글의 전체 내용입니다. 이 글의 내용이 여러분의 학습이나 업무에 어느 정도 도움이 되고 문제가 있으면 댓글로 교류하시기 바랍니다.

좋은 웹페이지 즐겨찾기