CodeGym /Java Blog /무작위의 /중첩된 내부 클래스
John Squirrels
레벨 41
San Francisco

중첩된 내부 클래스

무작위의 그룹에 게시되었습니다
안녕! 오늘 우리는 Java에서 중첩 클래스가 작동하는 방식이라는 중요한 주제를 다룰 것입니다. Java를 사용하면 다른 클래스 안에 클래스를 만들 수 있습니다.

class OuterClass {
    ...
    static class StaticNestedClass {
        ...
    }
    class InnerClass {
        ...
    }
}
이러한 내부 클래스를 중첩이라고 합니다. 두 가지 유형으로 나뉩니다.
  1. 비정적 중첩 클래스. 내부 클래스라고도 합니다.
  2. 정적 중첩 클래스.
차례로 내부 클래스에는 두 가지 하위 범주가 있습니다. 내부 클래스는 단순히 내부 클래스일 뿐만 아니라 다음과 같을 수도 있습니다.
  • 지역 수업
  • 익명 클래스
혼란스러운? :) 괜찮아요. 다음은 명확성을 위한 다이어그램입니다. 갑자기 혼란스러워지면 수업 중에 다시 찾아오세요! 중첩된 내부 클래스 - 2오늘 강의에서는 내부 클래스(비정적 중첩 클래스라고도 함)에 대해 설명합니다. 길을 잃지 않도록 전체 다이어그램에서 특별히 강조 표시되어 있습니다. :) 분명한 질문부터 시작하겠습니다. 왜 "내부" 클래스라고 불립니까? 대답은 매우 간단합니다. 다른 클래스 내부에서 생성되기 때문입니다. 다음은 예입니다.

public class Bicycle {

   private String model;
   private int weight;

   public Bicycle(String model, int weight) {
       this.model = model;
       this.weight = weight;
   }
  
   public void start() {
       System.out.println("Let's go!");
   }

   public class Handlebar {

       public void right() {
           System.out.println("Steer right!");
       }

       public void left() {

           System.out.println("Steer left!");
       }
   }

   public class Seat {
      
       public void up() {

           System.out.println("Seat up!");
       }
      
       public void down() {

           System.out.println("Seat down!");
       }
   }
}
여기에 수업이 있습니다 Bicycle. 2개의 필드와 1개의 메서드가 있습니다: start(). 중첩된 내부 클래스 - 3두 개의 클래스를 포함한다는 점에서 일반 클래스와 다릅니다. HandlebarSeat. 그들의 코드는 클래스 내부에 작성됩니다 Bicycle. 이들은 본격적인 클래스입니다. 보시다시피 각각 고유 한 방법이 있습니다. 이 시점에서 질문이 생길 수 있습니다. 왜 우리는 한 클래스 안에 다른 클래스를 넣어야 할까요? 내부 클래스로 만드는 이유는 무엇입니까? 프로그램에서 핸들바와 좌석의 개념에 대해 별도의 클래스가 필요하다고 가정합니다. 물론 그것들을 중첩시킬 필요는 없습니다! 우리는 평범한 수업을 할 수 있습니다. 예를 들면 다음과 같습니다.

public class Handlebar {
   public void right() {
       System.out.println("Steer right!");
   }

   public void left() {

       System.out.println("Steer left");
   }
}

public class Seat {

   public void up() {

       System.out.println("Seat up!");
   }

   public void down() {

       System.out.println("Seat down!");
   }
}
아주 좋은 질문입니다! 물론 우리는 기술에 제한을 받지 않습니다. 그렇게 하는 것은 확실히 선택 사항입니다. 여기서 중요한 것은 특정 프로그램과 그 목적의 관점에서 클래스를 올바르게 설계하는 것입니다. 내부 클래스는 다른 엔터티와 불가분하게 연결된 엔터티를 분리하기 위한 것입니다. 핸들바, 좌석 및 페달은 자전거의 구성 요소입니다. 자전거와 분리하면 별 의미가 없습니다. 이러한 모든 개념을 별도의 공용 클래스로 만들면 프로그램에 다음과 같은 코드가 있을 것입니다.

public class Main {

   public static void main(String[] args) {
       Handlebar handlebar = new Handlebar();
       handlebar.right();
   }
}
흠... 이 코드의 의미는 설명하기조차 어렵습니다. 모호한 핸들 바가 있습니다 (왜 필요한가요? 솔직히 모르겠습니다). 그리고 이 핸들은 오른쪽으로... 자전거 없이... 저절로... 어떤 이유에서인지. 자전거의 개념에서 핸들바의 개념을 분리함으로써 우리는 프로그램에서 일부 논리를 잃었습니다. 내부 클래스를 사용하면 코드가 매우 다르게 보입니다.

public class Main {

   public static void main(String[] args) {

       Bicycle peugeot = new Bicycle("Peugeot", 120);
       Bicycle.Handlebar handlebar = peugeot.new Handlebar();
       Bicycle.Seat seat = peugeot.new Seat();

       seat.up();
       peugeot.start();
       handlebar.left();
       handlebar.right();
   }
}
콘솔 출력:

Seat up! 
Let's go! 
Steer left! 
Steer right!
이제 우리가 보는 것이 갑자기 이해가 됩니다! :) 자전거 오브젝트를 만들었습니다. 핸들바와 좌석이라는 두 개의 자전거 "하위 객체"를 만들었습니다. 우리는 편안함을 위해 좌석을 올리고 출발했습니다. 필요에 따라 페달링과 스티어링을 했습니다! :) 우리에게 필요한 메소드는 적절한 객체에서 호출됩니다. 모두 간단하고 편리합니다. 이 예에서는 핸들바와 좌석을 분리하여 캡슐화를 강화하고(관련 클래스 내부의 자전거 부품에 대한 데이터를 숨김) 더 자세한 추상화를 만들 수 있습니다. 이제 다른 상황을 살펴보겠습니다. 자전거 상점과 자전거 예비 부품을 시뮬레이트하는 프로그램을 만들고 싶다고 가정합니다. 중첩된 내부 클래스 - 4이 상황에서는 이전 솔루션이 작동하지 않습니다. 자전거 매장에서는 자전거와 분리되어 있어도 각각의 개별 자전거 부품이 의미가 있습니다. 예를 들어 "고객에게 페달 판매", "새 좌석 구매" 등과 같은 메서드가 필요합니다. 여기서 내부 클래스를 사용하는 것은 실수입니다. 새 프로그램의 각 개별 자전거 부품에는 의미가 있습니다. 자체: 자전거의 개념과 분리할 수 있습니다. 내부 클래스를 사용해야 하는지 아니면 모든 엔터티를 별도의 클래스로 구성해야 하는지 궁금할 때 주의를 기울여야 할 사항입니다. 객체 지향 프로그래밍은 실제 엔터티를 쉽게 모델링할 수 있다는 점에서 좋습니다. 이는 내부 클래스를 사용할지 여부를 결정할 때 기본 원칙이 될 수 있습니다. 실제 매장에서는 예비 부품은 자전거와 분리되어 있습니다. 괜찮습니다. 이것은 프로그램을 설계할 때에도 괜찮다는 것을 의미합니다. 자, 우리는 "철학"을 알아냈습니다 :) 이제 내부 클래스의 중요한 "기술적" 기능에 대해 알아보겠습니다. 반드시 기억하고 이해해야 할 사항은 다음과 같습니다.
  1. 내부 클래스의 객체는 외부 클래스의 객체 없이 존재할 수 없습니다.

    Seat이것이 의미가 있습니다: 이것이 우리가 프로그램에서 및 내부 클래스를 만든 이유입니다 Handlebar. 그래서 우리는 고아 핸들바와 좌석으로 끝나지 않습니다.

    이 코드는 컴파일되지 않습니다.

    
    public static void main(String[] args) {
    
       Handlebar handlebar = new Handlebar();
    }
    

    또 다른 중요한 기능은 다음과 같습니다.

  2. 내부 클래스의 개체는 외부 클래스의 변수에 액세스할 수 있습니다.

    int seatPostDiameter예를 들어 클래스에 변수(안장 기둥의 직경을 나타냄)를 추가해 보겠습니다 Bicycle.

    그런 다음 내부 클래스에서 좌석 속성을 표시하는 메서드를 Seat만들 수 있습니다 .displaySeatProperties()

    
    public class Bicycle {
    
       private String model;
       private int weight;
    
       private int seatPostDiameter;
    
       public Bicycle(String model, int weight, int seatPostDiameter) {
           this.model = model;
           this.weight = weight;
           this.seatPostDiameter = seatPostDiameter;
    
       }
    
       public void start() {
           System.out.println("Let's go!");
       }
    
       public class Seat {
    
           public void up() {
    
               System.out.println("Seat up!");
           }
    
           public void down() {
    
               System.out.println("Seat down!");
           }
    
           public void displaySeatProperties() {
    
               System.out.println("Seat properties: seatpost diameter = " + Bicycle.this.seatPostDiameter);
           }
       }
    }
    

    이제 프로그램에 이 정보를 표시할 수 있습니다.

    
    public class Main {
    
       public static void main(String[] args) {
    
           Bicycle bicycle = new Bicycle("Peugeot", 120, 40);
           Bicycle.Seat seat = bicycle.new Seat();
    
           seat.displaySeatProperties();
       }
    }
    

    콘솔 출력:

    
    Seat properties: seatpost diameter = 40
    

    메모:새 변수는 가장 엄격한 액세스 한정자( private)로 선언됩니다. 그리고 여전히 내부 클래스에 액세스할 수 있습니다!

  3. 내부 클래스의 개체는 외부 클래스의 정적 메서드에서 만들 수 없습니다.

    이는 내부 클래스가 구성되는 방식의 특정 기능으로 설명됩니다. 내부 클래스에는 매개변수가 있는 생성자가 있거나 기본 생성자만 있을 수 있습니다. 그러나 그럼에도 불구하고 내부 클래스의 객체를 생성할 때 외부 클래스의 객체에 대한 참조가 내부 클래스의 생성된 객체에 보이지 않게 전달됩니다. 결국 이러한 개체 참조의 존재는 절대적인 요구 사항입니다. 그렇지 않으면 내부 클래스의 개체를 만들 수 없습니다.

    그러나 외부 클래스의 메서드가 정적이면 외부 클래스의 개체가 없을 수 있습니다! 그리고 이것은 내부 클래스가 작동하는 방식의 논리를 위반하는 것입니다. 이 상황에서 컴파일러는 오류를 생성합니다.

    
    public static Seat createSeat() {
      
       // Bicycle.this cannot be referenced from a static context
       return new Seat();
    }
    
  4. 내부 클래스는 정적 변수 및 메서드를 포함할 수 없습니다.

    논리는 동일합니다. 정적 메서드와 변수가 존재할 수 있고 개체가 없는 경우에도 호출하거나 참조할 수 있습니다.

    그러나 외부 클래스의 개체가 없으면 내부 클래스에 액세스할 수 없습니다.

    명백한 모순! 이것이 정적 변수와 메서드가 내부 클래스에서 허용되지 않는 이유입니다.

    생성하려고 하면 컴파일러에서 오류가 발생합니다.

    
    public class Bicycle {
    
       private int weight;
    
    
       public class Seat {
          
           // An inner class cannot have static declarations
           public static void displaySeatProperties() {
    
               System.out.println("Seat properties: seatpost diameter = " + Bicycle.this.seatPostDiameter);
           }
       }
    }
    
  5. 내부 클래스의 개체를 만들 때 액세스 한정자가 중요합니다.

    내부 클래스는 표준 액세스 수정자( public, private, protected및 ) 로 표시할 수 있습니다 package private.

    이것이 왜 중요한가요?

    이는 프로그램에서 내부 클래스의 인스턴스를 생성할 수 있는 위치에 영향을 미칩니다.

    Seat클래스가 로 선언 되면 다른 클래스에서 객체를 public만들 수 있습니다 . Seat유일한 요구 사항은 외부 클래스의 개체도 존재해야 한다는 것입니다.

    그건 그렇고, 우리는 이미 여기에서 이것을 했습니다:

    
    public class Main {
    
       public static void main(String[] args) {
    
           Bicycle peugeot = new Bicycle("Peugeot", 120);
           Bicycle.Handlebar handlebar = peugeot.new Handlebar();
           Bicycle.Seat seat = peugeot.new Seat();
    
           seat.up();
           peugeot.start();
           handlebar.left();
           handlebar.right();
       }
    }
    

    Handlebar클래스 에서 내부 클래스 에 쉽게 액세스할 수 있었습니다 Main.

    내부 클래스를 로 선언하면 private외부 클래스 내부에서만 객체를 생성할 수 있습니다.

    Seat더 이상 "외부에" 개체를 만들 수 없습니다 .

    
    private class Seat {
    
       // Methods
    }
    
    public class Main {
    
       public static void main(String[] args) {
    
           Bicycle bicycle = new Bicycle("Peugeot", 120, 40);
    
           // Bicycle.Seat has private access in Bicycle
           Bicycle.Seat seat = bicycle.new Seat();
       }
    }
    

    당신은 이미 논리를 이해했을 것입니다 :)

  6. 내부 클래스에 대한 액세스 한정자는 일반 변수와 동일하게 작동합니다.

    수정 protected자는 동일한 패키지에 있는 하위 클래스 및 클래스의 인스턴스 변수에 대한 액세스를 제공합니다.

    protected내부 클래스에서도 작동합니다. protected내부 클래스의 객체를 만들 수 있습니다 .

    • 외부 클래스에서;
    • 하위 클래스에서;
    • 동일한 패키지에 있는 클래스에서.

    내부 클래스에 액세스 한정자( )가 없으면 package private내부 클래스의 개체를 만들 수 있습니다.

    • 외부 클래스에서;
    • 동일한 패키지에 있는 클래스에서.

    오랫동안 수식어에 익숙했으므로 여기서는 문제가 없습니다.

지금은 여기까지입니다 :) 하지만 느슨해지지 마세요! 내부 클래스는 상당히 광범위한 주제이므로 다음 단원에서 계속 살펴보겠습니다. 이제 내부 클래스에 대한 과정 수업의 기억을 새로 고칠 수 있습니다 . 다음 시간에는 정적 중첩 클래스에 대해 이야기해 봅시다.
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION