구조적 프로그래밍?
아무리 복잡한 문제라도 작은 문제로 분할해서 하나씩 정복하다 보면 결국 해결된다는 전략입니다.
몇 천, 몇 만 라인을 논리적인 단위로 나누어 블록화해서 작성하자. 이런 논리적인 단위를 함수라고 합니다.
객체지향 프로그래밍?
함수를 이용한 프로그래밍이 좀 더 발전한 것이 객체지향 프로그래밍입니다.
세상 모든 눈으로 보여지는 것, 만져지는 것, 상상하는 것들을 객체로 판단해서 프로그래밍하는데 활용하겠다는 것.
- 세상의 존재하는 모든 것은 사물, 즉 객체(Object)이다.
- 각각의 사물은 고유하다.
- 사물은 속성을 갖는다.
- 사물은 행위를 한다.
사람은 사물을 하나하나 이해하기 보다는 분류(class)하고 싶어한다.
- 직립보행을 하며, 말을 하는 존재를 사람이라고 한다.
- 연미복, 짧은 다리, 날지 못하는 새를 펭귄이라고 한다.
- 밤하늘에 반짝이는 사물들을 별이라고 한다.
더 나아가,
객체? 속성? 메소드?
김연아(Object), 유재석(Object), 하하(Object), 강호동(Object) 등등
이런 사람이라는 객체들은 나이(Property), 몸무게(Property), 키(Property)와 같은 속성과
싸다(Method), 먹다(Method), 말하다(Method), 일하다(Method)와 같은 메소드를 가지고 있다.
객체 지향 이전 vs 객체 지향
객체 지향 이전에는 객체에 대한 속성과 메소드를 따로 구분하여 구현하였는데 반해,
객체 지향에서는 이런 속성(필드), 메소드(함수)를 합하여 객체화 시켜 구현을 하게 한다.
클래스와 객체와의 관계
클래스
분류이다.
객체
실체이다.
객체지향적 관점에서 사람은 클래스이고, 김연아는 객체이다.
클래스와 객체를 구분하는 간단한 방법
나이를 물어보는 것이다.
사람이 몇 살인가? => (X)
김연아는 몇 살인가? => (O)
펭귄은 몇 살인가? => (X)
뽀로로는 몇 살인가? => (O)
김연아와 뽀로로는 몇 살인지 답변 가능하다. 그러므로 객체이다.
하지만 사람과 펭귄의 나이를 물어보는 것은 무엇인가 이상하다. 이 것은 클래스(분류)이다.
객체지향의 4대 특징?
추상화, 상속, 캡슐화, 다형성
추상화(Abstraction)란?
객체에 대한 속성이나 특성을 가지고 모델링하는 것을 말한다.
ex) 환자라는 객체에 대한 추상화
환자라는 객체에 대해 추상화하기 위해서는 환자에 대한 속성이나 특성을 가지고 모델링하는 것을 말한다.
환자의 이름, 나이, 몸무게, 기저질환유무라는 속성(Property)와
운동하다, 운전하다, 화장실가다, 밥먹다와 같은 메소드(Method)로 추상화 할 수 있을 것이다.
환자라는 것에 국한한다는 것은 프로그래밍에서는 애플리케이션의 경계로부터 정한다고 한다.
=> 애플리케이션의 경계안에서 객체에 대한 속성이나 특성을 가지고 모델링하는 것을 말한다.
라고 정의할 수 있겠다.
클래스를 통해 객체를 만들어 낼 때의 메모리 구조는 어떻게 변화하나?
Mouse mickey = new Mouse();
3개의 명령문이 녹아있다.
Mouse mickey // Mouse객체에 대한 참조 변수 mickey를 만든다.
new Mouse() // Mouse클래스의 인스턴스를 하나 만들어 힙에 배치한다.
= 대입문 // Mouse객체애 대한 주소(포인터)를 참조 변수 mickey에 할당한다.
Mouse라는 클래스는 스태틱영역에 위치해있다.
new Mouse()라는 명령어를 만나면 인스턴스를 만들어 힙 영역에 배치한다.
또 지역 변수인 mickey라는 변수는 힙영역의 인스턴스를 가리키고 있는 모양이다.
클래스 멤버 vs 객체 멤버 = static 멤버 vs 인스턴스 멤버
static 키워드란 무엇을 말하는가?
미키마우스, 제리마우스, 마이티마우스란 객체에서 공통된 질문인 "꼬리가 몇 개인가?"를 해보자.
무조건 답은 "하나"이다. 마우스라는 클래스의 공통된 성질이다. 꼬리가 한 개 인 것.
그렇다면 이렇게 모든 객체가 가진 공통된 특성을 힙영역에 메모리를 잡고 할 당하고 있는 것은 낭비가 아닌가?
countofTail과 같은 변수를 스태틱 변수로 옮겨 버리면 메모리를 더욱 효율적으로 사용 할 수 있다.
변수 앞에 static이라는 키워드를 붙여서 사용한다.
static 멤버는 클래스의 공통된 특성을 가진 변수를 스태틱 영역에 할당하는 것을 말한다.
static변수에 접근하는 효율적인 방법은?
mickey라는 참조변수는 Mouse라는 객체에 도달한 후에 다시 스택틱 변수가 위치한 스태틱 영역으로 이동한다.
(스택영역 -> 힙 영역 -> 스태틱영역)
하지만 클래스명.정적멤버 형식으로 접근하게 되면 스택에서 바로 스태틱영역으로 접근하여 효율적이다.
(스택영역 -> 스태틱영역)
인스턴스 멤버는
힙 영역에 할당된 객체들의 멤버를 말한다.
클래스 멤버 = static 멤버 = 정적 멤버
객체 멤버 = 인스턴스 멤버
용어에 대해 부르는 것들이 조금 다양할 뿐 같은 말이다. 헷갈리지 말아야 한다.
상속(Inheritance)이란? => 재사용 + 확장
상속에 대한 정의는 상위 클래스를 하위 클래스가 재사용하고 확장할 수 있는 특징을 말한다.
보통 부모클래스, 자식클래스로 나누는데 이러한 용어보다는
상위 클래스 - 하위 클래스 또는 슈퍼 클래스 - 서브 클래스 라고 하는 것이 맞다.
이러한 관점은 계층적인 관점이 아니라, 분류적인 관점이기 때문이다.
이러한 주장을 뒷받침하듯이 자바의 문법은 Inheritance가 아닌 extends(확장하다)라는 키워드를 사용한다.
toString()이라는 메서드를 어느 클래스에서든지 사용 할 수 있는 이유는?
모든 클래스의 상속 구조에서의 최상위 클래스는 Object클래스이다.
결국 모든 클래스는 Object클래스의 특성을 물려받는다.
상속때문이다. 상속의 강력한 기능을 잘 표현한 예라고 할 수 있다.
상속관계를 맺기 위한 조건?
is a kind of의 조건을 만족해야 한다.
하위클래스 is a kind of 상위클래스 => 하위클래스는 상위 클래스의 한 종류이다?
펭귄 is a kind of 동물 => 펭귄은 동물의 한 종류이다.
고래 is a kind of 동물 => 고래는 동물의 한 종류이다.
조류 is a kind of 동물 => 조류는 동물의 한 종류이다.
자바가 다중 상속을 막은 이유는?
자바는 C++과 다르게 다중 상속을 포기했다.
다중 상속의 여러 문제점 때문에 다중 상속을 지원하지 않게 되었다.
다이아몬드 문제
TopA
MiddleB, middleC
BottomD
B는 A를 상속했다. C도 A를 상속했다.
D는 B와 C를 다중 상속했다.
=> A가 가지고 있는 공통된 특성이 중복으로 D가 가져야 된다.
그럼 자바는 다중 상속을 어떻게 보완했나? => Interface
다중 상속을 포기하고 인터페이스를 도입한 자바에서 인터페이스는 어떤 역할을 하며 어떤 관계를 나타내는 것인가?
- 인터페이스 : 구현 클래스 is able to 인터페이스
- 해석 : 구현 클래스는 인터페이스 할 수 있다.
- 예제 : 고래는 헤엄 칠 수 있다.
위의 관계도를 보면서 다중상속의 단점을 버리고, 이점을 취한 인터페이스에 대한 이해를 할 수 있겠다.
인터페이스는 be able to, 즉 "무엇을 할 수 있는"이라는 표현 형태로 만드는 것이 좋다.
자바 API에서도 이러한 be able to 형식의 인터페이스를 많이 볼 수 있다.
Serializable 인터페이스(직렬화 할 수 있는)
Cloneable 인터페이스(복제 할 수 있는)
Comparable 인터페이스(비교 할 수 있는)
Runnable 인터페이스(실행 할 수 있는)
// 동물.java package inheritance02; public class 동물{ String myClass; 동물(){ myClass = "동물"; } void showMe(){ System.out.println(myClass); } } // 날수있는.java package inheritance02; public interface 날수있는{ void fly(); } // 헤엄칠수있는.java package inheritance02; public interface 헤엄칠수있는{ void swim(); } // 포유류.java package inheritance02; public class 포유류 extends 동물{ 포유류(){ myClass = "포유류"; } } // 조류.java package inheritance02; public class 조류 extends 동물{ 조류(){ myClass = "조류"; } } // 고래.java package inheritance02; public class 고래 extends 포유류 implements 헤엄칠 수 있는{ 고래(){ myClass = "고래"; } @Override public void swim(){ System.out.println(myClass + "수영 중 어프!! 어프!!"); } } // 박쥐.java package inheritance02; public class 박쥐 extends 포유류 implements 날 수 있는{ 박쥐(){ myClass = "박쥐"; } @Override public void fly(){ System.out.println(myClass + "날고 있다..슈융"); } } | cs |
상속될 때의 메모리 구조는 어떻게 되나?
상속 받은 상위 클래스까지 힙 영역에 할당된다.
다형성 : 사용편의성
오버라이딩(Overriding) vs 오버로딩(Overloading)
- 라이딩 : 올라타기
- 로딩 : 적재하기
- 오버 라이딩 => 재정의 : 상위 클래스의 같은 메서드 이름, 같은 인자 리스트
- 오버 로딩 => 중복정의 : 상위 클래스의 같은 메서드 이름, 다른 인자 리스트
** 기억해야 되는 부분
상위 클래스의 객체 참조 변수를 사용하면 재정의하지 않은 메서드가 불려지나?
상위 클래스의 객체 참조 변수를 사용하더라도 하위 클래스에서 오버라이딩(재정의)한 메서드가 호출 된다는 점을 기억해야 한다.
다형성이 지원되지 않는다면?
예를 들어 연산하는 부분을 생각해볼 수 있다.
자바와 같은 경우에 정수 자료형으로 byte, short, int, long, char 부동소수점 수 자료형으로는 float, double이 있다.
만약 다형성이 지원되지 않는다면 다른 함수 이름을 7 * 7 = 49개 정도는 만들어줘야 한다.
다형성이 지원하기 때문에 하나의 메서드를 가지고 이 같은 필요를 충족시켜줄 수 있게 된다.
캡슐화란 무엇인가? 정보은닉이란 무엇인가?
객체지향의 특징 중 캡슐화란 접근 제어 지시자를 이용해 외부로부터 정보를 마구잡이로 접근 할 수 없게끔 할 수 있는 특징을 말한다.
긴설명은 생략하고 정확하게 이해하고 있고, 실전을 통해서 익혀야 한다고 생각한다.
간략히 표현하자면,
그 동안 실수로 알았던 것이
Protected가 상속 받은 클래스에서만 접근 가능한 줄 알았는데 같은 패키지에서도 접근 가능하다는 것이다.
참조변수의 복사?
Call By Value vs Call By Reference
참조 변수를 복사하는 것은 결국 주소를 복사하는 것이다.
String 변수에 대한 CBV, CBR에 대해서 설명해보겠다.
String a = "aaa";
String b = a;
String c = new String("aaa");
a와 b는 같은 주소값을 가진다.
c는 새로운 주소에 값이 할당된다.
그래서 == 연산자로 비교하면 a와 b는 같다
하지만 a와 c, b와 c를 비교하면 다르다.
== 연산자는 주소 값을 비교하고, equals()라는 함수를 통해 값을 비교 할 수 있다.
CBV와 CBR의 예라고 할 수 있다.