코드스테이츠 백엔드 부트캠프 10일차 [객체지향 프로그래밍 기초-2]

wish17·2022년 12월 27일
0
post-thumbnail

Section1 - [Java] 객체지향 프로그래밍 기초

생성자(Constructor)

앞서 다뤘던 new 키워드를 사용하여 객체를 생성할 때에 호출되는 것

%주의%

  • 인스턴스 생성은 new키워드가 하는거다. (생성자가 하는거X)
  • 생성자는 인스턴스 변수들을 초기화하는 데 사용되는 특수한 메서드

메서드와 구조는 비슷하지만 아래와 같은 차이가 있다.

  • 생성자의 이름은 반드시 클래스의 이름과 같아야 한다.
  • 생성자는 리턴 타입이 없다.
public class ConstructorExample {
    public static void main(String[] args) {
        Constructor constructor1 = new Constructor();
        Constructor constructor2 = new Constructor("Hello World");
        Constructor constructor3 = new Constructor(5,10);
    }
}

class Constructor {
    Constructor() { // (1) 생성자 오버로딩
        System.out.println("1번 생성자");
    }

    Constructor(String str) { // (2) 
        System.out.println("2번 생성자");
    }

    Constructor(int a, int b) { // (3) 
        System.out.println("3번 생성자");
    }
}

위와 같이 생성자도 오버로딩이 가능하다.


기본 생성자 vs 매개변수가 있는 생성자

기본 생성자(Default Constructor)

매개변수가 없는 생성자

클래스명(){} //기본 생성자

DefaultConst(){} // 예시) DefaultConst 클래스의 기본 생성자

모든 클래스에는 반드시 하나 이상의 생성자가 존재해야 하는데 만약 생성자가 클래스 안에 포함되어 있지 않은 경우에는 자바 컴파일러가 기본 생성자를 자동으로 추가한다.


매개변수가 있는 생성자

매개변수가 있는 생성자는 메서드처럼 매개변수를 통해 호출 시에 해당 값을 받아 인스턴스를 초기화하는 데 사용한다.

고유한 특성을 가진 인스턴스를 계속 만들어야하는 경우 인스턴스마다 각기 다른 값을 가지고 초기화할 수 있어서 매우 유용하다.


this vs this()

this()

자신이 속한 클래스에서 다른 생성자를 호출하는 경우에 사용

  • 반드시 생성자의 내부에서만 사용할 수 있다.
  • 반드시 생성자의 첫 줄에 위치해야 한다.
public class Test {
    public static void main(String[] args) {
        Example example = new Example();
        Example example2 = new Example(5);
    }
}

class Example  {
    public Example() {
        System.out.println("Example의 기본 생성자 호출!");
    };

    public Example(int x) {
        this();
        System.out.println("Example의 두 번째 생성자 호출!");
    }
}

//Output
Example의 기본 생성자 호출!
Example의 기본 생성자 호출!
Example의 두 번째 생성자 호출!

this 키워드

  • 인스턴스 변수와 매개변수를 구분해주기 위한 용도로 주로 사용
  • this는 인스턴스 자신을 가리키며, 우리가 참조변수를 통해 인스턴스의 멤버에 접근할 수 있는 것처럼 this를 통해서 인스턴스 자신의 변수에 접근할 수 있는 것이다.
public class ConstructorExample {
    public static void main(String[] args) {
        Car car = new Car("Model X", "빨간색", 250);
        System.out.println("제 차는 " + car.getModelName() + "이고, 컬러는 " +  car.getColor() + "입니다.");
    }
}

class Car {
    private String modelName;
    private String color;
    private int maxSpeed;

    public Car(String modelName, String color, int maxSpeed) {
        this.modelName = modelName;
      // 인스턴스 변수   =  지역변수(?)
        this.color = color;
        this.maxSpeed = maxSpeed;
    }

    public String getModelName() {
        return modelName;
    }

    public String getColor() {
        return color;
    }
}

//Output
제 차는 Model X이고, 컬러는 빨간색입니다.

만약 this.modelName = modelName 대신 modelName = modelName 라고 작성하면 둘 다 지역변수로 간주된다.

일반적으로 컴파일러가 this.를 추가해주기 때문에 생략하는 경우가 많다.
ex) Car 클래스의 modelName이라는 인스턴스 필드를 클래스 내부에 출력하고자 한다면 원래는 stem.out.println(this.modelName)이런 방식으로 작성해야 한다.

이해가 잘 안돼서 디버깅 해봤다.

!!!주의!!!
디버깅 할때 좌항 우항기준으로 위 사진처럼 나오는게 아니다!!
위 경우 좌항과 우항에 할당된 값이 반대로 나오니 착각 ㄴㄴ

위와 같이 인스턴스 생성 때 할당받은 Name을 메서드로 가져와 지역변수에 할당해주는 것 같다. 여기서 this는 인스턴스 변수를 지역변수와 연결해주기 위해 사용 된 것 같다.


내부 클래스(Inner Class)

클래스 내에 선언된 클래스
(외부 클래스와 내부 클래스가 서로 연관되어 있을 때 사용)

  class Outer { // 외부 클래스

      class Inner {
          // 인스턴스 내부 클래스	
      }

      static class StaticInner {
          // 정적 내부 클래스
      }

      void run() {
          class LocalInner {
          // 지역 내부 클래스
      	  }
      }
   } 
종 류선언 위치사용 가능한 변수
인스턴스 내부 클래스(instance inner class)외부 클래스의 멤버변수 선언위치에 선언(멤버 내부 클래스)외부 인스턴스 변수, 외부 전역 변수
정적 내부 클래스(static inner class)외부 클래스의 멤버변수 선언위치에 선언(멤버 내부 클래스)외부 전역 변수
지역 내부 클래스(local inner class)외부 클래스의 메서드나 초기화블럭 안에 선언외부 인스턴스 변수, 외부 전역 변수
익명 내부 클래스(anonymous inner class)클래스의 선언과 객체의 생성을 동시에 하는 일회용 익명 클래스외부 인스턴스 변수, 외부 전역 변수

익명 내부 클래스도 있지만, 우선순위가 낮아 자세한 설명은 생략했다.


멤버 내부 클래스

인스턴스 내부 클래스와 정적 내부클래스를 하나로 묶어 멤버 내부 클래스라 통칭한다.

인스턴스 내부 클래스

객체 내부에 멤버의 형태로 존재하며, 외부 클래스의 모든 접근 지정자의 멤버에 접근할 수 있다.

class Outer { //외부 클래스
    private int num = 1; //외부 클래스 인스턴스 변수
    private static int sNum = 2; // 외부 클래스 정적 변수

    private InClass inClass; // 내부 클래스 자료형 변수 선언

    public Outer() {
        inClass = new InClass(); //외부 클래스 생성자
    }

    class InClass { //인스턴스 내부 클래스
        int inNum = 10; //내부 클래스의 인스턴스 변수

        void Test() {
            System.out.println("Outer num = " + num + "(외부 클래스의 인스턴스 변수)");
            System.out.println("Outer sNum = " + sNum + "(외부 클래스의 정적 변수)");
        }
    }

    public void testClass() { // 외부클래스 메소드
        inClass.Test(); // 내부클래스 메소드 호출
    }
}

public class Main {
    public static void main(String[] args) {
        Outer outer = new Outer();
        System.out.println("외부 클래스 사용하여 내부 클래스 기능 호출");
        outer.testClass(); // 내부 클래스 기능 호출
    }
}

// 출력값

외부 클래스 사용하여 내부 클래스 기능 호출
Outer num = 1(외부 클래스의 인스턴스 변수)
Outer sNum = 2(외부 클래스의 정적 변수)

위에서 인스턴스 내부클래스는 private 접근 제어자(해당 클래스 안에서만 접근 가능한 멤버에 사용)를 사용하고 있음에도 내부에서 외부 클래스의 인스턴스 변수와 정적 변수에 각각 접근하여 해당 값을 사용하고 있다.

정적 변수와 정적 메서드는 인스턴스 내부 클래스에서 선언할 수 없다.

정적 내부 클래스

  • 인스턴스 내부 클래스와 동일하게 클래스의 멤버 변수 위치에 정의하지만, static 키워드를 사용한다는 점에서 차이가 있다

  • 정적 내부 클래스는 외부 클래스의 존재와 무관하게 정적 변수를 사용할 수 있다. (생성자 필요 없음)

class Outer { //외부 클래스
    private int num = 3; //내부 클래스의 인스턴스 변수
    private static int sNum = 4;

    void getPrint() {
        System.out.println("인스턴스 메서드");
    }

    static void getPrintStatic() {
        System.out.println("스태틱 메서드");
    }

    static class StaticInClass { // 정적 내부 클래스
        void test() {
            System.out.println("Outer num = " +sNum + "(외부 클래스의 정적 변수)");
            getPrintStatic();
            // num 과 getPrint() 는 정적 멤버가 아니라 사용 불가.
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Outer.StaticInClass a = new Outer.StaticInClass(); //정적 이너 클래스의 객체 생성
        a.test();
    }
}

//출력값
Outer num = 4(외부 클래스의 정적 변수)
스태틱 메서드

지역 내부 클래스

메서드 내부에서만 사용가능하기 때문에 일반적으로 메서드 안에서 선언 후 바로 객체를 생성해서 사용한다.

class Outer { //외부 클래스
    int num = 5; //인스턴스변수
    void test() {  // 메소드 선언
        int num2 = 6; //지역변수
        class LocalInClass { //지역 내부 클래스
            void getPrint() { // 메소드 선언
                System.out.println(num);
                System.out.println(num2);
            }
        }
        LocalInClass localInClass = new LocalInClass(); // 객체 생성
        localInClass.getPrint();
    }
}
public class Main {
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.test();
    }
}

//출력값
5
6

오늘의 정리

생성자가 메서드와 구분되는 두 가지 차이

  • 생성자의 이름은 반드시 클래스의 이름과 같아야 함
  • 생성자는 리턴 타입이 없음

this 와 this() 의 차이에 대해 설명할 수 있다.

  • this는 자신(인스턴스)을 가리켜 자신의 변수에 접근할 수 있게 해주는거고
  • this() 메서드는 다른 생성자를 호출하는 거

내부 클래스의 기본 개념과 장점

  • 클래스 내에 선언된 클래스
  • 외부적으로 불필요한 데이터를 감출 수 있어 캡슐화(encapsulation)를 달성하는 데 유용(외부 클래스와 내부 클래스가 서로 연관되어 있을 때 편의성을 챙길 수 있다.)

선언 위치에 따른 내부 클래스의 종류, 특징, 유효 범위, 접근성

외부 클래스 내에 존재하는 내부 클래스는 메소드 안에 쓰는 지녁 내부 클래스와 메소드 밖에 쓰는 멤버 내부 클래스가 있다.

  • 멤버 내부 클래스
    • 인스턴스 내부 클래스 => 외부 클래스에 생성자를 만들어서 써야 함
    • 정적 내부 클래스 => 생성자 없이도 외부 클래스에서 마음대로 꺼내 쓸 수 있다. (단, 인스턴스 변수는 정적 내부 클래스 안으로 들어갈 수 없으니 외부 클래스에 있는 static변수만 가져다 쓸 수 있다.)
  • 지역 내부 클래스 => 메서드 내부에서만 사양가능, 일반적으로 메서드 안에서 선언 후에 바로 객체를 생성해서 사용

내부 클래스 규칙

    1. 내부 클래스를 기준으로, 외부 클래스의 멤버를 참조할 때 적용되는 규칙
    • static 내부클래스는 외부클래스 인스턴스 멤버 참조 불가능
    1. 내부 클래스를 기준으로, 내부 클래스 자신의 멤버를 선언할 때 적용되는 규칙
    • 인스턴스 내부 클래스, 지역 내부 클래스에서는 스태틱 멤버를 선언 할 수 없다.
    • static 내부 클래스에서만 static 멤버를 선언 할 수 있다.(cf. 자바17부터는 이 규칙이 사라짐)

객체(object), 인스턴스(instance) 차이

클래스란 객체를 정의하고 만들어 내기 위한 설계도 혹은 틀을 말한다. 클래스 안에는 객체를 만들어내기 위해 필요한 변수와 메서드들이 존재한다.

객체란 클래스에 선언된 모양 그대로 생성된 실체를 말하며 '클래스의 인스턴스'라고 부른다.

인스턴스란 클래스를 통해서 구현해야할 대상(객체)이 실제로 구현된 구체적인 실체를 말한다.

예를들어 붕어빵을 만든다고 상황을 가정해보자. 여기서 클래스는 붕어빵을 만들기 위한 틀이 되고 객체는 붕어빵이다. 그리고 인스턴스는 붕어빵 틀로 찍어낸 각각의 붕어빵이다.

팥붕어빵과 슈크림붕어빵은 같은 타입의 객체이지만, 인스턴스 관점으로 보았을 때는 다르다.

이렇게 엄연히 따지면 다르지만 문법적으로 다르다고 할 수는 없다.


0개의 댓글