1. 상속

 

자바에서 상속(Inheritance)은 기존 클래스의 속성과 메서드를 새로운 클래스가 물려받아 재사용할 수 있게 해주는 객체지향의 핵심 개념 중 하나입니다. 상속을 사용하면 공통된 코드를 중복 없이 여러 클래스에서 사용할 수 있어 코드의 재사용성과 확장성이 높아집니다. 상속은 extends 키워드를 사용해 구현하며, 기존 클래스는 부모 클래스(슈퍼클래스), 새로 정의한 클래스는 자식 클래스(서브클래스)라고 부릅니다. 자식 클래스는 부모의 기능을 그대로 사용할 수 있을 뿐만 아니라, 필요에 따라 기능을 확장하거나 재정의(오버라이딩)할 수 있습니다.

 

class 부모클래스 {
    // 공통 속성 및 동작 정의
}

class 자식클래스 extends 부모클래스 {
    // 부모의 기능을 상속받고 추가적인 기능 정의
}
class Animal {
    public void eat() {
        System.out.println("먹는다.");
    }
}

class Dog extends Animal {
    public void bark() {
        System.out.println("멍멍 짖는다.");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.eat();  // 부모의 메서드 사용
        dog.bark(); // 자신의 메서드 사용
    }
}

 

1. 메서드 오버라이딩

자식 클래스는 부모 클래스의 메서드를 그대로 사용할 수도 있고, 필요에 따라 재정의(override)하여 자신에게 맞게 바꿀 수도 있습니다.

class Animal {
    public void sound() {
        System.out.println("동물이 소리를 낸다.");
    }
}

class Cat extends Animal {
    // 어노테이션 : 자바가 해석이 될 때, 오버라이드된 것을 컨파일러에게 지시를 내릴 때
    @Override
    public void sound() {
        System.out.println("야옹");
    }
}

 

2. 자바에서의 상속 제약 사항

- 자바는 단일 상속만 지원합니다. 즉, 한 클래스는 하나의 부모 클래스만 상속받을 수 있습니다.

class A {}
class B {}
class C extends A, B {} // ❌ 컴파일 에러

 

- final 클래스는 상속할 수 없습니다.

// final이 붙은 클래스는 상속을 못하게 한다.
final class Car {}
class SportsCar extends Car {} // ❌ 에러 발생

 

- 생성자는 상속되지 않습니다. 생성자는 자식 클래스가 직접 정의해야 하며, 부모 생성자를 호출하려면 super()를 사용합니다.

 

3. super 키워드

super는 부모 클래스의 필드나 메서드에 접근할 때 사용합니다. 또한 생성자 안에서 부모 생성자 호출에도 사용됩니다.

class Parent {
    public Parent(String msg) {
        System.out.println("부모 생성자: " + msg);
    }
}

class Child extends Parent {
    public Child() {
        super("안녕하세요");  // 부모 생성자 호출
        System.out.println("자식 생성자");
    }
}
class Person {
    String name;

    public Person(String name) {
        this.name = name;
    }

    public void greet() {
        System.out.println("안녕하세요, 저는 " + name + "입니다.");
    }
}

class Student extends Person {
    String school;

    public Student(String name, String school) {
        super(name); // 부모 생성자 호출
        this.school = school;
    }

    @Override
    public void greet() {
        super.greet(); // 부모 메서드 호출
        System.out.println("학교는 " + school + "입니다.");
    }
}

 

2. final

final은 자바에서 "변경할 수 없음"을 의미하는 키워드입니다. 변수, 메서드, 클래스에 모두 사용할 수 있으며, 각각의 의미가 조금씩 다릅니다.

 

1. final 변수: 값 변경 불가 (상수)

final을 변수에 사용하면, 초기화된 이후 값 변경이 불가능한 상수가 됩니다. 선언과 동시에 값을 설정하거나, 생성자에서 한 번만 초기화 가능하며 관례상 대문자로 작성합니다. (MAX_SIZE, PI 등)

final int MAX = 100;
MAX = 200; // ❌ 에러! 값을 바꿀 수 없음

 

2. final 메서드: 재정의(오버라이딩) 불가

final을 메서드에 사용하면, 자식 클래스에서 그 메서드를 오버라이딩할 수 없습니다. 보안성 유지하며 중요한 로직이 변경되지 않도록 보호합니다.

class Parent {
    public final void show() {
        System.out.println("부모 클래스 메서드");
    }
}

class Child extends Parent {
    // public void show() {} // ❌ 오류: final 메서드는 재정의할 수 없음
}

 

3. final 클래스: 상속 불가

final을 클래스에 사용하면, 그 클래스를 다른 클래스가 상속받을 수 없습니다. 클래스를 변경하거나 확장하지 못하도록 막고 싶을 때 사용합니다. String, Integer 같은 핵심 라이브러리 클래스들이 final로 선언되어 있습니다.

final class Animal {
    public void sound() {
        System.out.println("동물 소리");
    }
}

// class Dog extends Animal {} // ❌ 오류: final 클래스는 상속 불가

 

종합예제

// 부모 클래스
class Animal {
    String name;

    public Animal(String name) {
        this.name = name;
    }

    public void eat() {
        System.out.println(name + "가 먹습니다.");
    }

    public final void sleep() {
        System.out.println(name + "는 조용히 잠듭니다. (이건 반드시 이 방식으로!)");
    }

    public void speak() {
        System.out.println(name + "가 소리를 냅니다.");
    }
}

// 자식 클래스
class Dog extends Animal {

    public Dog(String name) {
        super(name);
    }

    // 오버라이딩: speak() 메서드를 개성 있게 변경
    @Override
    public void speak() {
        System.out.println(name + "가 멍멍 짖습니다!");
    }

    // 오버로딩: bark() 여러 버전
    public void bark() {
        System.out.println("멍멍!");
    }

    public void bark(String target) {
        System.out.println(target + "를 보고 멍멍!");
    }

    public void bark(int times) {
        for (int i = 0; i < times; i++) {
            System.out.print("멍! ");
        }
        System.out.println();
    }
}
public class Main {
    public static void main(String[] args) {
        Dog rucy = new Dog("루시");

        // 상속받은 메서드
        rucy.eat();   // 루시가 먹습니다.

        // final 메서드 (오버라이딩 불가)
        rucy.sleep(); // 루시는 조용히 잠듭니다.

        // 오버라이딩된 메서드
        rucy.speak(); // 루시가 멍멍 짖습니다!

        // 오버로딩된 메서드들
        rucy.bark();               // 멍멍!
        rucy.bark("택배 아저씨");     // 택배 아저씨를 보고 멍멍!
        rucy.bark(3);              // 멍! 멍! 멍!
    }
}

 

3. Object 클래스

자바에서 Object 클래스는 모든 클래스의 최상위 부모 클래스(슈퍼클래스)로, 자바에 존재하는 모든 클래스는 Object를 직접 또는 간접적으로 상속받습니다. 이 클래스는 객체를 비교하거나 문자열로 표현하고, 복제하거나 쓰레기 수집 전에 정리하는 등 객체에 대한 기본적인 동작을 정의한 메서드들을 제공합니다. 대표적인 메서드로는 toString(), equals(), hashCode(), clone(), finalize() 등이 있으며, 개발자는 필요에 따라 이 메서드들을 오버라이딩하여 자신만의 방식으로 객체의 동작을 정의할 수 있습니다. Object는 자바의 클래스 계층 구조에서 기본 뼈대 역할을 하는 핵심 클래스입니다.

 

class Person {
    // 실제로는 class Person extends Object 와 같음
}

 

Object 클래스가 제공하는 주요 메서드

toString() 객체를 문자열로 표현 (기본: 클래스이름@해시값)
equals(Object obj) 두 객체가 같은지를 비교 (기본: 주소 비교)
hashCode() 객체의 해시코드 반환
getClass() 클래스 정보를 담은 Class 객체 반환
clone() 객체 복제 (implements Cloneable 필요)
finalize() 가비지 컬렉션 전에 호출 (거의 사용되지 않음)

 

@Override
public String toString() {
    return "이름: " + name + ", 나이: " + age;
}
class Person {
    String name;
    int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // toString() 오버라이딩
    @Override
    public String toString() {
        return "이름: " + name + ", 나이: " + age;
    }

    // equals() 오버라이딩
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;                 // 같은 객체인지 비교
        if (obj == null || getClass() != obj.getClass()) return false; // 클래스 비교

        Person other = (Person) obj;
        return this.name.equals(other.name) && this.age == other.age;
    }
}

public class Main {
    public static void main(String[] args) {
        Person p1 = new Person("김사과", 20);
        Person p2 = new Person("반하나", 25);
        Person p3 = new Person("김사과", 20);

        System.out.println(p1);
        System.out.println(p1.equals(p2));
        System.out.println(p1.equals(p3));
    }
}

 

4. 업캐스팅

업캐스팅(Upcasting)은 자식 클래스 객체를 부모 클래스 타입으로 참조하는 것을 말합니다. 즉, 상속 관계에서 자식 클래스의 객체를 부모 클래스의 변수로 담는 것이다.

 

업캐스팅을 사용하는 이유

  1. 다형성(Polymorphism)을 구현하기 위해
    → 동일한 부모 타입으로 여러 자식 객체를 통일해서 다룰 수 있음
  2. 유지보수가 쉬운 코드 구조를 위해
    → 메서드 호출 시 동작은 실제 객체의 메서드(오버라이딩된 것)가 실행됨
  3. 코드 재사용성과 확장성 향상
class Animal {
    public void sound() {
        System.out.println("동물이 소리를 냅니다.");
    }
}

class Dog extends Animal {
    @Override
    public void sound() {
        System.out.println("멍멍!");
    }

    public void wagTail() {
        System.out.println("꼬리를 흔듭니다.");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();             // Dog 객체 생성
        Animal animal = dog;             // ✅ 업캐스팅 (자동)

        animal.sound();                  // 멍멍! (오버라이딩된 메서드 호출)
        // animal.wagTail();             // ❌ 컴파일 에러! Animal 타입에는 없음
    }
}

다운캐스팅과 비교

업캐스팅 자식 객체 → 부모 타입으로 참조 (자동)
다운캐스팅 부모 타입 참조 → 다시 자식 타입으로 형변환 (명시적)

 

Dog dog = new Dog();
Animal animal = dog;             // 업캐스팅 (자동)
Dog dog2 = (Dog) animal;         // 다운캐스팅 (명시적)
dog2.wagTail();             // 가능!

 

5. 이종모음

이종 모음(heterogeneous collection)은 서로 다른 타입의 객체들을 하나의 컬렉션에 담아 처리하는 구조를 의미합니다. 일반적으로 제네릭(Generic)을 사용하지 않거나, 상위 타입(예: Object)으로 업캐스팅하여 다양한 타입의 객체들을 하나의 리스트나 배열 등에 저장할 수 있습니다. 이 방식은 유연성을 제공하지만, 꺼낼 때 다시 원래 타입으로 다운캐스팅해야 하고, 타입 안정성이 떨어지며 런타임 오류의 위험이 있습니다. 이종 모음은 특수한 상황에서 사용되며, 자바에서는 보통 제네릭과 상속을 활용해 동종 모음(homogeneous collection)을 선호합니다.

 

class Book {
    String title;

    public Book(String title) {
        this.title = title;
    }

    public void read() {
        System.out.println("책 \"" + title + "\"을 읽습니다.");
    }
}

public class HeterogeneousArrayExample {
    public static void main(String[] args) {
        // Object 타입 배열로 이종 모음 구성
        Object[] items = new Object[3];

        items[0] = "안녕하세요";            // String
        items[1] = 100;                   // Integer (오토박싱)
        items[2] = new Book("자바의 정석"); // 사용자 정의 클래스

        // 배열 순회하며 타입 확인 및 처리
        for (Object obj : items) {
            if (obj instanceof String) {
                System.out.println("문자열: " + obj);
            } else if (obj instanceof Integer) {
                System.out.println("정수: " + obj);
            } else if (obj instanceof Book) {
                Book book = (Book) obj; // 다운캐스팅
                book.read();
            }
        }
    }
}

instanceof란?

instanceof는 객체가 특정 클래스의 인스턴스인지 확인하는 연산자입니다. 이 연산자는 객체가 어떤 클래스 또는 그 하위 타입으로부터 생성되었는지를 판별할 때 사용되며, 결과는 true 또는 false를 반환합니다.

객체 instanceof 클래스이름
  • 결과는 boolean 타입
  • 객체가 해당 클래스 또는 그 자식 클래스의 인스턴스이면 true, 아니면 false
  • 주로 다운캐스팅하기 전에 안전하게 타입 확인할 때 사용
  • 자바 16부터는 instanceof와 다운캐스팅을 한 줄로 작성할 수 있게 패턴 매칭이 도입
class Book {
    String title;

    public Book(String title) {
        this.title = title;
    }

    public void read() {
        System.out.println("책 \"" + title + "\"을 읽습니다.");
    }
}

public class HeterogeneousArrayExample {
    public static void main(String[] args) {
        // Object 타입 배열로 이종 모음 구성
        Object[] items = new Object[3];

        items[0] = "안녕하세요";            // String
        items[1] = 100;                   // Integer (오토박싱)
        items[2] = new Book("자바의 정석"); // 사용자 정의 클래스

        // 배열 순회하며 타입 확인 및 처리
        for (Object obj : items) {
            if (obj instanceof String str) {
                System.out.println("문자열: " + str);
            } else if (obj instanceof Integer num) {
                System.out.println("정수: " + num);
            } else if (obj instanceof Book book) {
                book.read();  // 자동으로 Book 타입으로 다운캐스팅됨
            }
        }
    }
}

'Server > Java' 카테고리의 다른 글

String 클래스  (0) 2025.05.20
접근 제한자  (0) 2025.05.20
클래스와 객체  (3) 2025.05.19
메서드  (0) 2025.05.19
배열  (1) 2025.05.15

1. 객체지향 프로그래밍

객체지향 프로그래밍(Object-Oriented Programming, OOP)은 현실 세계를 객체(object)라는 단위로 모델링하여 프로그램을 구성하는 방식으로, 코드의 재사용성과 확장성을 높여주는 프로그래밍 패러다임입니다. 객체는 데이터(속성)와 그 데이터를 처리하는 함수(메서드)를 함께 가지며, 클래스(class)를 통해 설계되고 인스턴스를 통해 사용됩니다. 객체지향의 주요 특징은 캡슐화, 상속, 다형성, 추상화로, 이 네 가지 특성을 통해 코드의 구조를 체계화하고 유지보수와 협업을 용이하게 합니다.

cf. 인스턴스 : 클래스를 실체화 시켜 객체에 올라가있는 것 

 

2. 클래스

클래스(Class)는 객체를 만들기 위한 설계도로, 객체의 속성과 동작을 정의하는 사용자 정의 자료형입니다. 클래스는 변수(필드, 속성)와 메서드(함수)를 포함하여 하나의 단위로 묶으며, 이를 바탕으로 실제 사용할 수 있는 객체(인스턴스)를 생성할 수 있습니다. 예를 들어 Car라는 클래스를 만들면, 이 클래스는 자동차의 속성(예: 색상, 속도)과 동작(예: 달리기, 멈추기)을 정의하고, 이를 기반으로 여러 대의 자동차 객체를 생성하여 사용할 수 있습니다. 클래스는 객체지향 프로그래밍의 핵심 구성요소로, 코드의 재사용성과 구조화를 가능하게 합니다.

 

// 1. 만약, 두 개의 리턴값의 자료형이 다를 떄 클래스로 통합해서 리턴시켜도됨
class car{
	a=10 
    b="문자"
}
// 2. object Type --> 최상위 객체를 사용해도됨
public Car(내가 만든 클래스 타입) hello(){
		if ...{
        		return 10
        }
        return car

}

"자동차"라는 개념을 프로그래밍으로 표현하고 싶다면?

  • 속성(필드): 색상, 속도, 브랜드 등
  • 동작(메서드): 달리다(run), 멈추다(stop) 등

이런 속성과 동작을 정의한 것이 클래스이고, 이 클래스를 바탕으로 만들어진 각각의 자동차는 객체(Object) 혹은 인스턴스(Instance)라고 부릅니다.

 

1. 클래스의 구성 요소

필드(Field) 객체가 가지는 변수, 속성 (예: 이름, 나이 등)
메서드(Method) 객체가 할 수 있는 동작, 함수
생성자(Constructor) 객체가 생성될 때 호출되는 특수한 메서드

 

// 클래스 정의
public class Dog {
    // 필드(속성)
    String name;
    int age;

    // 메서드(동작)
    public void bark() {
        System.out.println(name + "가 멍멍 짖습니다!");
    }

    public void introduce() {
        System.out.println("안녕하세요! 제 이름은 " + name + "이고, 나이는 " + age + "살입니다.");
    }
}
public class Main {
    public static void main(String[] args) {
        // Dog 클래스의 객체 생성
        Dog myDog = new Dog();

        // 필드 값 설정
        myDog.name = "루시";
        myDog.age = 15;

        // 메서드 호출
        myDog.introduce(); // 출력: 안녕하세요! 제 이름은 루시이고, 나이는 15살입니다.
        myDog.bark();      // 출력: 루시가 멍멍 짖습니다!
    }
}

 

객체

객체(Object)는 클래스라는 설계도를 바탕으로 생성된 실제 사용 가능한 실체(instance)입니다. 객체는 클래스에 정의된 속성(필드)과 동작(메서드)을 그대로 가지고 있으며, 프로그램 내에서 다양한 데이터를 저장하고 기능을 수행하는 주체로 활용됩니다. 예를 들어 Car라는 클래스가 있다면, myCar = new Car();처럼 생성된 myCar는 Car 클래스의 객체이며, 고유한 색상, 속도 등의 값을 가지며 달리기(run) 같은 동작을 수행할 수 있습니다. 즉, 객체는 클래스에서 정의한 구조를 바탕으로 실제 메모리에 생성되어 작동하는 실질적인 요소입니다.

 

객체(Object, 추상적) vs 인스턴스(Instance, 구체적)

정의 클래스에 의해 생성된 실체를 의미 객체가 특정 클래스의 구성 요소로 생성되었을 때를 강조하는 표현
포괄성 더 일반적인 개념 보다 구체적인 의미, 어떤 클래스의 인스턴스인지 명확히 함
예시 표현 "메모리에 존재하는 독립된 실체" "이 객체는 A라는 클래스의 인스턴스다"
관점 프로그래밍 실체 자체를 말할 때 사용 클래스와의 관계를 강조할 때 사용
비유 '강아지'라는 개체 '강아지는 동물(Animal) 클래스의 인스턴스다'

 

2. 생성자(method 중에 클래스 이름과 동일한 것)

생성자(Constructor) 생성자는 클래스로부터 객체를 생성할 때 호출되는 특수한 메서드입니다. 주된 목적은 객체가 생성될 때 필요한 초기값을 설정(초기화)해주는 것입니다.

이름 클래스 이름과 동일해야 함 (반드시!)
반환형 없음 (void도 쓰지 않음)
호출 시점 new 키워드로 객체를 생성할 때 자동으로 호출됨
여러 개 가능 매개변수를 달리하여 생성자 오버로딩 가능

 

매개변수가 없는 생성자

public class Person {
    String name;
    int age;

    // 기본 생성자
    public Person() {
        System.out.println("기본 생성자 호출됨!");
    }
}

// Person person(변수명) = new(힙에 데이터 만듦) Person(생성자)()

 

매개변수가 있는 생성자

  • this : 현재 객체 자신을 가리킴
  • this(...) : 다른 생성자 호출 (생성자 안에서만 첫 줄에 사용 가능)
public class Person {
    String name;
    int age;

    // 생성자 (이름과 나이를 초기화)
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

// Person person = new Person("apple",20);  --> 순서 맞춰서 넣어야한다.
public class Main {
    public static void main(String[] args) {
        Person p1 = new Person("김사과", 20);  // 생성자 호출됨
        System.out.println(p1.name + ", " + p1.age);
    }
}

 

https://docs.oracle.com/en/java/javase/17/docs/api/index.html

 

Overview (Java SE 17 & JDK 17)

This document is divided into two sections: Java SE The Java Platform, Standard Edition (Java SE) APIs define the core Java platform for general-purpose computing. These APIs are in modules whose names start with java. JDK The Java Development Kit (JDK) AP

docs.oracle.com

cf. 자바 문서 참고하여 프로그래밍하는 편이 좋음!

3. 생성자 오버로딩

같은 이름의 생성자를 매개변수 개수나 타입이 다르게 여러 개 정의할 수 있습니다.

public class User {
    String name;
    int age;

    // 1. 기본 생성자
    public User() {
        this("이름없음", 0);  // this()를 통해 다른 생성자 호출
        System.out.println("기본 생성자 호출됨");
    }

    // 2. 이름만 받는 생성자
    public User(String name) {
        this(name, 0);  // age를 0으로 설정하여 다른 생성자 호출
        System.out.println("이름만 받는 생성자 호출됨");
    }

    // 3. 이름과 나이를 받는 생성자
    public User(String name, int age) {
        System.out.println("이름과 나이를 받는 생성자 호출됨");

        // 조건 분기 로직: 나이 유효성 검사
        if (age < 0) {
            System.out.println("나이는 음수가 될 수 없습니다. 0으로 설정합니다.");
            this.age = 0;
        } else {
            this.age = age;
        }

        // 이름이 null이거나 빈 문자열이면 기본값 설정
        if (name == null || name.trim().isEmpty()) {
            this.name = "이름없음";
        } else {
            this.name = name;
        }
    }

    // 소개 메서드
    public void introduce() {
        System.out.println("안녕하세요. 제 이름은 " + name + "이고 나이는 " + age + "살입니다.");
    }

    // main 메서드로 테스트
    public static void main(String[] args) {
        User u1 = new User();                     // 기본 생성자
        User u2 = new User("김사과");                // 이름만 받는 생성자
        User u3 = new User("반하나", -5);           // 잘못된 나이로 조건 분기 확인
        User u4 = new User("", 20);              // 잘못된 이름으로 조건 분기 확인

        u1.introduce();
        u2.introduce();
        u3.introduce();
        u4.introduce();
    }
}

 

3. null

null은 참조형 변수(객체)의 기본값이며, "아직 어떤 객체도 참조하지 않고 있음"을 의미합니다. null은 기본형(int, double 등)에는 사용할 수 없고, 객체 타입(참조형)에만 사용할 수 있습니다.

String s = null;  // s는 아직 아무 문자열도 참조하지 않음

 

1. NullPointerException(NPE)이란?

null 값을 가진 변수에서 메서드를 호출하거나 필드에 접근하려고 하면 자바는 NullPointerException을 발생시킵니다.

String s = null;
System.out.println(s.length());  // ❌ NPE 발생

 

2. null 처리 시 주의할 점 5가지

메서드 호출 전에 null 체크 필수

if (s != null) {
    System.out.println(s.length());
}

 

equals 비교는 null 객체로 하지 말고, 상수로 시작

String name = null;

// 잘못된 방식 (null에서 메서드 호출)
if (name.equals("김사과")) { }  // ❌ NPE

// 올바른 방식
if ("김사과".equals(name)) { }  // ✅ 안전

 

래퍼 클래스는 언박싱 시 null이면 에러

Integer num = null;
int x = num;  // ❌ NPE 발생 (null → int 언박싱 불가)

// 해결 방법
if (num != null) {
    int x = num;
}
// 또는
int x = (num != null) ? num : 0;

 

배열 또는 리스트에서 null 요소 존재 여부 확인

String[] names = new String[3];  // [null, null, null]

for (String n : names) {
    if (n != null) {
        System.out.println(n.length());
    }
}

 

Optional (선택적) 사용으로 null 안전하게 처리

// generic 형식
Optional<String> opt = Optional.ofNullable(name);

opt.ifPresent(n -> System.out.println(n.length())); // null이면 실행 안 함

String result = opt.orElse("기본값"); // null이면 기본값 사용

 

4. 가비지 컬렉터

가비지 컬렉터(Garbage Collector)는 자바에서 더 이상 사용되지 않는 객체를 자동으로 메모리에서 제거해주는 기능으로, 개발자가 직접 메모리를 해제하지 않아도 되도록 도와주는 자동 메모리 관리 시스템입니다. 객체가 생성되면 힙(heap) 메모리에 저장되는데, 더 이상 어떤 변수나 객체에서도 참조되지 않는 객체는 "쓸모없다"고 판단되어 가비지 컬렉터의 대상이 됩니다. 이 과정은 JVM이 자동으로 수행하며, 메모리 누수를 방지하고 안정적인 프로그램 실행을 돕습니다. 필요할 경우 System.gc()로 수동 요청도 가능하지만, 실제 실행 여부는 JVM의 판단에 따릅니다.

 

객체에 대한 참조(reference)가 사라지면, JVM은 "이건 이제 필요 없는 객체"라고 판단하고 제거 대상에 넣습니다.

Dog dog = new Dog();  // Dog 객체 생성
dog = null;           // 참조 제거 → 이 객체는 더 이상 접근할 수 없음

1. 가비지 컬렉터의 동작시기

가비지 컬렉터는 JVM이 자동으로 판단하여 실행합니다.

  • 메모리가 부족할 때
  • 시스템이 한가할 때
  • 명시적으로 요청할 수도 있음 (단, 반드시 실행된다는 보장은 없음)
System.gc();  // JVM에게 가비지 컬렉션을 요청함 (강제는 아님)

 

2. 가비지 컬렉터의 내부 동작 방법

  • Reachability 분석
    루트(root, 예: 지역변수, static 변수 등)에서부터 접근할 수 없는 객체를 탐지
  • Mark and Sweep (표시 & 제거)
    • 사용 중인 객체는 표시(mark)
    • 사용되지 않는 객체는 제거(sweep)
  • Compact (압축)
    남은 객체들을 메모리 앞쪽으로 정리해서 메모리 단편화 방지

 

  단편화  

단편화는 메모리에 빈 공간이 조각조각 나뉘어 흩어져 있어서, 충분한 총 공간은 있지만 연속된 공간이 부족하여 새로운 데이터를 저장할 수 없는 상태를 말합니다. 자바의 가비지 컬렉터는 단순히 객체만 지우는 게 아니라, 필요 시 남은 객체들을 앞으로 땡겨서(압축하여) 단편화를 줄이는 작업(compaction)도 수행합니다.

 

 

5. 패키지

자바에서 패키지(Package)는 관련된 클래스, 인터페이스, 열거형 등을 논리적으로 묶어주는 디렉터리 형태의 구조로, 코드의 조직화와 관리를 쉽게 해줍니다. 패키지를 사용하면 클래스 이름이 충돌하는 것을 방지할 수 있고, 서로 관련 있는 기능들을 그룹으로 묶어 모듈화와 재사용성을 높일 수 있습니다. 패키지는 package 키워드로 선언하며, 예를 들어 package com.example.util;처럼 계층적으로 구성할 수 있고, 다른 패키지의 클래스를 사용하려면 import 문을 통해 명시적으로 불러와야 합니다.

 

1. 패키지 선언

자바 소스파일의 가장 첫 줄에 package 키워드를 사용합니다.

src/
 └── com/
     └── example/
         └── utils/
             └── MathHelper.java
package com.example.utils;

public class MathHelper {
    public static int add(int a, int b) {
        return a + b;
    }
}

 

2. 다른 패키지 클래스 사용

cf. 같은 패키지 내에서는 import 하지 않아도된다.

import com.example.utils.MathHelper;

public class Main {
    public static void main(String[] args) {
        int result = MathHelper.add(5, 10);
        System.out.println("결과: " + result);
    }
}

// 전체 패키지를 임포트할 수도 있습니다
import com.example.utils.*;

 

3. 기본 패키지 (default package)

  • 패키지를 명시하지 않으면 자동으로 default package에 속합니다.
  • 하지만 실제 프로젝트에서는 패키지 명시를 강력히 권장합니다.
 

'Server > Java' 카테고리의 다른 글

접근 제한자  (0) 2025.05.20
상속  (2) 2025.05.19
메서드  (0) 2025.05.19
배열  (1) 2025.05.15
Scanner API  (1) 2025.05.15

1. 메서드

자바에서 메서드(Method)는 특정 작업을 수행하는 코드 블록으로, 프로그램의 재사용성과 구조화를 위해 사용됩니다. 메서드는 클래스 안에 정의되며, 호출 시 실행되어 결과를 반환하거나 작업을 수행합니다. 메서드는 리턴타입 메서드이름(매개변수) 형식으로 선언되며, 예를 들어 int(리턴 타입) add(int a, int b)는 두 정수를 더해 결과를 반환하는 메서드입니다. 메서드는 반복되는 코드를 하나로 묶어 코드의 가독성과 유지보수성을 높여주며, 클래스 내부에서 객체의 동작을 정의하는 핵심 요소입니다.

리턴타입 메서드이름(매개변수들) {
    // 실행할 코드
    return 값; // 리턴타입이 void가 아닌 경우
}
리턴타입 메서드가 반환하는 값의 자료형. 값을 반환하지 않을 경우 void 사용
메서드 이름 메서드를 호출할 때 사용할 이름. 소문자로 시작하며 동사형으로 많이 사용
매개변수 메서드 호출 시 전달되는 값 (없을 수도 있음)
return 결과를 호출한 쪽으로 돌려줌 (void면 생략 가능)

 

 

1. 반환값이 없고 매개변수도 없는 메서드

public void printHello() {
    System.out.println("안녕하세요!");
}

 

2. 반환값이 없고 매개변수가 있는 메서드

public void printName(String name) {
    System.out.println("이름: " + name);
}

 

3. 반환값이 있고 매개변수가 없는 메서드

public int getRandomNumber() {
    return (int)(Math.random() * 100); // 0~99 사이의 정수
}

 

4. 반환값이 있고 매개변수가 있는 메서드

public int multiply(int a, int b) {
    return a * b;
}

 

 

5. 가변 매개변수를 사용한 메서드

public int sum(int... numbers) {
    int total = 0;
    for (int n : numbers) {
        total += n;
    }
    return total;
}

// int... : 여러개를 배열로 받음. 그래서 for문이 가능함

 

public class MethodExample {

    // 1. 반환값 X, 매개변수 X
    public void printHello() {
        System.out.println("안녕하세요!");
    }

    // 2. 반환값 X, 매개변수 O
    public void printName(String name) {
        System.out.println("이름: " + name);
    }

    // 3. 반환값 O, 매개변수 X
    public int getRandomNumber() {
        return (int)(Math.random() * 100);
    }

    // 4. 반환값 O, 매개변수 O
    public int multiply(int a, int b) {
        return a * b;
    }

    // 5. 반환값 O, 가변 매개변수 O
    public int sumAll(int... numbers) {
        int sum = 0;
        for (int n : numbers) {
            sum += n;
        }
        return sum;
    }

    public static void main(String[] args) {
        MethodExample ex = new MethodExample();

        ex.printHello();

        ex.printName("김사과");

        int rand = ex.getRandomNumber();
        System.out.println("랜덤 숫자: " + rand);

        int result = ex.multiply(4, 5);
        System.out.println("4 x 5 = " + result);

        int total = ex.sumAll(1, 2, 3, 4, 5);
        System.out.println("1부터 5까지의 합: " + total);

        System.out.println("합계(없음): " + ex.sumAll());
    }
}

 

2. return

자바에서 return은 메서드 실행을 끝내고, 호출한 쪽에 값을 전달할 때 사용하는 키워드입니다. 메서드에서 return이 실행되면 그 즉시 메서드는 종료되며, 지정한 값이 호출한 코드로 돌아갑니다.

 

1. void 메서드에서의 return (생략도 가능)

public void sayHello() {
    System.out.println("안녕하세요!");
    return; // 생략해도 자동으로 메서드는 끝납니다.
}

2. 값을 반환하는 메서드

public int add(int a, int b) {
    return a + b; // 결과를 호출한 쪽으로 돌려줌
}

3. 조건문 안에서 return 사용

- 제일 중요함 + 자주 쓰이는 방식 

- 에러는 전부 위에서 처리하고, 결론적으로 반환해야하는 결과는 맨 마지막에 리턴

public String checkEven(int number) {
    if (number % 2 == 0) {
        return "짝수입니다";
    }
    return "홀수입니다";
}

 

4. return은 즉시 메서드 종료

public void testReturn() {
    System.out.println("시작");
    return;
    // 아래 코드는 절대 실행되지 않음
    // System.out.println("끝");
}

'Server > Java' 카테고리의 다른 글

상속  (2) 2025.05.19
클래스와 객체  (3) 2025.05.19
배열  (1) 2025.05.15
Scanner API  (1) 2025.05.15
연산자  (0) 2025.05.15

1. 배열

자바에서 배열(Array)은 같은 자료형의 값들을 여러 개 저장할 수 있는 연속된 공간입니다. 배열은 한 번 생성되면 크기가 고정되며, 각 요소는 인덱스(순번)를 통해 접근할 수 있습니다. 인덱스는 0부터 시작하고, 배열의 크기보다 큰 인덱스를 참조하면 오류가 발생합니다. 배열을 사용하면 반복문과 함께 데이터를 효율적으로 처리할 수 있으며, int[ ], String[ ]처럼 자료형 뒤에 대괄호([])를 붙여 선언합니다.

 

1. 배열의 특징

  • 같은 자료형만 저장 가능 (int[ ], String[ ], double[ ] 등)
  • 크기(길이)를 미리 정해야 함 → 한 번 정해지면 변경 불가
  • 인덱스는 0부터 시작 (arr[0], arr[1], …)
  • 반복문과 함께 사용하면 효율적으로 데이터 처리 가능

 

2. 배열 선언과 생성

자료형[] 배열이름 = new 자료형[크기];
// 방법 1
int[] scores = new int[5]; // 정수형 5개를 저장할 수 있는 배열 생성

// 방법 2
int[] scores = {90, 80, 100, 70, 40};	// 배열 생성과 동시에 값을 저장
  • new int[5] → 실제 정수 5개를 저장할 메모리 공간(배열 객체)을 생성
  • scores → 그 메모리 공간의 주소를 저장한 참조 변수

즉, scores  자체는 배열을 직접 저장하는 게 아니라, 배열이 저장된 메모리의 위치(주소)를 참조하는 것입니다.

 

int[] a = {1, 2, 3};
int[] b = a;           // 배열 a의 참조값을 b에 복사

b[0] = 99;             // b 배열의 첫 번째 값을 변경

System.out.println(a[0]);  // 출력: 99

 

import java.util.Scanner;

public class ArrayInputEx {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);    // Scanner 생성
        int[] scores = new int[3];              // 정수 3개 저장할 배열 생성

        // 각 점수를 개별적으로 입력받기
        System.out.print("1번째 점수를 입력하세요: ");
        scores[0] = sc.nextInt();

        System.out.print("2번째 점수를 입력하세요: ");
        scores[1] = sc.nextInt();

        System.out.print("3번째 점수를 입력하세요: ");
        scores[2] = sc.nextInt();

        // 입력한 점수 출력
        System.out.println("1번째 점수: " + scores[0]);
        System.out.println("2번째 점수: " + scores[1]);
        System.out.println("3번째 점수: " + scores[2]);

        sc.close();  // Scanner 닫기
    }
}

 

2. 2차원 배열

배열 안에 또 다른 배열이 있는 구조입니다. 자바의 2차원 배열은 사실 1차원 배열을 요소로 가지는 배열입니다. 즉, 행(row)마다 각각의 1차원 배열이 따로 존재합니다.

 

  • 1차원 배열: int[]
  • 2차원 배열: int[][] ← 배열의 배열
int[][] matrix = new int[2][3]; // 2행 3열 배열
int[][] arr = {
    {1, 2, 3},
    {4, 5, 6}
};

 

  • arr는 2개의 배열(행)을 참조하는 배열
  • arr[0]은 {1, 2, 3}, arr[1]은 {4, 5, 6}을 참조
  • 각각은 독립된 1차원 배열이고, arr[0][1] 같은 식으로 접근
public class JaggedArrayExample {
    public static void main(String[] args) {
        // 3행짜리 배열 만들기 (열 크기는 아직 정하지 않음)
        int[][] jagged = new int[3][];  

        // 각 행에 다른 크기의 배열을 할당 (가변 배열)
        jagged[0] = new int[] {1, 2};          // 2열
        jagged[1] = new int[] {3, 4, 5};       // 3열
        jagged[2] = new int[] {6};             // 1열

        System.out.println("jagged[0][0] = " + jagged[0][0]);
        System.out.println("jagged[0][1] = " + jagged[0][1]);

        System.out.println("jagged[1][0] = " + jagged[1][0]);
        System.out.println("jagged[1][1] = " + jagged[1][1]);
        System.out.println("jagged[1][2] = " + jagged[1][2]);

        System.out.println("jagged[2][0] = " + jagged[2][0]);
    }
}

 

3. 얕은 복사와 깊은 복사

자바에서 얕은 복사(Shallow Copy)는 객체나 배열의 참조값(주소)만 복사하여 원본과 복사본이 같은 데이터를 공유하는 방식이며, 한쪽을 변경하면 다른 쪽에도 영향을 줍니다. 반면, 깊은 복사(Deep Copy)는 새로운 메모리 공간을 만들고 원본의 값을 하나하나 복사하여 원본과 복사본이 서로 독립적으로 동작하게 만드는 방식입니다. 따라서 깊은 복사는 값을 변경해도 서로 영향을 주지 않습니다.

 

1. 얕은 복사(Shallow Copy)

얕은 복사는 값 자체를 복사하는 게 아니라 주소(참조값)를 복사하는 것입니다. 즉, 두 변수가 같은 객체(또는 배열)를 가리키게 됩니다.

int[] a = {1, 2, 3};
int[] b = a;  // 얕은 복사

b[0] = 99;

System.out.println("a[0] = " + a[0]);  // 99
System.out.println("b[0] = " + b[0]);  // 99

 

2. 깊은 복사(Deep Copy)란?

깊은 복사는 내용을 완전히 새로 복사하는 것입니다. 즉, 새로운 공간을 만들고 값만 복사하므로 서로 완전히 독립적입니다.

// 원본 배열
int[] a = {1, 2, 3};

// 새로운 배열(깊은 복사용)
int[] b = new int[3];

b[0] = a[0];
b[1] = a[1];
b[2] = a[2];

// b 배열 값 변경
b[0] = 99;

// 결과 출력
System.out.println("a[0] = " + a[0]);  // 1 (원본 그대로)
System.out.println("b[0] = " + b[0]);  // 99 (복사본 변경)

'Server > Java' 카테고리의 다른 글

클래스와 객체  (3) 2025.05.19
메서드  (0) 2025.05.19
Scanner API  (1) 2025.05.15
연산자  (0) 2025.05.15
변수  (1) 2025.05.14

1. Scanner

자바에서 Scanner는 사용자로부터 키보드 입력을 받을 수 있게 해주는 표준 입력 처리 도구입니다. java.util 패키지에 포함되어 있으며, 숫자, 문자열 등 다양한 형식의 데이터를 쉽게 입력받을 수 있도록 도와줍니다. 보통 콘솔에서 입력을 받을 때 사용되며, System.in을 통해 표준 입력 스트림을 읽습니다.

 

 

2. Scanner 사용

  1. 먼저 import java.util.Scanner;를 선언합니다.
  2. Scanner sc = new Scanner(System.in); 으로 객체를 생성합니다.
  3. sc.nextInt(), sc.nextLine(), sc.nextDouble() 등 다양한 메서드를 사용해 입력을 받습니다.
  4. 사용이 끝나면 sc.close();를 호출해서 자원을 정리합니다. --> 써주는 것이 관례

 

3. 메서드 정리

next() 단어 하나 (공백 전까지) 읽음
ex)  apple banana 를 입력하면 apple까지만 출력
nextLine() 한 줄 전체 입력 (공백 포함)
nextInt() 정수 입력
nextDouble() 실수 입력
nextBoolean() true/false 입력

 

import java.util.Scanner;

public class ScannerEx {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);  // Scanner 객체 생성

        System.out.print("이름을 입력하세요: ");
        String name = sc.nextLine();          // 문자열 입력

        System.out.print("나이를 입력하세요: ");
        int age = sc.nextInt();               // 정수 입력

        System.out.println("안녕하세요, " + name + "님! 당신의 나이는 " + age + "세입니다.");

        sc.close();  // Scanner 닫기 (권장)
    }

 

주의사항

nextInt() 후에 nextLine()을 바로 쓰면 입력이 꼬일 수 있습니다. 이때는 sc.nextLine()을 한 번 더 호출해서 버퍼를 비워줘야 합니다.

int age = sc.nextInt();
sc.nextLine();  // 개행 문자 제거
String name = sc.nextLine();



4. System.in

System.in은 자바에서 표준 입력 장치를 의미하며, 일반적으로 키보드 입력을 받을 때 사용되는 입력 스트림(InputStream)입니다. 보통 Scanner, BufferedReader와 함께 사용되어 입력값을 읽는 데 활용되며, 바이트 단위로 데이터를 읽는 특성을 갖습니다. 텍스트 입력을 더 쉽게 다루기 위해 보통 래퍼 클래스들과 함께 사용됩니다.

 

** 입력 스트림(InputStream) : 키보드 입력 스트림 > OS > Java 순서로 데이터 이동

** OS : 중간매체로 파일 생성 및 삭제를 담당한다.

import java.io.IOException;

public class SystemInEx {
    public static void main(String[] args) throws IOException {
        System.out.print("문자 하나를 입력하세요: ");
        int input = System.in.read();  // 한 글자(바이트)를 읽음

        System.out.println("입력한 문자: " + (char)input);
    }
}

'Server > Java' 카테고리의 다른 글

메서드  (0) 2025.05.19
배열  (1) 2025.05.15
연산자  (0) 2025.05.15
변수  (1) 2025.05.14
자바  (0) 2025.05.14

1. 연산자

연산자는 변수나 값에 대해 연산(계산, 비교 등)을 수행할 수 있도록 도와주는 기호 또는 예약어입니다.

 

1. 산술 연산자 (Arithmetic Operators)

숫자 계산을 위한 연산자입니다.

+ 덧셈 3 + 2 5
- 뺄셈 5 - 2 3
* 곱셈 4 * 2 8
/ 나눗셈 5 / 2 2 (정수 나눗셈)
% 나머지 (mod) 5 % 2 1
주의: 정수끼리 나누면 소수점은 버려집니다. 5 / 2 = 2, 소수를 얻으려면 5.0 / 2처럼 하나 이상이 실수여야 합니다.
 

2. 대입 연산자 (Assignment Operator)

변수에 값을 저장(할당)할 때 사용합니다.

= 대입 int a = 10;

 

복합 대입 연산자

+= 더해서 대입 a += 3;
-= 빼서 대입 a -= 2;
*= 곱해서 대입 a *= 5;
/= 나눠서 대입 a /= 2;
%= 나머지 대입 a %= 3;

 

3. 비교 연산자 (비교 결과는 true 또는 false)

두 값을 비교할 때 사용하며, 주로 조건문에서 사용됩니다.

== 같음 3 == 3 true
!= 같지 않음 3 != 2 true
> 크다 5 > 2 true
< 작다 2 < 5 true
>= 크거나 같다 5 >= 5 true
<= 작거나 같다 4 <= 3 false

 

4. 논리 연산자 (Boolean값을 연결할 때)

여러 조건을 함께 처리할 때 사용됩니다.

&& AND (그리고) true && false false
|| OR (또는) true || false OR (또는)
! NOT (부정) !true false

 

5. 증감 연산자 (값 1 증가 또는 감소)

++ 1 증가 a++ 사용 후 증가 (후위)
-- 1 감소 --a 사용 전 감소 (전위)
 

 

6. 조건(삼항) 연산자

조건에 따라 값을 선택할 수 있게 해주는 연산자입니다.

조건 ? 참일 때 값 : 거짓일 때 값

 

7. 비트 연산자 

2진수로 연산을 수행할 때 사용합니다.

& AND
| OR
^ XOR
~ NOT (반전)
<< 왼쪽 쉬프트
>> 오른쪽 쉬프트

'Server > Java' 카테고리의 다른 글

메서드  (0) 2025.05.19
배열  (1) 2025.05.15
Scanner API  (1) 2025.05.15
변수  (1) 2025.05.14
자바  (0) 2025.05.14

+ Recent posts