[Java] 자바 기본, 주요 특징, 배열

Sangho Han·2025년 2월 4일
3

☕️ Java

목록 보기
14/17
post-thumbnail

📝 정리

1. 자바 기본

변수와 타입

  • 변수 : 자료를 저장하기 위한 메모리 공간 (=그릇)
  • 타입 : 데이터의 형태
    • 기본형 : 미리 정해진 크기의 데이터를 표현 (ex. age = 10)
    • 참조형 : 크기가 미리 정해질 수 없는 데이터를 표현, 실제 값을 참조할 수 있는 주소를 저장 (집을 가져올 수는 없으니, 집 주소를 저장하는 느낌)
  • 자바는 Strongly Typed Language == 변수 선언 시 타입을 명시해야 한다.
    • var 키워드를 통해서 로컬 변수를 선언할 수 있다.
      • ex) var a = 1;
      • 파라미터로 사용 불가하다.
      • 변수 선언 시, 값 할당까지 진행해야 한다.

String pool?

  • String 타입은 기본형이 아닌 참조형
  • 문자열을 생성하는 방법에는 2가지가 존재한다.
    1. 리터럴 방식 : “ “ 사용 → String Pool에 저장된다.

      String str1 = "hello";
      String str2 = "hello";
      System.out.println(str1 == str2); // true (같은 주소 참조)
      System.out.println(str1.equals(str2)); // true (문자열 내용 같음)
    2. new String() 방식 : Heap에 새로운 객체가 생성된다.

      → Heap은 자바의 new 키워드로 생성되는 객체가 저장되는 공간이다.

      String str3 = new String("hello");
      String str4 = new String("hello");
      System.out.println(str3 == str4); // false (서로 다른 객체)
      System.out.println(str3.equals(str4)); // true (문자열 내용 같음)

포멧 문자 형식

  • 너비(width)
  • 정렬(alignment)
  • 소수점 자리수(precision)
public class FormatExample {
    public static void main(String[] args) {
        double num = 123.4567;

        System.out.printf("[%10.2f]%n", num);  // 너비 10, 소수점 2자리 (오른쪽 정렬)
        System.out.printf("[%-10.2f]%n", num); // 너비 10, 소수점 2자리 (왼쪽 정렬)
        System.out.printf("[%010.2f]%n", num); // 너비 10, 소수점 2자리, 0으로 채움
    }
}

// 결과
[    123.46]  // 너비 10, 오른쪽 정렬, 소수점 2자리
[123.46    ]  // 너비 10, 왼쪽 정렬, 소수점 2자리
[0000123.46]  // 너비 10, 0 채움, 소수점 2자리

명시적 형변환 vs 묵시적 형변환

명시적 형변환

  • 큰 범위 (저장 크기) → 작은 범위 (저장 크기)로 변환할 때 사용한다.
  • 데이터 손실이 발생할 가능성이 있기 때문에, 개발자가 반드시 명시적으로 변환해야 한다.
public class ExplicitCasting {
    public static void main(String[] args) {
        double doubleVal = 9.78;
        int intVal = (int) doubleVal; // 실수(double) → 정수(int) 강제 변환

        System.out.println("double: " + doubleVal); // double: 9.78
        System.out.println("int: " + intVal);       // int: 9 (소수점 이하 버림)
    }
}
  • 큰 숫자를 작은 타입으로 변환하는 경우 오버플로우가 발생할 수 있다.
int bigNum = 130;
byte smallNum = (byte) bigNum; // int → byte 변환 (오버플로우 발생 가능)
System.out.println(smallNum); // -126 (오버플로우 발생)

묵시적 형변환

  • 작은 범위 (저장 크기) → 큰 범위 (저장 크기)로 변환할 때 자동으로 적용된다.
  • 데이터 손실이 발생하지 않기 때문에, 별도의 변환 코드 없이 자동으로 변환이 가능하다.
public class ImplicitCasting {
    public static void main(String[] args) {
        int intVal = 100;
        double doubleVal = intVal; // 정수(int) → 실수(double) 자동 변환

        System.out.println("int: " + intVal);     // int: 100
        System.out.println("double: " + doubleVal); // double: 100.0
    }
}

Wrapper 클래스

  • 8개의 기본형에 대응하는 클래스이다.
    • Byte
    • Short
    • Integer
    • Long
    • Float
    • Double
    • Character
    • Boolean
  • 객체형은 기본형과 달리 추가적인 속성과 기능을 포함한다.
    • ex) Integer.MAX_VALUE; / Integer.parseInt(); …

2. 주요 특징

  • 객체 지향 프로그래밍(OOP)를 기반으로 하는 프로그래밍 언어이다.
    • 클래스와 객체를 사용하여 데이터를 구조화하고, 캡슐화, 상속, 다형성과 같은 개념을 활용한다.
  • 플랫폼 독립성(WORA)를 특징으로 가진다.
    • Java 코드는 .class로 컴파일 되며, JVM에서 실행되므로 운영체제에 상관없이 동작한다.
      1. .java 확장자를 가진 파일로 작성된다.
      2. Java Compiler에 의해 바이트코드(.class)로 변환된다. 이는 사람이 읽을 수 있는 고급 언어가 아닌, JVM이 이해할 수 있는 이진 코드이다.
      3. JVM이 파일을 로드, Class Loader가 필요한 클래스를 메모리에 로드한다.
      4. 바이트코드 검증기가 코드의 안정성을 확인한 후, JIT(Just-In-Time) 컴파일러가 바이트코드를 네이티브 코드로 변환하여 최종 실행한다.
  • 자동 메모리 관리(Garbage Collection)을 제공하여 개발자가 직접 메모리 관리를 할 필요가 없다.
  • Java는 기본적으로 스레드를 지원하며, 멀티 스레딩도 지원하여 병렬 프로그래밍이 가능하다.
  • Java Standard API(java.lang, java.util, java.io 등..)를 통해 다양한 기능을 지원한다.

3. 배열

  • 배열 : 동일한 타입의 데이터 0개 이상을 하나의 연속된 메모리 공간에서 관리하는 것
int[] points = new int[3]; // points는 메모리에 있는 배열을 가리키는 참조형 변수이다.
  • 아래의 2가지 방식으로 생성과 동시에 할당할 수 있다.
    1. 리터럴 방식 : int[] points = {1, 2, 3};
    2. new type[]{} 방식 : int[] points = new int[]{1, 2, 3};

→ String 리터럴 방식과 다르게, 배열은 두 방식 모두 Heap에 저장된다. String Pool은 String만 저장하는 Heap 내의 특수한 공간이기 때문이다. (String은 불변 객체라 가능)

for-each with Array

  • 가독성이 개선된 반복문으로, 배열 및 Collections에서 사용된다.
  • 인덱스 대신, 직접 요소에 접근하는 변수를 제공한다.
public class ForEachExample {
    public static void main(String[] args) {
        int[] numbers = {10, 20, 30, 40, 50};

        // for-each 문을 사용한 배열 반복
        for (int num : numbers) {
            System.out.println(num);
        }
    }
}

배열의 크기는 불변이다

  • 배열은 최초 메모리 할당 이후, 변경할 수 없다.
  • 개별 요소는 다른 값으로 변경 가능하나, 요소를 추가하거나 삭제할 수는 없다.

4. 다차원배열

  • 다차원 배열은 배열 안에 또 다른 배열이 포함된 구조로 2차원 이상의 배열을 다룰 때 사용된다.
// 2차원 배열 선언 (4행 3열)
int[][] arr1 = new int[4][3];

// 선언과 동시에 초기화
int[][] arr2 = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9},
    {10, 11, 12}
};

// 가변 배열 (각 행의 길이가 다름)
int[][] arr3 = new int[4][];
arr3[0] = new int[2];  // 첫 번째 행은 2개의 열
arr3[1] = new int[3];  // 두 번째 행은 3개의 열
arr3[2] = new int[1];  // 세 번째 행은 1개의 열
arr3[3] = new int[4];  // 네 번째 행은 4개의 열

배열 선언 OX

코드설명올바른가?
int intArray1[][] = new int[4][3];(정상) 4x3 크기의 2차원 배열 생성
int[] intArray2[] = new int[4][3];(정상) 배열 선언 방식 변경 (int[][]와 동일)
int [][] intArray3 = new int[4][];(정상) 가변 배열을 위한 선언 (열 개수 미지정)
int [] intArray4 = new int[4]{1,2,3};🚨 (오류) 배열 크기가 4인데, 3개의 값만 넣었음
int [][] intArray5 = new int[][] {{1,2,3},{1,2,3},{1,2,3},{1,2,3}};(정상) 4x3 크기의 배열 초기화
int [][] intArray6 = {{1,2,3},{1,2,3},{1,2,3},{1,2,3}};(정상) 배열 리터럴 방식 사용

💡 느낀 점 및 배운 점

  1. var 에 대해서 학습할 수 있었다.

  2. 리터럴 방식, String Pool, Heap 에 대해 학습할 수 있었다.

  3. 명시적 형변환을 할 때 오버플로우가 발생할 수 있음을 알게 되었다.

  4. 가변 배열에 대해 알 수 있었다.

profile
안녕하세요. 비즈니스를 이해하는 백엔드 개발자, 한상호입니다.

0개의 댓글