06_클래스

Tasker_Jang·2024년 2월 26일
0

06_클래스

1. 객체란?

객체란 물리적으로 존재하거나 추상적으로 생각할 수 있는 것 중 자신의 속성을 가지고 있으면서 식별 가능한 것을 의미한다.

2. 메서드란?

객체 지향 프로그래밍에서 객체 간의 상호작용은 주로 메서드를 통해 이루어집니다. 메서드는 객체가 수행하는 특정 작업이나 동작을 나타내는 함수입니다. 이 메서드를 통해 다른 객체는 해당 객체의 상태에 접근하거나 특정 동작을 유발할 수 있습니다.

메서드는 객체의 특정 행동을 정의하고, 이를 호출하여 해당 행동을 수행합니다. 객체의 상태는 메서드를 통해서만 변경되며, 외부에서 직접 접근할 수 없도록 캡슐화되어 있습니다. 이로써 객체의 내부 구현이 외부로부터 숨겨지고, 객체 간의 인터페이스를 통한 상호작용이 간소화됩니다.

객체의 상호작용은 메시지 전달을 통해 이루어지는데, 메시지는 다른 객체에 대한 요청 또는 명령을 의미합니다. 객체는 이 메시지를 받아서 해당하는 메서드를 실행하고, 그 결과로 다시 메시지를 반환할 수 있습니다. 이런 방식으로 객체 간의 협력이 이루어지며, 전체 시스템이 유연하게 동작하게 됩니다.

3. 매개 변수

메서드 호출을 통해 객체들은 데이터를 주고 받습니다. 이 과정에서 메서드에는 매개변수(parameter)가 사용됩니다. 매개변수는 메서드가 호출될 때 전달되는 데이터를 받는 변수로서, 메서드가 수행될 때 이 데이터를 활용하여 특정 작업을 수행합니다.

메서드는 종종 입력값을 필요로 하며, 이러한 입력값은 매개변수를 통해 전달됩니다. 매개변수는 메서드 정의에서 선언되며, 메서드가 호출될 때 실제 값이 전달됩니다. 이렇게 전달된 값은 메서드 내에서 해당 매개변수를 통해 활용됩니다.

public class Car {
    private int currentSpeed;

    // Method definition for accelerating
    public void accelerate(int speed) {
        // Performing acceleration using the speed parameter
        this.currentSpeed += speed;
    }

    // Method to get current speed
    public int getCurrentSpeed() {
        return this.currentSpeed;
    }

    public static void main(String[] args) {
        // Creating a car object
        Car myCar = new Car();

        // Calling the accelerate method
        myCar.accelerate(20);

        // Printing the current speed
        System.out.println("Current speed: " + myCar.getCurrentSpeed() + " km/h");
    }
}

4. 객체간의 관계

객체 지향 프로그래밍에서 객체 간의 관계는 주로 세 가지 유형으로 나뉩니다.

  1. 집합 관계 (Composition/Aggregation): 이 관계에서는 하나의 객체가 다른 객체를 포함하거나 그 객체의 일부로 간주됩니다. 완성품과 부품의 관계와 유사하며, 한 객체의 수명이 다른 객체에 의해 영향을 받는 경우가 많습니다.

  2. 사용 관계 (Dependency): 이 관계에서는 한 객체가 다른 객체를 사용하거나 그 객체의 기능을 호출합니다. 다른 객체의 필드를 읽고 변경하거나 메서드를 호출하여 작업을 수행하는 관계입니다.

  3. 상속 관계 (Inheritance): 이 관계에서는 부모 클래스와 자식 클래스 사이의 관계가 있습니다. 자식 클래스는 부모 클래스의 모든 속성과 메서드를 상속받아 사용할 수 있습니다. 이를 통해 코드 재사용성을 높일 수 있습니다.

이러한 객체 간의 관계를 통해 객체 지향 프로그래밍에서 유연하고 모듈화된 설계를 할 수 있습니다.

5. 객체 지향 프로그래밍의 특성

객체 지향 프로그래밍(OOP)은 몇 가지 중요한 특징을 가지고 있습니다.

  1. 캡슐화 (Encapsulation): 객체의 상태(데이터)와 행동(메서드)을 하나로 묶어 외부에서의 접근을 제어하는 것을 말합니다. 캡슐화는 객체의 내부 구현을 외부로부터 감추어 정보 은닉을 통해 객체의 안정성과 보안을 강화합니다.

  2. 상속 (Inheritance): 부모 클래스에서 정의된 속성과 메서드를 자식 클래스에서 재사용할 수 있게 하는 메커니즘입니다. 이를 통해 코드 재사용성이 증가하며, 계층 구조를 통해 일반적인 특성을 상위 클래스에서 정의하고 특수한 특성을 하위 클래스에서 추가할 수 있습니다.

  3. 다형성 (Polymorphism): 동일한 인터페이스를 가진 여러 객체가 각각의 특정 구현을 가지고 있는 것을 의미합니다. 다형성은 같은 메서드 호출이 다른 객체에 따라 다르게 구현될 수 있음을 나타내며, 이는 코드의 유연성과 확장성을 높여줍니다.

이러한 특징들은 객체 지향 프로그래밍의 기본 원칙으로서, 모듈화, 재사용성, 유지보수성 등을 증가시키고 복잡한 시스템을 효과적으로 설계하고 구현할 수 있도록 도와줍니다.

6. 클래스와 객체

클래스 (Class): 클래스는 객체를 만들기 위한 설계도 혹은 틀입니다. 클래스는 객체가 가져야 할 속성(멤버 변수)과 동작(메서드)을 정의합니다. 즉, 클래스는 어떤 종류의 객체를 생성할 것인지에 대한 템플릿 역할을 합니다.

예를 들어, 자동차 클래스는 자동차 객체가 가져야 할 속성(색상, 속도 등)과 동작(가속, 제동 등)을 정의하는데 사용될 수 있습니다.

객체 (Object): 객체는 클래스의 인스턴스로, 클래스를 기반으로 생성된 실제 데이터입니다. 클래스를 사용하여 객체를 생성하면, 해당 객체는 클래스에서 정의한 속성과 동작을 가지게 됩니다.

// Class definition for a Car
public class Car {
    // Member variables (attributes)
    String color;
    int speed;

    // Method (behavior)
    public void accelerate(int speed) {
        this.speed += speed;
    }
}

// Main class to demonstrate creating and using objects
public class Main {
    public static void main(String[] args) {
        // Creating an object based on the Car class
        Car myCar = new Car();

        // Using the object's attributes and behavior
        myCar.color = "Blue";
        myCar.accelerate(30);

        System.out.println("Color: " + myCar.color);
        System.out.println("Speed: " + myCar.speed);
    }
}

7. 인스턴스

클래스로부터 생성된 객체를 해당 클래스의 인스턴스(instance)라고 부릅니다. 객체 지향 프로그래밍에서 클래스는 일종의 설계도이고, 이 설계도를 기반으로 실제 데이터를 가지는 객체가 만들어집니다. 이때, 이 객체는 해당 클래스의 인스턴스로 취급됩니다.

예를 들어 앞서 언급한 자동차 클래스의 경우 Car 클래스로부터 생성된 실제 자동차 객체는 Car 클래스의 인스턴스입니다. 인스턴스는 클래스에 정의된 특성과 행동을 가지며, 클래스의 설계에 따라 동작합니다.

8. 클래스의 선언

public class ClassName {
    // Define class members such as variables and methods here
}
public class Car {
    // Member variables (attributes)
    String color;
    int speed;

    // Method (behavior)
    public void accelerate(int speed) {
        this.speed += speed;
    }
}

8. 클래스와 변수

객체를 생성하기 위해서는 new 연산자를 사용합니다. 클래스 변수에 대입할 때는 다음과 같은 구문을 사용합니다:


ClassName variableName = new ClassName();

Car myCar = new Car();

9. 라이브러리 클래스와 실행 클래스

라이브러리 클래스와 실행 클래스는 다음과 같이 정의할 수 있습니다:

  1. 라이브러리 클래스 (Library Class): 라이브러리 클래스는 실행 가능한 main() 메서드가 없으며, 주로 다른 클래스에서 재사용되는 클래스입니다. 라이브러리 클래스는 다양한 기능을 제공하고, 다른 프로그램에서 이용할 수 있도록 설계되어 있습니다.

  2. 실행 클래스 (Executable Class): 실행 클래스는 main() 메서드를 포함하고 있어 프로그램을 실행할 수 있는 클래스입니다. 이 클래스는 일반적으로 프로그램의 시작점으로 사용되며, 프로그램의 진입점(entry point)이라고도 합니다. 실행 클래스에서는 프로그램의 시작 및 종료, 그리고 다른 클래스 및 라이브러리를 활용하여 프로그램의 흐름을 조절합니다.

// 라이브러리 클래스
public class LibraryClass {
    public void doSomething() {
        System.out.println("Library class is doing something.");
    }
}

// 실행 클래스
public class ExecutableClass {
    public static void main(String[] args) {
        // 라이브러리 클래스의 인스턴스 생성 및 사용
        LibraryClass libraryObject = new LibraryClass();
        libraryObject.doSomething();

        // 실행 클래스의 로직
        System.out.println("Executable class is running.");
    }
}

10. 클래스의 구성 멤버

클래스의 선언에는 필드, 생성자, 그리고 메서드를 정의할 수 있습니다.

  1. 필드 (Field): 필드는 객체의 데이터를 저장하는 데 사용되는 변수로, 클래스 내부에서 선언됩니다. 이는 객체의 상태를 나타내는데 사용됩니다. 필드를 선언하는 방법은 변수를 선언하는 방법과 동일합니다.
public class MyClass {
    // 필드 선언
    int myField;
    String anotherField;
}
  1. 생성자 (Constructor): 생성자는 객체의 초기화를 담당하는 특별한 메서드입니다. 객체가 생성될 때 자동으로 호출되며, 주로 필드 초기화 및 다른 초기화 작업을 수행하는 데 사용됩니다.
public class MyClass {
    // 필드 선언
    int myField;
    String anotherField;

    // 생성자 선언
    public MyClass(int initialValue, String initialString) {
        this.myField = initialValue;
        this.anotherField = initialString;
    }
}
  1. 메서드 (Method): 메서드는 객체가 수행할 동작을 정의하는 데 사용됩니다. 메서드는 클래스 내부에 선언되며, 객체의 행동을 구현합니다.
public class MyClass {
    // 필드 선언
    int myField;
    String anotherField;

    // 생성자 선언
    public MyClass(int initialValue, String initialString) {
        this.myField = initialValue;
        this.anotherField = initialString;
    }

    // 메서드 선언
    public void myMethod() {
        System.out.println("This is a method in MyClass.");
    }
}

이러한 선언을 통해 클래스는 필드를 통해 상태를 나타내고, 생성자를 통해 초기화를 수행하며, 메서드를 통해 특정 동작을 정의합니다.

11. 필드와 로컬 변수의 차이점

필드와 로컬 변수는 선언된 위치, 생명 주기, 및 접근성 등에서 차이가 있습니다.

  1. 필드 (Field):
    • 선언 위치: 필드는 클래스 블록 내에서 선언되어 객체의 상태를 나타냅니다.
    • 생명 주기: 객체의 인스턴스와 함께 생성되며, 객체가 소멸할 때까지 존재합니다.
    • 접근성: 필드는 클래스 내부와 외부에서 접근 가능하며, 보통 접근 제어자를 사용하여 접근 범위를 제어할 수 있습니다.
public class MyClass {
    // 필드 선언
    int myField;
}
  1. 로컬 변수 (Local Variable):
    • 선언 위치: 로컬 변수는 메서드나 생성자 블록 내에서 선언되며, 해당 블록 내에서만 사용 가능합니다.
    • 생명 주기: 로컬 변수는 해당 블록이 실행될 때 생성되고 블록을 빠져나가면 소멸됩니다.
    • 접근성: 로컬 변수는 선언된 블록 내에서만 접근 가능하며, 외부에서는 직접적으로 접근할 수 없습니다.
public class MyClass {
    // 메서드 선언
    public void myMethod() {
        // 로컬 변수 선언
        int localVar = 10;
    }
}

로컬 변수는 주로 메서드나 생성자 내에서 일시적인 데이터를 저장하는 데 사용되며, 필드는 객체의 상태를 표현하는 데 사용됩니다.

12. 필드의 기본값

필드가 객체 생성 시에 초기값을 명시적으로 지정되지 않으면 해당 필드는 자바에서 정의한 기본값으로 자동으로 초기화됩니다. 초기화되는 기본값은 필드의 데이터 타입에 따라 정해집니다. 아래는 몇 가지 기본 데이터 타입에 대한 기본값입니다:

  • 정수 타입 (byte, short, int, long): 0
  • 실수 타입 (float, double): 0.0
  • 논리 타입 (boolean): false
  • 문자 타입 (char): '\u0000' (null character)
  • 객체 참조 타입 (class, interface, array): null

예를 들어, 다음과 같은 클래스에서 intboolean 타입의 필드는 객체 생성 시에 각각 0과 false로 초기화됩니다:

public class MyClass {
    int myIntegerField;      // 초기값: 0
    boolean myBooleanField;  // 초기값: false
}

따라서 명시적으로 초기값을 제공하지 않았을 때, 필드는 자동으로 해당 타입의 기본값으로 초기화됩니다.

13. 필드의 조건

필드는 객체의 데이터를 나타내기 위한 변수이며, 따라서 해당 필드를 사용하려면 객체가 이미 생성되어야 합니다. 필드는 객체의 인스턴스 변수로서, 클래스로부터 생성된 객체에 속하며 객체의 상태를 나타냅니다.

public class MyClass {
    // 필드 선언
    int myField;

    // 메서드 선언
    public void setMyField(int value) {
        // 객체의 필드에 값 할당
        this.myField = value;
    }

    public void printMyField() {
        // 객체의 필드 값 출력
        System.out.println("myField: " + this.myField);
    }

    public static void main(String[] args) {
        // MyClass 객체 생성
        MyClass myObject = new MyClass();

        // 객체의 메서드를 호출하여 필드 조작
        myObject.setMyField(42);
        myObject.printMyField();  // 출력: myField: 42
    }
}

14. 필드의 사용

객체 내부에서는 필드에 직접 접근하여 읽고 변경할 수 있지만, 외부에서는 객체에 대한 참조 변수와 도트 연산자(.)를 사용하여 필드에 접근해야 합니다. 이것은 객체 지향 프로그래밍에서 정보 은닉(Encapsulation) 개념과 관련이 있습니다.

  1. 객체 내부에서 필드 읽고 변경:

    public class MyClass {
        // 필드 선언
        int myField;
    
        // 메서드 내에서 필드 읽고 변경
        public void updateField() {
            myField = 42;  // 필드 변경
            int value = myField;  // 필드 읽기
        }
    }
  2. 외부에서 참조 변수와 도트 연산자를 사용하여 필드 읽고 변경:

    public class Main {
        public static void main(String[] args) {
            // MyClass 객체 생성
            MyClass myObject = new MyClass();
    
            // 외부에서 객체의 필드에 접근하여 읽고 변경
            myObject.myField = 10;  // 필드 변경
            int value = myObject.myField;  // 필드 읽기
        }
    }

객체 내부에서는 필드에 직접 접근하는 것이 일반적으로 허용되지만, 외부에서는 객체의 상태를 일관되게 유지하기 위해 필드에 직접 접근하는 대신 메서드를 통한 간접 접근을 선호하는 경우가 많습니다. 이는 정보 은닉을 통해 객체의 내부 구현을 외부로부터 감추고, 객체의 상태를 제어하고 유지보수하기 쉽게 만듭니다.

15. 생성자 선언과 호출

생성자는 객체가 생성될 때 호출되어 초기화 작업을 수행하는 특별한 메서드입니다. new 연산자를 사용하여 객체를 생성할 때 생성자가 호출되어 객체의 초기화를 담당합니다. 객체 초기화는 필드 초기화, 메서드 호출 등을 포함합니다.

생성자 선언은 클래스 내부에서 이루어지며, 생성자는 클래스의 이름과 동일합니다. 생성자는 리턴 타입을 가지지 않고, 객체 생성 시 한 번 호출됩니다.

public class MyClass {
    // 필드 선언
    int myField;

    // 생성자 선언
    public MyClass() {
        // 생성자에서 필드 초기화
        myField = 42;
        System.out.println("Constructor is called. myField is initialized to " + myField);
    }

    // 메서드 선언
    public void someMethod() {
        System.out.println("someMethod is called. myField is " + myField);
    }

    public static void main(String[] args) {
        // 생성자 호출을 통한 객체 생성
        MyClass myObject = new MyClass();

        // 생성된 객체의 메서드 호출
        myObject.someMethod();
    }
}

위 예제에서 MyClass의 생성자는 객체가 생성될 때 호출되어 myField를 초기화하고 메시지를 출력합니다. 생성자는 main 메서드에서 new MyClass()로 객체를 생성할 때 호출되며, 생성된 객체의 someMethod 메서드가 호출될 때 myField 값이 출력됩니다.

16. 필드의 초기화

필드를 선언할 때 초기값을 대입하면 해당 필드는 모든 객체에 대해 동일한 초기값을 가지게 됩니다. 이는 모든 객체가 동일한 상태로 시작하도록 하는 편리한 방법입니다.

반면에 생성자를 사용하여 필드를 초기화하면 각 객체마다 다른 값을 가질 수 있습니다. 생성자를 통해 객체를 초기화함으로써 서로 다른 객체가 서로 다른 초기값을 갖도록 할 수 있습니다.

예를 들어, 다음은 초기값을 필드 선언과 생성자에서 각각 대입하는 예제입니다:

public class MyClass {
    // 필드 선언과 초기값 대입
    int defaultFieldValue = 10;

    // 생성자를 통한 초기화
    int customFieldValue;

    public MyClass() {
        // 생성자에서 필드 초기화
        customFieldValue = 42;
    }

    public static void main(String[] args) {
        // 객체 생성
        MyClass defaultObject = new MyClass();
        MyClass customObject = new MyClass();

        // 필드 값 출력
        System.out.println("defaultObject: " + defaultObject.defaultFieldValue);  // 출력: 10
        System.out.println("customObject: " + customObject.customFieldValue);    // 출력: 42
    }
}

이러한 접근 방식을 사용하면 각 객체가 원하는 초기값을 갖도록 할 수 있으며, 코드를 더 유연하게 만들 수 있습니다.

17. this의 사용

필드명과 매개변수명이 같은 경우, 초기화할 필드에 this 키워드를 사용하여 현재 객체의 필드임을 명시할 수 있습니다. this는 현재 객체를 가리키는 참조 변수로, 해당 객체의 멤버에 접근할 때 사용됩니다.

public class MyClass {
    // 필드 선언
    int myField;

    // 생성자 선언
    public MyClass(int myField) {
        // this를 사용하여 필드 초기화
        this.myField = myField;
    }

    // 메서드 선언
    public void printMyField() {
        // this를 사용하여 필드 값 출력
        System.out.println("myField: " + this.myField);
    }

    public static void main(String[] args) {
        // 객체 생성 시 생성자를 통해 필드 초기화
        MyClass myObject = new MyClass(42);

        // 메서드 호출을 통해 필드 값 출력
        myObject.printMyField();  // 출력: myField: 42
    }
}

this.myField를 사용하면 필드명과 매개변수명이 같을 때도 명확하게 현재 객체의 필드를 참조할 수 있습니다. 이는 코드의 가독성을 높이고 혼동을 방지하는 데 도움이 됩니다.

18. 생성자의 오버로딩

생성자 오버로딩은 같은 클래스 내에서 동일한 이름의 생성자를 여러 개 정의하는 것을 의미합니다. 각 생성자는 서로 다른 매개변수를 가지고 있어야 합니다. 이렇게 함으로써 동일한 생성자 이름을 가지면서 다양한 매개변수 조합을 통해 객체를 초기화할 수 있습니다.

생성자 오버로딩을 사용하면 객체를 다양한 방식으로 초기화할 수 있어 편리합니다. 예를 들어, 기본 생성자와 매개변수를 받는 생성자를 함께 정의할 수 있습니다.

public class MyClass {
    // 필드 선언
    int myField;

    // 기본 생성자
    public MyClass() {
        this.myField = 0;
    }

    // 매개변수를 받는 생성자 (생성자 오버로딩)
    public MyClass(int myField) {
        this.myField = myField;
    }

    // 메서드 선언
    public void printMyField() {
        System.out.println("myField: " + this.myField);
    }

    public static void main(String[] args) {
        // 생성자 오버로딩을 통해 객체 생성
        MyClass object1 = new MyClass();          // 기본 생성자 호출
        MyClass object2 = new MyClass(42);        // 매개변수를 받는 생성자 호출

        // 메서드 호출을 통해 필드 값 출력
        object1.printMyField();  // 출력: myField: 0
        object2.printMyField();  // 출력: myField: 42
    }
}

19. 생성자의 유지보수성

생성자 오버로딩이 많아질 경우 중복된 코드를 최소화하고 유지보수성을 높이기 위해 공통 코드를 한 생성자에 집중적으로 작성하는 것이 좋습니다. 이때 this(...)를 사용하여 다른 생성자를 호출할 수 있습니다.

public class MyClass {
    // 필드 선언
    int myField;

    // 기본 생성자
    public MyClass() {
        // 공통 코드 호출
        this(0);
    }

    // 매개변수를 받는 생성자 (생성자 오버로딩)
    public MyClass(int myField) {
        // 공통 코드
        this.myField = myField;
    }

    // 메서드 선언
    public void printMyField() {
        System.out.println("myField: " + this.myField);
    }

    public static void main(String[] args) {
        // 생성자 오버로딩을 통해 객체 생성
        MyClass object1 = new MyClass();          // 기본 생성자 호출
        MyClass object2 = new MyClass(42);        // 매개변수를 받는 생성자 호출

        // 메서드 호출을 통해 필드 값 출력
        object1.printMyField();  // 출력: myField: 0
        object2.printMyField();  // 출력: myField: 42
    }
}

20. 메서드 선언

  • 리턴타입: 메서드가 반환하는 값의 데이터 타입을 나타냅니다. 만약 메서드가 어떤 값을 반환하지 않는다면 void로 지정합니다.
  • 메서드명: 메서드의 이름입니다. 다른 부분에서 메서드를 호출할 때 사용됩니다.
  • 매개변수: 메서드가 받는 입력 값들을 나타냅니다. 메서드를 호출할 때 이에 해당하는 값들을 전달합니다.
  • 실행 블록: 중괄호 {} 안에 메서드가 수행할 동작을 정의합니다.
public class MyClass {
    // 메서드 선언
    public int addNumbers(int a, int b) {
        // 실행 블록
        // 두 정수를 더한 값을 반환
        return a + b;
    }

    public static void main(String[] args) {
        // 객체 생성
        MyClass myObject = new MyClass();

        // 메서드 호출
        int result = myObject.addNumbers(3, 5);

        // 결과 출력
        System.out.println("Result: " + result);  // 출력: Result: 8
    }
}

21. return 값

메서드의 리턴타입이 void가 아닌 경우, 메서드의 실행 블록 안에서 반드시 return 키워드를 사용하여 해당 리턴타입에 맞는 값을 반환해야 합니다. return 문을 통해 메서드의 실행이 종료되고, 그 값을 호출한 부분으로 반환됩니다.

public class MyClass {
    // 메서드 선언
    public int addNumbers(int a, int b) {
        // 실행 블록
        // 두 정수를 더한 값을 반환
        return a + b;
    }

    public static void main(String[] args) {
        // 객체 생성
        MyClass myObject = new MyClass();

        // 메서드 호출
        int result = myObject.addNumbers(3, 5);

        // 결과 출력
        System.out.println("Result: " + result);  // 출력: Result: 8
    }
}

22. 메서드와 캐멀스타일

자바에서는 메서드명을 작성할 때 주로 캐멀 케이스(camelCase) 규칙을 따릅니다. 캐멀 케이스는 여러 단어로 이루어진 식별자에서 각 단어의 첫 글자를 대문자로 표기하고, 나머지는 소문자로 표기하는 규칙입니다.

public class CamelCaseExample {
    // 메서드 선언
    public void calculateTotalAmount(int quantity, double price) {
        // 실행 블록
        // 메서드가 수행할 동작을 정의
        double totalAmount = quantity * price;
        System.out.println("Total Amount: " + totalAmount);
    }

    public static void main(String[] args) {
        // 객체 생성
        CamelCaseExample exampleObject = new CamelCaseExample();

        // 메서드 호출
        exampleObject.calculateTotalAmount(5, 10.5);
    }
}

23. 가변길이 매개변수

가변길이 매개변수(variable-length parameter)는 메서드가 동적으로 변하는 매개변수의 개수를 처리할 수 있도록 하는 기능입니다. 이를 통해 메서드 호출 시 필요한 개수의 매개변수를 전달할 수 있습니다.
메서드선언에서 매개변수 타입 뒤에 ...을 붙여서 사용합니다. 이 가변길이 매개변수는 메서드 내부에서 배열로 처리됩니다.

public class VarargsExample {
    // 가변길이 매개변수를 사용한 메서드
    public void printNumbers(int... numbers) {
        System.out.println("Number of arguments: " + numbers.length);

        // 가변길이 매개변수는 배열로 처리되므로 반복문을 통해 접근 가능
        for (int number : numbers) {
            System.out.print(number + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        // 객체 생성
        VarargsExample exampleObject = new VarargsExample();

        // 가변길이 매개변수를 사용한 메서드 호출
        exampleObject.printNumbers(1, 2, 3);
        exampleObject.printNumbers(10, 20, 30, 40, 50);
    }
}

24. 리턴문 이후의 실행문

return문은 메서드의 실행을 강제로 종료하고, 메서드를 호출한 곳으로 돌아가게 합니다. return문 이후에 나오는 실행문들은 실행되지 않습니다.

return문은 메서드가 값을 반환할 때 사용되기도 하며, 메서드가 void 타입이라면 단순히 메서드의 실행을 종료시킵니다. 반환값이 있는 메서드에서 return문을 사용할 때는 해당 반환값의 타입과 일치하는 값을 지정해야 합니다.

public class ReturnExample {
    // 반환값이 있는 메서드
    public int addNumbers(int a, int b) {
        int sum = a + b;

        // 반환문
        return sum;

        // 반환문 이후의 실행문은 실행되지 않음
        // 아래의 코드는 도달할 수 없는 코드로 컴파일러 오류 발생
        // System.out.println("This line will not be executed.");
    }

    public static void main(String[] args) {
        // 객체 생성
        ReturnExample exampleObject = new ReturnExample();

        // 메서드 호출과 반환값 사용
        int result = exampleObject.addNumbers(3, 5);

        // 결과 출력
        System.out.println("Result: " + result);  // 출력: Result: 8
    }
}

이 코드에서 addNumbers 메서드는 두 정수를 더한 값을 반환하고 있습니다. return sum; 문을 통해 메서드가 실행되고 값을 반환한 후, 호출한 곳으로 돌아갑니다. 이후에 있는 코드는 실행되지 않습니다.

return문은 메서드의 실행 흐름을 제어하고, 값을 반환하여 메서드 호출자에게 결과를 전달하는 중요한 역할을 합니다.

25. 인스턴스 멤버와 정적 멤버

필드(멤버 변수)와 메서드는 선언 방법에 따라 인스턴스 멤버와 정적 멤버로 분류됩니다.

  1. 인스턴스 멤버(Instance Member):
    • 필드: 객체(인스턴스)가 생성될 때마다 각 객체마다 별도의 메모리 공간에 할당되는 멤버 변수입니다. 즉, 객체마다 각각의 값을 가지며, 객체 생성 후에 사용할 수 있습니다.
    • 메서드: 객체(인스턴스)에 속한 메서드로, 객체가 생성된 후에 호출하여 사용할 수 있습니다.
public class MyClass {
    // 인스턴스 멤버 - 필드
    int instanceField;

    // 인스턴스 멤버 - 메서드
    public void instanceMethod() {
        // 메서드 내용
    }

    public static void main(String[] args) {
        // 객체 생성
        MyClass myObject = new MyClass();

        // 인스턴스 멤버 사용
        myObject.instanceField = 10;
        myObject.instanceMethod();
    }
}
  1. 정적 멤버(Static Member):
    • 정적 필드(static field): 모든 객체가 공유하는 공통된 메모리 공간에 할당되는 멤버 변수입니다. 객체 생성 없이도 사용할 수 있습니다.
    • 정적 메서드(static method): 객체와 무관하게 클래스에 속한 메서드로, 객체 생성 없이도 호출하여 사용할 수 있습니다.
public class MyClass {
    // 정적 멤버 - 정적 필드
    static int staticField;

    // 정적 멤버 - 정적 메서드
    public static void staticMethod() {
        // 메서드 내용
    }

    public static void main(String[] args) {
        // 정적 멤버 사용
        staticField = 20;
        staticMethod();
    }
}

26. 정적 메서드

정적 메서드(static method)와 정적 초기화 블록(static block)은 클래스의 인스턴스에 속하지 않고 클래스 자체에 속하므로, 객체 생성 없이도 호출되는 특징이 있습니다. 이로 인해 정적 메서드나 정적 초기화 블록 내부에서는 인스턴스 필드나 인스턴스 메서드를 직접적으로 사용할 수 없습니다.

public class MyClass {
    // 정적 멤버 - 정적 필드
    static int staticField;

    // 정적 멤버 - 정적 메서드
    public static void staticMethod() {
        // 여기에서는 인스턴스 필드나 메서드를 직접 사용할 수 없음
        // this.instanceField = 10;  // 오류: 정적 메서드에서는 인스턴스 필드 사용 불가
        // instanceMethod();         // 오류: 정적 메서드에서는 인스턴스 메서드 호출 불가

        // 정적 필드 사용은 가능
        staticField = 20;
    }

    // 정적 초기화 블록
    static {
        // 여기에서도 인스턴스 필드나 메서드를 직접 사용할 수 없음
        // this.instanceField = 10;  // 오류: 정적 초기화 블록에서는 인스턴스 필드 사용 불가
        // instanceMethod();         // 오류: 정적 초기화 블록에서는 인스턴스 메서드 호출 불가

        // 정적 필드 사용은 가능
        staticField = 30;
    }

    // 인스턴스 멤버 - 필드
    int instanceField;

    // 인스턴스 멤버 - 메서드
    public void instanceMethod() {
        // 인스턴스 메서드 내에서는 정적 멤버와 인스턴스 멤버를 모두 사용 가능
        staticField = 40;
        instanceField = 50;
        staticMethod();
    }
}

27. final의 특성

final 키워드는 변수, 메서드, 클래스 등에 사용되어 해당 요소에 대한 변경이 불가능하도록 지정합니다.

  1. 변수에 사용하는 경우:

    • final 변수는 상수로 취급되며, 한 번 초기화되면 값을 변경할 수 없습니다.
    final int MY_CONSTANT = 10;
    // MY_CONSTANT = 20; // 오류: final 변수는 값을 변경할 수 없음
  2. 메서드에 사용하는 경우:

    • final 메서드는 하위 클래스에서 오버라이드(재정의)할 수 없습니다.
    public class Parent {
        public final void finalMethod() {
            // 메서드 내용
        }
    }
    
    public class Child extends Parent {
        // 오류: final 메서드를 오버라이드할 수 없음
        // public void finalMethod() {
        //     // 메서드 내용
        // }
    }
  3. 클래스에 사용하는 경우:

    • final 클래스는 다른 클래스에서 상속받을 수 없습니다.
    final class FinalClass {
        // 클래스 내용
    }
    
    // 오류: final 클래스를 상속받을 수 없음
    // class AnotherClass extends FinalClass {
    //     // 클래스 내용
    // }

28. 패키지 작성법

일반적으로 자바에서는 패키지를 만들 때 개발 회사의 도메인 이름을 역순으로 사용하는 것이 권장되는 관례입니다. 이렇게 하면 패키지 명이 고유하게 유지되어 충돌을 피하고, 패키지를 생성한 조직의 도메인 구조를 반영할 수 있습니다.

예를 들어, "com.example.myapp"와 같은 패키지 명을 사용하는 것이 일반적입니다. 이 경우, "com"은 상위 도메인을 나타내고, "example"은 도메인의 서브 도메인이며, "myapp"은 실제 패키지의 이름입니다. 이런 식으로 패키지를 구성하면 유사한 명명 규칙을 사용하는 여러 조직 간에 충돌을 방지할 수 있습니다.

이러한 관례는 패키지 명명 규칙을 일관되게 유지하고, 코드를 더 쉽게 이해하고 유지보수할 수 있도록 도와줍니다.

29. 접근제한자

접근 제한자(access modifier)는 클래스의 필드, 메서드, 생성자 등의 멤버에 대한 접근 권한을 지정하는 데 사용됩니다.

  1. public:

    • public으로 선언된 멤버는 모든 곳에서 접근 가능합니다. 다른 패키지에 속한 클래스에서도 접근이 가능합니다.
    public class MyClass {
        public int publicField;
        public void publicMethod() {
            // 메서드 내용
        }
    }
  2. protected:

    • protected로 선언된 멤버는 같은 패키지에 속한 클래스와 해당 클래스를 상속받은 클래스에서 접근 가능합니다.
    class MyClass {
        protected int protectedField;
        protected void protectedMethod() {
            // 메서드 내용
        }
    }
  3. private:

    • private으로 선언된 멤버는 같은 클래스 내에서만 접근 가능하며, 다른 클래스에서는 접근할 수 없습니다.
    public class MyClass {
        private int privateField;
        private void privateMethod() {
            // 메서드 내용
        }
    }

30. 생성자의 접근 제한자

생성자 또한 접근 제한자를 가질 수 있습니다.

  1. public:

    • public으로 선언된 생성자는 모든 곳에서 접근 가능합니다. 다른 패키지에서도 접근이 가능합니다.
    public class MyClass {
        // public 생성자
        public MyClass() {
            // 생성자 내용
        }
    }
  2. default (package-private):

    • 접근 제한자를 명시하지 않은 경우, 기본적으로 패키지 내에서만 접근이 가능한 생성자가 됩니다.
    class MyClass {
        // default 생성자 (패키지 내에서만 접근 가능)
        MyClass() {
            // 생성자 내용
        }
    }
  3. private:

    • private으로 선언된 생성자는 같은 클래스 내에서만 접근 가능합니다. 다른 클래스에서는 접근할 수 없습니다.
    public class MyClass {
        // private 생성자
        private MyClass() {
            // 생성자 내용
        }
    }

31. 필드와 메서드

필드와 메서드도 생성자와 마찬가지로 접근 제한자를 가질 수 있습니다.

  1. public:

    • public으로 선언된 필드 또는 메서드는 모든 곳에서 접근 가능합니다. 다른 패키지에서도 접근이 가능합니다.
    public class MyClass {
        // public 필드
        public int publicField;
    
        // public 메서드
        public void publicMethod() {
            // 메서드 내용
        }
    }
  2. default (package-private):

    • 접근 제한자를 명시하지 않은 경우, 기본적으로 패키지 내에서만 접근 가능한 멤버가 됩니다.
    class MyClass {
        // default (package-private) 필드
        int defaultField;
    
        // default (package-private) 메서드
        void defaultMethod() {
            // 메서드 내용
        }
    }
  3. private:

    • private으로 선언된 필드 또는 메서드는 같은 클래스 내에서만 접근 가능합니다. 다른 클래스에서는 직접 접근할 수 없습니다.
    public class MyClass {
        // private 필드
        private int privateField;
    
        // private 메서드
        private void privateMethod() {
            // 메서드 내용
        }
    }

이러한 접근 제한자를 사용하여 객체의 필드와 메서드에 대한 접근을 제어할 수 있습니다. 정보 은닉과 캡슐화를 통해 객체의 내부를 보호하고, 외부로부터의 불필요한 접근을 방지하는 데 도움이 됩니다.

32. getter와 setter

객체지향 프로그래밍에서는 정보 은닉(Encapsulation)의 원칙에 따라 직접적인 필드 접근을 피하고, 대신 메서드를 통해 필드에 접근하는 것을 선호합니다. 이때 사용되는 메서드가 바로 getter와 setter입니다.

  1. Getter (접근자 메서드):

    • 필드의 값을 외부로 반환하는 메서드입니다.
    • 일반적으로 필드 이름 앞에 "get"을 붙여서 메서드 이름을 지정합니다.
    public class MyClass {
        private int myField;
    
        // Getter 메서드
        public int getMyField() {
            return myField;
        }
    }
  2. Setter (설정자 메서드):

    • 필드의 값을 외부에서 설정하는 메서드입니다.
    • 일반적으로 필드 이름 앞에 "set"을 붙여서 메서드 이름을 지정하며, 매개변수를 통해 설정할 값을 전달합니다.
    public class MyClass {
        private int myField;
    
        // Setter 메서드
        public void setMyField(int value) {
            myField = value;
        }
    }

33. 싱글톤

싱글톤 패턴(Singleton Pattern)은 디자인 패턴 중 하나로, 특정 클래스가 단 하나의 인스턴스를 가지고 이에 대한 전역적인 접근을 제공하는 패턴입니다. 이를 구현하기 위해 생성자를 private으로 선언하고, 유일한 인스턴스를 반환하는 메소드를 제공하여 외부에서는 해당 클래스의 객체를 직접적으로 생성하지 못하도록 합니다.

일반적으로 싱글톤 패턴은 다음과 같은 형태를 가집니다:

public class Singleton {
    // 유일한 인스턴스를 저장하는 private 정적 변수
    private static Singleton instance;

    // private 생성자
    private Singleton() {
        // 생성자 내용
    }

    // 유일한 인스턴스를 반환하는 public 정적 메소드
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

위의 예제에서 Singleton 클래스는 생성자를 private으로 선언하여 외부에서 객체를 직접 생성할 수 없도록 하고, getInstance 메소드를 통해 유일한 인스턴스를 반환하도록 합니다. 또한, 이 구현은 초기화된 인스턴스가 없을 경우에만 생성하여 메모리를 절약하는 방식입니다.

이렇게 구현된 싱글톤 패턴은 전역 상태의 유일한 인스턴스를 제공하여, 특정한 상황에서 하나의 객체만을 필요로 할 때 사용됩니다.

profile
터널을 지나고 있을 뿐, 길은 여전히 열려 있다.

0개의 댓글