본문 바로가기

카테고리 없음

[코드스테이츠 BE 45기] <Section1> Week3 (객체지향 프로그래밍 기초2)

생성자

: 객체를 생성하는 역할을 하는 클래스의 구성 요소로서, 인스턴스가 생성될 때 호출되는 인스턴스 초기화 메서드

인스턴스 생성을 담당하는 것은 new 키워드

생성자는 인스턴스 변수들을 초기화하는 데 사용되는 특수한 메서드

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

1 생성자의 이름은 반드시 클래스의 이름과 같아야 함. 클래스 이름과 생성자의 이름이 다르다면 그 메서드는 더 이상 생성자로서의 기능을 수행할 수 없음.

2 생성자는 리턴 타입이 없음.

생성자는 리턴 타입 자체가 존재하지 않기 때문에 무언가를 ‘리턴하지 않는다’ 는 의미를 가진 리턴 값이 없을 때 표시하는 void 키워드를 사용하지 않음.

클래스명(매개변수) { // 생성자 기본 구조
	...생략...
}

• 클래스명과 같은 이름의 생성자명을 작성해 주고 리턴 타입이 없기 때문에 리턴 타입에는 아무것도 적지 않음 (매개변수는 있을 수도 있고 없을 수도 있음)

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번 생성자");
    }
}

• 한 클래스 내에 여러 개의 생성자가 존재할 수 있음 (생성자도 오버로딩이 가능)

• 생성자의 모양에 따라서 객체를 생성하는 방법이 결정됨

(2) 번 생성자를 호출하기 위해서는 객체 생성 시에 문자열을 전달해주어야 함

(3) 번 생성자를 위해서는 두 개의 int형 매개변수를 전달해주어야 함
class Car {
    public String model;
    public String color;

    public Car(){} // 기본생성자. 생성자가 없는 경우 자동 생성

		// 생성자 오버로딩
    public Car(String model, String color) { // 매개변수가 있는 생성자
        this.model = model;
        this.color = color;
    }

    void power() {
        System.out.println("시동을 걸었습니다.");
    }

    void accelerate() {
        System.out.println("더 빠르게!");
    }

    void stop(){
        System.out.println("멈춤");
    }
}

//Output
내 차의 모델은 Model 3이고 색은 빨강입니다.
시동을 걸었습니다.
더 빠르게!
멈춤

• Car 클래스에는 두 개의 생성자가 정의되어 있음

하나는 매개변수가 없는 기본 생성자

다른 하나는 model과 color라는 두 가지의 매개변수를 받고 있는 생성자

• 두 개 이상의 생성자를 정의할 수 있는 이유는 자바가 오버로딩을 지원하기 때문

메서드 오버로딩

매개변수의 타입, 속성, 개수가 다르면 메서드 이름이 달라도 됨

호출할 때는 매개변수로 확인

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

1 기본 생성자(Default Constructor)

모든 클래스에는 반드시 하나 이상의 생성자가 존재해야 함

생성자를 따로 만들지 않아도 정상적으로 인스턴스를 만들 수 있었던 이유는 만약 생성자가 클래스 안에 포함되어 있지 않은 경우에는 자바 컴파일러가 기본 생성자를 자동으로 추가해 줬기 때문

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

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

2 매개변수가 있는 생성자

메서드처럼 매개변수를 통해 호출 시에 해당 값을 받아 인스턴스를 초기화하는 데 사용됨

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

public class ConstructorExample {
    public static void main(String[] args) {
        Car c = new Car("Model X", "빨간색", 250);
        System.out.println("제 차는 " + c.getModelName() + "이고, 컬러는 " +  c.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이고, 컬러는 빨간색입니다.

• car 인스턴스를 생성 시 매개변수가 있는 생성자를 사용하게 되면 인스턴스를 만든 후에 인스턴스의 필드값을 일일이 설정해 줄 필요 없이 생성과 동시에 원하는 값으로 설정해 줄 수 있음

• 생성자의 모양에 따라서 객체를 생성하는 방법도 달라지게 됨

-기본 생성자: 매개변수가 없었기 때문에 원래 우리가 객체를 생성하던 방식으로 new 키워드와 생성자를 호출

-매개변수가 있는 생성자: 그 개수와 타입에 알맞게 생성자를 호출

this vs this()

1 this()

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

예) 클래스명이 Car라는 Car 클래스의 생성자를 호출하는 것은 Car()가 아니라 this()이고, 그 효과는 Car() 생성자를 호출하는 것과 동일

  • this() 메서드를 사용하기 위해서 충족시켜야 할 두 가지 문법요소

1 this() 메서드는 반드시 생성자의 내부에서만 사용할 수 있음

2 this() 메서드는 반드시 생성자의 첫 줄에 위치해야 함

public class Test {
    public static void main(String[] args) {
        Example example = new Example();  **// 매개변수가 필요하지 않은 기본 생성자**
        Example example2 = new Example(5);  **// int 타입의 매개변수를 받고 있는 생성자**
    }
}

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

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

//Output
Example의 기본 생성자 호출!  **// 첫 번째 생성자 호출**
Example의 기본 생성자 호출!  **// 두 번째 생성자의 this() 메서드가 출력되어 다시 첫 번째 기본생성자가 호출됨**
Example의 두 번째 생성자 호출!  **// 두 번째 생성자 호출**

2 this 키워드

this는 인스턴스 자신을 가리키며, 참조변수를 통해 인스턴스의 멤버에 접근할 수 있는 것처럼 this를 통해서 인스턴스 자신의 변수에 접근할 수 있음

• 주로 인스턴스의 필드명과 지역변수를 구분하기 위한 용도로 사용됨

예) color = color 가 아닌 this.color = color

• this 키워드를 사용하는 이유

: 인스턴스 변수가 선언되어 있는 동시에 생성자의 매개변수로 정의되어 있는 경우,

인스턴스 변수와 매개변수를 이름만으로는 구분하기가 어려워지는 문제가 발생하게 되는데, 이를 구분해 주기 위한 용도로 주로 사용

public class ConstructorExample {
    public static void main(String[] args) {
        Car car = new Car("Model X", "빨간색", 250);
        System.out.println("제 차는 " + car.getModelName() + "이고, 컬러는 " +  car.getColor() + "입니다.");
    }
}

**// 인스턴스 변수로 modelName, color, 그리고 maxSpeed가 선언**
class Car {
    private String modelName;
    private String color;
    private int maxSpeed;

**// ()안에 생성자의 매개변수로 modelName, color, maxSpeed 정의**
    public Car(String modelName, String color, int maxSpeed) { 
        this.modelName = modelName;  **// this 키워드**
        this.color = color;  **//this.color = color 대신 color = color 라고 작성하면 둘 다 지역변수로 간주되게 됨**
        this.maxSpeed = maxSpeed;
    }

    public String getModelName() {
        return modelName;
    }

    public String getColor() {
        return color;
    }
}

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

• 모든 메서드에는 자신이 포함된 클래스의 객체를 가리키는 this라는 참조변수가 있는데, 일반적인 경우에는 컴파일러가 this. 를 추가해 주기 때문에 생략하는 경우가 많음

예) Car 클래스의 modelName이라는 인스턴스 필드를 클래스 내부에 출력하고자 한다면 원래는 System.out.println(this.modelName) 이런 방식으로 작성해주어야 함

내부 클래스

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

내부 클래스를 사용하면 외부 클래스의 멤버들에 쉽게 접근할 수 있고, 코드의 복잡성을 줄일 수 있음

외부적으로 불필요한 데이터를 감출 수 있어 뒤에서 학습하게 될 객체지향의 중요한 핵심 원칙인 캡슐화를 달성하는 데 유용

class Outer {  **// 외부 클래스**
	
	class Inner {
		**// 인스턴스 내부 클래스**	
	}
	
	static class StaticInner {
		**// 정적 내부 클래스**
	}

	void run() {
		class LocalInner {
		**// 지역 내부 클래스**
		}
	}
}

1 인스턴스 내부 클래스

객체 내부에 멤버의 형태로 존재

외부 클래스의 모든 접근 지정자의 멤버에 접근 가능

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 + "(외부 클래스의 정적 변수)");
**// private 접근 제어자를 사용하고 있음에도 내부에서 외부 클래스의 인스턴스 변수와 정적 변수에 각각 접근하여 해당 값 사용함 (*private 접근 제어자: 해당 클래스 안에서만 접근 가능한 멤버에 사용)**
        }
    }

    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(외부 클래스의 정적 변수)

2 정적 내부 클래스

내부 클래스가 외부 클래스의 존재와 무관하게 정적 변수를 사용할 수 있게 함

정적 내부 클래스는 인스턴스 내부 클래스와 동일하게 클래스의 멤버 변수 위치에 정의하지만, 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 {  **// 정적 내부 클래스 (static 키워드 사용)**
        void test() {
            System.out.println("Outer sNum = " +sNum + "(외부 클래스의 정적 변수)");
            getPrintStatic();
            // num 과 getPrint() 는 정적 멤버가 아니라 사용 불가.
        }
    }
}

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

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

3 지역 내부 클래스

클래스의 멤버가 아닌 메서드 내에서 정의되는 클래스

지역 변수와 유사하게 메서드 내부에서만 사용가능하기 때문에 일반적으로 메서드 안에서 선언 후에 바로 객체를 생성해서 사용

 

 

 

회고

오늘의 나는 지난 주의 나보다 집중력이 좋았다^^

오늘 내용을 다 받아들인 기분..

역시 똑같은 내용을 반복하는 것이 습득의 길인 듯 하다..