JavaRush /Java Blog /Random-KO /클래스, 중첩 클래스 유형(예제 포함)
Ярослав
레벨 40
Днепр

클래스, 중첩 클래스 유형(예제 포함)

Random-KO 그룹에 게시되었습니다
안녕하세요 여러분. 이 주제에서는 초보자가 이 주제를 이해하고 아마도 초보자가 아닌 사람들이 새로운 것을 배울 수 있도록 Java 클래스와 해당 유형에 대해 자세히 이야기하고 싶습니다. 가능한 경우 코드 예제와 함께 실제 예제를 사용하여 모든 내용을 보여줍니다. 시작하자. 클래스, 중첩 클래스 유형(예제 포함) - 1그리고 가장 중요한 것은 처음 두 가지 유형의 클래스를 이해하는 것이며 로컬 및 익명은 단순히 내부 클래스의 하위 유형이라는 점에 주목하고 싶습니다.

수업이란 무엇입니까?

클래스는 무언가에 대한 논리적 설명이며, 바로 그 사물의 실제 인스턴스를 생성할 수 있는 템플릿입니다. 즉, 생성된 엔터티가 어떤 모습이어야 하는지, 즉 어떤 속성과 메서드를 가져야 하는지에 대한 설명일 뿐입니다. 속성 은 엔터티의 특성이고 메서드는 엔터티가 수행할 수 있는 작업입니다. 클래스가 무엇인지 이해하는 데 도움이 되는 실제 클래스의 좋은 예는 그림으로 간주될 수 있습니다. 그림은 구조(투석기, 드라이버)를 설명하는 데 사용되지만 그림은 디자인이 아닙니다. 엔지니어가 청사진을 사용하여 디자인을 만드는 것처럼 프로그래밍에서는 클래스를 사용하여 속성과 메서드를 설명하는 개체를 만듭니다.
public class Student {
    private String name, group, specialty;

    public Student(String name, String group, String specialty) {
       this.name = name;
       this.group = group;
       this.specialty = specialty;
   }

   // getters/setters
}
이 예에서는 "학생" 엔터티를 설명하는 Java 클래스를 만들었습니다. 각 학생에게는 이름, 그룹 및 전문 분야가 있습니다. 이제 프로그램의 다른 위치에서 이 클래스의 실제 예제를 만들 수 있습니다. 즉, 수업이 Student학생이 어떤 모습이어야 하는지에 대한 초상화라면 생성된 인스턴스는 실제 학생 자체입니다. 새로운 학생을 생성하는 예: new Student("Ivan", "KI-17-2", "Computer Engineering");운영자는 new클래스를 검색 Student한 후 이 클래스의 특수 메서드(생성자)를 호출합니다. 생성자는 기성품 클래스 개체를 반환합니다 Student. 장학금 없이도 배고픈 우리의 사랑스러운 학생입니다. :))

Java의 클래스 유형

Java에는 다른 클래스 안에 4가지 종류의 클래스가 있습니다.
  1. 중첩된 내부 클래스는 외부 클래스 내부의 비정적 클래스입니다.

  2. 중첩된 정적 클래스는 외부 클래스 내부의 정적 클래스입니다.

  3. Java 로컬 클래스는 메소드 내의 클래스입니다.

  4. 익명 Java 클래스는 즉시 생성되는 클래스입니다.

각각에 대해 별도로 이야기하겠습니다.

외부 클래스 내부의 비정적 클래스

먼저, 실제 예를 통해 이것이 무엇인지 이해하시기 바랍니다. 이해하기가 훨씬 쉽기 때문입니다. 이제 우리는 정말 큰 것을 더 작은 구성 요소로 분해하고 비행기를 분해해 보겠습니다! 그러나 예를 들어 조금만 보여주면 충분하므로 완전히 분해하지는 않겠습니다. 이 과정을 시각화하기 위해 비행기 다이어그램을 사용하겠습니다. 먼저 항공기 이름, 식별 코드, 항공편 등 간단한 설명을 추가할 수 있는 클래스, 중첩 클래스 유형(예제 포함) - 2 클래스를 만들어야 합니다 .Airplane
public class Airplane {
    private String name, id, flight;

    public Airplane(String name, String id, String flight) {
        this.name = name;
        this.id = id;
        this.flight = flight;
    }

    // getters/setters
}
이제 날개를 추가하고 싶습니다. 별도의 수업을 만드시겠어요? 아마도 이것은 비행기 설계를 위한 복잡한 프로그램이 있고 엄청난 수의 파생 클래스(상위 클래스와 동일한 논리를 갖는 클래스, 즉 상속되는 클래스이지만 클래스)를 생성해야 하는 경우 논리일 것입니다. 따라서 논리나 더 자세한 특성을 추가하여 상위 클래스를 확장합니다. 하지만 평면이 하나 있는 게임만 있으면 어떻게 될까요? 그러면 전체 구조를 한 곳(한 클래스)에서 완성하는 것이 더 합리적일 것입니다. 비정적 중첩 클래스가 작동하는 곳입니다. 본질적으로 이것은 외부 클래스의 일부 세부 사항에 대한 더 자세한 설명입니다. 이 예에서는 왼쪽과 오른쪽 비행기의 날개를 만들어야 합니다. 만들어 보자!
public class Airplane {
    private String name, id, flight;
    private Wing leftWing = new Wing("Red", "X3"), rightWing = new Wing("Blue", "X3");

    public Airplane(String name, String id, String flight) {
        this.name = name;
        this.id = id;
        this.flight = flight;
    }

    private class Wing {
        private String color, model;

        private Wing(String color, String model) {
            this.color = color;
            this.model = model;
        }

        // getters/setters
    }

    // getters/setters
}
Wing그래서 우리는 클래스(비행기) 내에 비정적 중첩 클래스(날개)를 만들고 Airplane두 개의 변수(왼쪽 날개와 오른쪽 날개)를 추가했습니다. 그리고 각 날개에는 변경할 수 있는 고유한 속성(색상, 모델)이 있습니다. 이렇게 하면 필요한 만큼 구조물에 직원을 배치할 수 있습니다. 참고: 다이어그램 앞부분에는 항공기 부품이 상당히 많았으며 실제로 모든 부품을 내부 클래스로 나눌 수 있지만 이러한 프로세스가 항상 권장되는 것은 아닙니다. 이러한 순간은 작업에 따라 추적되어야 합니다. 문제를 해결하기 위해 날개가 전혀 필요하지 않을 수도 있습니다. 그렇다면 그렇게 할 필요가 없습니다. 사람을 다리, 팔, 몸통, 머리로 자르는 것과 같습니다. 가능하지만 이 클래스가 사람에 대한 데이터를 저장하는 데만 사용된다면 왜 그럴까요? 비정적 중첩 Java 클래스의 기능:
  1. 객체에만 존재하므로 생성하려면 객체가 필요합니다. 즉, 우리는 날개를 비행기의 일부로 설계했기 때문에 날개를 만들려면 비행기가 필요하고, 그렇지 않으면 비행기가 필요하지 않습니다.
  2. Java 클래스 내부에는 정적 변수가 있을 수 없습니다. 상수나 기타 정적 항목이 필요한 경우 이를 외부 클래스로 이동해야 합니다. 이는 비정적 중첩 클래스가 외부 클래스와 밀접하게 결합되어 있기 때문입니다.
  3. 클래스는 외부 클래스의 모든 비공개 필드에 대한 전체 액세스 권한을 갖습니다. 이 기능은 두 가지 방식으로 작동합니다.
  4. 외부 클래스의 인스턴스에 대한 참조를 얻을 수 있습니다. 예: 비행기. 이것은 비행기에 대한 링크이고, 이것은 날개에 대한 링크입니다.

외부 클래스 내부의 정적 클래스

이 유형의 클래스는 한 가지를 제외하면 일반 외부 클래스와 다르지 않습니다. 이러한 클래스의 인스턴스를 생성하려면 외부 클래스에서 원하는 클래스까지의 전체 경로를 점으로 구분하여 나열해야 합니다. 예: Building.Plaftorm platform = new Building.Platform(); 정적 클래스는 논리적 구조를 더 쉽게 작업할 수 있도록 관련 클래스를 나란히 배치하는 데 사용됩니다. Building예를 들어, 특정 건물을 나타내는 특정 클래스 목록이 있는 외부 클래스를 만들 수 있습니다 .
public abstract class Building {
    private String name, address, type;

    Building(String name, String address) {
        this.name = name;
        this.address = address;
    }

    public static class Platform extends Building {
        public Platform(String name, String address) {
            super(name, address);
            setType("Platform");
        }

        // some additional logic
    }

    public static class House extends Building {
        public House(String name, String address) {
            super(name, address);
            setType("House");
        }

        // some additional logic
    }

    public static class Shop extends Building {
        public Shop(String name, String address) {
            super(name, address);
            setType("Shop");
        }

        // some additional logic
    }

    // getters/setters
}
이 예에서는 정적 클래스를 사용하여 논리적 구조를 보다 편리한 형식으로 패키징하는 방법을 보여줍니다. 존재하지 않는다면 완전히 다른 4개의 클래스를 만들어야 합니다. 이 접근 방식의 장점:
  1. 수업 수가 감소했습니다.
  2. 모든 클래스는 상위 클래스 내에 있습니다. 각 클래스를 별도로 열지 않고도 전체 계층 구조를 추적할 수 있습니다.
  3. Building 클래스를 참조할 수 있으며 IDE는 이미 이 클래스의 모든 하위 클래스에 대한 전체 목록을 표시합니다. 이렇게 하면 필요한 클래스를 더 쉽게 찾을 수 있고 전체 그림을 더욱 전체적으로 보여줄 수 있습니다.
중첩된 정적 클래스의 인스턴스를 생성하는 예:Building.Shop myShop = new Building.Shop(“Food & Fun!”, “Kalyaeva 8/53”); 이 전략은 Line2D, Arc2D, Ellipse2D 등과 같은 모양을 설명하기 위해 AWT 2D 클래스에서 사용된다는 점에도 주목하고 싶습니다.

지역 수업

이러한 클래스는 다른 메서드 내에서 선언됩니다. 실제로 이들은 비정적 중첩 클래스의 모든 속성을 갖고 있으며 해당 인스턴스만 메서드에서만 생성할 수 있으며 메서드는 정적일 수 없습니다(이를 생성하려면 외부 클래스의 인스턴스, 클래스에 대한 참조가 필요함). 호출 개체의 인스턴스는 암시적으로 비정적 메서드에 전달되며 정적 메서드에는 이 링크에 대한 메서드가 없습니다. 그러나 그들은 고유한 특성을 가지고 있습니다:
  1. 로컬 클래스는 최종 메서드 변수에서만 작동할 수 있습니다. 문제는 메소드가 완료된 후 로컬 클래스의 인스턴스가 힙에 저장될 수 있고 변수가 지워질 수 있다는 것입니다. 변수가 final로 선언되면 컴파일러는 나중에 개체에서 사용할 수 있도록 변수의 복사본을 저장할 수 있습니다. 그리고 한 가지 더: Java 버전 8 이상부터 로컬 클래스에서 최종이 아닌 변수를 사용할 수 있지만 변경되지 않는다는 조건에서만 사용할 수 있습니다.
  2. 로컬 클래스는 액세스 한정자를 사용하여 선언할 수 없습니다.
  3. 로컬 클래스는 메서드 변수에 액세스할 수 있습니다.
로컬 클래스는 코드를 읽기 어렵게 만들고 메소드 변수에 대한 액세스를 제외하고는 장점이 없기 때문에 극히 드물게 발견됩니다. 효과적인 활용을 보여줄 수 있는 지역 수업의 어떤 예를 취할 수 있는지 모르기 때문에 그냥 예를 보여 드리겠습니다. (거리), (집) 속성을 가진 클래스 Person(사람이라고 가정)가 있다고 가정해 보겠습니다 . 우리는 그 사람의 위치에만 접근하기 위해 어떤 객체를 반환하고 싶습니다. 이를 위해 우리는 사람의 위치에 대한 데이터 저장을 의미하는 AddressContainer 인터페이스를 만들었습니다. streethouse
public class Person {
    private String name, street, house;

    public Person(String name, String street, String house) {
        this.name = name;
        this.street = street;
        this.house = house;
    }

    private interface AddressContainer {
        String getStreet();
        String getHouse();
    }

    public AddressContainer getAddressContainer() {
        class PersonAddressContainer implements AddressContainer {
            final String street = Person.this.street, house = Person.this.house;

            @Override
            public String getStreet() {
                return this.street;
            }

            @Override
            public String getHouse() {
                return this.house;
            }
        }

        return new PersonAddressContainer();
    }

    public static void main(String[] args) {
        Person person = new Person("Nikita", "Sholohova", "17");

        AddressContainer address = person.getAddressContainer();

        System.out.println("Address: street - " + address.getStreet() + ", house - " + address.getHouse());
    }

    // getters/setters
}
보시다시피, 메서드 내에서 사람의 위치 저장을 구현하는 클래스를 만들고 거기에 상수 변수를 만들고(메서드를 종료한 후 변수가 객체에 저장되도록) 주소와 주소를 가져오는 메서드를 구현했습니다. 집. 이제 프로그램의 다른 위치에서 이 개체를 사용하여 사람의 위치를 ​​얻을 수 있습니다. 나는 이 예제가 이상적이지 않으며 클래스에 getter를 그대로 두는 것이 더 정확할 것이라는 점을 이해합니다 Person. 그러나 이 클래스의 생성과 가능한 사용 방법이 표시되었으며 그 다음은 귀하에게 달려 있습니다.

익명 수업

내부적으로는 익명 클래스는 일반적인 비정적 중첩 클래스입니다. 그들의 특징은 사용하기 쉽다는 것입니다. 다른 클래스의 인스턴스를 생성할 때 클래스를 직접 작성할 수 있습니다.
public class Animal {
    public void meow() {
        System.out.println("Meow!");
    }

    public static void main(String[] args) {
        Animal anonTiger = new Animal() {
            @Override
            public void meow() {
                System.out.println("Raaar!");
            }
        };

        Animal notAnonTiger = new Animal().new Tiger();

        anonTiger.meow(); // будет выведено Raaar!
        notAnonTiger.meow(); // будет выведено Raaar!
    }

    private class Tiger extends Animal {
        @Override
        public void meow() {
            System.out.println("Raaar!");
        }
    }
}
본질적으로 우리는 단순히 두 가지를 한 곳에 결합합니다. 한 클래스의 인스턴스 생성( Animal)과 상속자 내부 클래스의 인스턴스 생성( Tiger)입니다. 그렇지 않으면 클래스를 별도로 생성하고 동일한 결과를 얻기 위해 더 긴 구문을 사용해야 합니다. 익명 클래스의 사용은 많은 경우, 특히 다음과 같은 경우에 정당화됩니다.
  • 클래스 본문은 매우 짧습니다.
  • 클래스의 인스턴스는 하나만 필요합니다.
  • 클래스는 생성된 장소나 클래스 직후에 사용됩니다.
  • 클래스 이름은 중요하지 않으며 코드를 이해하기 쉽게 만들지 않습니다.
익명 클래스는 이벤트 핸들러를 생성하기 위해 GUI에서 자주 사용됩니다. 예를 들어 버튼을 만들고 클릭에 반응하려면 다음을 수행하세요.
JButton b2 = new JButton("Click");
b2.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        System.out.println("Кнопка нажата!");
    }
});
그러나 Java 8 이후에는 람다 표현식을 사용하기 시작했지만 여전히 많은 코드가 버전 8 이전에 작성되었으며 이러한 비문을 접할 수 있습니다(JavaRush 교육 중에 접하게 됩니다).\ 람다와 유사:
JButton b2 = new JButton("Click");
b2.addActionListener(e -> System.out.println("Кнопка нажата!"));
기사 끝 관심을 가져주신 모든 분들께 감사드리며, 새로운 것을 배우셨거나 이전에 이해하지 못했던 것을 이해하셨기를 바랍니다. 또한 이 기사는 "세부 사항에 대한 관심" 범주 에 속한다는 점을 분명히 하고 싶습니다 . 첫 작품이라 누군가에게 도움이 됐으면 좋겠습니다. 가까운 장래에 새로운 아이디어가 떠오르면 다른 것을 작성하려고 노력할 것입니다. 아이디어는 하나뿐입니다... 모두에게 행운을 빕니다. 프로그래밍에서 성공하기를 바랍니다 :)
코멘트
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION