머리말
Java에서는 객체를 사용하기 전에 객체를 올바르게 초기화해야하며 Java 사양에 의해 규정되어 있습니다. 최근에 나는 흥미로운 질문을 발견했고,이 질문에 대한 답은 언뜻보기에 내 눈을 속였다. 이 세 가지 범주를 살펴보십시오.
package com.ds.test; public class 상단 {String Upperstring; public topt () {initializer.initialize (this); }} package com.ds.test; public class 아래는 상단 {string lowerstring = null; public lower () {super (); System.out.println ( "상단 :" + upperstring); System.out.println ( "하단 :" + lowerstring); } public static void main (Final String [] args) {new lower (); }} package com.ds.test; public class 이니셜 라이저 {static void initialize (최종 상단 anupper) {if (anupper instancef) {하부 하부 = (하단) anupper; Lower.lowerstring = "LowerInited"; } anupper.upperstring = "상류"; }} Lower 클래스를 실행하여 어떤 출력을 얻을 수 있습니까? 이 최소한의 예에서, 전체 상황은 더 쉽게 볼 수 있지만,이 상황은 실제로 발생하며 사람을 산만하게하는 많은 코드가있을 것입니다.
어쨌든 출력은 다음과 같습니다.
어퍼 : 어퍼 티니티드어 : NULL;
String 유형은 작은 예제에서 사용되지만, Initializer 클래스의 실제 코드는 등록을위한 대의원 객체를 가지고 있으며, 이는 Lower 클래스의 함수와 동일합니다. 최소한 Lower 클래스가 의도입니다. 그러나 어떤 이유로 응용 프로그램을 실행할 때는 작동하지 않습니다. 대신 기본 경로가 사용되고 대의원 객체가 설정되지 않습니다 (NULL).
이제 Lower 의 코드를 약간 변경하십시오.
package com.ds.test; public class 아래는 상단 {String Lowerstring; public lower () {super (); System.out.println ( "상단 :" + upperstring); System.out.println ( "하단 :" + lowerstring); } public static void main (Final String [] args) {new lower (); }}출력은 이제 다음과 같습니다.
상단 : 어퍼 티니티드어 : 하단
코드의 차이를 찾았습니까?
그렇습니다.이 lowerString 필드는 더 이상 명시 적으로 비어 있지 않습니다. 이것이 왜 다른가? 어쨌든, 참조 유형 필드 (예 : String )의 기본값이 비어 있지 않습니까? 물론 비어 있습니다. 이 약간의 변화가 분명히 코드의 동작을 변화 시키지는 않지만 결과를 다르게 만듭니다.
그렇다면 정확히 무슨 일이 있었습니까? 초기화 순서를 확인할 때 모든 것이 명확 해집니다.
1. main() 함수는 Lower 생성자를 호출합니다.
2. Lower 인스턴스가 준비되었습니다. 즉, 모든 필드가 생성되고 기본값으로 채워져 있으며, 예를 들어, 참조 유형의 기본값은 비어 있고 부울 유형의 기본값은 false 입니다. 현재 필드에 대한 인라인 할당은 발생하지 않습니다.
3. 부모 클래스 생성자가 호출됩니다. 이것은 언어의 특성에 의해 시행됩니다. 따라서 다른 일이 일어나기 전에 어퍼의 생성자가 호출됩니다.
4.이 생성자가 실행되고 새로 생성 된 Initializer.initialize() 메소드의 인스턴스에 대한 참조를 지정합니다.
5. Initializer 클래스는 새 문자열을 두 개의 필드 ( upperString and lowerString )에 첨부합니다. 인스턴스 점검의 약간 더러운 instanceof 를 사용 하여이 두 필드에 값을 할당하는 것은 특히 좋은 디자인 패턴이 아니지만 효과적이지 않으며 그다지 걱정하지 마십시오. 그런 일이 발생하면 upperString 및 lowerString 에 대한 참조가 더 이상 비어 있지 않습니다.
6. Initializer.initialize() 에 대한 호출이 완료되고 Upper 생성자도 완료됩니다.
7. 이제 흥미로워지고 있습니다. Lower 인스턴스의 구성은 계속됩니다. lowerString 필드 선언에서 =null 할당이 명시 적으로 지정되지 않았다고 가정하면, Lower 생성자는 실행을 재개하고 필드에 연결된 두 줄을 인쇄합니다.
그러나 NULL을 명시 적으로 할당하는 작업이 있으면 실행 프로세스가 약간 다릅니다. 부모 클래스 생성자가 완료되면 나머지 생성자가 실행되기 전에 변수 초기화가 수행됩니다 (Java 언어 사양의 섹션 12.5 참조). 이 경우, 이전에 lowerString 에 할당 된 문자열 참조는 다시 NULL으로 할당되지 않습니다. 그런 다음 나머지 기능 구성을 계속 실행하고 이제 lowerString 의 값을 다음과 같이 인쇄하십시오.
이것은 객체 작성에 대한 세부 사항 (또는 Java 코딩 사양, 인쇄 또는 온라인을 확인하는 위치를 알고 있음)에 대한 세부 사항에주의를 기울일뿐만 아니라 이와 같은 초기화를 쓰는 것이 나쁜 이유를 보여주는 훌륭한 예입니다. 우리는 어퍼의 서브 클래스에 대해 전혀 신경 쓰지 않아야합니다. 반대로, 어떤 이유로, 특정 필드의 초기화를 서브 클래스 자체에서 수행 할 수없는 경우, 자체 초기화 도우미 클래스의 일부 변형 만 있으면됩니다. 이 경우 String lowString 또는 String lowerString = null 사용하면 실제로 차이가 없습니다.
요약
위는이 기사의 전체 내용입니다. 이 기사의 내용이 모든 사람의 연구 나 업무에 도움이되기를 바랍니다. 궁금한 점이 있으면 의사 소통을 위해 메시지를 남길 수 있습니다.