OOP의 4가지 특징
- 상속 추상화 캡슐화 다형성 (상추 캡이다)
- 추상화 : 객체들의 공통적인 특징을 뽑아내는 것. 객체들의 공통적인 데이터와 기능을 도출: 현실의 복잡성을 극복하고 목적에 집중
- 캡슐화 : 맡은 목적 실행 위해 상태와 행동을 하나의 단위로 묶는 자율적 실체 + 데이터 은닉
- 상속 : 새로운 클래스가 기존의 클래스의 자료와 연산을 이용하게 해주는 것. 중복되는 속성과 기능을 재사용
- 다형성 : 다양한 형태로 표현이 가능하다는 의미 + 동일 요청에 대해 서로 다른 방식으로 응답할 수 있음
- Overriding : 상속받은 동일한 메소드 재정의
- Overloading : 동일한 메소드가 매개변수 타입, 개수 차이에 따라 다르게 동작
JVM, JRE, JDK
-
JVM(Java Virtual Machine) : 자바 가상머신
- JVM은 자바 소스코드로부터 만들어지는 자바 바이너리 파일(.class)을 실행할 수 있는 런타임 환경을 제공해주는 규격
- JVM은 플랫폼에 의존적(리눅스의 JVM과 윈도우즈의 JVM은 다름)
- 단 컴파일된 바이너리 코드는 어떤 JVM에서도 동작시킬 수 있음
- OS마다 구성이 다르므로 JDK, JRE, JVM은 플랫폼에 의존적이지만 자바 자체는 플랫폼에 독립적임
-
JRE(Java Runtime Enviroment) : 컴파일된 자바 프로그램을 실행시킬 수 있는 자바 환경
- JRE는 JVM이 자바 프로그램을 동작시킬 때 필요한 라이브러리 파일들과 기타 파일들을 가지고 있음
- JRE는 JVM의 실행환경을 구현했다고 할 수 있음
- 자바 프로그램을 실행시키기 위해선 JRE를 반드시 설치해야 함
- 하지만 자바 프로그래밍 도구는 포함되어있지 않기 때문에 자바 프로그래밍을 하기 위해선 JDK가 필요
-
JDK(Java Development kit) : 자바 프로그래밍시 필요한 컴파일러 등 포함
- JDK는 개발을 위해 필요한 도구(javac, java등)들을 포함
- JDK를 설치하면 JRE도 같이 설치됨
- JDK = JRE + @
자바의 메모리 구조
참조형(Reference Type)의 데이터 타입을 갖는 객체(인스턴스), 배열 등은 Heap 영역에 데이터가 저장된다. 이때 변수(객체, 객체변수, 참조변수)는 Stack 영역의 공간에서 실제 데이터가 저장된 Heap 영역의 참조값(reference value, 해시코드 / 메모리에 저장된 주소를 연결해주는 값)을 new 연산자를 통해 리턴 받는다. 다시 말하면 실제 데이터를 갖고 있는 Heap 영역의 참조 값을 Stack 영역의 객체가 갖고 있다. 이렇게 리턴 받은 참조 값을 갖고 있는 객체를 통해서만 해당 인스턴스를 핸들 할 수 있다.
자바 프로그램 실행 과정
- 자바 컴파일러(Java compiler): 작성한 자바 소스 코드를 JVM이 이해할 수 있는 자바 바이트 코드로 변환
- 컴파일: 프로그래밍 언어를 Runtime 이전에 기계어로 해석하는 작업 방식
- 자바 바이트 코드(Java bytecode): JVM이 이해할 수 있는 언어로 변환된 자바 소스 코드(.class)
- 자바 바이트 코드는 JVM이 설치되어 있으면, 어떤 운영체제에서라도 실행될 수 있습니다.
- 자바 인터프리터:
- interpret: Runtime 이후에 Row 단위로 해석하며 프로그램을 구동시키는 방식
- 프로그래밍 언어를 기계어로 바로 바꾸지않고 중간 단계를 거친 뒤 런타임에 즉시 해석하기 때문에 바로 컴팩트한 패키지 형태로 Binary 파일을 뽑아낼 수 있는 Compile 방식에 비해 낮은 퍼포먼스
- Bytecode -> BinaryCode로 해석
클래스 변수와 인스턴스 변수
https://itmining.tistory.com/20
public class test {
int iv; // 인스턴스 변수
static int cv; // 클래스 변수
void method() {
int lv; // 지역 변수
}
}
-> 개인적으로 용어가 약간 혼동되는데 여기서의 선언위치란 메모리 위치가 아닌 코드상의 위치이다
- 인스턴스 변수
- 인스턴스가 생성될 때 생성->값을 읽어오거나 저장하려면 인스턴스를 먼저 생성해야 함
- 인스턴스 별로 다른 값을 가질 수 있으므로, 각각의 인스턴스마다 고유의 값을 가져야할 때는 인스턴스 변수로 선언
- 클래스 변수
- 인스턴스 변수 + static
- 클래스 변수는 모든 인스턴스가 공통된 값을 공유하게 됨
- 한 클래스의 모든 인스턴스들이 공통적인 값을 가져야할 때
- 클래스가 로딩될 때 생성, 메모리에 딱 한번만 올라감
- 인스턴스를 생성하지 않고 클래스이름.클래스변수명 으로 접근 가능
- -> Static 변수와 static 메소드는 Static 메모리 영역에 존재하므로 객체가 생성되기 이전에 이미 할당이 되어 있기 때문
- static 변수의 초기화
- primitive type이 static이라면 명시적으로 초기화하지 않으면 default value로 초기화, reference인 경우에는 null로 초기화
- 객체가 생성될 때
- 클래스의 static 맴버를 처음 액세스 할 때
- static method는 상속이 되지 않는다. static 메서드는 클래스가 컴파일 되는 시점에 결정이 되지만 Override에 경우에는 런타임 시점에 사용될 메서드가 결정이 되기 때문. 대신 hiding이라고 override를 하지 않고 같은 이름으로 하는 잔꾀기술이 있는데 되도록 쓰지 않아야함
- 클래스변수의 초기화시점 : 클래스가 처음 로딩될 때
- 인스턴스변수의 초기화시점 : 인스턴스가 생성될 때마다 각 인스턴스별로 초기화
- 지역 변수
- 메서드 내에서 선언되며 메서드 내에서만 사용 가능
- 메서드가 실행될 때 메모리를 할당 받으며 메서드가 끝나면 소멸되어 사용할 수 없음
Interface vs Abstract Class
- 자바8 부터는 인터페이스의 변화
- default 키워드를 통해 구현체를 가질 수 있음(일반적인 메소드 구현 가능). 인터페이스가 변경 되면 인터페이스를 구현하는 모든 클래스들이 해당 메소드를 구현해야 하는 문제를 해결하기 해 인터페이스에 메소드를 구현해 놓을 수 있도록 함
- static 메소드 선언 가능
- 인터페이스에서 정의한 static메소드는 반드시 인터페이스명.메소드 형식으로 호출해야한다. 인터페이스에 static 메소드를 선언함으로써, 인터페이스를 이용하여 간단한 기능을 가지는 유틸리티성 인터페이스를 만들 수 있게 되었다.
public interface Calculator {
public int plus(int i, int j);
public int multiple(int i, int j);
default int exec(int i, int j){
return i + j;
}
public static int exec2(int i, int j){ //static 메소드
return i * j;
}
}
public class MyCalculatorExam {
public static void main(String[] args){
Calculator cal = new MyCalculator();
int value = cal.exec(5, 10);
System.out.println(value);
//인터페이스에서 정의한 static메소드는 반드시 인터페이스명.메소드 형식으로 호출해야한다.
int value2 = Calculator.exec2(5, 10); //static메소드 호출
System.out.println(value2);
}
}
-
공통점
- 자기 자신이 new를 해서 객체를 생성할 수 없으며,
추상클래스를 extends 받거나, interface를 implements 한 자식만이 객체를 생성할 수 있다.
- 상속받은 자식이 구현을 반드시 하도록 해야할 때 사용한다.
- 추상 메소드가 있으면 자식은 반드시 다 구현해야 한다.
-
추상클래스
- abstract 메소드가 하나라도 존재하는 클래스
- 구현되어 있는 메소드도 존재할 수 있음 (JAVA8부터는 인터페이스도)
- 동일한 부모를 가지는 클래스를 묶는 개념으로 상속을 받아서 기능을 확장시키는 것이 목적
- 관련성이 높은 클래스 간에 코드를 공유하고 싶은 경우
-
인터페이스
- 구현해야 할 메소드들의 명세
- 인터페이스의 경우, default 또는 static 으로 선언되지 않은 모든 메소드는 암묵적으로 abstract
- 서로 관련성이 없는 클래스들이 인터페이스를 구현하게 되는 경우에 사용한다. 예를 들어, Comparable, Cloneable 인터페이스는 여러 클래스들에서 구현되는데, 구현클래스들 간에 관련성이 없는 경우가 대부분
- 특정 데이터 타입의 행동을 명시하고 싶은데, 어디서 그 행동이 구현되는지는 신경쓰지 않는 경우.
-
차이점
- 인터페이스에서 모든 변수는 기본적으로 public static final 이며, 모든 메소드는 public abstract 인 반면
- 추상클래스에서는 static 이나 final 이 아닌 필드를 지정할 수 있고, public, protected, private 메소드를 가질 수 있다.
인터페이스를 구현하는 어떤 클래스는, 다른 여러개의 인터페이스들을 함께 구현할 수 있다. 추상클래스는 상속을 통해 구현되는데, 자바에서는 다중상속을 지원하지 않으므로 추상클래스를 상속받은 서브클래스는 다른 클래스를 상속받을 수 없다.
예시: HashMap
public class HashMap<K,V>
extends AbstractMap<K,V>
implements Map<K,V>, Cloneable, Serializable
-
AbstractMap 의 서브클래스인 HashMap, TreeMap, ConcurrentHashMap 에서는 AbstractMap 에 정의되어 있는 get, put, isEmpty, containsKey, containsValue 등의 메소드를 공유한다.
-
또한 HashMap은 Serializable, Cloneable, Map<K,V> 세 개의 인터페이스를 구현한 클래스이다. 위 인터페이스를 통해 HashMap 의 인스턴스는 복제가능하며, 직렬화(byte stream 으로 컨버팅)가 가능하며, map 으로써의 기능을 가진다는 것을 추론할 수 있다.
원시형 데이터, 참조형 데이터
- 원시형 데이터(Primitive)
- 반드시 사용하기 전에 선언되어야 함
- OS에 따라 자료형의 길이가 변하지 않음
- 비객체 타입이므로
null
값을 가질 수 없음
- 참조형 데이터(Reference)
- 클래스에 정의된 생성자를 사용하여 만들어지며 디폴트 값은 null
- 객체를 참조하는데 사용
- 저장 위치
Wrapper Class
public final class Integer extends Number implements Comparable {
...
private int value;
...
}
- 이런식으로 Wrapper Class안에 값이 들어있음
- Wrapper Class는 unboxing을 하지 않으면 산술 연산 불가능
- null값 처리 가능
- wrapper 클래스들은 모드 equals()가 오버라이딩되어 있어 비교를 해도 주소값이 아닌 객체가 가지고 있는 값을 비교
- MAX_VALUE, MIN_VALUE, SIZE, TYPE 등 static 멤버 공통으로 가짐
직렬화와 역직렬화
제네릭(Generic)
- 컬렉션(collection) 클래스에서 제네릭을 사용하는 이유
- 컬렉션 클래스에 저장하는 인스턴스 타입을 제한하여 런타임에 발생할 수 있는 잠재적인 모든 예외를 컴파일타임에 잡아낼 수 있도록 도와줌
자바 Reflection API
- 클래스의 구조를 개발자가 확인할 수 있고, 값을 가져오거나 메소드를 호출하는데 사용
- JVM에서 실행되는 애플리케이션의 런타임 동작을 검사하거나 수정할 수 있는 기능이 필요한 프로그램
- 구체적인 클래스 타입을 알지 못해도 클래스의 타입, 메소드, 변수를 접근할 수 있게 해주는 API
- 예시: 스프링 프레임워크, 대표적 ORM 기술인 하이버네이트, jackson라이브러리 등
- 스프링에서는 런타임 시에 개발자가 등록한 빈을 애플리케이션에서 가져와 사용할 수 있게 되는 것
.getClass
, Class.forName("ko.maeng.reflection.ReflectionApplication");
등
String과 StringBuffer의 차이
- String은 immutable(불변)하고 StringBuffer, StringBuilder는 mutable(가변)
- String (literal)
- 리터럴로 생성하면 String Pool에 생성, 문자열 값은 절대 변하지 않음
-
'+' 연산이나 .concat() 메소드를 이용해서 문자열 값에 변화를 줘도 메모리 공간 내의 값이 변하는 것이 아니라, String Pool에 메모리를 할당받아 새로운 String 클래스 객체를 만듬
-
String 클래스가 적절한 경우
- 문자열 연산이 적고 자주 참조하는 경우(멀티 쓰레드 환경에서 신경쓸일X)
-
StringBuffer, StringBuilder
-
.append()
등을 통해 동일 객체내에서 문자열 변경 가능
- StringBuffer/StringBuilder 클래스가 적절한 경우
- StringBuffer VS StringBuilder
- StringBuffer는 동기화 키워드를 지원, thread-safe
- StringBuilder는 동기화 키워드 지원X, thread-unsafe 하지만 단일쓰레드에서의 성능은 StringBuffer보다 뛰어남
Jar(Java Archive) vs War(Web Application Archive) vs Ear(Enterprise Archive)
-
공통점
- JAVA의 jar tool을 이용해 생성된 압축(아카이브) 파일
- 압축의 해제없이 JDK에서 각 파일들을 접근하여 사용할 수 있도록 설계
- 관련 파일(리소스, 속성파일 등)들을 패키징
- 각각 다른 목적을 가지고 사용
-
Jar
- Class, 라이브러리 등 자바 프로젝트를 압축한 파일
- 원하는 구조로 구성 가능, JDK의 JRE만 가지고도 실행 가능
-
War
- Servlet, JSP Container에 배치할 수 있는 웹 어플리케이션 압축 포맷
- Servlet Context 관련 파일들로 패키징
- 웹 응용 프로그램을 위한 포맷이므로 웹 관련 자원만 포함
- WEB-INF, META-INF 디렉토리로 사전 정의 된 구조 사용
- 실행하려면 Tomcat같은 웹 서버 혹은 WAS가 필요
- war도
java -jar
을 이용해 생성함
-
Ear
참고자료
https://itmining.tistory.com/20
https://goodgid.github.io/Java-JDK-JRE/
https://ktko.tistory.com/entry/%EA%B0%9C%EB%B0%9C%EC%9E%90-%EB%A9%B4%EC%A0%91-%EC%A7%88%EB%AC%B8%EC%9E%90%EB%B0%94-%EC%8A%A4%ED%94%84%EB%A7%81
https://woowabros.github.io/experience/2017/10/17/java-serialize2.html
https://yaboong.github.io/java/2019/01/19/java-generics-1/
http://tcpschool.com/java/java_intro_programming
https://medium.com/msolo021015/%EC%9E%90%EB%B0%94-reflection%EC%9D%B4%EB%9E%80-ee71caf7eec5
https://jusungpark.tistory.com/17
https://ifuwanna.tistory.com/221
https://jeong-pro.tistory.com/85
https://yaboong.github.io/java/2018/09/25/interface-vs-abstract-in-java8/
https://programmers.co.kr/learn/courses/5/lessons/241