Java는 대표적인 객체 지향 프로그래밍 언어 이다.
서비스의 기능을 필드와 메서드( 상태와 행위 ) 로 나타내고, 관련있는 기능끼리 카테고리화를 진행할 수 있다.
이 과정에서 OOP 4대특징인 상속, 캡슐화, 다형성, 추상화의 개념이 들어간다.
기능별로 구현하기 때문에 특정 기능을 교체해야하거나 문제가 발생하였을 때, 해당 기능을 찾아내고 대처하기 편하다는 장점이 있다.
하지만 오랜기간동안 사용되어온 웹프로그래밍 언어이다보니 처음 접했을 때, 배워야하는 내용도 많고 문법을 학습하는게 Python 등과 비교하였을 때 쉽지 않은편이다.
먼저 Java에 사용되는 자료형을 알아보자
크게 Primitive Type ( 기본형 ) 과 Refrerence Type ( 참조형 ) 으로 나뉜다.
기본형의 존재때문에 Java는 순수한 객체지향언어가 아니다
기본형은 이미 정해진 메모리크기를 가지고있으며, 동작 시 메모리영역에 직접 데이터가 들어간다
참조형은 정해진 메모리크기가 없으며, 동작 시 Heap영역에 데이터가 저장되고 해당 주소값이 사용된다
기본형의 예시로는 int, long, float, double, char, boolean 등이 존재하며
참조형의 예시로는 String, Integer 등의 클래스타입들이 존재한다.기본형은 크게 정수, 실수, 논리, 문자로 나뉘며 기본적으로 각각 int, double, boolean, char 이 사용된다
구분 | Type | bit 수 | 값 |
---|---|---|---|
논리형 | boolean | true / false | |
정수형 | byte | 8 | -2^7 ~ 2^7-1 ( -128 ~ 127 ) |
short | 16 | -2^15 ~ 2^15-1 ( -32768 ~ 32767) | |
int | 32 | -2^31 ~ 2^31-1 ( -2_147_483_648 ~ 2_147_483_647 ) | |
long | 64 | -2^63 ~ 2^63-1 | |
실수형 | float | 32 | float f = 0.1234567890123456789f |
double | 64 | double d = 0.12345667890123456789; | |
문자형 | char | 16 | \u0000 ~ \uffff ( 0 ~ 2^16-1 ) |
위 표는 기본형이 차지하는 메모리크기와 값 범위를 나타낸 표이다.
이 중에서 정수형과 실수형의 경우, 다양한 타입들이 존재하는데 이 타입간의 변환에서 형변환 ( Type Casting ) 의 개념이 사용된다.
큰 타입 -> 작은 타입의 변환은 명시적 형변환 이라고 불린다.
long v1 = 100L;
int v2 = (int) v1;
위 예시와 같이 변환되는 타입을 직접 명시해야하며 작은 타입으로 변환하기 때문에 값이 변경될 위험이 있다.
작은 타입 -> 큰 타입의 변환은 묵시적 형변환 이라고 불린다.
int v1 = 100;
long v2 = v1;
위 예시와 같이 변환되는 타입을 명시하지 않아도 되며, 큰 타입으로 변환하기 때문에 값이 그대로 전달된다.
int[] arr = new int[10]; // 0 ~ 9 인덱스
연속되는 값, 혹은 관련있는 값들을 모아서 저장하고 싶을 때 사용되는 참조형이다.
참조형이기 때문에 실제 데이터는 Heap 영역에서 관리되며, 주소값을 이용하여 접근한다.
선언시에 크기를 지정하며, 이를 수정하기 위해서는 새로운 선언이 필요하다.
연속된 메모리공간에 데이터를 저장하기 때문에 조회속도가 빠르지만, 데이터를 삽입하거나 삭제하는 연산이 불가능하다.
배열의 복사의 경우 주소값을 이용하여 참조하는 형식이기 때문에 단순한 대입을 통한 복사는 실제 복사와 동작이 다르다.
때문에 제공되는 메서드( clone, Arrays.copyOf ) 를 통하여 복사해야한다.
List<Integer> list = new ArrayList<>();
배열과 동일한 목적에 데이터의 삽입, 삭제가 필요할 때 사용하는 Collection 이다.
주로 ArrayList, LinkedList 등이 사용되는데 각각의 차이는 아래와 같다.
ArrayList의 경우 내부적으로 배열을 사용한다.
따라서 데이터의 조회속도가 빠른 편이다. 데이터의 삽입을 통하여 처음 설정한 배열크기를 초과하게 되면 새로운 크기의 배열을 할당하고 복사하는 작업이 진행된다.
LinkedList의 경우 노드간의 참조를 통해 구성된다.
따라서 데이터의 조회속도는 느린편이지만 데이터의 삽입이나 삭제의 경우 빠르다.
공통적으로 참조형이기 때문에 단순한 대입을 통한 복사가 아닌 Collections의 메서드를 이용하는 방식을 통해 복사해야한다.
Set<Integer> set = new HashSet<>();
중복을 허락하지 않고, 순서가 필요없을때 사용되는 참조형이다.
크게 HashTable을 이용하는 HashSet과 RBT를 이용하는 TreeSet이 존재한다.
HashSet의 경우 내부적으로 key만 사용되는 HashMap이 사용된다.
주로 HashMap이 사용되며, 데이터의 존재유무를 판단하는데 사용된다.
직접적으로 조회하기 위해서는 Iterator를 사용해야한다.
Map<Integer, Integer> map = new HashMap<>();
key - value 쌍의 데이터를 저장하는데 사용되는 참조형이다.
key의 중복을 허락하지않으며 순서또한 보장하지 않는다.
HashTable과 동일하나, thread 안정성을 보장하지 않는다.
따라서 싱글스레드 환경이라면 속도면에서 이득이다.
조회속도가 O(1) 이라는 특징이 있다.
상속, 다형성, 캡슐화, 추상화
객체지향 프로그래밍이 가지는 4가지의 주요특징이다.
상속
다형성
캡슐화
추상화
public class User {
public String name;
}
앞서 OOP 4대특징에서 클래스와 인터페이스의 이야기를 했는데, 이에 대해 알아보자
공통적으로 서비스 기획시에 기능단위로 묶을때 사용되는 개념 혹은 기술이다.
클래스의 경우 크게 필드와 메서드로 구성되는데 Java에서 기능구현하는데 사용되는 최소단위라고 볼 수 있다.
앞서 설명한 OOP 4대특징이 모두 사용된다
단일상속이라는 큰 특징이 있다
public interface Vehicle{
public void run();
}
클래스간의 연관관계를 만들어주는데 사용된다
주로 상속을 통한 구현의 강제를 하기위해 사용되며, 추상클래스와 동일하다
추상클래스 ?
추상 메서드가 존재하는 클래스, abstract 키워드가 사용된다
추상 메서드는 구현부가 존재하지 않고, 메서드 시그니처만 존재하는 메서드를 의미한다
객체생성이 불가능하다public abstract class Vehicle{ private int curX, curY; public void reportPosition(){ System.out.printf("차종: %s, 현재 위치: (%d, %d)\n", this.getClass().getSimpleName(), curX, curY); } public abstract void addFuel(); }
기본적으로 public 접근제한자가 사용되며, 상수와 추상메서드로만 이루어진다.
public interface Vehicle{
default void reportPosition(int curX, int curY){
System.out.printf("차종: %s, 현재 위치: (%d, %d)\n", this.getClass().getSimpleName(), curX, curY);
}
static void run(){
System.out.println("부릉");
}
}
java8 에서 default 메서드와 static 메서드가 추가됐다
상속받는 클래스들에서 동일한 내용으로 구현되는 메서드를 위해 추가된 메서드다
default 메서드의 경우 구현체를 통하여 접근이 가능하고 static 메서드의 경우 클래스를 통한 접근이 가능하다