1. 프로젝트 생성
최상단 메뉴바에서 File → New → Project 를 통해 프로젝트를 생성해보자.

소스코드가 들어가는 폴더를 Package라 부른다. (src 는 소스코드를 의미한다.)
src 에서 Package 부터 만들고, 동일한 방법으로 패키지 안에 Java Class 도 만들어본다.

2. 객체지향의 핵심
객체는 상태와 행위를 가진다. 상태는 행위를 통해서만 변경한다.
여기서 상태는 변수다. stack에 있는 변수가 아니라, 객체가 만들어질 때(생성될 때) 지니고 있는 변수를 의미한다.
‘객체’ 라는건 상태와 행위 두 가지를 같이 가진다.
상태만 가진 것은 그저 데이터 덩어리임, 객체라고 부르긴하지만 엄밀히 따지면 객체가 아니다.
아래의 int 목마름; 은 그저 데이터 덩어리인 것이다.
class 앨리스 {
int 목마름;
}
int 목마름 은 상태이다. static 이 안붙어있으니, 메모리에 뜨지 않는다. 띄우려면 heap 메모리에 띄워야 한다.
엘리스를 이 세상에 태어나게 하려면 new 를 통해 heap 메모리에 올려야 한다.
package ex00;
class 엘리스 {
private int 목마름; // 객체는 상태를 직접 변경 못함, 상태를 직접 변경하지 못하도록 private 붙임 // -> static 안붙어있으니까 heap
}
public 엘리스(int 목마름) { // 객체는 생성자로 초기화 하는거야
this.목마름 = 목마름;
}
public class Mem01 {
public static void main(String[] args) {
엘리스 e = new 엘리스(100);
}
}
2-1. JVM 의 메모리 공간

RAM을 8GB 라 할 때, 절반인 4GB 로 나뉘어 일반적으로 운영체제(OS)가 절반을 사용하고,
남은 공간 중 JVM 은 500MB 를 차지한다고 보면 된다.
여기서 한 칸(의 용량)은 8bit = 1byte 이다.
byte단위는 문자 하나를 의미하는 것으로, 영어 letter 하나를 의미.
JVM 이 쓰는 공간은 아래와 같이 나뉘어진다.(효율적으로 메모리를 나눠쓰려기 위함)

JVM 공간에서 main 이 실행되면, new 할 때마다 heap 에 채우고, stack과 static 한테 물어보고 너네 자리남니? 슥슥 늘릴 수도 있다. 하지만, 자리 없으면 못늘림.
stack에 더 이상 늘어날 자리가 없으면, stackoverflow error가 발생하는 것이다.
static 메서드는 클래스명.메서드이름(); 으로 호출한다.
Mem01.hello(); 로 main 에서 메서드가 실행되면 stack 메모리에 뜬다.
int 는 4byte이고, 4byte가 stack에 쌓이게 된다.
11번 라인에서 stack 종료되면 4byte 는 날아가고,
14번 라인에서 hello 호출하면 stack이 호출되고 hello 만들어지고 그 안에 4byte 할당 하고 있는데,
11번 라인에서 stack 종료되면서 4byte 는 해제된다.

package ex00;
class 엘리스 {
private int 목마름; // 객체는 상태를 직접 변경 못함, 상태를 직접 변경하지 못하도록 private 붙임 // -> static 안붙어있으니까 heap
}
public 엘리스(int 목마름) { // 객체는 생성자로 초기화 하는거야
this.목마름 = 목마름;
}
public class Mem01 {
static void hello() { // hello stack 생김
int num = 10; // 4byte
// hello(); // -> 이러면 메서드가 종료가 안되니까 stack 에 계속 쌓임, stack 이 모지라니까 StackOverflowError 가 발생함
}
public static void main(String[] args) {
// Mem01.hello();
엘리스 e = new 엘리스(100);
// 엘리스 e1 = new 엘리스(목마름: 100);
// e.목마름 = 100; 가 되지 않도록
// 1. 값 변경 (행위)
e.물마시기(); // -> 의도한 결과가 나옴. 0
// 2. 값 확인
int 목마름 = e.목마름확인하기();
System.out.println(목마름);
}
}
상태를 직접 변경하지 못하도록 private 을 붙이는데,
private 이 붙은 변수에 접근하려면 getter 가 필요하다.
setter: 상태를 변경하는 애 / getter: 상태를 확인하는 애
static 은 여러 공간 띄우는게 불가하나, heap 은 여러 공간 띄우는 것이 가능.
static 안붙어있으면 다 heap 에 뜬다.
new 할때 뜨는 heap.
2-2. 정리
변수는 heap 변수 / static 변수 / stack 변수 로만 생각하면 된다.
매개변수() 도 메서드의 stack 변수
생성자도 생긴 모양새가 메서드이니 stack 변수(실행 시에 뜨니까)
3. 상속과 컴퍼지션
3-1. 다형성

다형성: 하나의 대상을 두고 여러가지 이름으로 부를 수 있다.(최주호, 사람, 강사)
has → 포함 / is → 동일

스포츠카이자 자동차, 이것이 다형성이다.
자동차야 너 엔진이니? → No. (다형성X)
정확히 상속은 다형성으로 보일 수 있는 타입을 물려받는 것이다.
자동차를 상속하면 다형성으로 보일 수 있어야 한다.
스포츠카야, 너 자동차니? → Yes.
자동차야, 스포츠카니? → No.
부모가 자식에게 타입을 물려주는 것, 두 가지로 불릴 수 있게.
3-2. 다형성 적용
레이싱 메서드를 매번 매개변수를 바꿔서 만들 수 없으니, 부모인 Car 를 매개변수로 만들었다.
package ex00;
class Car {
// car 상태
// car 행위
int carNum = 10;
}
class Sonata extends Car { // 다형성
// Sonata 상태
// Sonata 행위
int sonataNum = 20;
}
class Genesis extends Car {
// Genesis 상태
// Genesis 행위
}
public class Mem02 {
/*
static void 레이싱(Sonata s1) {
}
static void 레이싱(Genesis g1) {
}
*/
static void 레이싱(Car g1) {
}
public static void main(String[] args) {
// Sonata s1 = new Sonata(); // Sonata, Car
Car s1 = new Sonata();
// System.out.println(s1.carNum);
// System.out.println(s1.sonataNum);
System.out.println(s1.carNum);
Car g1 = new Genesis(); // Genesis, Car
레이싱(s1);
레이싱(g1);
}
}
레이싱을 하나로 통일 할 수 있었던 이유는 다형성 때문이다.
만약 extends 하지 않으면, 타입 인식이 안되니 불가능하다. extends 필수
static void 레이싱(Car g1) {
}
public static void main(String[] args) {
// Sonata s1 = new Sonata(); // Sonata, Car
Car s1 = new Sonata();
Car g1 = new Genesis(); // Genesis, Car
레이싱(s1);
레이싱(g1);
}
instanceof 는 타입 검사
static void 레이싱(Car car) {
if(car instanceof Sonata) {
System.out.println("소나타 달린다~~~");
} else if(car instanceof Genesis) {
System.out.println("제네시스 달린다~~~");
}
}
위의 방법을 사용한다면 tico … 늘어날 때마다
매번 else if 로 써야하니까 몹시 번거롭다.
3-3. 동적바인딩

생성자의 첫줄에 super() 로 부모 생성해주고, 부모 타입을 제일 먼저 생성해줘야 한다.
자식이 부모가 가진 메서드를 똑같이 만들었어(재정의)
동적바인딩
부모의 메서드를 호출하면 오버라이드됨(무효화됨)
부모의 메서드가 호출되어도 자식이 재정의한 메서드가 나옴(동적바인딩)
무효화되었기 때문.
상속으로 타입을 일치 시킬 수 있다. is-a 관계로 만들면 추상화 할 수 있다. (Car 로)
추상화가 안되면 소나타, 제네시스… 매번 매개변수만 다른 메서드를 여러개를 만들어야하는데,
추상화를 시키면 부모인 Car 만 메서드의 매개변수로 만들면 된다.
동적바인딩으로 car.run() 만 해도된다.
Car 는 소나타와 제네시스를 묶는 타입을 묶는 용도로만 썼다.
Car c = new Car(); 라고 new 할 필요가 없음
추상화시키면 부를 때 굉장히 편하거든’
Car의 역할은 그게 다야~ 모든 자동차가 다 달리게 해~
자동차는 이 세상에 존재하지 않는 추상적인 것. new를 못하게 막자 abstract 로 정의하면 됨(실수를 하지 않게)
{} 어떻게 달리는지 모르겠을 때 이렇게 만들지, 몸체를 안만드는 것 (→ 추상메서드)
이때
void run() {}
가 아닌
abstract void run() {}
으로 만드는거야 추상적인건 이 세상에 존재하지않는다. 이 세상에 존재하지 않는 것을 heap 에 띄울 수 없음
Share article