[Java] 추상화(Abstraction)
추상화 : 구체적인 것을 분해해서 관찰자가 관심 있는 특성만 가지고 재조합하는 것
클래스(class) : 같은 특성을 지닌 여러 객체를 총칭하는 집합의 개념
객체(instance) : 유일무이(unique)한 사물, 클래스의 인스턴스
클래스:객체 = 사람:김연아 = 사람:홍길동
ex) 사람 클래스를 만들기 위해 주변에 보이는 공통적인 특성
시력, 몸무게, 혈액형, 키, 나이 등 명사로 표현되는 것 -> 속성(값)
먹다, 자다, 일하다 , 침 뱉다. -> 기능 행위(함수)
class 사람 { |
float 시력; int 몸무게; int 키; |
void 먹다{...} void 일하다{...} |
만약 애플리케이션을 만들었는데 사람에 대한 클래스를 이용해 객체를 만들때 필요없는 속성과 기능들이 있을 것이다.
병원 애플리케이션과 은행 애플리케이션으로 예시를 들어보면
병원 어플리케이션 | 은행 어플리케이션 |
class 사람 { | class 사람 { |
float 시력; int 몸무게; int 키; int 나이; |
String 직업; String 연봉; |
void 먹다{...} void 일하다{...} |
void 일하다{...} void 입금하다{...} void 출금하다{...} |
추상화는 모델링이다. 라고 하는데 모델은 추상화를 통해 실제 사물을 단순하게 묘사하는 것
추상화의 개념을 넓게 보자면
- 상속을 통한 추상화, 구체화
- 인터페이스를 통한 추상화
- 다형성을 통한 추상화
클래스 객체_참조_변수 = new 클래스();
Person 학생 = new Person();
미키마우스 | 제리 |
성명 : 미키마우스 국적 : 미국 나이 : 87 종교 : 무교 신장 : 70cm 체중 : 11.5 kg |
성명 : 제리 국적 : 미국 나이: 75 종교 : 기독교 친구 : 톰 여자친구: null |
달리다() 먹다() 휘파람 불다() 데이트하다() 울다() |
달리다() 먹다() 장난치다() |
추상화
쥐 |
성명 나이 |
달리다() 먹다 |
public class Mouse{
public String name;
public int age;
public void sing(){
System.out.println(name + "찍찍"!!");
}
public class MouseDriver{
public static void main(String[] args){
Mouse mickey = new Mouse();
mickey.name = "미키";
mickey.age = 85;
mickey.countOfTail = 1;
mickey.sing();
Mouse jerry = new Mouse();
jerry.name = "제리";
jerry.age = 73;
jerry.countOfTail = 1;
jerry.sing()
}
}
main 메서드 실행되기 직전에 메모리
스태틱 영역 함수 정보, 속성 정보만 저장 |
name age |
sing() |
이 때 name, age 속성은 Mouse 클래스에 속한 속성이 아닌 Mouse 객체에 속한 속성이기 때문에 객체가 생성되야만 값을 저장하기 위해 스태틱 영역이 아닌 힙 영역에 할당된다.
Static
- 스태틱 영역에 올라간 정보는 main() 메서드가 시작되기 전에 올라가서 main() 메서드가 종료된 후에 내려올 정도로 스태틱 영역에 고정되어 있다.
- 다음과 같은 질문을 던져본다.
- 미키마우스의 꼬리는 몇개인가?
- 제리의 꼬리는 몇개인가?
- 쥐의 꼬리는 몇개인가?
-> 답은 1개이다.
만약 이것을 static 이 아닌 객체의 속성으로 구현하게 된다면 각각 메모리에 하나씩 잡히게 된다.
Mouse name 꼬리 |
Mouse(micky) name : micky 꼬리: 1 |
Mouse(jerry) name: jerry 꼬리: 1 |
스태틱을 구현하게 된다면 스태틱 영역에 단 하나의 저장 공간을 갖게 되는 것이다.
Mouse name 꼬리 |
Mouse(micky) name : micky |
Mouse(jerry) name: jerry |
public class Mouse {
public String name;
public int age;
public static int countOfTail = 1;
public void sing(){
System.out.println(name + "찍찍"
}
}
클래스로 선언된 속성은 객체.속성이 아닌 Mouse.countOfTail 로 접근이 가능하다
클래스 멤버 = static 멤버 = 정적 멤버
객체 멤버 = 인스턴스 멤버
정적 멤버 속성은 클래스의 모든 객체들이 같은 값을 가질 때 사용하는 것이 정석.
또한 정적 멤버/메소드는 객체가 아닌 클래스에 속해 있으며, 클래스는 JVM 구동 시 메모리의 스태틱 영역에 바로 배치되기 때문에 객체의 존재 여부와 상관없이 쓸 수 있다.
정적 변수에 대한 접근 지정자 접근 메소드(getter)와 설정 메서드(setter)로 사용되어진다.
정적 속성은 스태틱 영역에 클래스가 배치될 때 클래스 내부에 메모리 공간을 확보하고 있지만
객체 속성(이름, 나이)는 속성명만 있고 실제 메모리 공간은 확보해 놓지 않는다. 힙 영역에 객체가 생성되면 그때 각 객체안에 멤버 속성을 위한 메모리 공간이 할당된다.
non - static 멤버 = 객체용 멤버 | static 멤버 = 클래스용 멤버 | |
공간적 특성 | 멤버들은 객체마다 독립적으로 별도 존재 | 클래스 당 하나마 생성/ 객체 내부가 아닌 별도 공간에 생성 |
시간적 특성 | 속성과 메소드는 객체 생성 후 사용 가능 | 클래스가 로딩될 때 공간 할당 객체가 사라져도 멤버는 사라지지 않음 프로그램 종료 시 사라짐 |
공유 특성 | 멤버들은 다른 객체에 의해 공유되지 않음(비공유적) | 동일한 클래스의 모든 객체에 의해 공유 |
class StaticSample{
int n;
void g() {...}
static int m;
static void f() {...}
- 함수 g()는 non-static이기 때문에 어떤 객체가 호출했는지 암 -> this 사용가능
- 속성 m과 함수 f()는 static 이기 때문에 누가 호출했는지 모름 -> this 사용 불가 / 클래스이름.m 으로 호출 해야함
static 메소드의 제약조건
- static 메소드는 non-static 멤버(일반 객체 맴버)에 접근할 수 없음
- 객체가 생성되지 않는 상황에서 해당 메소드는 실행 될 수 없기 때문
- non-static 메소드는 static 멤버 사용 가능
- 모든 객체가 공유하기 때문
- this 사용 불가
- 어떤 객체가 가르키는 지 this 래퍼런스를 사용 할 수 없음.
지역 변수 vs 멤버 변수
지역 변수 : 스택 영역에 저장 / 한 지역에서만 쓰는 변수로 초기화가 반드시 필요하다. 초기화가 없으면 쓰레기 값을 가짐 / 한 지역에서 사용되고 소멸되기 때문에 초기화 하는 것이 논리적으로 맞다.
멤버 변수 : 객체 메서드가 공유하는 변수 / 초기화 없이 자동으로 초기화가 된다.