itsource

Java에서 Double Brace 초기화란 무엇입니까?

mycopycode 2022. 9. 29. 00:18
반응형

Java에서 Double Brace 초기화란 무엇입니까?

Brace 구문Double Brace " " " " " " )이 죠?{{ ... }}★★★★★★★★★★★★★★★★★?

이중 괄호 초기화에서는 지정된 클래스(외부 괄호)에서 파생된 익명 클래스가 생성되어 해당 클래스(내부 괄호) 내에서 이니셜라이저 블록이 제공됩니다.예.

new ArrayList<Integer>() {{
   add(1);
   add(2);
}};

이 이중괄호 초기화를 사용하면 익명 내부 클래스가 생성됩니다.인 '이러다'가 .this주변 외부 클래스로의 포인터.일반적으로 문제가 되지는 않지만, 연재나 쓰레기 수집 등 상황에 따라 슬픔을 야기할 수 있습니다.이 점에 유의할 필요가 있습니다.

누군가 더블 브레이스를 사용할 때마다 고양이 한 마리가 죽임을 당합니다.

구문이 다소 특이하고 관용적이지 않은 것(물론 맛은 논쟁의 여지가 있다)을 제외하고, 당신은 불필요하게 당신의 어플리케이션에서 두 가지 중요한 문제를 야기하고 있다.이것에 대해서는, 내가 최근 여기서 좀 더 자세하게 블로그에 올렸다.

1. 너무 많은 익명의 수업을 만들고 있습니다.

이중 괄호 초기화를 사용할 때마다 새 클래스가 만들어집니다.예:

Map source = new HashMap(){{
    put("firstName", "John");
    put("lastName", "Smith");
    put("organizations", new HashMap(){{
        put("0", new HashMap(){{
            put("id", "1234");
        }});
        put("abc", new HashMap(){{
            put("id", "5678");
        }});
    }});
}};

...는 다음 클래스를 생성합니다.

Test$1$1$1.class
Test$1$1$2.class
Test$1$1.class
Test$1.class
Test.class

그것은 당신의 클래스 로더에게는 꽤 많은 오버헤드이다. - 공짜로!물론 한 번 하면 초기화 시간이 많이 걸리지 않습니다.그러나 엔터프라이즈 애플리케이션 전체에 걸쳐 20,000회 이 작업을 수행하면...'설탕' 조금 때문에 그 많은 기억들이 쌓였단 말인가?

2. 메모리 누수가 발생할 수 있습니다!

위의 코드를 가져와 메서드에서 해당 맵을 반환하면 해당 메서드의 발신자가 예상하지 못하게 가비지 수집이 불가능한 매우 무거운 리소스를 보유하고 있을 수 있습니다.다음 예를 생각해 보겠습니다.

public class ReallyHeavyObject {

    // Just to illustrate...
    private int[] tonsOfValues;
    private Resource[] tonsOfResources;

    // This method almost does nothing
    public Map quickHarmlessMethod() {
        Map source = new HashMap(){{
            put("firstName", "John");
            put("lastName", "Smith");
            put("organizations", new HashMap(){{
                put("0", new HashMap(){{
                    put("id", "1234");
                }});
                put("abc", new HashMap(){{
                    put("id", "5678");
                }});
            }});
        }};

        return source;
    }
}

는 반환된 「」 「 」Map에는 에 둘러싸인 가 포함됩니다.ReallyHeavyObject위험을 감수하고 싶지 않을 수도 있습니다.

바로 여기서 메모리 누전

이미지: http://blog.jooq.org/2014/12/08/dont-be-clever-the-double-curly-braces-anti-pattern/

3. Java에 지도 리터럴이 있다고 가정할 수 있습니다.

실제 질문에 답하기 위해 사람들은 이 구문을 사용하여 Java에 기존 어레이 리터럴과 유사한 맵 리터럴이 있다고 가정합니다.

String[] array = { "John", "Doe" };
Map map = new HashMap() {{ put("John", "Doe"); }};

어떤 사람들은 이것이 통사적으로 자극적이라고 생각할지도 모른다.

  • 첫 번째 중괄호는 새 익명 내부 클래스를 만듭니다.
  • 두 번째 가새 집합은 클래스의 정적 블록과 같은 인스턴스 이니셜라이저를 만듭니다.

예를 들어 다음과 같습니다.

   public class TestHashMap {
    public static void main(String[] args) {
        HashMap<String,String> map = new HashMap<String,String>(){
        {
            put("1", "ONE");
        }{
            put("2", "TWO");
        }{
            put("3", "THREE");
        }
        };
        Set<String> keySet = map.keySet();
        for (String string : keySet) {
            System.out.println(string+" ->"+map.get(string));
        }
    }
    
}

구조

번째 중괄호는 새 익명 내부 클래스를 만듭니다.이러한 내부 클래스는 부모 클래스의 동작에 액세스 할 수 있습니다.이 경우 실제로 HashSet 클래스의 서브클래스를 만들고 있기 때문에 이 내부 클래스는 put() 메서드를 사용할 수 있습니다.

두 번째 중괄호는 인스턴스 이니셜라이저에 불과합니다.핵심 Java 개념을 기억하는 경우 구조와 같은 유사한 괄호로 인해 인스턴스 이니셜라이저 블록을 정적 이니셜라이저와 쉽게 연결할 수 있습니다.유일한 차이점은 static initializer가 static 키워드와 함께 추가되어 생성되는 객체의 수에 관계없이1회만 실행됩니다.

이중 괄호 초기화의 재미있는 적용에 대해서는, 여기를 참조해 주세요.

발췌문

private static class IndustrialRaverMonkey
  extends Creature.Base {{
    life = 46;
    strength = 35;
    charisma = 91;
    weapon = 2;
  }}

private static class DwarvenAngel
  extends Creature.Base {{
    life = 540;
    strength = 6;
    charisma = 144;
    weapon = 50;
  }}

그럼 '아, 아, 아, 아, 아, 아, 아, 아, 아, 아.BattleOfGrottoOfSausageSmells그리고... 통통한 베이컨!

자바에는 'Double Brace initialization'이라는 것이 없다는 것을 강조하는 것이 중요하다고 생각합니다.Oracle 웹 사이트에는 이 용어가 없습니다.이 예에서는 어나니머스 클래스와 이니셜라이저 블록의 2가지 기능을 병용하고 있습니다.오래된 이니셜라이저 블록이 개발자에 의해 잊혀져 이 토픽에 혼란이 생긴 것 같습니다.Oracle 문서에서 인용:

인스턴스 변수의 이니셜라이저 블록은 스태틱인테셜라이저 블록과 동일하게 보이지만 static 키워드는 없습니다.

{
    // whatever code is needed for initialization goes here
}

1- 이중 괄호는 없습니다.
더블 브레이스 초기화라는 것은 존재하지 않는다는 것을 지적하고 싶습니다.일반적인 전통적인 원 브레이스 초기화 블록만 있습니다.두 번째 중괄호 블록은 초기화와는 관계가 없습니다.그 두 개의 교정기가 무언가를 초기화한다고 하지만, 그건 그렇지 않다.

- 모든 2 - 어나니머스 클래스:
거의 모든 답변이 익명의 내부 계층을 만들 때 사용되는 것이라고 말한다.나는 그 답을 읽는 사람들이 익명의 내적 수업을 만들 때에만 이것이 사용된다는 인상을 받을 것이라고 생각한다.이치노그 답들을 읽는 것은 익명의 수업에만 전념하는 새로운 특별한 기능이고 나는 그것이 오해의 소지가 있다고 생각한다.

3 - 목적은 브래킷을 서로 겹쳐 배치하는 것일 뿐 새로운 개념이 아닙니다.
더 나아가 이 질문은 두 번째 개방 브래킷이 첫 번째 개방 브래킷 바로 뒤에 있을 때의 상황에 대해 이야기합니다.일반 클래스에서 사용할 경우 보통 두 개의 교정기 사이에 코드가 있지만 완전히 동일합니다.이치노그래서 저는 이것이 새로운 흥미로운 것이라고 말하지 말아야 한다고 생각합니다. 왜냐하면 이것은 우리 모두가 알고 있는 것이기 때문입니다. 단지 괄호 사이에 코드를 몇 개 넣었을 뿐입니다.이중괄호 초기화라는 새로운 개념을 만들어서는 안 됩니다.

4 - 네스트된 어나니머스 클래스를 만드는 것은 다음 두 개의 중괄호와는 관계가 없습니다.
저는 당신이 익명의 수업을 너무 많이 만든다는 주장에 동의하지 않습니다.초기화 블록 때문에 작성하는 것이 아니라 사용자가 작성하기 때문에 작성하는 것입니다.이러한 문제는 2개의 브레이스 초기화를 사용하지 않아도 생성되므로 초기화하지 않아도 발생합니다.초기화는 초기화된 개체를 생성하는 요소가 아닙니다.

또, 이 존재하지 않는 「이중괄호 초기화」를 사용했을 경우나, 통상의 1개의 괄호 초기화에서도 발생하는 문제에 대해서는 이야기하지 말아 주세요.이는 어나니머스 클래스를 만드는 것만으로 문제가 존재하기 때문에, 원래의 질문과는 관계가 없기 때문입니다.그러나 모든 답변은 익명의 수업을 만든 것이 잘못이 아니라 '이중괄호 초기화'라는 사악한 것(존재하지 않는 것)이라는 인상을 독자에게 준다.

이중 가새 초기화의 모든 부정적인 영향을 방지하려면 다음과 같이 하십시오.

  1. "동일한" 호환성이 깨졌습니다.
  2. 직접 할당을 사용하는 경우 검사가 수행되지 않습니다.
  3. 메모리 누수 가능성.

다음 작업을 수행합니다.

  1. 특히 이중 괄호 초기화를 위해 별도의 "빌더" 클래스를 만듭니다.
  2. 기본값으로 필드를 선언합니다.
  3. 해당 클래스에 개체 생성 메서드를 넣습니다.

예제:

public class MyClass {
    public static class Builder {
        public int    first  = -1        ;
        public double second = Double.NaN;
        public String third  = null      ;

        public MyClass create() {
            return new MyClass(first, second, third);
        }
    }

    protected final int    first ;
    protected final double second;
    protected final String third ;

    protected MyClass(
        int    first ,
        double second,
        String third
    ) {
        this.first = first ;
        this.second= second;
        this.third = third ;
    }

    public int    first () { return first ; }
    public double second() { return second; }
    public String third () { return third ; }
}

사용방법:

MyClass my = new MyClass.Builder(){{ first = 1; third = "3"; }}.create();

장점:

  1. 간단하게 사용할 수 있습니다.
  2. 「동일한」호환성을 깨뜨리지 말아 주세요.
  3. 작성 방법에서 체크를 수행할 수 있습니다.
  4. 메모리 누수는 없다.

단점:

  • 없음.

그 결과, 지금까지 가장 심플한 Java Builder 패턴을 얻을 수 있었습니다.

github의 모든 샘플 참조: java-sf-builder-simple-example

@Lukas Eder에서 지적한 바와 같이 컬렉션의 초기화는 피해야 합니다.

익명 내부 클래스를 만들고 모든 내부 클래스는 상위 인스턴스에 대한 참조를 유지하므로 이러한 수집 개체가 선언 개체뿐만 아니라 더 많은 개체에서 참조되는 경우 가비지 수집을 방지할 수 있습니다(99%).

한 방법 Java 9를 했습니다.List.of,Set.of , , , , 입니다.Map.of대신 사용해야 합니다.이중 브레이스 이니셜라이저보다 빠르고 효율적입니다.

다른 용도 중에서도 컬렉션을 초기화하기 위한 바로 가기입니다.상세 정보...

이런 거 말하는 거야?

List<String> blah = new ArrayList<String>(){{add("asdfa");add("bbb");}};

어레이 리스트의 작성 시간에서의 초기화입니다(표준).

수집을 초기화하기 위해 일부 Java 문을 루프로 넣을 수 있습니다.

List<Character> characters = new ArrayList<Character>() {
    {
        for (char c = 'A'; c <= 'E'; c++) add(c);
    }
};

Random rnd = new Random();

List<Integer> integers = new ArrayList<Integer>() {
    {
         while (size() < 10) add(rnd.nextInt(1_000_000));
    }
};

그러나 이 경우는 퍼포먼스에 영향을 미칩니다.이 논의를 확인해 주십시오.

첫 번째 중괄호는 새로운 Anonymous Class를 만들고 두 번째 중괄호는 정적 블록과 같은 인스턴스 이니셜라이저를 만듭니다.

다른 사람들이 지적한 것처럼, 그것은 사용하기에 안전하지 않다.

그러나 수집을 초기화하려면 언제든지 이 대안을 사용할 수 있습니다.

  • 자바 8
List<String> list = new ArrayList<>(Arrays.asList("A", "B", "C"));
  • 자바 9
List<String> list = List.of("A", "B", "C");

이는 플래시 및 vbscript에서 매우 인기 있는 키워드와 동일한 것으로 보입니다.this그 이상도 이하도 아니다.

언급URL : https://stackoverflow.com/questions/1958636/what-is-double-brace-initialization-in-java

반응형