Java 핵심 개념 정리: 기초부터 객체지향까지

1. Java 언어 개요

Java는 고급 프로그래밍 언어로, 플랫폼에 독립적인 애플리케이션 개발을 지원하며 완전한 객체지향 언어입니다. Java는 크게 세 가지 기술 플랫폼으로 나뉩니다.

  • Java SE: 데스크톱 애플리케이션 개발용 표준 에디션
  • Java EE: 웹 및 엔터프라이즈 애플리케이션 개발용
  • Java ME: 모바일 및 임베디드 장치용 마이크로 에디션

Java의 주요 특징으로는 단순성, 보안성, 플랫폼 독립성(Java Virtual Machine 기반), 객체지향, 멀티스레딩 지원, 자동 가비지 컬렉션이 있습니다. JVM(Java Virtual Machine)은 다양한 운영체제에서 Java 프로그램을 실행할 수 있게 해줍니다.

2. JDK 디렉토리 구조

디렉토리설명
binjavac.exe(컴파일러), java.exe(런타임), jar.exe(패키징), javadoc.exe(문서 생성) 등 실행 파일
db내장 경량 데이터베이스(Derby)
includeC 언어 헤더 파일 (네이티브 메서드 지원)
jreJava 런타임 환경 (JVM, 클래스 라이브러리 포함, 개발 도구 불포함)
lib개발용 클래스 라이브러리 및 아카이브 파일
srcJDK 핵심 클래스의 소스 코드

3. 환경 변수와 컴파일/실행

  • PATH: bin 디렉토리 경로를 설정하여 javac, java 명령어를 어디서든 사용 가능하게 합니다.
  • .class 파일은 바이너리가 아니므로 JVM이 해석하여 실행합니다.
  • java HelloWorld 명령어는 클래스 로더를 통해 바이트코드를 메모리에 로드합니다.
  • Java는 "한 번 컴파일하면 어디서든 실행" 가능하지만, JVM 자체는 플랫폼 종속적입니다.
  • 하나의 .java 파일에 여러 클래스가 있으면 각 클래스마다 별도의 .class 파일이 생성됩니다.
  • 파일에는 public 클래스가 최대 하나만 존재할 수 있으며, 파일명과 클래스명이 일치해야 합니다.

4. 핵심 용어 정리

  • javac: Java 소스 파일(.java)을 바이트코드(.class)로 컴파일합니다.
  • java: Java 인터프리터로, JVM을 구동하여 바이트코드를 실행합니다.
  • classpath: JVM이 .class 파일을 찾는 경로를 지정합니다.
  • java.util: Arrays, List, Set 등 유틸리티 및 컬렉션 클래스 포함.

5. 식별자와 명명 규칙

식별자는 패키지, 클래스, 메서드, 변수 등의 이름을 지정하는 데 사용되며, 영문자, 숫자, 밑줄(_), 달러 기호($)로 구성됩니다. 단, 숫자로 시작할 수 없고 Java 예약어나 JDK 클래스명과 중복될 수 없습니다.

  • 패키지명: 모두 소문자 (예: com.example)
  • 클래스/인터페이스명: 각 단어의 첫 글자를 대문자로 (예: ArrayList)
  • 상수명: 모두 대문자, 단어 사이는 밑줄 (예: DAY_OF_MONTH)
  • 변수/메서드명: 첫 단어는 소문자, 이후 단어는 대문자로 시작하는 카멜 표기법 (예: lineNumber)

6. 데이터 타입과 형변환

  • float 타입 변수에는 값 뒤에 f 또는 F를 붙입니다.
  • double 타입은 선택적으로 d/D를 붙일 수 있으며, 기본값입니다.
  • Java의 charUnicode 인코딩을 사용하며, 2바이트(16비트)입니다.
  • char 값은 작은따옴표(' ')로 감싸며, 반드시 한 문자만 포함해야 합니다.
  • Java는 C와 달리 true/false만 논리값으로 사용하며, 숫자(0/1)는 사용할 수 없습니다.
  • 작은 범위 타입은 자동으로 큰 범위 타입으로 변환됩니다.
  • 강제 형변환 시 (타입)(표현식) 형식을 사용합니다.

형변환 예제

public class TestConversion {
    public static void main(String[] args) {
        System.out.println(2 + 3 + 'a');   // int로 자동 변환
        System.out.println(2 + 3 + "a");   // String으로 변환
        System.out.println("a" + 2 + 3);   // String으로 변환
    }
}

7. 상수와 리터럴

상수는 final 키워드로 선언하며, 한 번 초기화되면 값을 변경할 수 없습니다. 리터럴은 다양한 진법으로 표현할 수 있습니다.

  • 2진수: 0b 또는 0B 접두사 사용 (예: 0b01101100)
  • 8진수: 0 접두사 사용 (예: 0324)
  • 16진수: 0x 또는 0X 접두사 사용 (예: 0x25AF)
System.out.println(0b01101100); // 108
System.out.println(0324);        // 212
System.out.println(0x10);        // 16

8. 연산자

8.1 모듈러 연산자(%)

System.out.println(-20 % 3);  // -2
System.out.println(20 % -3);  // 2

8.2 비트 연산자

  • & (AND): 두 비트가 모두 1일 때 1
  • | (OR): 두 비트가 모두 0일 때 0
  • ~ (NOT): 비트 반전 (보수 연산)
  • ^ (XOR): 두 비트가 다를 때 1
  • <<: 왼쪽 시프트 (빈 자리는 0으로 채움)
  • >>: 오른쪽 시프트 (부호 비트로 빈 자리 채움)
  • >>>: 부호 없는 오른쪽 시프트 (빈 자리는 무조건 0)
// ~7: 7(00000111) -> 11111000 -> -8
System.out.println(~7);  // -8

9. 제어문

switch 문은 char, int, String, enum 타입을 지원하며, float/double/boolean은 지원하지 않습니다.

10. 메서드

메서드는 세 가지 요소로 구성됩니다: 메서드명, 매개변수, 반환 타입. return 문으로 반환하는 값의 타입이 메서드의 반환 타입과 일치해야 합니다.

11. 입력 처리

  • System.in.read(): 단일 문자를 읽어 정수로 반환하며, 필요시 char로 형변환합니다.
  • Scanner: 문자열과 여러 문자 입력에 사용됩니다. Scanner sc = new Scanner(System.in);

12. 배열

배열의 주요 연산으로는 삽입, 삭제, 수정, 검색, 정렬, 초기화가 있습니다. 일반 for문이나 향상된 for문(forEach)으로 순회할 수 있습니다.

public class ArrayExample {
    public static void main(String[] args) {
        int[] numbers = {11, 22, 33, 44, 55};
        for (int val : numbers) {
            System.out.print(val + " ");
        }
    }
}

12.1 다차원 배열

public class MultiDimArray {
    public static void main(String[] args) {
        int[][] a;        // 올바름
        int[] b[];        // 올바름
        int c[][];        // 올바름

        int[][] d = new int[3][4];  // 올바름
        int[][] e = new int[3][];   // 올바름 (가변 배열)
        // int[][] f = new int[][4]; // 오류
    }
}

가변 배열은 각 행의 열 개수를 다르게 지정할 수 있습니다.

int[][] jagged = {
    {1, 2, 3},
    {4, 5},
    {6, 7, 8, 9}
};

13. 객체지향 프로그래밍

13.1 객체지향의 세 가지 특징

  1. 캡슐화(Encapsulation): 데이터와 메서드를 하나로 묶고, 외부 접근을 제한합니다.
  2. 상속(Inheritance): 부모 클래스의 기능을 자식 클래스가 재사용합니다.
  3. 다형성(Polymorphism): 동일한 메서드가 다양한 방식으로 동작합니다.
  • 자식 클래스는 부모 클래스의 생성자를 상속받지 못합니다.
  • 클래스는 특정 사물에 대한 추상적 정의이며, 객체는 그 클래스의 구체적인 인스턴스입니다.
  • 생성자를 통해 멤버 변수에 초기값을 할당합니다.

13.2 생성자 간 호출 (this())

public class Point {
    int x;
    int y;

    Point(int x) {
        this.x = x;
    }

    Point(int x, int y) {
        this(x);        // 반드시 첫 번째 줄에 위치
        this.y = y;
    }
}

13.3 캡슐화 구현

  • 멤버 변수는 private으로 선언합니다.
  • public 접근자인 get/set 메서드를 제공합니다.
  • get 메서드는 반환값이 있고 매개변수가 없습니다.
  • set 메서드는 void이며 매개변수를 받습니다.

13.4 클래스와 메서드 제한자

  • 클래스는 private/protected로 직접 수정할 수 없습니다.
  • 클래스에 abstractfinal을 동시에 사용할 수 없습니다.
  • 메서드 오버로딩: 같은 클래스 내에서 이름은 같고 매개변수 타입/개수/순서가 다른 메서드를 여러 개 정의하는 것입니다. 반환 타입만 다른 것은 오버로딩이 아닙니다.

14. static 키워드

  • 정적 메서드는 정적 멤버만 접근 가능합니다.
  • 모든 객체가 동일한 값을 가지는 경우에 static을 사용합니다.
  • 메서드 내용이 객체 호출과 무관하면 static으로 선언할 수 있습니다.
  • 비정적 메서드에서는 this를 사용해 다른 비정적 멤버에 접근할 수 있습니다.
  • 정적 멤버는 객체 생성 전에 메모리에 로드됩니다.
  • 생성자는 private으로 선언할 수 없습니다 (default, protected, public만 가능).
  • static은 클래스에 사용할 수 없으며, 지역 변수에도 사용할 수 없습니다.

15. 상속과 super

  • 부모 클래스의 생성자는 상속되지 않습니다.
  • super 키워드는 부모 클래스의 멤버(변수, 메서드, 생성자)에 접근할 때 사용합니다.
  • 메서드 오버라이딩: 이름, 매개변수, 반환 타입이 모두 동일해야 합니다.
  • 오버라이딩 시 접근 제어자의 범위는 부모보다 좁아질 수 없습니다.
  • 자식 메서드는 부모 메서드보다 더 많은 예외를 던질 수 없습니다.

16. final 키워드

  • final 클래스: 상속 불가
  • final 메서드: 오버라이딩 불가
  • final 변수: 상수로, 한 번만 할당 가능 (재할당 불가)
  • String 클래스는 final로 선언되어 있습니다.

17. 추상 클래스와 인터페이스

  • 추상 메서드를 포함하는 클래스는 반드시 추상 클래스(abstract class)여야 하지만, 추상 클래스가 반드시 추상 메서드를 가질 필요는 없습니다.
  • 인터페이스는 일종의 특수한 추상 클래스입니다.
  • 인터페이스에는 추상 메서드 외에도 default 메서드와 static 메서드를 포함할 수 있으며, 이들은 메서드 본문을 가질 수 있습니다.
public interface SampleInterface {
    void abstractMethod();                    // public abstract
    default void defaultMethod() {            // 본문 있음
        System.out.println("Default method");
    }
    static void staticMethod() {              // 본문 있음
        System.out.println("Static method");
    }
    // private void privateMethod() { }       // 무의미함
}
  • 인터페이스의 모든 메서드는 기본적으로 public abstract입니다.
  • 인터페이스의 변수는 public static final로, 사실상 상수입니다.
  • 클래스는 단일 상속만 가능하지만, 인터페이스는 다중 구현이 가능합니다.
  • 부모 타입 참조 변수는 자식 객체를 가리킬 수 있지만, 반대는 불가능합니다. 단, 부모 참조가 실제 자식 객체를 가리키는 경우에만 강제 형변환이 가능합니다.

18. 예외 처리

  • 컴파일 타임 예외(Checked Exception): 반드시 처리해야 합니다.
  • 런타임 예외(Unchecked Exception): 선택적으로 처리합니다. (예: 배열 인덱스 초과)
  • Error: 프로그램이 복구할 수 없는 심각한 오류입니다.
  • catch 블록에 여러 예외를 지정할 때는 하위 클래스를 상위 클래스보다 먼저 배치해야 합니다.
  • throwsthrow 키워드를 사용하여 예외를 선언하거나 발생시킵니다.
  • 사용자 정의 예외는 Exception 클래스를 상속받아 만듭니다.

19. 문자열 관련 클래스

  • String: 불변(Immutable) 문자열
  • StringBuffer: 가변(Mutable) 문자열, 스레드 안전
public class StringReverse {
    public static void main(String[] args) {
        String original = "abcde";
        StringBuffer buffer = new StringBuffer(original);
        buffer.reverse();
        String reversed = buffer.toString();
        System.out.println(reversed);  // edcba
    }
}

20. 날짜와 시간

  • Date, Calendar: java.util 패키지
  • DateFormat: java.text 패키지, 날짜를 원하는 형식의 문자열로 변환

21. 컬렉션 프레임워크

  • TreeSet 생성 시 Comparator 인터페이스를 구현한 사용자 정의 비교기를 전달할 수 있습니다.
  • Iterator를 사용할 때는 먼저 hasNext()로 다음 요소 존재 여부를 확인한 후 next()로 요소를 가져옵니다.
import java.util.ArrayList;
import java.util.Iterator;

public class IteratorExample {
    public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(10);
        list.add(25);
        list.add(37);

        Iterator<Integer> it = list.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
        }
    }
}
  • List: 순서가 있고 중복 허용 (ArrayList, LinkedList)
  • Set: 순서가 없고 중복 불허 (HashSet, TreeSet)
  • Map: 키-값 쌍 저장 (HashMap, TreeMap)
  • 컬렉션에는 기본 타입을 직접 저장할 수 없으며, 래퍼 클래스 등을 사용해야 합니다.
  • Properties 클래스는 설정 파일 저장에 자주 사용됩니다.

22. 주요 확인 사항

  1. == 연산자는 참조(주소)와 값을 비교하고, equals() 메서드는 논리적 동등성을 비교합니다.
  2. System.currentTimeMillis()long 타입의 현재 시간(밀리초)을 반환합니다.
  3. System 클래스의 모든 속성과 메서드는 정적(static)입니다.

태그: java JDK JVM 객체지향 컬렉션프레임워크

7월 13일 04:56에 게시됨