추상 메소드만 담고 있는 인터페이스 인터페이스는 다음과 같다. class 대신 interface라는 선언을 쓰고, 메소드는 바디 없이 세미콜론으로 마무리 된다. 위에서 보듯이 메소드의 몸체가 비어 있는 메소드를 가리켜 추상 메소드라 한다. 인터페이스를 대상으로는 인스턴스 생성이 불가능하다. 클래스가 인터페이스를 상속하는 행위는 상속이 아닌 구현이다. 인터페이스 구현에는 다음과 같은 특징이 있다. 구현할 인터페이스를 명시할 때 implements를 사용한다. 한 클래스는 둘 이상의 인터페이스를 동시에 구현할 수 있다. 상속과 구현은 동시에 가능하다. 인터페이스 관련하여 다음 두 특징도 기억해야 한다. 인터페이스의 형을 대상으로 참조변수의 선언이 가능하다. 인터페이스의 추상 메소드와 이를 구현하는 메소드 사이에 오버라이딩 관계사 성립한다. 다음은 인터페이스 문법을 확인하는 예제다. 인터페이스의 본질적 의미 인터페이스
제네릭 클래스 상속 제네릭 클래스도 상속이 가능하다. Box 와 같은 것을 매개변수화 타입 또는 제네릭 타입이라 한다. 타입이라는 단어는 Box를 일종의 자료형으로, 정확히는 클래스의 이름으로 간주함을 뜻한다. 따라서 다음과 같은 상속 관계를 표현할 수 있다. 하지만 다음은 성립하지 않는다. 타겟 타입 (Target Types) 컴파일러가 자료형 유추를 진행하는 상황은 다양하다. EmptyBoxFactory 클래스의 makeBox 메소드는 인자를 전달받지 않는다. 따라서 다음과 같이 T에 대한 타입 인자를 전달해야 한다. 그런데 자바 7부터 다음과 같이 호출하는 것이 가능하다. makeBox 메소드는
제네릭이 갖는 의미는 일반화이다. 자바에서 일반화의 대상은 자료형이다. 제네릭 이전의 코드 위 예제에서 AppleBox, OrangeBox의 역할과 내용은 같다. 따라서 이 둘은 하나로 대체할 수 있다. 위 예제에 Object형을 사용하므로 다음을 주의해야한다. Box 인스턴스에서 내용물을 꺼낼 때 형 변환을 해야 한다. Box 내에서 인스턴스를 저장하는 참조변수가 Object형이기 때문에, 저장된 인스턴스를 꺼낼 때에는 인스턴스에 맞는 형 변환을 해야만 한다. 이 과정은 다음과 같은 실수가 발생할 수도 있다. 모든 실수는 컴파일 단계에서 드러나는 것이 좋다. 컴파일 오류는 원인을 바로 찾을 수 있다. 실행 중 발생하는 예외는 다르다. 예외의 원인은 쉽게 발견되지 않는 경우도 많다. 뿐만 아니라 위와 같은 실수는 드러나지 않을 수도 있다. 위 예제는 대형 사고로 이어질 수 있다. 제네릭 기반의 클래스 정의하기 제
스레드 풀 스레드의 생성과 소멸은 그 자체로 시스템의 부담을 주는 일이다. 처리해야 할 일이 있을 때마다 스레드를 생성하는 것은 성능의 저하로 이어질 수 있다. 그래서 스레드 풀(Thread Pool)이라는 것을 만들고 미리 제한된 수의 스레드를 생성해 두고 이를 재활용하는 기술을 사용한다. 처리해야 할 작업이 있을 때 풀에서 스레드를 꺼내 작업을 처리한다. 작업을 끝낸 스레드는 다시 풀로 돌아가 다음 작업을 대기하게 된다. 하지만 다음과 같이 스레드를 만들면 스레드는 작업이 종료된 후 소멸한다. 따라서 멀티 스레드 프로그래밍에서 스레드 풀의 활용은 매우 중요하다. 스레드 풀의 구현은 concuurent 패키지를 활용하면 된다. Executors 클래스의 다음 메
스레드의 메모리 접근 방식과 그에 따른 문제점 다음 코드는 둘 이상의 스레드가 한 메모리 공간(한 변수)에 접근했을 때 발생하는 문제를 보여준다. 다음 join 메소드는 특정 스레드의 실행이 완료되기를 기다릴 때 호출한다. main 스레드가 두 스레드의 실행이 완료되기를 기다리기 위해서 join 메소드를 호출했다. 실행 결과는 예상과 다르다. increment 천 번, decrement 천 번이므로 출력 결과는 0이어야 하는데, 실행할 때마다 출력 값이 다르다. 이를 통해 다음을 유추할 수 있다. 둘 이상의 스레드가 동일한 변수에 접근하는 것은 문제를 일으킬 수 있다. 따라서 둘 이상의 스레드가 동일한 메모리 공간에 접근해도 문제가 발생하지 않도록 동기화(synchronization)를 해야한다. 동일한 메모리 공간에 접근하는 것은 왜 문제가 되는가? 변수에 저장된 값을 1씩 증가하는 연산을 두 스레드가 동시에 진행한다고 가정한다.
스레드의 이해와 스레드 생성 방법 스레드는 실행 중인 프로그램 내에서 또 다른 실행의 흐름을 형성하는 주체이다. 다음과 같은 프로그램을 실행하면 JVM은 하나의 스레드를 생성해서 main 메소드의 실행을 담당한다. 스레드 생성 방법 스레드 생성을 위해 java.lang.Runnable 인터페이스를 구현하는 인스턴스를 생성한다. Runnable은 추상 메소드 하나만 존재하는 함수형 인터페이스다. void run 만 가지고 있다. JVM은 스레드를 생성해서 Thread 인스턴스 생성 시 전달된 run 메소드를 실행한다. 실행 결과의 Thread-0는 기본적으로 주어진 이름이다. 별도의 이름을 붙이고 싶다면 다음 생성자를 이용한다. 실행 결과를 보면 main 스레드가 작업을 먼저 끝냈다. 스레드 생성에는 시간이 걸리므로 이러한 결과는 쉽게 나온다. main 스레드가 작업을 종료하더라도 프로그램은 종료되지 않는다. 모
기존 매퍼 클래스 entity → dto 변환을 생성자를 통해 직접 해줘야한다. MapStruct 인터페이스 다음과 같이 인터페이스에 메소드 정의만 하면 됨 인터페이스 위에 @Mapper 어노테이션 사용 MapStruct를 실제 이용 MapStruct 인터페이스에서 정의한 static 변수를 이용해 메소드에 접근한다. 사용 방법은 기존 매퍼 클래스와 크게 다르지 않다. 인터페이스의 구현체는 어디서? MapStruct 인터페이스를 정의하고 프로그램을 실행하면 다음과 같이 generated 폴더가 생긴다. 다음과 같이 인터페이스명Impl 클래스를 확인해보면 자동으로 인터페이스에서 정의한 메소드의 인자와 반환 값에 맞는 매핑 로직을 만
학습할 것 package 키워드 import 키워드 클래스패스 CLASSPATH 환경변수 classpath 옵션 접근지시자 package 키워드 패키지란 클래스를 구분짓는 폴더 개념이다. 자바는 패키지의 가장 상위 디렉토리에서 실행해야한다는 약속이 있다. 그렇기 때문에 해당 패키지로 가서 컴파일하지 않는다. 소스에 가장 첫 줄에 있어야하고, 패키지 선언은 소스 파일에 하나만 있어야 한다. 패키지 이름과 위치한 폴더의 이름이 같아야한다. 패키지 이름을 java로 시작하면 안된다. 클래스의 이름은 패키지 이름도 포함한다. 패키지 명명 규칙 패키지 이름은 모두 소문자여야 한다. 자바의 예약어를 사용하면 안된다. (int, static) 개발 패키지 표준은 정하는 것에 따라 지정한다. Built-in 패키지 패키지의 종류는 사용자 정의 패키지와 Built-in 패키지로 나눈다. Built-i
제어자는 클래스, 변수 또는 메서드의 선언부에 함께 사용되어 부가적인 의미를 부여한다. 제어자의 종류는 접근 제어자와 그 외의 제어자로 나눌 수 있다. 제어자는 클래스나 멤버변수와 메서드에 주로 사용된다. 하나의 대상에 대해서 여러 제어자를 조합하여 사용하는 것이 가능하다. 단 접근 제어자는 한 번에 하나만 선택해서 사용한다. 제어자의 조합 제어자를 조합할해서 사용할 때 다음 사항을 주의해야한다. 메서드에 static과 abstarct를 함께 사용할 수 없다 static 메서드는 몸통이 있는 메서드에만 사용할 수 있다. 클래스에 abstract와 final을 동시에 사용할 수 없다 클래스에 사용되는 final은 클래스를 확장할 수 없다는 의미다. abstract는 상속을 통해서 완성되어야 한다는 의미다. 이 둘은 서로 모순된다. abstract 메서드의 접근 제어자가 private일 수 없다
학습할 것 자바 상속의 특징 super 키워드 메소드 오버라이딩 다이나믹 메소드 디스패치 (Dynamic Method Dispatch) 추상 클래스 final 키워드 Object 클래스 자바 상속 상속이란 상위클래스에서 정의한 필드와 메서드를 하위클래스도 동일하게 사용할 수 있게 물려받는 것이다. 상속은 코드의 재사용성을 통해 코드의 간결성을 확보해준다. 상속의 특징 상속은 단일 상속만 가능하다. 최상위 부모는 Object 클래스다. 부모 클래스의 필드와 메소드만 상속된다. super 키워드 super 키워드는 자식 클래스에서 부모 클래스로부터 상속 받은 멤버를 참조하는데 사용한다. 상속 받은 멤버와 자식 클래스에 정의된 멤버의 이름이 같을 때는 super를 이용해서 구별할 수 있다. 메소드 오버라이딩 메소드 오버라이딩은 부모의 메소드를 자식 클래스에서 재정의하
학습할 것 클래스 정의하는 방법 객체 만드는 방법 (new 키워드 이해하기) 메소드 정의하는 방법 생성자 정의하는 방법 this 키워드 이해하기 클래스 클래스란 “객체를 정의해놓은 것” 또는 “객체의 설계도”라고 정의할 수 있다. 클래스는 객체를 생성하는데 사용한다. 객체는 클래스에 정의된 대로 생성된다. 클래스 정의하는 방법 예시 객체 만드는 방법 (new 키워드) new 연산자를 이용해서 객체를 생성한다. new 연산자는 클래스의 인스턴스를 생성하는 역할을 하고, 메모리에 데이터를 저장할 공간을 할당받는다. 할당한 공간의 참조값을 객체에게 반환하고 생성자를 호출한다. 메서드 정의하
JVM의 구성 JVM은 클래스 로더, 실행 데이터 영역, 실행 엔진 3가지로 구성되어 있다. 클래스 로더 (Class Loader) 런타임 시점에 클래스 파일을 로딩, 연결, 초기화하는 작업을 한다. 자바는 모든 것이 클래스다. 자바 애플리케이션을 실행하기 위해서는 JVM이 컴파일된 .class 파일을 로딩해야 한다. 클래스 로더는 이 기능을 수행한다. 클래스 로더는 클래스를 메모리에 로드하고 실행을 위해 사용할 수 있게 만든다. 클래스 로딩을 최대한 효율적으로 수행하기 위해 지연 로딩, 캐싱 같은 기법을 사용한다. 실행 데이터 영역 (Runtime Data Areas) JVM이 프로그램을 수행하기 위해 OS로부터 별도로 할당받은 메모리 공간이다. 크게 5가지 영역
super는 자식 클래스에서 부모 클래스로부터 상속받은 멤버를 참조하는데 사용한다. 상속받은 멤버와 자식의 클래스에 정의된 멤버의 이름이 같을 때는 super를 사용해서 구별할 수 있다.
오버라이딩은 메서드의 내용만을 새로 작성하는 것이므로 메서드의 선언부는 조상의 것과 완전히 일치해야 한다. 자식 클래스에서 오버라이딩하는 메서드는 다음과 같은 조건을 만족해야 한다. 이름이 같아야 한다. 매개변수가 같아야 한다. 반환 타입이 같아야 한다. 다만 접근 제어자와 예외는 제한된 조건 하에서만 다르게 변경할 수 있다. 접근 제어자는 부모 클래스의 메서드보다 좁은 범위로 변경할 수 없다. 부모 클래스의 메서드가 protected라면, 자식 클래스에서 메서드는 protected, public 이어야 한다. 부모 클래스의 메서드보다 많은 수의 예외를 선언할 수 없다. 아래는 자식 클래스가 부모 클래스보다 예외의 개수가 적으므로 바르게 오버라이딩 했다. 단순히 예외의 개수가 아니라 예외의 종류도 중요하다. 아래처름 Exception은 모든 예외의 최고 부모이므로 가장 많은 개수의 예외를 던
Java Specification Requests JSR은 Java 플랫폼에 대한 제안 및 최종 사양에 대한 설명이다. 제안 (proposal) : 무언가 결정되어야 하는 것에 대해 쓰거나 말하는 것 요청 (request) : 무언가를 요청하기 위해 쓰거나 말하는 것 다음과 같은 것들이 있다. https://jcp.org/en/jsr/overview
자바 프로그램은 완전한 기계어가 아닌 바이트 코드 파일(.class)로 구성된다. 바이트 코드 파일은 OS에서 바로 실행할 수 없고, JVM을 이용한다. image
변수의 초기화 멤버변수는 초기화를 하지 않아도 변수의 자료형에 맞는 기본값으로 초기화가 이루어진다. 지역변수는 사용하기 전에 반드시 초기화해야 한다. Screenshot from 2022-11-12 16-22-28 초기화 블럭 클래스 초기화 블럭은 클래스 변수의 초기화에 사용된다. 인스턴스 초기화 블럭은 인스턴스 변수의 초기화에 사용된다. 실행 결과 Screenshot from 2022-11-12 16-32-05 멤버변수의 초기화 시기와 순서 클래스 변수의 초기화 시점:
응용프로그램이 실행되면, JVM은 시스템으로부터 프로그램을 수행하는데 필요한 메모리를 할당받고 JVM은 메모리를 용도에 따라 여러 영역으로 나누어 관리한다. 3가지 주요영역인 method area, call stack, heap이 있다. image 메서드 영역 프로그램 실행 중 클래스가 사용되면, JVM은 해당 클래스 파일(*.class)을 읽고 분석해 클래스 정보를 이곳에 저장한다. 이 때, 클래스 변수도 이 영역에 함께 생성된다. 스택 호출 스택은 메서드의 작업에 필요한 메모리 공간을 제공한다. 메서드가 호출되면, 스택에 메서드를 위한 메모리가 할당되며, 메서드가 작업을 수행하는 동안 지역변수들과 연산의 중간결과 등을 저장하는데 사용한다. 메서드가 작업을 마치면
우선순위가 같은 연산자들끼리는 연산의 방향에 따라 우선순위가 다르다. 대부분의 연산자는 왼쪽에서 오른쪽 방향으로 연산을 수행한다. 단항 연산자 (++, —, ~, !), 부호 연산자 (+, -), 대입 연사자(=, +=, -=, …)는 오른쪽에서 왼쪽 방향으로 연산을 수행한다.