내 질문은 정적 키워드의 특정 사용법에 관한 것입니다. static
키워드 를 사용 하여 어떤 함수에 속하지 않은 클래스 내의 코드 블록을 커버 할 수 있습니다. 예를 들어 다음 코드는 컴파일됩니다.
public class Test {
private static final int a;
static {
a = 5;
doSomething(a);
}
private static int doSomething(int x) {
return (x+5);
}
}
static
키워드 를 제거 하면 변수 a
가 이므로 불평합니다 final
. 그러나 모두 제거 할 수 final
및 static
키워드를하고 컴파일합니다.
두 가지 방법으로 나를 혼란스럽게합니다. 어떤 메소드에 속하지 않은 코드 섹션이 있어야합니까? 어떻게 호출 할 수 있습니까? 일반적으로이 사용법의 목적은 무엇입니까? 아니면 이것에 관한 문서를 어디서 찾을 수 있습니까?
답변
정적 수정자를 사용하는 코드 블록은 클래스 이니셜 라이저를 나타냅니다 . 정적 수정자가 없으면 코드 블록은 인스턴스 이니셜 라이저입니다.
클래스 이니셜 라이저는 클래스가로드 될 때 (실제로, 해결 될 때 기술이지만) 정의 된 순서대로 실행됩니다 (단순 변수 이니셜 라이저와 마찬가지로 하향식).
인스턴스 이니셜 라이저는 클래스 생성시 생성자 코드가 실행되기 직전, 수퍼 생성자 호출 직후에 정의 된 순서대로 실행됩니다.
static
에서 제거하면 int a
변수가 인스턴스 변수가되어 정적 초기화 블록에서 액세스 할 수 없습니다. “정적이 아닌 변수 a는 정적 컨텍스트에서 참조 할 수 없습니다”라는 오류로 컴파일에 실패합니다.
static
이니셜 라이저 블록에서 제거 하면 인스턴스 이니셜 int a
라이저가되어 구성시 초기화됩니다.
답변
어이! 정적 이니셜 라이저 란 무엇입니까?
정적 이니셜 라이저는 static {}
java 클래스 내부의 코드 블록이며 생성자 또는 main 메소드가 호출되기 전에 한 번만 실행됩니다.
확인! 더 말 해주세요…
static { ... }
Java 클래스 내부 의 코드 블록입니다 . 클래스가 호출 될 때 가상 머신에 의해 실행됩니다.return
지원되는 진술이 없습니다 .- 지원되는 인수가 없습니다.
- 아니요
this
또는super
지원됩니다.
흠, 어디서 사용할 수 있습니까?
🙂 간단하다고 느끼는 곳이라면 어디에서나 사용할 수 있습니다. 그러나 데이터베이스 연결, API 초기화, 로깅 등을 수행 할 때 대부분의 시간이 사용됩니다.
껍질을 벗기지 마십시오! 예는 어디에 있습니까?
package com.example.learnjava;
import java.util.ArrayList;
public class Fruit {
static {
System.out.println("Inside Static Initializer.");
// fruits array
ArrayList<String> fruits = new ArrayList<>();
fruits.add("Apple");
fruits.add("Orange");
fruits.add("Pear");
// print fruits
for (String fruit : fruits) {
System.out.println(fruit);
}
System.out.println("End Static Initializer.\n");
}
public static void main(String[] args) {
System.out.println("Inside Main Method.");
}
}
산출???
내부 정적 이니셜 라이저.
사과
주황색
배
정적 이니셜 라이저를 종료하십시오.
내부 주요 방법.
도움이 되었기를 바랍니다!
답변
static
블록은 “static 초기화”이다.
클래스가로드 될 때 자동으로 호출되며 다른 방법으로 리플렉션을 통해 호출 할 수 없습니다.
JNI 코드를 작성할 때 개인적으로 만 사용했습니다.
class JNIGlue {
static {
System.loadLibrary("foo");
}
}
답변
이것은 http://www.programcreek.com/2011/10/java-class-instance-initializers/ 에서 직접 가져온 것입니다 .
1. 실행 순서
다음 수업을 살펴보십시오. 먼저 어느 수업이 먼저 실행되는지 알고 있습니까?
public class Foo {
//instance variable initializer
String s = "abc";
//constructor
public Foo() {
System.out.println("constructor called");
}
//static initializer
static {
System.out.println("static initializer called");
}
//instance initializer
{
System.out.println("instance initializer called");
}
public static void main(String[] args) {
new Foo();
new Foo();
}
}
산출:
정적 이니셜 라이저 호출
인스턴스 이니셜 라이저 호출
생성자 호출
인스턴스 이니셜 라이저 호출
생성자 호출
2. Java 인스턴스 이니셜 라이저는 어떻게 작동합니까?
위의 인스턴스 이니셜 라이저에는 println 문이 포함되어 있습니다. 작동 방식을 이해하기 위해 변수 할당 문으로 취급 할 수 있습니다 (예 🙂 b = 0
. 이것은 이해하기 더 명확하게 만들 수 있습니다.
대신에
int b = 0
, 당신은 쓸 수 있습니다
int b;
b = 0;
따라서 인스턴스 이니셜 라이저와 인스턴스 변수 이니셜 라이저는 거의 동일합니다.
3. 인스턴스 이니셜 라이저는 언제 유용합니까?
인스턴스 이니셜 라이저를 사용하는 경우는 드물지만 다음과 같은 경우 인스턴스 변수 이니셜 라이저를 대체 할 수 있습니다.
- 이니셜 라이저 코드는 예외를 처리해야합니다
- 인스턴스 변수 이니셜 라이저로 표현할 수없는 계산을 수행하십시오.
물론 이러한 코드는 생성자에서 작성할 수 있습니다. 그러나 클래스에 생성자가 여러 개인 경우 각 생성자에서 코드를 반복해야합니다.
인스턴스 이니셜 라이저를 사용하면 코드를 한 번만 작성할 수 있으며 객체를 생성하는 데 사용 된 생성자에 관계없이 실행됩니다. (이것은 단지 개념 일 뿐이며 자주 사용되지는 않습니다.)
인스턴스 이니셜 라이저가 유용한 또 다른 경우는 생성자를 전혀 선언 할 수없는 익명 내부 클래스입니다. (이것은 로깅 기능을 배치하기에 좋은 장소입니까?)
Derhein에게 감사합니다.
또한 인터페이스 [1]을 구현하는 익명 클래스에는 생성자가 없습니다. 따라서 생성시 모든 종류의 표현식을 실행하려면 인스턴스 이니셜 라이저가 필요합니다.
답변
“final”은 객체 이니셜 라이저 코드가 끝나기 전에 변수를 초기화해야합니다. 마찬가지로 “정적 최종”은 클래스 초기화 코드의 끝에서 변수가 초기화되도록합니다. 초기화 코드에서 “정적”을 생략하면 객체 초기화 코드로 바뀝니다. 따라서 변수가 더 이상 보장을 만족시키지 않습니다.
답변
프로그램의 어느 곳에서나 호출해야하는 정적 블록에 코드를 쓰지 않습니다. 코드의 목적이 호출되는 경우 메소드에 배치해야합니다.
클래스가로드 될 때 정적 변수를 초기화하기 위해 정적 초기화 블록을 작성할 수 있지만이 코드는 더 복잡 할 수 있습니다.
정적 이니셜 라이저 블록은 이름, 인수 및 반환 유형이없는 메서드처럼 보입니다. 전화하지 않기 때문에 이름이 필요하지 않습니다. 가상 머신이 클래스를로드 할 때만 호출됩니다.
답변
개발자가 초기화 블록을 사용하면 Java 컴파일러는 초기화를 현재 클래스의 각 생성자에 복사합니다.
예:
다음 코드 :
class MyClass {
private int myField = 3;
{
myField = myField + 2;
//myField is worth 5 for all instance
}
public MyClass() {
myField = myField * 4;
//myField is worth 20 for all instance initialized with this construtor
}
public MyClass(int _myParam) {
if (_myParam > 0) {
myField = myField * 4;
//myField is worth 20 for all instance initialized with this construtor
//if _myParam is greater than 0
} else {
myField = myField + 5;
//myField is worth 10 for all instance initialized with this construtor
//if _myParam is lower than 0 or if _myParam is worth 0
}
}
public void setMyField(int _myField) {
myField = _myField;
}
public int getMyField() {
return myField;
}
}
public class MainClass{
public static void main(String[] args) {
MyClass myFirstInstance_ = new MyClass();
System.out.println(myFirstInstance_.getMyField());//20
MyClass mySecondInstance_ = new MyClass(1);
System.out.println(mySecondInstance_.getMyField());//20
MyClass myThirdInstance_ = new MyClass(-1);
System.out.println(myThirdInstance_.getMyField());//10
}
}
다음과 같습니다.
class MyClass {
private int myField = 3;
public MyClass() {
myField = myField + 2;
myField = myField * 4;
//myField is worth 20 for all instance initialized with this construtor
}
public MyClass(int _myParam) {
myField = myField + 2;
if (_myParam > 0) {
myField = myField * 4;
//myField is worth 20 for all instance initialized with this construtor
//if _myParam is greater than 0
} else {
myField = myField + 5;
//myField is worth 10 for all instance initialized with this construtor
//if _myParam is lower than 0 or if _myParam is worth 0
}
}
public void setMyField(int _myField) {
myField = _myField;
}
public int getMyField() {
return myField;
}
}
public class MainClass{
public static void main(String[] args) {
MyClass myFirstInstance_ = new MyClass();
System.out.println(myFirstInstance_.getMyField());//20
MyClass mySecondInstance_ = new MyClass(1);
System.out.println(mySecondInstance_.getMyField());//20
MyClass myThirdInstance_ = new MyClass(-1);
System.out.println(myThirdInstance_.getMyField());//10
}
}
개발자가 내 모범을 이해하기를 바랍니다.
