Java 정리 (1)

Hazel·2025년 2월 3일

배열

  • 동일한 데이터 타입의 값들을 저장하기 위한 자료구조
  • 인덱스를 이용하여 각 요소에 접근할 수 있음
  • 고정된 크기
  • 메모리에 연속적으로 저장
  • random access에 유용함
  • 데이터타입[] 배열 이름

배열 생성과 초기화

  1. 배열 생성 (자료형의 초기값으로 초기화)
  • 자료형[] 배열 이름 = new 자료형[길이];
  1. 배열 생성 및 값 초기화
  • 자료형[] 배열 이름 = new 자료형[] {값, 값, 값, ,,,};
  1. 선언과 동시에 초기화
  • 자료형[] 배열이름 = {값, 값, 값, ,,,};
int[]  nums  = new int[3];
nums[0] = 1;
nums[2] = 2;
nums[2] = 5;
---------------------------
int[] nums = new int[]{3,44,21};

배열의 인덱스

  • 0부터 시작
  • 접근 가능한 배열의 인덱스 범위 벗어나면 오류 발생
    - java.lang.ArrayIndexOutOfBoundsException

배열 순회

int intArray[] = {1,3,5,7,9};

for(int i=0; i<intArray.length; i++){
	System.out.println(intArray[i]);
}

배열의 순회 (for-each)

  • 가독성이 개선된 반복문으로 배열 및 Collections에서 사용 가능
  • index 대신 직접 요소에 접근하는 변수 제공
  • read only
int intArray[] nums = {1,3,5,7,9};

for(int x : nums) {
			System.out.println(x);
		}

배열의 출력

  • java.utils.Arrays 클래스의 메소드 toString() 활용
import java.util.Arrays;

int[] num = {1,2,3};
System.out.println(Arrays.toString(num));

얕은 복사

  • 객체 내부의 참조형 변수는 원본 객체의 참조를 복사
  • 원본 객체와 복사본이 같은 참조를 가리키므로, 하나를 수정하면 다른 객체에도 영향을 미침
int[] original = { 1, 2, 3 };
int[] sCopy = original; // 얕은 복사 (참조 공유)

sCopy[0] = 10;

System.out.println("원본 배열: " + Arrays.toString(original)); 			// [10, 2, 3]
System.out.println("복사본 배열: " + Arrays.toString(sCopy)); 				// [10, 2, 3]

깊은 복사

  • 객체의 모든 필드 값을 새로 복사하여 독립적인 객체를 생성
  • 원본 객체와 복사본은 완전히 별개의 메모리 공간을 가지므로 한 객체의 변경이 다른 객체에 영향 X
int[] original = { 1, 2, 3 };
int[] dCopy = new int[original.length];

for(int i  = 0 ; i<original.length; i++) {
	dCopy[i] = original[i];
}
dCopy[0] = 10;

System.out.println("원본 배열: " + Arrays.toString(original)); 		// [1, 2, 3]
System.out.println("복사본 배열: " + Arrays.toString(dCopy)); 		// [10, 2, 3]

클래스

클래스의 구성 요소

1) 필드(Field)

  • 클래스 내부에 선언된 변수로, 객체가 가지는 속성이나 상태를 저장
  • 인스턴스 변수클래스 변수(정적 변수)로 구분
class Car {
    String color; // 인스턴스 변수 (객체별로 개별적인 값)
    static int wheels = 4; // 클래스 변수 (모든 객체가 공유)
}

2) 생성자(Constructor)

  • 객체가 생성될 때 호출되는 특수한 메서드로, 객체의 초기화를 담당
  • 생성자의 이름은 클래스명과 동일
  • 매개변수가 없는 기본 생성자와 매개변수가 있는 생성자가 있음
class Car {
    String color;

    // 기본 생성자
    Car() {
        this.color = "Black";
    }

    // 매개변수가 있는 생성자
    Car(String color) {
        this.color = color;
    }
}

3) 메서드(Method)

  • 객체가 수행할 동작(행동)을 정의
  • 반환 타입, 메서드 이름, 매개변수, 실행 코드로 구성
class Car {
    String color;

    // 생성자
    Car(String color) {
        this.color = color;
    }

    // 메서드
    void drive() {
        System.out.println(color + "색 자동차가 달립니다.");
    }
}

클래스 선언

[제한자] class 클래스이름 {
    
    // 멤버 변수 (필드, 속성)
    [제한자] 데이터타입 변수이름 [= 초기값];

    // 생성자
    [제한자] 클래스이름([매개변수]) {
        // 생성자 본문
    }

    // 메서드 (기능 정의)
    [제한자] 반환타입 메서드이름([매개변수]) {
        // 메서드 본문
    }
}
제한자설명
public어디서든 접근 가능
protected같은 패키지 또는 상속 관계에서 접근 가능
(default)같은 패키지에서만 접근 가능 (제한자 생략)
private해당 클래스 내부에서만 접근 가능

기본 클래스 예제

public class Person {
    
    // 필드 (멤버 변수)
    private String name; // private: 외부에서 직접 접근 불가
    private int age = 20; // 초기값 설정 가능

    // 생성자
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 메서드 (행동 정의)
    public void introduce() {
        System.out.println("안녕하세요! 저는 " + name + "이고, " + age + "살입니다.");
    }
    
    // Getter (name 반환)
    public String getName() {
        return name;
    }
    
    // Setter (name 변경)
    public void setName(String name) {
        this.name = name;
    }
}

public class Main {
    public static void main(String[] args) {
        Person p1 = new Person("지민", 25);
        p1.introduce();
        
        p1.setName("정국"); // 이름 변경
        System.out.println("변경된 이름: " + p1.getName());
    }
}

객체

  • Java에서 객체(Object)클래스를 기반으로 생성된 실체(Instance)
  • 클래스는 설계도(blueprint) 역할을 하고, 객체는 그 설계도를 기반으로 만들어진 실제 데이터(메모리에 생성된 것)

객체 생성

  1. new 키워드
class Car {
    String color;

    // 생성자
    Car(String color) {
        this.color = color;
    }

    void drive() {
        System.out.println(color + "색 자동차가 달립니다.");
    }
}

public class Main {
    public static void main(String[] args) {
        Car myCar = new Car("빨강"); // 객체 생성
        myCar.drive(); 				// 메서드 호출
    }
}
  • new 키워드를 사용하여 클래스의 생성자(Constructor)를 호출해 객체 생성
  • 생성된 객체는 myCar라는 변수에 저장됨
  • 객체의 속성과 메서드를 .(점) 연산자로 접근 가능
  1. static을 활용하여 객체 생성 없이 사용
class MathUtil {
    static int square(int num) {
        return num * num;
    }
}

public class Main {
    public static void main(String[] args) {
        int result = MathUtil.square(5); 	// 객체 생성 없이 호출
        System.out.println("5의 제곱: " + result);
    }
}
  1. 싱글톤(Singleton) 패턴을 활용한 객체 생성
class Singleton {
    private static Singleton instance = new Singleton(); // 유일한 객체 생성

    private Singleton() {} 								// 외부에서 new 사용 불가

    public static Singleton getInstance() {
        return instance;
    }

    void showMessage() {
        System.out.println("싱글톤 객체입니다!");
    }
}

public class Main {
    public static void main(String[] args) {
        Singleton obj1 = Singleton.getInstance();
        Singleton obj2 = Singleton.getInstance();

        obj1.showMessage();
        System.out.println(obj1 == obj2); // true (같은 객체)
    }
}
  • 한 개의 객체만 생성되도록 하는 패턴 (new 없이 getInstance() 메서드로 접근)
    - private 생성자 사용 → 외부에서 new Singleton() 호출 불가능
    - static 필드에 객체를 하나만 생성하여 getInstance()로 반환

변수

class Example {
    // 인스턴스 변수 (객체마다 다르게 저장됨)
    String instanceVar = "인스턴스 변수";

    // 클래스 변수 (모든 객체가 공유)
    static String classVar = "클래스 변수";

    void showVariables() {
        // 지역 변수 (메서드 내부에서만 사용 가능)
        String localVar = "지역 변수";
        
        System.out.println(localVar);      // 지역 변수 출력
        System.out.println(instanceVar);   // 인스턴스 변수 출력
        System.out.println(classVar);      // 클래스 변수 출력
    }
}

public class Main {
    public static void main(String[] args) {
        Example ex1 = new Example(); 			// 첫 번째 객체 생성
        Example ex2 = new Example(); 			// 두 번째 객체 생성

        // 첫 번째 객체에서 변수 값 변경
        ex1.instanceVar = "변경된 인스턴스 변수"; 
        Example.classVar = "변경된 클래스 변수"; // 클래스 변수는 모든 객체에서 공유

        ex1.showVariables();
        ex2.showVariables(); // 두 번째 객체에서 호출
    }
}

// -----------------------[결과]--------------------------
지역 변수
변경된 인스턴스 변수
변경된 클래스 변수

지역 변수
인스턴스 변수
변경된 클래스 변수

  1. 지역 변수 (localVar)
  • showVariables() 메서드 내부에서 선언된 변수
    → 해당 메서드 안에서만 사용 가능
  • 메서드가 실행될 때 생성되고, 종료되면 사라짐
  1. 인스턴스 변수 (instanceVar)
  • ex1과 ex2 각각 독립적인 값을 가짐
  • ex1.instanceVar 값만 변경했으므로, ex2.instanceVar 값은 그대로 유지됨
  1. 클래스 변수 (classVar)
  • 모든 객체가 공유하는 변수 (static)
  • ex1에서 값을 변경했더라도, ex2에서도 동일한 값이 출력됨

오버로딩

1. 메서드 오버로딩 (Method Overloading)

  • 같은 이름의 메서드를 여러 개 정의하되, 매개변수의 개수, 타입, 순서가 다르게 정의하는 것
  • 리턴 타입만 다르면 오버로딩 성립 X
    - int add(int a, int b) vs double add(int a, int b) → 오류 발생
class MathUtil {
    // 정수형 덧셈
    int add(int a, int b) {
        return a + b;
    }

    // 실수형 덧셈 (매개변수 타입이 다름)
    double add(double a, double b) {
        return a + b;
    }

    // 세 개의 정수를 더하는 경우 (매개변수 개수가 다름)
    int add(int a, int b, int c) {
        return a + b + c;
    }
}

public class Main {
    public static void main(String[] args) {
        MathUtil math = new MathUtil();
        
        System.out.println(math.add(3, 4));         // 7 (정수 덧셈)
        System.out.println(math.add(2.5, 3.5));     // 6.0 (실수 덧셈)
        System.out.println(math.add(1, 2, 3));      // 6 (세 개의 정수 덧셈)
    }
}

2. 생성자 오버로딩 (Constructor Overloading)

  • 같은 이름의 생성자를 여러 개 정의하되, 매개변수의 개수, 타입, 순서가 다르게 정의하는 것
  • 객체 생성 시 다양한 방법을 제공할 수 있음
class Person {
    String name;
    int age;

    // 기본 생성자 (매개변수 없음)
    Person() {
        this.name = "이름 없음";
        this.age = 0;
    }

    // 이름만 입력받는 생성자 (매개변수 개수가 다름)
    Person(String name) {
        this.name = name;
        this.age = 0;
    }

    // 이름과 나이를 입력받는 생성자 (매개변수 개수가 다름)
    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    void introduce() {
        System.out.println("이름: " + name + ", 나이: " + age);
    }
}

public class Main {
    public static void main(String[] args) {
        Person p1 = new Person(); 			// 기본 생성자 호출
        Person p2 = new Person("지민"); 		// 이름만 입력
        Person p3 = new Person("태형", 25); 	// 이름과 나이 입력

        p1.introduce();
        p2.introduce();
        p3.introduce();
    }
}

생성자 오버로딩 테스트

public class Dog {

    // 1.
    public Dog() { }

    // 2.
    public Dog(String name) { }

    // 3. 
    public Dog(int age) { }

    // 4.
    public Dog(String name, int age) { }

    // 5.
    public Dog(String name, String type) { }

    // 6.
    public Dog(String type, int age) { }

    // 7.
    public Dog(String type, String name) { }

    // 8.
    public Dog(String name, String type, int age) { }

    // 9.
    public Dog(String name, int age, String type) { }
}

4번과 6번 중 하나는 없애야 됨
5번과 7번 중 하나 없애야 됨
8번과 9번은 매개 변수 타입 순서가 달라서 가능

this. & this()

1. this.

→ 현재 객체를 가리키는 키워드

  • this.는 현재 클래스의 인스턴스(객체) 자신을 가리키는 키워드
  • 주로 멤버 변수(인스턴스 변수)와 지역 변수(메서드 안에서 선언한 변수)의 이름이 같을 때 구분할 때 사용
class Student {
    String name; // 멤버 변수 (인스턴스 변수)

    // 생성자 (객체를 만들 때 호출되는 메서드)
    Student(String name) {
        this.name = name; // this.name은 인스턴스 변수, name은 지역 변수
    }

    void showName() {
        System.out.println("이름: " + this.name);
    }
}

public class Main {
    public static void main(String[] args) {
        Student s1 = new Student("메롱");
        s1.showName(); 			// 출력: 이름: 메롱
    }
}

2. this()

→ 다른 생성자를 호출할 때 사용

  • this()는 같은 클래스의 다른 생성자를 호출할 때 사용
  • 객체 생성 시 중복 코드 작성을 줄일 수 있음
  • 반드시 생성자의 첫 번째 줄에 위치
class Car {
    String brand;
    String model;
    int year;

    // 기본 생성자 → 매개변수 2개짜리 생성자 호출
    Car() {
        this("Unknown", "Unknown");  // this()를 사용하여 다른 생성자 호출
    }

    // 매개변수 2개 생성자 → 매개변수 3개짜리 생성자 호출
    Car(String brand, String model) {
        this(brand, model, 2024);  // 기본 연식은 2024로 설정
    }

    // 매개변수 3개 생성자 (모든 값을 초기화)
    Car(String brand, String model, int year) {
        this.brand = brand;
        this.model = model;
        this.year = year;
    }

    void display() {
        System.out.println("Car: " + brand + " " + model + " (" + year + ")");
    }

    public static void main(String[] args) {
        Car car1 = new Car(); 						  // 기본 생성자 호출 → this("Unknown", "Unknown")
        Car car2 = new Car("Toyota", "Camry"); 		  // 2개짜리 생성자 호출 → this("Toyota", "Camry", 2024)
        Car car3 = new Car("Tesla", "Model S", 2023);  // 3개짜리 생성자 호출

        car1.display();
        car2.display();
        car3.display();
    }
}

객체 지향 프로그래밍

  • 데이터(속성, 변수)와 기능(메서드)을 하나의 단위로 묶어 놓은 것
  • 객체 = 데이터 + 기능

객체 지향 프로그래밍(OOP)의 4대 특징

profile
이것저것 학습 기록장

0개의 댓글