[Java] 핵심 키워드
Updated:
Categories:
CS
자바에서 꼭 알아야하는 핵심 키워드에 대해 알아보자
용어정리
변수
- 전역 변수(== 멤버 변수, 필드)
- 인스턴스 변수 : 클래스 내부에 선언한 변수
- 클래스 변수 : 인스턴스 변수를 static으로 선언한 변수
- 지역 변수
- 메소드 내부에 선언한 변수
- 매개 변수(파라미터) 포함
클래스 vs 객체 vs 인스턴스
- 클래스 : 코드상으로만 존재하는 설계
- 객체 : 설계된 클래스를 선언한 상태
- 인스턴스 : 객체를 초기화하여 메모리에 할당한 상태
- 객체가 인스턴스의 의미까지 포함하므로 굳이 구분하여 말하지 않아도 된다.
함수 vs 메소드
- 함수 : 독립적으로 존재함
- 메소드 : 객체지향 언어에서 클래스에 종속적인 함수. 클래스 함수라고도 함
- 클래스 외부에 함수가 존재할 수 없으므로, 자바에서는 모든 함수를 메소드라 칭함
Overloading vs Overriding
- Method Signature
- 자바 컴파일러가 메소드를 구분하는 기준
- 메소드의 이름, 매개변수 개수, 매개변수 타입의 순서
- 리턴 타입은 포함 X
- 매개변수 타입은 다형성을 보장함 (ex. Object라면 모든 타입 가능)
- Overloading
- 기존에 없는 메소드를 추가하는 것
- 메소드 이름을 제외한 메소드 시그니처가 달라야함
- 매개변수 개수, 타입이 다르면 새로운 메소드를 선언할 수 있음
- 같은 클래스 내에서 적용됨
- Overriding
- 기존에 존재하는 메소드를 상속하여 재정의하는 것
- 기존의 메소드와 메소드 시그니처 + 리턴 타입이 같아야함
- 메소드 이름, 매개변수 개수, 타입, 리턴 타입이 같아야 함
- 상속관계에서 적용되며, 부모클래스보다 접근제어자를 좁게 재정의 불가
- static 메소드는 재정의 불가
- 객체지향의 다형성을 장점을 얻는다.
Type
원시타입 (Primitive Type)
- 실제 데이터를 메모리에 저장하는 타입
- 실제 값을 stack 영역에 저장하며, 고유한 주소를 가진다.
- 8가지 종류가 있음
- boolean, byte, short, int, long, float, double, char
종류 |
데이터형 |
byte |
bit |
범위 |
논리형 |
boolean |
1 |
8 |
true 또는 false |
문자형 |
char |
2 |
16 |
‘\u0000’ ~ ‘uFFFF’ (16비트 유니코드 문자 데이터) |
정수형 |
byte |
1 |
8 |
-128 ~ 127 |
정수형 |
short |
2 |
16 |
-32768 ~ 32767 |
정수형 |
int |
4 |
32 |
-2147483648 ~ 2147483647 (21억) |
정수형 |
long |
8 |
64 |
-9223372036854775808 ~ 9223372036854775807 (100경) |
실수형 |
float |
4 |
32 |
1.4E-45 ~ 3.4028235E38 |
실수형 |
double |
8 |
64 |
4.9E-324 ~ 1.7976931348623157E308 |
- Java에서 데이터를 다루는 최소 범위는 1 Byte
- boolean도 1bit만 필요하지만, 어쩔수 없이 1 Byte로 저장.
- jvm에서는 스택 영역에 4 Byte 단위로 저장함
- 기본적으로 int로 형변환하여 연산함
- long 사용시
L
, float 사용시 F
를 붙여야함
참조타입 (Reference Type)
- 데이터가 저장된 주소값을 저장하는 타입
- stack 영역에 저장된 데이터의 주소값을 heap 영역에 저장한다
- 원시타입을 제외한 모든 타입이다
차이점
- 각 타입마다 기본값이 있기 때문에 원시타입에는 null을 넣을수 없지만, 참조타입은 가능
- 원시타입은 제네릭 타입으로 사용할 수 없지만, 참조타입은 가능
- 원시타입은 stack에 바로 접근하기에 접근속도가 빠르지만, 참조타입은 주소를 통해 한번더 접근해야하기에(언박싱) 느리다.
Wrapper Class
- 8가지의 원시타입을 객체로 표현한 것
- jdk 1.5부터 오토박싱과 오토언박싱을 지원한다.
- 오토박싱 :
Integer a = 1
- 오토언박싱 :
int a = new Integer(1)
- 비교시에도 오토박싱과 오토언박싱을 지원한다.
1 == Integer(1)
- 단 래퍼 클래스 비교시
==
사용하면 주소값을 비교함
- 사용이유
- 객체이므로
Object
를 사용함으로써 타입이 유연함 (메소드의 매개변수로 받을때)
java.util
패키지에서 객체만 처리하므로 래퍼 클래스 필요
- 원시타입을 제네릭 타입으로 사용 불가
- ex)
ArrayList<Integer>
에 1 저장시 오토박싱 일어남
- 멀티스레드에서 동기화를 하기 위해서 (공유 메모리 영역인 힙영역에 저장되므로)
Call By Reference vs Call By Value
- 메소드의 매개변수 호출 방식
- Call By Reference
- Call By Value
- 자바는 Call By Value !!!
- 자바는 데이터(주소값) 자체를 복사함
- 헷갈리는 이유 : 참조타입은 데이터에 주소값이 들어있는데, 이를 복사하기 때문에 Call By Reference처럼 보이기 때문
동일성 vs 동등성
- 동일성(identity) : 두 객체가 완전히 같은 경우
- 주소까지 완전히 동일한 객체일 때 (stack or heap 영역이 완벽히 일치)
==
연산의 결과
- 동등성(equality) : 두 객체가 같은 정보를 갖고 있는 경우
- 주소가 달라도 내용이 동일할때
- equals 연산의 결과
hashcode & equals
- hashcode()
- 객체가 가지는 고유의 값을 반환하는 메소드
- Object 클래스의 기본 메소드는 객체의 메모리 주소값을 해시코드로 만들어 반환한다
HashMap
과 같은 자료구조에서 동등성 비교를 위해 사용된다.
- equals()
- 객체가 가진 정보로 객체의 동등성을 비교한 결과를 나타내는 메소드
- Object 클래스의 기본 메소드는 객체의 메모리 주소값을 비교한다
- equals()와 hashcode() 두 메소드 모두 객체의 동등성을 검사하기 위한 것이다.
- 한 객체의 동등성 검사 기준은 동일해야 한다.
- 즉, 두 메소드 중 하나를 재정의한다면 나머지 하나도 반드시 재정의해줘야 한다!
Throwable
Error와 Exception의 차이
- Error
- 시스템에 오류가 발생한 경우 (메모리 부족, 스택오버플로우 등등)
- jvm에서 발생시키기 때문에 어플리케이션 레벨에서 잡을 수 없다
- Exception
- 정상적인 프로그램 흐름이 어긋날 때 발생한다 (배열 인덱스 초과, 널포인터 등등)
- 예외 상황을 예측하여 개발자가 직접 핸들링할 수 있다
Checked Exception vs UnChecked Exception
- Checked Exception
- 실행 전 발생할 수 있는 에러 -> 컴파일 시점에서 발생함
- Exception 처리를 강제한다
- UnChecked Exception
- 실행 중 발생할 수 있는 에러 -> 런타임 시점에서 발생함
- RuntimeException을 상속받는다.
- 롤백 관련 참고링크
제어자
접근제어자
- 허용범위 : public > protected > default > private
- 접근제어자는 타 사용자로부터 객체내부 접근을 제한하여 의도치 않은 오작동을 막기 위해 사용한다.
일반제어자
- static, final, abstract, native, transient, synchronized, volatile, strictfp
static
- 일반적인 변수는 jvm 힙 영역에 저장되는 반면, static 변수는 메소드 영역에 저장된다
- 메소드 영역은 가비지 컬렉터가 동작하지 않으므로, 프로그램 종료시까지 할당된 채로 존재함
- 모든 인스턴스가 같은 값을 유지해야할 때 사용
- 유틸 클래스처럼 인스턴스를 생성할 필요가 없는 클래스에서 사용.
- 장점
- 단점
- 무분별하게 사용시 JVM 메소드 영역을 너무 많이 차지함
final
- 객체를 단 한번만 할당하는 제어자. 두번 할당하려하면 컴파일 오류 발생
- 변수, 메소드, 클래스에 적용할 수 있음
- 변수는 상수처럼 고정하여 사용
- 메소드는 Overriding 불가
- 클래스는 상속 불가
- ex) Wrapper class
- 하지만 내부 값은 변경 가능
Effectively final
- Java 8 에 추가된 syntactic sugar의 일종 (문법적인 의미)
- 변수가 초기화 된 이후 값이 한번도 변경되지 않았다면 Final과 동일하게 컴파일러에서 처리하는 것.
generic
- 객체 생성 시점에 타입을 결정하여, 유연한 설계를 가능하게 하는 기능
- 컴파일시 타입을 미리 체크한다
- ex) Collection 라이브러리
Object와의 차이
- Object는 객체 생성시 타입을 지정하지 않는다.
- generic은 객체 생성시 타입을 지정해준다
- Object를 사용하면 값을 리턴받을 때마다 캐스팅을 해줘야 하고, 개발자가 실수할 수도 있다
- generic을 사용하면 객체 생성시 타입을 지정했기에 캐스팅이 필요 없다.
- Object는 런타임시 오류가 발생한다
- generic은 컴파일 시점에서 오류를 체크할수 있다.
syncronized
- 멀티 스레드 환경에서 동기화 문제를 해결하기 위한 제어자
- thread-safe한 환경을 만들기 위해 사용
- 경쟁(Race condition)을 방지
- 한 스레드가 자원을 점유하면 코드블록을 block 상태로 바꾸어 다른 스레드가 접근하지 못하게 함
- 코드블록을 synchronized 제어자로 감싸주면 된다
- 인스턴스 단위로 동기화됨 -> 메소드에는 잘 사용하지 않음
- 제대로 설정하지 않으면 비효율적으로 동작하게 된다
volatile
- 변수를 CPU 캐시가 아닌 메인 메모리에서 저장 + 조회할 것을 명시하기 위해 쓰이는 제어자
- 변수가 CPU 캐시를 사용하지 않도록 선언하기
- 자바는 성능 향상을 위해 메인 메모리에서 읽은 변수를 CPU 캐시에 저장한다
- 멀티스레드 환경에서 스레드마다 다른 CPU 캐시를 가지고, 이는 동기화되지 않기 때문에 데이터 무결성 보장 X
- 따라서 멀티스레드 환경에서 사용될 변수는
volatile
제어자를 붙여 메인메모리만 사용하도록 한다
- 물론 동시성 처리는 thread-safe하도록 따로 구현해야함
interface vs abstract class
abstract class
- 부모 클래스에서 필요한 대부분의 기능을 구현하고, 자식 클래스가 재정의할 부분은 추상 메소드로 선언하는 것
- 상속 + 다형성을 통해 기능을 확장하는 것
- 클래스와 메소드에 abstract 제어자를 붙여준다
- 다중 extends 불가능
- 필드값과 일반 메소드를 가질 수 있다.
interface
- 인터페이스를 implements하는 여러 클래스들의 메소드 구현을 강제하기 위해 사용한다
- static 필드는 선언 가능
- 다중 implements가 가능하다
- java 8부터 default 메소드로 기본 구현이 가능하다
정리
차이점
- 인터페이스는 필드값을 가지지 못한다
- 추상 클래스는 다중 상속이 불가능하지만 인터페이스는 다중 구현이 가능하다
- 의미에 차이가 있다
- 추상 클래스는 공통된 개념에 초점을 맞춘다
- 인터페이스는 공통된 기능에 초점을 맞춘다
Annotation
- 주석의 의미로 특별한 의미를 부여하거나 기능을 수행하도록 하는 메타데이터
기능
- 컴파일러에게 코드 작성 문법 에러를 체크하도록 정보 제공
- 빌드나 배치시 코드를 자동으로 생성할 수 있도록 정보 제공
- 런타임시 특정 기능을 실행하도록 정보를 제공
종류
- 표준 어노테이션 : 자바의 기본 제공 어노테이션
- 메타 어노테이션 : 어노테이션을 위한 어노테이션
- 마커 어노테이션 : 값을 지정할 필요가 없는 경우. 의미만 나타냄
@Serializable
, @Cloneable
, @Test
생성하기
@Target() // 적용 가능한 대상 종류 지정
@Retention( ) // 어노테이션 적용 시점 지정
public @interface 어노테이션 {
타입 요소();
String str(); default{};
}
- 정의는 인터페이스와 동일함
- 규칙
- 상속 불가
- 요소 타입은 기본형, String, enum, 어노테이션, Class만 허용
- ()안에 매개변수 선언 불가
- 예외 선언 불가
- 요소를 타입 매개변수로 정의 불가
Enum
Lambda
- 익명함수를 뜻하고, 그 자체로 일급객체가 되며 매개변수처럼 사용할 수 있다.
- 람다함수 내부에서는 외부 지역 변수를 사용할 수 없음
- but
final
or Effectively final
변수는 사용할 수 있다
- 람다 실행시 임시 스레드가 따로 생성되므로, 스택영역을 공유하지 않기 때문
final
변수 또한 공유하는 것이 아닌 람다식에서 ‘복사’하여 사용하는 것.
Functional Interface
- 추상메소드가 하나만 존재하는 인터페이스
- 인터페이스가 포함하는 메소드가 여러개여도 추상메소드만 하나면 조건 만족
@FunctionalInterface
어노테이션을 달아준다.
- Functional Interface의 메소드를 람다식으로 재정의하여 사용한다
- 여러 종류가 있음
종류 |
인자값 |
리턴값 |
용도 |
Runnable |
X |
X |
실행시키기 |
Supplier |
X |
T |
데이터 생성 |
Consumer |
T |
X |
데이터 사용 |
Function |
T |
R |
타입 변환 |
Predicate |
T |
bool |
조건식 |
Stream
- 컬렉션이나 배열의 요소를 내부적으로 반복 처리하는 기능
- 원본 객체를 변경하지 않는다.
- 원본 객체를 참조하여 어떠한 새로운 결과를 도출해 내는것
- 일회용으로만 사용가능하다
- stream 객체는 한번 선언하면 재사용이 불가능하다.
- 3가지 단계를 거쳐 사용된다
- stream 생성
- 중개 연산 : filter-map API를 사용하여 지연(lazy) 연산을 통해 선응을 최적화함
- 최종 연산 : 이때 실제로 연산이 이루어지며, 지연됐던 모든 연산을 처리한다
- lambda와 stream의 장점
- 불필요한 코드를 줄여 가독성을 좋게한다.
- 내부 연산으로 병렬 처리가 가능하다
- 단점
Reflection
- 객체에서 클래스의 정보를 가져와 분석할 수 있도록하는 기법
- JVM에서의 런타임시 동작을 검사하고 수정하기 위해 사용된다
- 이미 로딩된 클래스에서 동일한 새로운 클래스를 동적로딩하여 사용할 수 있도록 함
- Proxy 패턴을 구현하기 위해 자주 사용된다
Class class = "객체".getClass();