[java] 자바 내부 클래스와 정적 중첩 클래스


Answers

Java 튜토리얼의 내용 :

용어 : 중첩 클래스는 정적 및 비 정적이라는 두 가지 범주로 나뉩니다. 정적으로 선언 된 중첩 클래스는 단순히 정적 중첩 클래스라고합니다. 비 정적 중첩 클래스는 내부 클래스라고합니다.

일반적으로 말하면 "중첩 된"및 "내부"라는 용어는 대부분의 프로그래머가 상호 교환하여 사용하지만 내부 및 정적을 모두 포함하는 올바른 "중첩 된 클래스"라는 용어를 사용합니다.

클래스는 클래스 D를 포함하는 클래스 C를 포함하는 클래스 B를 포함 할 수 있습니다. 예를 들어, 클래스 A는 클래스 D를 포함하는 클래스 B를 포함 할 수 있습니다. 그러나 일반적으로 나쁜 디자인이기 때문에 둘 이상의 클래스 중첩 수준은 드뭅니다.

중첩 된 클래스를 만들 수있는 세 가지 이유가 있습니다.

  • organization : 때로는 다른 클래스의 네임 스페이스로 클래스를 정렬하는 것이 가장 현명한 것 같습니다. 특히 어떤 다른 컨텍스트에서 사용되지 않을 때입니다.
  • 액세스 : 중첩 클래스는 포함하는 클래스의 변수 / 필드에 대한 특별한 액세스 권한을가집니다 (내부 또는 정적 여부와 상관없이 중첩 클래스의 종류에 따라 정확히 어떤 변수 / 필드가 사용되는지).
  • 편의성 : 모든 새로운 유형에 대해 새 파일을 작성해야하는 번거 로움이 있습니다. 특히 형식이 한 문맥에서만 사용될 때 특히 그렇습니다.

Java 에는 4 가지 중첩 클래스가 있습니다. 요약하면 다음과 같습니다.

  • 정적 클래스 : 다른 클래스의 정적 멤버로 선언
  • 내부 클래스 : 다른 클래스의 인스턴스 멤버로 선언
  • 로컬 내부 클래스 : 다른 클래스의 인스턴스 메서드 내에서 선언
  • 익명 내부 클래스 : 로컬 내부 클래스와 비슷하지만 일회용 객체를 반환하는 표현식으로 작성되었습니다.

좀 더 자세하게 설명해 드리겠습니다.


정적 클래스

정적 클래스는 포함하는 클래스의 인스턴스와 아무 관련이 없기 때문에 가장 이해하기 쉬운 클래스입니다.

정적 클래스는 다른 클래스의 정적 멤버로 선언 된 클래스입니다. 다른 정적 멤버와 마찬가지로 클래스는 실제로 클래스를 포함하는 클래스를 네임 스페이스로 사용합니다. 예를 들어 패키지 피자 에서 Rhino 클래스의 정적 멤버로 선언 된 Goat 클래스는 pizza.Rhino.Goat 라는 이름으로 알려져 있습니다. .

package pizza;

public class Rhino {

    ...

    public static class Goat {
        ...
    }
}

솔직히 정적 클래스는 클래스가 이미 패키지별로 네임 스페이스로 나누어 져 있기 때문에 쓸데없는 기능입니다. 정적 클래스를 만드는 유일한 이유는 클래스가 포함 된 클래스의 개인 정적 멤버에 액세스 할 수 있다는 것입니다.하지만이 클래스는 정적 클래스 기능이 존재하기에 꽤 절름발이라는 것을 알았습니다.


내부 수업

내부 클래스는 다른 클래스의 비 정적 멤버로 선언 된 클래스입니다.

package pizza;

public class Rhino {

    public class Goat {
        ...
    }

    private void jerry() {
        Goat g = new Goat();
    }
}

정적 클래스와 마찬가지로 내부 클래스는 클래스 이름 인 pizza.Rhino.Goat 가 포함 된 것으로 한정되어 있지만 포함 된 클래스 내부에서는 간단한 이름으로 알 수 있습니다. 그러나 내부 클래스의 모든 인스턴스는 포함하는 클래스의 특정 인스턴스에 연결됩니다. 위의 jerry 에서 만든 Goatjerry 에서 Rhino 인스턴스에 암시 적으로 연결되어 있습니다. 그렇지 않으면 Goat 을 인스턴스화 할 때 연관된 Rhino 인스턴스를 명시 적으로 만듭니다.

Rhino rhino = new Rhino();
Rhino.Goat goat = rhino.new Goat();

(자바가 Rhino 에서 포함 된 타입을 추론하고, 새로운 rhino.Goat () 가 나에게 더 의미가 있었을 것입니다.

그러면 우리가 무엇을 얻게 될까요? 내부 클래스 인스턴스는 포함하는 클래스 인스턴스의 인스턴스 멤버에 액세스 할 수 있습니다. 이러한 인 클로징 인스턴스 멤버는 이것을 통하지 않고 단순한 이름을 통해 내부 클래스 내부에서 참조됩니다 (내부 클래스의 경우 내부 클래스 인스턴스를 참조하며 연결된 클래스 인스턴스는 포함하지 않습니다).

public class Rhino {

    private String barry;

    public class Goat {
        public void colin() {
            System.out.println(barry);
        }
    }
}

내부 클래스에서 이것을 포함하는 클래스를 Rhino 로 참조 할 수 있습니다. 클래스를 사용하여 Rhino.this.barry같은 멤버를 참조 할 수 있습니다.


로컬 내부 클래스

로컬 내부 클래스는 메서드 본문에서 선언 된 클래스입니다. 이러한 클래스는 포함하는 메서드 내에서만 알 수 있으므로 인스턴스화하고 해당 멤버를 포함하는 메서드 내에서 멤버에 액세스 할 수 있습니다. 이득은 로컬 내부 클래스 인스턴스가 묶여 있고 포함하는 메서드의 최종 로컬 변수에 액세스 할 수 있다는 것입니다. 인스턴스가 포함 메서드의 최종 로컬을 사용하면 변수가 범위를 벗어 났더라도 (즉, Java의 제한된 클로저의 제한된 버전의 클로저 인 경우에도) 변수는 인스턴스를 만들 때 보유한 값을 유지합니다.

로컬 내부 클래스는 클래스 또는 패키지의 멤버가 아니므로 액세스 수준으로 선언되지 않습니다. (그러나 자신의 멤버는 일반 클래스와 같은 액세스 수준을가집니다.)

인스턴스 메소드로 로컬의 내부 클래스가 선언되고있는 경우, 내부 클래스의 인스턴스화는 인스턴스의 작성시에 this 를 포함하고있는 메소드에 의해 보관 유지되고있는 인스턴스에 묶여 지므로, 포함하는 클래스의 인스턴스 멤버는 인스턴스와 같이 액세스 할 수 있습니다 내부 클래스. 로컬 내부 클래스는 이름을 통해 간단히 인스턴스화 됩니다 ( 예 : 로컬 내부 클래스). Cat 은 새로운 this ()가 아니라 새 this.Cat ()로 인스턴스화됩니다.


익명 내부 클래스

익명 내부 클래스는 로컬 내부 클래스를 작성하는 구문 적으로 편리한 방법입니다. 일반적으로 로컬 내부 클래스는 메서드가 포함될 때마다 한 번만 인스턴스화됩니다. 로컬 내부 클래스 정의와 그 단일 인스턴스화를 하나의 편리한 구문 형식으로 결합 할 수 있다면 좋을 것입니다. 그리고 우리가 클래스 이름을 생각할 필요가 없다면 좋을 것입니다. 귀하의 코드에 포함 된 이름, 더 좋음). 익명의 내부 클래스는 다음 두 가지를 허용합니다.

new *ParentClassName*(*constructorArgs*) {*members*}

이것은 ParentClassName 을 확장하는 이름없는 클래스의 새 인스턴스를 반환하는 표현식입니다. 자신 만의 생성자를 제공 할 수는 없습니다. 오히려 단순히 슈퍼 생성자를 호출하는 하나가 암시 적으로 제공되므로 제공된 인수는 슈퍼 생성자에 적합해야합니다. (부모가 여러 생성자를 포함하고 있다면 "가장 단순한"이라고 불리는데, 자세히 배우는 데 신경 쓸 가치가없는 다소 복잡한 규칙 집합에 의해 결정되므로 "NetBeans 또는 Eclipse에 대한 설명에주의하십시오.)

또는 구현할 인터페이스를 지정할 수 있습니다.

new *InterfaceName*() {*members*}

이러한 선언은 Object를 확장하고 InterfaceName을 구현하는 이름없는 클래스의 새 인스턴스를 만듭니다. 다시 말하지만, 자신 만의 생성자를 제공 할 수는 없습니다. 이 경우, Java는 암묵적으로 인수가없는 무결성 생성자를 제공합니다 (이 경우에는 생성자 인수가 없을 것입니다).

익명 내부 클래스에 생성자를 제공 할 수는 없지만 초기화 메서드 블록 (메서드 외부에있는 {} 블록)을 사용하여 원하는 모든 설정을 수행 할 수 있습니다.

익명의 내부 클래스는 하나의 인스턴스로 로컬 내부 클래스를 만드는 덜 유연한 방법이라는 것을 분명히하십시오. 여러 개의 인터페이스를 구현하는 로컬 내부 클래스 또는 Object가 아닌 다른 클래스를 확장하거나 자체 생성자를 지정하는 인터페이스를 구현하려는 경우에는 로컬 내부 클래스를 만듭니다.

Question

자바에서 내부 클래스와 정적 중첩 클래스의 주요 차이점은 무엇입니까? 설계 / 구현이 이들 중 하나를 선택하는 데 중요한 역할을합니까?




제 생각에, 일반적으로 뒤따라 지키고있는 대회는 다음과 같습니다 :

  • 최상위 클래스의 static 클래스중첩 클래스입니다.
  • 최상위 클래스 내에서 정적이 아닌 클래스는 내부 클래스로 두 개의 형식이 더 있습니다.
    • 로컬 클래스 - 메서드 또는 생성자 본문처럼 블록 내부에 선언 된 명명 된 클래스
    • 익명 클래스 - 인스턴스가 표현식 및 명령문에서 작성된 이름이없는 클래스

그러나 기억해야 할 몇 가지 다른 은 다음과 같습니다.

  • 최상위 클래스와 정적 중첩 클래스는 정적으로 중첩 된 클래스의 경우 Outer [parent] 클래스의 전용 정적 필드 / 메서드에 대한 정적 참조를 만들 수 있다는 점을 제외하고는 의미 상 동일합니다.

  • 내부 클래스는 바깥 쪽 [부모] 클래스의 둘러싸는 인스턴스의 인스턴스 변수에 액세스 할 수 있습니다. 그러나 모든 내부 클래스가 인 클로징 인스턴스를 가지고있는 것은 아닙니다 (예 : 정적 이니셜 라이저 블록에서 사용되는 익명 클래스와 같이 정적 컨텍스트의 내부 클래스).

  • 익명 클래스는 기본적으로 상위 클래스를 확장하거나 상위 인터페이스를 구현하므로 다른 클래스를 확장하거나 더 이상 인터페이스를 구현할 절이 없습니다. 그래서,

    • new YourClass(){}; class [Anonymous] extends YourClass {} 한다는 것을 의미합니다.
    • new YourInterface(){}; class [Anonymous] implements YourInterface {} 한다는 것을 의미합니다.

어느 쪽이 언제 열려야하는 더 큰 질문이 언제 느껴지나요? 글쎄요, 대부분 당신이 다루는 시나리오에 달려 있지만, @jrudolph가 준 답장을 읽는 것은 당신이 어떤 결정을 내리는 데 도움이 될 수 있습니다.




위의 답변 중 어느 것도 중첩 된 클래스와 정적 인 중첩 클래스 사이의 실제 차이점을 응용 프로그램 디자인의 관점에서 설명하지 못한다고 생각합니다.

오버뷰

중첩 된 클래스 는 비 정적이거나 정적 일 수 있으며 각각의 경우 에 다른 클래스 내에 정의 된 클래스 입니다. 중첩 된 클래스는 오직 클래스를 둘러싸는 클래스로만 존재해야합니다 . 중첩 된 클래스가 다른 클래스에서 유용 할 경우 (둘러싸기만 해당) 최상위 클래스로 선언해야합니다.

Nonstatic Nested class : 포함하는 클래스의 둘러싼 인스턴스에 암시 적으로 연결되어 있습니다. 즉, 포함 된 인스턴스의 메서드 및 액세스 변수를 호출 할 수 있습니다. 비 정적 중첩 클래스의 일반적인 용도 중 하나는 Adapter 클래스를 정의하는 것입니다.

정적 중첩 클래스 : 둘러싸는 클래스 인스턴스에 액세스 할 수없고 메서드를 호출 할 수 없으므로 중첩 클래스가 해당 클래스의 인스턴스에 액세스하지 않아도되는 경우 사용해야합니다. 정적 중첩 클래스의 일반적인 용도는 외부 객체의 구성 요소를 구현하는 것입니다.

결론

따라서 디자인 관점에서 볼 때 두 가지의 주요 차이점은 비 정적 중첩 클래스는 컨테이너 클래스의 인스턴스에 액세스 할 수 있지만 정적은 그렇지 못합니다 .




When we declare static member class inside a class, it is known as top level nested class or a static nested class. It can be demonstrated as below :

class Test{
    private static int x = 1;
        static class A{
        private static int y = 2;
        public static int getZ(){
            return B.z+x;
        }
    }
    static class B{
        private static int z = 3;
        public static int getY(){
            return A.y;
        }
    }
}

class TestDemo{
     public static void main(String[] args){
        Test t = new Test();
        System.out.println(Test.A.getZ());
        System.out.println(Test.B.getY());
    }
}

When we declare non-static member class inside a class it is known as inner class. Inner class can be demonstrated as below :

    class Test{
        private int i = 10;
        class A{
            private int i =20;
            void display(){
            int i = 30;
            System.out.println(i);
            System.out.println(this.i);
            System.out.println(Test.this.i);
        }
    }
}



Targeting learner, who are novice to Java and/or Nested Classes

Nested classes can be either:
1. Static Nested classes.
2. Non Static Nested classes. (also known as Inner classes ) =>Please remember this


1.Inner classes
예:

class OuterClass  {
/*  some code here...*/
     class InnerClass  {  }
/*  some code here...*/
}


Inner classes are subsets of nested classes:

  • inner class is a specific type of nested class
  • inner classes are subsets of nested classes
  • You can say that an inner class is also a nested class, but you can NOT say that a nested class is also an inner class .

Specialty of Inner class:

  • instance of an inner class has access to all of the members of the outer class, even those that are marked “private”


2.Static Nested Classes:
예:

class EnclosingClass {
  static class Nested {
    void someMethod() { System.out.println("hello SO"); }
  }
}

Case 1:Instantiating a static nested class from a non-enclosing class

class NonEnclosingClass {

  public static void main(String[] args) {
    /*instantiate the Nested class that is a static
      member of the EnclosingClass class:
    */

    EnclosingClass.Nested n = new EnclosingClass.Nested(); 
    n.someMethod();  //prints out "hello"
  }
}

Case 2:Instantiating a static nested class from an enclosing class

class EnclosingClass {

  static class Nested {
    void anotherMethod() { System.out.println("hi again"); } 
  }

  public static void main(String[] args) {
    //access enclosed class:

    Nested n = new Nested(); 
    n.anotherMethod();  //prints out "hi again"
  }

}

Specialty of Static classes:

  • Static inner class would only have access to the static members of the outer class, and have no access to non-static members.

결론:
Question: What is the main difference between a inner class and a static nested class in Java?
Answer: just go through specifics of each class mentioned above.




The following is an example of static nested class and inner class :

OuterClass.java

public class OuterClass {
     private String someVariable = "Non Static";

     private static String anotherStaticVariable = "Static";  

     OuterClass(){

     }

     //Nested classes are static
     static class StaticNestedClass{
        private static String privateStaticNestedClassVariable = "Private Static Nested Class Variable"; 

        //can access private variables declared in the outer class
        public static void getPrivateVariableofOuterClass(){
            System.out.println(anotherStaticVariable);
        }
     }

     //non static
     class InnerClass{

         //can access private variables of outer class
         public String getPrivateNonStaticVariableOfOuterClass(){
             return someVariable;
         }
     }

     public static void accessStaticClass(){
         //can access any variable declared inside the Static Nested Class 
         //even if it private
         String var = OuterClass.StaticNestedClass.privateStaticNestedClassVariable; 
         System.out.println(var);
     }

}

OuterClassTest:

public class OuterClassTest {
    public static void main(String[] args) {

        //access the Static Nested Class
        OuterClass.StaticNestedClass.getPrivateVariableofOuterClass();

        //test the private variable declared inside the static nested class
        OuterClass.accessStaticClass();
        /*
         * Inner Class Test
         * */

        //Declaration

        //first instantiate the outer class
        OuterClass outerClass = new OuterClass();

        //then instantiate the inner class
        OuterClass.InnerClass innerClassExample =  outerClass. new InnerClass();

        //test the non static private variable
        System.out.println(innerClassExample.getPrivateNonStaticVariableOfOuterClass()); 

    }

}



First of all There is no such class called Static class.The Static modifier use with inner class (called as Nested Class) says that it is a static member of Outer Class which means we can access it as with other static members and without having any instance of Outer class. (Which is benefit of static originally.)

Difference between using Nested class and regular Inner class is:

OuterClass.InnerClass inner = new OuterClass().new InnerClass();

First We can to instantiate Outerclass then we Can access Inner.

But if Class is Nested then syntax is:

OuterClass.InnerClass inner = new OuterClass.InnerClass();

Which uses the static Syntax as normal implementation of static keyword.




특정 상황에서 유용 할 수있는 중첩 된 정적 클래스의 사용에 대한 미묘한 차이가 있습니다.

클래스가 생성자를 통해 인스턴스화되기 전에 정적 속성이 인스턴스화되는 반면, 중첩 된 정적 클래스 내부의 정적 속성은 클래스의 생성자가 호출 될 때까지 또는 적어도 속성이 처음 참조 될 때까지 인스턴스화되지 않는 것처럼 보입니다. 그들은 '최종'으로 표시됩니다.

다음 예제를 고려하십시오.

public class C0 {

    static C0 instance = null;

    // Uncomment the following line and a null pointer exception will be
    // generated before anything gets printed.
    //public static final String outerItem = instance.makeString(98.6);

    public C0() {
        instance = this;
    }

    public String makeString(int i) {
        return ((new Integer(i)).toString());
    }

    public String makeString(double d) {
        return ((new Double(d)).toString());
    }

    public static final class nested {
        public static final String innerItem = instance.makeString(42);
    }

    static public void main(String[] argv) {
        System.out.println("start");
        // Comment out this line and a null pointer exception will be
        // generated after "start" prints and before the following
        // try/catch block even gets entered.
        new C0();
        try {
            System.out.println("retrieve item: " + nested.innerItem);
        }
        catch (Exception e) {
            System.out.println("failed to retrieve item: " + e.toString());
        }
        System.out.println("finish");
    }
}

'중첩 된'과 'innerItem'은 둘 다 '정적 최종'으로 선언됩니다. nested.innerItem의 설정은 클래스가 인스턴스화 될 때까지 (또는 중첩 된 정적 항목이 처음 참조 될 때까지) 적어도 내가 참조하는 행을 주석 처리하고 주석 처리를 제거하여 볼 수 있기 전까지는 일어나지 않습니다. 위. 'outerItem'도 마찬가지입니다.

적어도 이것이 Java 6.0에서보고있는 것입니다.




중첩 된 클래스 : 클래스 내부의 클래스

유형 :

  1. 정적 중첩 클래스
  2. 비 정적 중첩 클래스 [내부 클래스]

차:

비 정적 중첩 클래스 [내부 클래스]

비 정적 인 중첩 클래스에서 내부 클래스의 객체는 외부 클래스의 객체 내에 존재합니다. 그래서 외부 클래스의 데이터 멤버는 내부 클래스에 액세스 할 수 있습니다. 따라서 내부 클래스의 객체를 생성하기 위해서는 먼저 외부 클래스의 객체를 생성해야합니다.

outerclass outerobject=new outerobject();
outerclass.innerclass innerobjcet=outerobject.new innerclass(); 

정적 중첩 클래스

내부 클래스의 정적 중첩 클래스 객체에서는 "정적"이라는 단어가 객체를 만들 필요가 없음을 나타 내기 때문에 외부 클래스의 객체가 필요하지 않습니다.

class outerclass A {
    static class nestedclass B {
        static int x = 10;
    }
}

x에 액세스하려면 다음 내부 메소드를 작성하십시오.

  outerclass.nestedclass.x;  i.e. System.out.prinltn( outerclass.nestedclass.x);



이 용어는 서로 바꿔서 사용할 수 있습니다. 만약 당신이 정말로 그것에 대해 솔직하게 말한다면, "내포 된 클래스"를 정의하여 내부 클래스가없는 정적 인 내부 클래스를 정의 할 있습니다. 코드에서 다음과 같은 것을 가질 수 있습니다 :

public class Outer {
    public class Inner {}

    public static class Nested {}
}

그것은 실제로 널리 받아 들여지는 정의가 아닙니다.




중첩 된 클래스는 매우 일반적인 용어입니다. 최상위 수준이 아닌 모든 클래스는 중첩 된 클래스입니다. 내부 클래스는 비 정적 중첩 클래스입니다. Joseph Darcy는 Nested, Inner, Member 및 Top-Level Classes에 대해 아주 좋은 설명을했습니다.




Related