자바 기초 - 클래스 활용

지우·2023년 1월 6일
0

CNU SW 아카데미 2기

목록 보기
4/10

본격적으로 클래스 구성에 대해 파헤쳐보려고 한다. 마찬가지로 당장의 과제를 처리하기에 급급했던 나머지 개념을 두루뭉술하게 알고 있던 것이 많았던 것 같다. 오류가 나면 구글링해서 고치고 내고 고치고 내고 반복하다보니... 중요한 것을 놓치고 있었던 기분이 든다.



✔️객체와 오버로딩

💡this

클래스에서 객체 자신을 가리키는 키워드이다. 왜 굳이 자기 자신임을 알려야 하는 걸까? 처음엔 이런 궁금증이 들었던 것 같다.

가장 큰 이유는 우선순위 때문이다. 메소드나 생성자 내부에서는 매개변수가 가장 우선순위가 높고, 매개변수와 필드명이 동일한 경우 필드에 접근하지 못하는 문제가 생긴다. 또한 가독성의 문제도 있다.

public class Car {
	String name;
	int price;
	public Car(String name, int price) {
    	name = name; //접근 불가, 가독성 역시 좋지 않음!
        price = price;
    }
}

이러한 코드보다는, "필드에 매개변수를 대입한다"는 동작을 정확히 작성해주는 것이 좋다.

public class Car {
	String name;
	int price;
	public Car(String name, int price) {
    	this.name = name; //필드의 name을 매개변수 name으로 초기화!
        this.price = price;
    }
}

this를 사용하면 객체의 name, 즉 객체의 필드를 명확히 나타내고 매개변수와 구분지을 수 있다.

int getPrice() {
	return this.price;
}

이렇게 메소드를 작성하면 가독성 면에서 객체의 필드라는 것을 보여줄 수 있으므로 좋다.

💡오버로딩

메소드 오버로딩
이름이 같은 메소드를 여러 개 선언하는 것에 해당한다. 다양한 상황에 맞게 같은 동작을 수행할 수 있다.

  1. 동일한 메소드명
  2. 매개변수의 타입 or 개수가 달라야 한다. (리턴값은 상관 x)

위 조건에 해당해야 메소드 오버로딩에 해당한다.

//기존 메소드
int cal(int a){...}

//1. 매개변수의 타입이 다른 경우
String cal(String a){...}
//2. 매개변수의 개수가 다른 경우
int cal(int a, int b){...}
//3. 둘 다 다른 경우
int cal(String a, boolean b){...}

위 전부 오버로딩에 해당한다.

int cal (int a, int b) {
	return a + b;
}
String cal (String a, String b) {
	return a + b;
}

메소드 오버로딩을 하면 이처럼 다른 타입의 매개변수가 주어질 수 있는 상황에서 에러가 발생하지 않고 상황에 맞는 동작을 적절히 수행할 수 있다. 같은 동작이지만 이름이 다른 함수를 또 정의하면 헷갈리지만, 오버로딩으로 간단히 해결 가능하다.

생성자 오버로딩
생성자의 기능을 생각해보자. 생성자는 객체 생성 시 값들을 초기화하는 기능을 한다. 생성자를 오버로딩하면 매개변수가 없을 때, 하나만 있을 때, 등등... 다양한 케이스에 맞게 초기화하는 역할을 한다.

  1. 매개변수의 타입 or 개수가 달라야 한다. (생성자명은 통일, 리턴값은 없음)

매개변수에 의해 결정된다고 볼 수 있다.

public class Car {
	String name;
    int price;
    
    Car(String name) {
    	//this.name = name;
        //this.price = 500;
        this(name, 500);
    }
    Car(int price) {
    	//this.name = "없음";
        //this.price = price;
        this("없음", price);
    }
    Car(String name, int price) {
    	this.name = name;
        this.price = price;
    }
}

이처럼 어떤 필드만 초기화할지 선택할 수 있다.
주석 처리한 코드와 this( ... ) 코드는 같은 기능을 하지만 후자가 중복 코드를 줄여준다. this()는 생성자를 호출하는 기능이 있기 때문에 이 코드 속 가장 마지막 생성자를 호출한다. (괄호 속 매개변수 2개 = 마지막 생성자 매개변수 2개) 매개변수의 타입과 개수에 맞는 생성자를 호출한다고 보면 될 것 같다.

✔️인스턴스 or 정적 멤버

💡정의

인스턴스 : 클래스 → 객체 → 실체화한 것. 힙 메모리 영역에 객체가 생성된 것을 뜻하며, new 연산자를 사용하여 생성한다.

그렇다면 인스턴스 멤버란? 인스턴스에 속한 멤버이다. 클래스를 구체화한 것이 인스턴스이므로, 필드+메소드+생성자라 생각할 수 있겠지만 다른 개념이다. 정확히는 인스턴스 필드, 정적 필드 이런식...

비교를 위해 정적 멤버도 알아보자. static 키워드를 자주 보았을 것이다. 이러한 static이 붙은 멤버를 의미하며, 인스턴스에 속하지 않고 (= 객체를 생성하지 않고) 클래스에 고정된, static한 멤버를 의미한다. 정적 필드, 정적 메소드가 존재한다.

따라 인스턴스 멤버는 객체를 생성했을 때 할당된다는 것을 알 수 있다.

public class Car {
	/* 인스턴스 멤버 */
	String name; //인스턴스 필드
    void setName(String name) {
    	this.name = name;
    } //인스턴스 메소드
    
    /* 정적 멤버 */
    static int maxPrice = 1000; //정적 필드
    static int getMaxPrice() {
    	return maxPrice;
    } //정적 메소드
}

💡차이

  1. 메모리 영역
    인스턴스는 힙 메모리 영역에 객체가 생성된 것 이다. 따라 인스턴스 멤버 name, setName(String name) 역시 힙 메모리 영역에 각 객체별로 생성된다.
    하지만 정적 멤버는 static (정적) 메모리에 클래스 단위로 관리된다. 따라 한 번 할당되면 프로그램 종료 시까지 release 되지 않는다. 객체별로 할당된 것이 아니므로 어떤 객체에서도 정적 멤버를 공유하고 참조 가능하다.

  2. 호출 방법
    인스턴스 멤버는 객체를 생성한 뒤, 객체명.필드 or 객체명.메소드()처럼 호출한다.
    정적 멤버는 객체를 생성하지 않고, 클래스에 고정되어 있기 때문에 클래스명.필드 or 클래스명.메소드()로 호출한다. 객체 없이 클래스명으로 바로 호출하면 된다.

  3. 클래스 내부 접근
    클래스 내에서 인스턴스 멤버끼리, 정적 멤버끼리 접근은 가능하지만 교차 접근은 불가능하다. 정적 멤버에 접근하려면 클래스명.멤버 / 인스턴스 멤버에 접근하려면 new로 인스턴스를 생성해야한다.

정적 멤버는 인스턴스와 독립적인 존재이기 때문에, 주로 인스턴스에 영향을 받지 않는 기능을 구현할 때 사용한다.

💡final

맨 앞에 final을 추가하여 상수를 정의한다. 상수의 특징처럼 값을 한 번만 대입할 수 있고 이후 변경할 수 없다.

final 키워드는 상수, 즉 수정할 수 없는 최종 값을 정의하는 데 사용했다.

인스턴스 멤버로 선언하면 객체마다 final 필드를 갖게 된다.

final int MAX_PRICE;

선언만 한 다음, 생성자에서 매개변수를 받아 초기화할 수도 있다.


반면 정적 멤버로서 final 필드를 선언하면, 객체별로 존재하는 것이 아닌 클래스에 단 하나, 불변의 값이 된다. 즉 상수가 된다.

static final int MAX_PRICE = 1000;

인스턴스 멤버와 달리, static final 키워드를 작성하고 선언과 동시에 값을 선언해야한다.


요약

  1. 객체와 매개변수를 명확히하고, 가독성을 높이기 위해 this를 사용
  2. 오버로딩(매개변수의 타입, 개수만 달라야 함)을 사용하여 다양한 케이스 대처
  3. 인스턴스 멤버는 힙 메모리에 객체별로, 정적 멤버는 정적 메모리에 클래스별로
  4. 정적 멤버는 객체의 영향을 받지 않게 하는 기능을 하며 클래스의 유일값
profile
기록용

0개의 댓글