연관된 "상태"와 "행위"를 결정하는 기능을 묶어 주는 것을 의미합니다. => 이렇게 묶어 주면 기능을 클래스 밖에서 접근 가능한 대상을 제한하는 정보 은닉이 가능하다. => 하나의 객체를 위한 코드가, 다른 객체를 위한 코드와 무관하게 수행할 수 있는 모듈화(modularity)가 가능해진다.
객체가 기능을 어떻게 구현했는지 외부에 감추는 것 -> 구현에 사용된 데이터의 상세 내용을 외부에 감춘다.
public class Common {
private int state; // private로 선언함으로써 정보 은닉
public void setState(int newState) { // 상태를 변경 가능
}
}
캡슐화를 하는 이유
외부에 영향 없이 객체 내부 구현 변경 가능
요구사항의 변화가 발생 했을 때, 연쇄적으로 변경이 전파 되는 걸 최소화 할 수 있다. -> 캡슐화된 기능을 사용하는 코드에 변경에 따른 영향을 최소화 할 수 있는 이점 -> 캡슐화를 사용하는 가장 큰 이유
캡슐화 시도는 기능에 대한 (의도) 이해를 높임 * 작성된 코드의 의도를 파악해야 캡슐화를 할 수 있다.
# 캡슐화를 위한 규칙
Tell, Don't Ask -> 데이터 달라 하지 말고 해달라고 하기
왼쪽 코드처럼 acc.getMembership()으로 데이터를 가져와 해당 데이터가 REGULAR인지 확인 하는 것이 아닌,
자바 가상 머신(Java Virtual Machine)은 자바 바이트코드를 실행, 해석할 수 있는 주체이다.
JVM의 역할은 자바 애플리케이션을 클래스 로더(Class Loader)를 통해 읽어 들여서 자바 기본 API를 동적으로 연결해 자바 프로그램을 실행하는 것입니다.
기술적 정의 -> 코드를 실행하고 해당 코드에 대해 런타임 환경을 제공하는 소프트웨어 프로그램에 대한 사양(Specification)
일반적 정의 -> JVM은 자바 프로그램을 실행하는 방법이다. JVM의 설정을 구성한 다음 설정 사항에 따라 실행 중에 프로그램 리소스를 관리한다.
* 가상 머신 : 프로그램을 실행하기 위해 물리적 머신과 유사한 머신을 소프트웨어로 구현한 것.
#JVM의 특징
스택 기반의 가상 머신 -> 대표적인 컴퓨터 아키텍처인 인텔 x86 아키텍처나 ARM 아키텍처와 같은 하드웨어가 레지스터 기반으로 동작하는 데 비해 JVM은 스택 기반으로 동작한다.
심볼릭 레퍼런스(Symbolic Reference) -> 기본 자료형(primitive data type)을 제외한 모든 타입(클래스와 인터페이스)을 명시적인 메모리 주소 기반의 레퍼런스가 아니라 심볼릭 레퍼런스를 통해 참조한다.
가비지 컬렉션(Garbage collection) -> 클래스 인스턴스는 사용자 코드에 의해 명시적으로 생성되고 가비지 컬렉션에 의해 자동으로 파괴된다.
기본 자료형을 명확하게 정의하여 플랫폼 독립성 보장 -> C/C++ 등의 전통적인 언어는 플랫폼에 따라 int 형의 크기가 변한다. JVM은 기본 자료형을 명확하게 정의하여 호환성을 유지하고 플랫폼 독립성을 보장한다.
네트워크 바이트 오더(Network byte order) -> 자바 클래스 파일은 네트워크 바이트 오더를 사용한다. 인텔 x86 아키텍처가 사용하는 리틀 엔디안이나, RISC 계열 아키텍처가 주로 사용하는 빅 엔디안 사이에서 플랫폼 독립성을 유지하려면 고정된 바이트 오더를 유지해야 하므로 네트워크 전송 시에 사용하는 바이트 오더인 네트워크 바이트 오더를 사용한다. 네트워크 바이트 오더는 빅 엔디안이다.
java.exe:자바 응용 프로그램 로더. -> javac 컴파일러가 만든 클래스 파일을 해석 및 실행한다. 현재 하나의 런처가 개발 및 배포에 동일하게 사용된다. 예전에 사용되던 배포용 런처 jre는 더 이상 Sun JDK에서는 제공되지 않고, 이 로더로 대체되었다. * 한 줄 정리 =>자바 인터프리터, 바이트코드를 실행한다.
javac.exe:자바 컴파일러. 자바 소스 파일을 바이트코드로 변환해준다.
javap.exe:클래스 파일을 자바 소스 코드로 디스어셈블해주는 도구
# 본격적으로 자바 소스코드 작성 후 컴파일해보기
class HelloWorld
{
public static void main(String[] args) {
System.out.println("Hello World!!");
}
}
- 우선적으로 해당 소스 코드를 아래와 같이 메모장에 작성합니다.
- 작성 완료 후 C 드라이브에 HelloWorld라는 폴더를 만듭니다.
* 폴더 이름을 꼭 HelloWorld로 할 필요는 없습니다. 원하시는 이름으로 만들어주세요.
- 폴더를 만들었으면 해당 폴더에 메모장 파일을 .Java 확장자로 저장합니다.
꼭 .Java 확장자로 저장을 해야 합니다.
저장을 완료했으면 cmd 창을 열어 위와 같이 입력합니다.
cmd창 명령어인 cd(Change Directory) 명령어를 사용해 해당 경로 이동
javac 명령어를 통해 자바 소스 파일을 자바 바이트코드로 변환합니다. => .class 파일 생성
javac 컴파일러가 만든 클래스 파일을 java 명령어를 통해 해석 및 실행한다. => 위 사진에서 볼 수 있듯이 Hello World 가 출력된 모습을 확인할 수 있습니다.
클래스 로더(Class Loader)가 컴파일된 자바 바이트코드를 런타임 데이터 영역(Runtime Data Areas)에 로드하고, 실행 엔진(Excution Engine)이 자바 바이트코드를 실행한다.
Class Loader(클래스 로더) - JVM내로 클래스(.class파일)를 로드하고, 링크를 통해 치하는 작업을 수행하는 모듈이다. - Runtime 시에 동적으로 클래스를 로드한다. - jar파일 내 저장된 클래스들을 JVM위에 탑재하고 사용하지 않는 클래스들은 메모리에서 삭제한다. - (컴파일러 역할) 자바는 동적 코드, 컴파일 타임이 아니라 런타임에 참조한다. 즉, 클래스를 처음으로 참조할 때, 해당 클래스를 로드하고 링크한다는 것이다.
Execution Engine(실행 엔진) - 클래스를 실행시키는 역할이다. - 클래스 로더가 JVM내의 런타임 데이터 영역에 바이트 코드를 배치시키고, 이것은 실행 엔진에 의해 실행된다. - 자바 바이트코드는 기계가 바로 수행할 수 있는 언어보다는 비교적 인간이 보기 편한 형태로 기술된 것이다. - 실행 엔진은 이와 같은 바이트코드를 실제로 JVM내부에서 기계가 실행할 수 있는 형태로 변경한다.
Interpreter(인터프리터) 실행 엔진은 자바 바이트 코드를 명령어 단위로 읽어서 실행한다. 하지만 이 방식은 인터프리터 언어의 단점을 그대로 갖고 있다. 한 줄씩 수행하기 때문에 느리다는 것이다.
JIT(Just - In - Time) - 인터프리터 방식의 단점을 보완하기 위해 도입된 JIT 컴파일러이다. - 인터프리터 방식으로 실행하다가 적절한 시점에 바이트코드 전체를 컴파일하여 네이티브 코드로 변경하고, 이후에는 해당 더 이상 인터프리팅 하지 않고네이티브 코드로 직접 실행하는 방식이다. - 네이티브 코드는 캐시에 보관하기 때문에 한 번 컴파일된 코드는 빠르게 수행하게 된다. - JIT컴파일러가 컴파일하는 과정은 바이트코드를 인터프리팅하는 것보다 훨씬 오래걸리므로 한번만 실행되는 코드라면 컴파일하지 않고 인터프리팅 하는 것이 유리하다. - JIT 컴파일러를 사용하는 JVM들은 내부적으로 해당 메서드가 얼마나 자주 수행되는지 체크하고, 일정 정도를 넘을 때에만 컴파일을 수행한다.
*네이티브 코드: 언매니지드 코드라고도 불립니다. 코드가 바로 Machine Code로 컴파일되고, 컴파일한 Machine과 동일한 칩 등을 사용하는 환경에서만 실행이 가능합니다.(예를 들면 C언어)
프로그램 언어의 다형성(多形性, polymorphism; 폴리모피즘)은 그 프로그래밍 언어의 자료형 체계의 성질을 나타내는 것으로, 프로그램 언어의 각 요소들(상수, 변수, 식, 오브젝트, 함수, 메소드 등)이 다양한 자료형(type)에 속하는 것이 허가되는 성질을 가리킨다. (출처 : 위키피디아)
# 오버라이딩(overriding)과 오버로딩(overloading)
오버라이딩과 오버로딩을 다형성이라고 정의 할 수 없다고 생각한다.
(위 책에서는 다형성에 가장 기본을 오버라이딩, 오버로딩으로 보고 있다.)
다형성을 구현하는 방법 중 대표적으로 알려진 것이다.
같은 메서드 이름, 같은 인자 목록으로 상위 클래스의 메서드를 재정의(오버라이딩)
같은 메서드 이름, 다른 인자 목록으로 다수의 메서드를 중복 정의(오버로딩)
ride : 올라타다
load: 적재하다
인공위성에서 내려볼 때 오버라이딩(올라타기)된 경우는 맨 위에 올라탄 존재만 보인다.
오버로딩(적재하기) 된 경우는 옆으로 적재된 모든 적재물이 다 보인다.
Animal.java
package polymorphism01;
public class Animal {
public String name;
public void showName() {
System.out.printf("안녕 나는 %s야. 반가워\n", name);
}
}
Penguin.java
package polymorphism01;
public class Penguin extends Animal {
public String habitat;
public void showHabitat() {
System.out.printf("%s는 %s에 살아\n", name, habitat);
}
// 오버라이딩 - 재정의 : 상위클래스의 메서드와 같은 메서드 이름, 같은 인자 리스트
public void showName() {
System.out.printf("어머 내 이름은 알아서 뭐하게요?");
}
// 오버로딩 - 중복정의 : 같은 메서드 이름, 다른 인자 리스트
public void showName(String yourName) {
System.out.printf("%s 안녕, 나는 %s라고 해\n", yourName, name);
}
}
Driver.java
package polymorphism01;
public class Driver {
public static void main(String[] args) {
Penguin pororo = new Penguin();
pororo.name = "뽀로로";
pororo.habitat = "남극";
pororo.showName();
pororo.showName("초보람보");
pororo.showHabitat();
Animal pingu = new Penguin();
pingu.name = "핑구";
pingu.showName();
}
}