자바 객체 지향의 원리와 이해 - #3 자바와 객체지향

jhkim·2023년 3월 18일
0

객체지향의 4대 특성 - 캡상추다!

클래스는 같은 특성을 지닌 여러 객체를 총칭하는 집합의 개념이다.

추상화 = 구체적인 것을 분해해서 관심 영역에 있는 특성만 가지고 재조립하는 것, 즉 모델링이다.
모델은 실제 사물에서 관심있는 특성만을 추출하여 표현하는 것


정적 멤버(static 멤버)

같은 클래스의 모든 객체가 같은 값을 가지고 있다면 값을 클래스에 저장한다
--> 클래스에 static키워드를 통해서 static 멤버로 할당
클래스의 static멤버로 하지 않고 인스턴스의 멤버 변수가 되면,
공통되는 값임에도 불구하고 모든 인스턴스가 메모리를 차지하고 있어 공간 낭비를 한다.
이렇게 되면 해당 static멤버(클래스 멤버)는 static메모리에 클래스와 함께 올라간다.

정적 메소드

객체들의 존재 여부에 관계없이 쓸 수 있는 메소드
main메소드는 객체의 존재 여부에 관계 없이 실행되어야 하므로, 정적 메서드여야 한다.
또한 실무에서는 클래스의 인스턴스를 만들지 않고 사용하게 되는 유틸리티성 메소드를 정적 메서드로 구성한다.

초기화를 해야하는 지역 변수

클래스 속성과 객체 속성은 별도로 초기화하지 않아도 0, 0.0, false, null로 초기화되지만 지역 변수는 초기화해야 한다.
지역 변수는 한 지역에서만 쓰지만, 멤버 변수는 공유 변수의 성격을 가지고 있다.
공유 변수는 별도로 초기화하지 않아도 기본값으로 초기화되지만,
지역 변수는 한 지역 내에서만 사용되고 소멸되는 변수이므로 그 지역에서 초기화된다.

변수 유형

static 변수 - 스태틱 영역에 저장
인스턴스 변수 - 힙 영역에 저장
지역 변수 - 스택 영역의 스택 프레임 내부에 저장


### 객체 지향에서의 상속 상속은 재사용과 확장으로 이해해야 한다. _**하위 클래스는 상위 클래스를 확장하고, 필요한 특성을 추가해서 사용하는 것이다.**_ 그래서 상속 키워드도 extends이다. 그래서 is a 관계보다는 is a kind of 관계로 이해해야 한다. 하위클래스 is a kind of 상위클래스 (펭귄 is a kind of 동물)

클래스의 이름은 클래스스럽게, 인스턴스의 이름은 유일무이한 인스턴스스럽게 짓자!



인터페이스

구현클래스 is able to 인터페이스
ex 고래는 헤엄칠 수 있다

인터페이스는 "~를 할 수 있는"으로 표현하는 것이 적합하다.
인터페이스는 클래스가 "무언가를 할 수 있다"는 기능을 구현하도록 강제한다.

public interface 날 수 있는 {
void fly();
}

public class 박쥐 extends 포유류 implements 날 수 있는 {
...
@Override
public void fly() {
날아랏 슈웅 슈웅
}
}
날 수 있는 날라리1 = new 박쥐 ();
날 수 있는[] 날라리들 = new 날 수 있는[2];
날라리들[0] = new 펭귄();
날라리들[1] = new 박쥐();
for(날 수 있는 날라리 : 날라리들) {
날라리.fly();
}

위를 보면, 인터페이스를 구현하는 객체는 인터페이스 타입으로 업캐스팅 될 수 있다는 사실을 알 수 있다.

날 수 있는 날라리 = new 펭귄();과 같이


상속 - T메모리는 어떻게 될까>

Animal을 상속받은 Penguin 클래스가 있다고 하자.
Penguin 펭수 = new Penguin(); 하면 힙 영역은 어떻게 될까?
힙 영역에 Penguin의 인스턴스가 저장된다.
근데 여기서 penguin뿐 아니라, Animal의 인스턴스와 Obejct클래스의 인스턴스까지 힙 영역에 생긴다.



Animal 핑구 = new 펭귄()과 Penguin 뽀로로 = new 펭귄()의 차이

전자는 업캐스팅이다.
핑구와 뽀로로라는 변수는 힙영역에 생성된 인스턴스의 주소를 담고 있는데,
이 때 전자는 Animal의 주소를 가지고, 후자는 Penguin의 주소를 가진다.

핑구의 경우는 자신이 펭귄이라기보단 animal이라고 인식하고 있어,
펭귄 클래스에만 존재하는 메소드는 사용할 수 없다.
즉, 업캐스팅하면 하위클래스의 메소드는 사용할 수 없다.



명시적 형변환과 암묵적 형변환

암묵적: double형과 int형을 더하면 컴파일러가 자동으로 int를 double로(범위가 작은->큰) 변경함
명시적: 사용자가 직접 (double)int와 같이 형변환함



오버라이딩과 오버로딩

오버라이딩 : 같은 메서드 이름과 같은 인자 목록으로 상위 클래스의 메소드를 하위 클래스에서 재정의
오버로딩 : 같은 메서드 이름과 다른 인자 목록으로 다수의 메서드를 중복정의

Animal 클래스 내의 showName은 "난 동물이야",
Penguin 클래스 내의 showName은 "난 펭귄이야"라고 하자.
Penguin은 extends Animal 해서 Animal을 상속받는다.

Penguin 펭수 = new Penguin();을 했을때
펭수.showName하면 당연히 "난 펭귄이야"라고 할 것이다.

그렇다면 Animal 펭도리 = new Penguin();을 한다면?
펭도리.showName의 결과는 뭘까?

펭도리 객체 참조 변수는 Animal타입이지만, showName은 Penguin에 재정의된 showName이 실행된다.

결론적으로 상위 클래스 타입의 객체 참조 변수를 사용해도, 하위 클래스에서 오바리이딩한 메서드가 호출된다.

즉, 동물[] 동물들 = new 동물[3];
동물들[0] = new 고양이 ();
동물들[1] = new 강아지 ();
동물들[2] = new 송아지 ();

for(동물 i:동물들) {
동물들[i].울어!();
}

하게 되면, 각각 야옹! 멍멍! 음머! 하고 운다.



정보 은닉: 캡슐화

(-) private,
(~) default,
(+) public,
(#) protected

protected는 상속 관계에 있는 클래스 뿐 아니라, 같은 패키지 내의 모든 클래스 내에서 접근이 가능하다.
그렇다면 다른 파일 안에 같은 이름의 패키지가 있다면?
public이나 protected, default멤버에 자유롭게 서로 접근할 수 있다.


정적 멤버의 접근

Penguin 클래스가 가진 정적 멤버는 어떻게 접근하는게 좋을까?
Penguin 펭수 = new Penguin();
Penguin.정적멤버로 접근하는 것이 펭수.정적멤버로 접근하는 것보다 좋다.
의미적으로도 그렇고, 물리적 접근에 따른 이유로도 전자가 좋다.


참조 변수의 복사

기본 자료형 변수를 복사할 경우, Call by Value에 의해 값이 복사되며, 두 변수는 서로에게 영향을 미치지 않는다.
int a = 10;
int b = a;

b = 20;
한다고 해서, a가 20이 되지는 않는다.

그러나,

Animal ref_a = new Animal();
Animal ref_b = ref_a;

ref_a.age = 10;
ref_b.age = 20;

하게 되면 둘다 age값은 최종적으로 20이 된다.
Call by Reference기 떄문이다.

왜냐면 ref_a와 ref_b는 같은 주소를 가지고 있고, 즉 같은 객체를 참조하고 있기 때문이다.

0개의 댓글