Java의 정적 생성자를 완전히 이해하지 못했습니다. 허용된다면 왜 허용됩니까? 어떤 시나리오에서 사용 하시겠습니까? 어떤 목적으로 사용됩니까? 누군가 나에게 간단한 예를 들어 줄 수 있습니까?
Java의 정적 생성자를 완전히 이해하지 못했습니다. 허용된다면 왜 허용됩니까? 어떤 시나리오에서 사용 하시겠습니까? 어떤 목적으로 사용됩니까? 누군가 나에게 간단한 예를 들어 줄 수 있습니까?
답변:
생성자가, 정의에 의해, 수 없기 때문에 엄밀히 말하면, 자바는 정적 생성자가없는 수 의 정적. 당신이 말하는 것을 "정적 초기화 블록"이라고합니다. 생성자는 객체를 생성하고 있음을 의미합니다. 클래스는 자체 인스턴스가 아니기 때문에 클래스의 생성자를 가질 수 없습니다. 그것은 단순히 수업입니다. 클래스를 "구성하는"것을 컴파일러 (또는 "구조"의 의미에 따라 가상 머신)라고하며, 다른 코드 내에서 코드를 작성하면 코드 생성에 들어가게됩니다. 완전히 다른 짐승.
정적 초기화 블록은 클래스의 복잡한 정적 (또는 클래스 수준) 필드를 초기화하는 데 사용됩니다. 일반적으로 이들은 한 줄로 초기화 할 수 없거나 정적 블록이 구현 된 클래스에 있거나 없을 수있는 다른 객체를 먼저 초기화 해야하는 것을 초기화하는 데 사용됩니다.
기본적으로이 변수를 사용하여 클래스 A에게 변수 A를 먼저이 값으로 설정 한 다음 완료되면 A의 값을 사용하여 B를 초기화 할 수 있습니다. Java는 표준 필드 초기화를 생성자 또는 메소드 내에서 또는 생성자 또는 메소드 호출 (리터럴이 아닌 경우)을 통해 수행해야하므로 복잡한 정적 오브젝트를 초기화하는 편리한 방법이 될 수 있습니다.
정적 초기화 블록은 너무 자주 필요하지 않으며 실제로 사용 하지 않는 한 일반적으로 피해야 합니다. 나를 잘못 이해하지 말고 Java로 자리를 차지하지만 많은 다른 것들 (예 : break, return, switch 및 goto 문)과 같이 쉽게 과도하게 사용될 수 있으므로 코드의 가독성과 유지 관리 성이 떨어집니다. -베이스가 사용됩니다.
사용되는 정적 초기화 블록의 간단한 예는 다음과 같습니다 ( 여기있는 정적 초기화 블록에 대한 훌륭한 설명에 따라 ).
암호:
public class StaticExample{
static {
System.out.println("This is first static block");
}
public StaticExample(){
System.out.println("This is constructor");
}
public static String staticString = "Static Variable";
static {
System.out.println("This is second static block and "
+ staticString);
}
public static void main(String[] args){
StaticExample statEx = new StaticExample();
StaticExample.staticMethod2();
}
static {
staticMethod();
System.out.println("This is third static block");
}
public static void staticMethod() {
System.out.println("This is static method");
}
public static void staticMethod2() {
System.out.println("This is static method2");
}
}
산출:
This is first static block
This is second static block and Static Variable
This is static method
This is third static block
This is constructor
This is static method2
정적 블록이 유용 할 수있는 경우를 나열하는 경우가 있습니다.
정적 블록을 사용하지 않는 몇 가지 이유 (다른 상황에서) :
this
인스턴스가 없으므로 키워드를 사용할 수 없습니다 .C #과 같은 일부 언어는 정적 인 "생성자"에 대한 구문을 가질 수 있지만 이러한 "생성자"는 정적 초기화 블록이 Java에서하는 것과 거의 같은 방식으로 작동하며 OOP 생성자 의 기본 개념을 감안할 때 언어의 잘못된 이모 자 .
단순히 할당하는 것보다 어려운 필드를 초기화하는 데 사용됩니다.
public class Example{
public final static Map<String, String> preFilledField;
static{
Map<String, String> tmp = new HashMap<>();
//fill map
preFilledField = Collections.unmodifiableMap(tmp);
}
}
초기화시 맵을 채울 수는 없습니다 (익명 서브 클래스 핵을 사용하지 않는 한) 이것은 처음 사용하기 전에 채워지는 것을 보장하는 가장 좋은 방법입니다
초기화 할 때 확인 된 예외를 포착하기 위해이 작업을 수행 할 수도 있습니다
Gurgadurgen의 대답은 아마도 당신이 찾고있는 것일 것입니다. 그러나 누군가가 "정적 생성자"를 원할 때 때때로 무시되는 몇 가지 다른 점을 추가 할 것입니다.
클래스의 인스턴스를 만드는 정적 메서드를 원한다면 클래스의 생성자를 호출하는 정적 메서드를 만들 수 있습니다.
public class Example
{
/** Static method to create an instance. */
public static Example build()
{ return new Example() ; }
/** A field of each instance. */
private String stuff ;
/** The class's actual constructor. */
public Example()
{ stuff = new String() ; }
public String getStuff()
{ return this.stuff ; }
/**
* Mutator for "stuff" property. By convention this returns "void"
* but you might want to return the object itself, to support the
* sort of chained invocations that are becoming trendy now. You'll
* see the stylistic benefits of chaining later in this example.
*/
public Example setStuff( String newStuff )
{
this.stuff = newStuff ;
return this ;
}
}
public class ExampleTest
{
public static void main( String[] args )
{
// The usual instance model.
Example first = new Example() ;
System.out.println( first.setStuff("stuff").getStuff() ) ;
// Using your static method to construct an instance:
Example second = Example.build() ;
System.out.println( second.setStuff("more stuff").getStuff() ) ;
// Chaining all the invocations at once:
System.out.println( Example.build().setStuff("even more stuff").getStuff() ) ;
}
}
출력이 생성됩니다.
stuff
more stuff
even more stuff
인스턴스를 생성하기 위해 정적 메서드를 만드는 다른 이유는 주어진 시간에 클래스의 인스턴스 가 정확히 하나 존재 하는지 확인하려는 경우입니다. 이것을 싱글 톤 이라고합니다 . 관례 적으로 이러한 클래스는 "단일"로 취급되는 유일한 인스턴스getInstance()
를 얻기 위해 호출되는 정적 메소드를 제공합니다 .
public class SingletonExample extends Example
{
// Note: This extends my previous example, which has a "stuff"
// property, and a trivial constructor.
/** The singleton instance, statically initialized as null. */
private static SingletonExample singleton = null ;
/**
* The static accessor for the singleton. If no instance exists,
* then it will be created; otherwise, the one that already exists
* will be returned.
*/
public static SingletonExample getInstance()
{
if( singleton == null )
singleton = new SingletonExample() ;
return singleton ;
}
}
public class SingletonExampleTest
{
public static void main( String[] args )
{
System.out.println( SingletonExample.getInstance().setStuff("stuff").getStuff() ) ;
// You could still create instances of this class normally if you want to.
SingletonExample otherstuff = new SingletonExample() ;
otherstuff.setStuff("other stuff") ;
// But watch what happens to this.
System.out.println( SingletonExample.getInstance().getStuff() ) ;
System.out.println( otherstuff.getStuff() ) ;
// Now we show what happens when you start modifying the singleton.
SingletonExample theoneandonly = SingletonExample.getInstance() ;
theoneandonly.setStuff("changed stuff") ;
System.out.println( SingletonExample.getInstance().getStuff() ) ;
}
}
이것은 다음을 생성합니다.
stuff
stuff
other stuff
changed stuff
싱글 톤에 대한 참조를 저장 한 다음 수정함으로써 다음 호출 getInstance()
은 수정 된 싱글 톤 을 가져 옵니다 .
응용 프로그램의 전역 변수를 만드는 시작 방법으로 싱글 톤을 사용하고 싶습니다. 일부 상황에서는 이것이 유용 할 수 있지만 문제가 발생할 수도 있습니다. 특히 싱글 톤 인스턴스가 손실 될 수있는 Android 앱을 개발하는 동안 흥미로운 버그가 발생했습니다. 한 활동에서 다른 활동으로 점프하면 JVM이 이전 클래스 로더에 의해 정적으로 저장된 싱글 톤에 대해 알지 못하는 새로운 "클래스 로더"를 사용할 수 있습니다.
나는 "정적 생성자"라는 개념을 오해라고 생각하는 사람들이 많다는 것을 이해하지만, 그런 경우라고 생각하지 않습니다. 이 문제는 클래스와 해당 인스턴스 객체를 생성하는 중 입니다. 다른 스레드에서는 클래스 구성이 컴파일러의 작업이라고 명시되어 있습니다. Java에서도 마찬가지입니다.
컴파일러는 각 클래스 정의에 대한 스캐 폴드를 구성합니다. 스캐 폴드에는 클래스에 대한 메타 데이터와 구성시 인스턴스에 포함되어야하는 인스턴스가 포함되어 있습니다. 클래스가 상수 프리미티브 값이 할당 된 필드를 정의하면 해당 값은 컴파일러에 의해 스캐 폴드에 포함됩니다. 할당 된 다른 값 유형의 경우 컴파일러는 첫 번째 클래스 인스턴스를 작성하기 전에 1 회 실행되는 초기화 루틴을 생성하여 스캐 폴드를 적절한 값으로 업데이트합니다. 이 업데이트 는 컴파일러에서 수행 할 수 없습니다.
스캐 폴드에 대한이 일회성 업데이트는 종종 인스턴스 생성자의 올바른 기능을위한 중요한 전제 조건이므로 생성자 유형이라고 부르는 것도 합리적입니다. 이것이 개념을 지원하는 일반적인 OO 언어에서 정적 생성자라고하는 이유입니다. Java에서 정적 초기화 블록의 개념은 Java 프로그래머가 시스템과 구현에 모두 독립적이어야한다는 개념과 일치하도록 의미 상 변경에 지나지 않습니다.
다른 답변에서 말했듯이 객체를 구성하는 정적 메서드를 작성할 수 있습니다. 이것은 자바에서 명명 된 생성자가 부족하다는 것입니다. 매개 변수의 유형과 순서를 사용할 수는 있지만 불분명하고 취약한 코드로 이어질 수 있습니다.
예를 들어, XML 문자열 또는 JSON 문자열로 객체를 구성 할 수있는 시나리오를 만들 수 있습니다. 다음과 같은 메소드를 작성할 수 있습니다.
static MyObject createFromXml(String xml);
static MyObject createFromJson(String json);
이름이 지정된 초기화 메소드를 사용하여 매개 변수가없는 생성자의 대안으로 이것을 종종 사용했습니다.
MyObject myObject = new MyObject();
myObject.loadXml(xml).
클래스 내에서 빌더 패턴을 구현하는 것으로 정적 작성 메소드를 볼 수 있습니다.