Back-End (Web)/JAVA

[JAVA] 응용 정리

JABHACK 2024. 11. 15. 21:39

★Enum (열거형)

 

Enum의 주요 메서드

  • values(): 열거형에 정의된 모든 값을 배열로 반환.
  • valueOf(String name): 이름으로 열거형 상수를 찾음.
// 모든 값을 배열로 반환
enum Day {
    MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
}

public class EnumValuesExample {
    public static void main(String[] args) {
        Day[] days = Day.values();
        for (Day day : days) {
            System.out.println(day);  // MONDAY, TUESDAY, ... 출력
        }
    }
}

 

사용 시 유의점

  • Enum은 상수 값을 정의하는 데 유용하지만, 값의 추가나 변경이 자주 일어날 경우 유연성에서 부족할 수 있습니다.
  • Enum을 사용할 때는 상수의 집합이 의미가 있는지, 그 값들이 변경되지 않도록 보장해야 하는 경우 적합합니다.

 

< 예제 >

enum Day {
    MONDAY("월요일"), TUESDAY("화요일"), WEDNESDAY("수요일"),
    THURSDAY("목요일"), FRIDAY("금요일"), SATURDAY("토요일"), SUNDAY("일요일");

    private String koreanName;

    Day(String koreanName) {
        this.koreanName = koreanName;
    }

    public String getKoreanName() {
        return koreanName;
    }
}

public class EnumExample {
    public static void main(String[] args) {
        Day today = Day.MONDAY;
        System.out.println(today.getKoreanName());  // 월요일 출력
    }
}

//////////////////////////////응용


enum Season {
    SPRING, SUMMER, FALL, WINTER
}

public class EnumComparisonExample {
    public static void main(String[] args) {
        Season currentSeason = Season.SUMMER;

        if (currentSeason == Season.SUMMER) {
            System.out.println("It's summer!");
        }
    }
}

 

 

★람다 (Lambda Expression)

 

 

★스트림 (Stream)

 

 

 

★제네릭 (Generics)

📌 클래스, 인터페이스, 메서드 등에서 사용하는 타입을 매개변수화하여 코드의 재사용성유연성을 높여주는 Java의 중요한 기능

제네릭의 사용 상황

  1. 컬렉션 프레임워크:
    • List, Set, Map 등에서 제네릭을 사용하여 타입을 명확히 지정함으로써 타입 안전성을 보장하고, 불필요한 캐스팅을 피할 수 있습니다.
  2. 유틸리티 클래스 작성:
    • 제네릭을 사용하면 다양한 타입에 대해 범용적으로 사용할 수 있는 클래스나 메서드를 작성할 수 있습니다. 예를 들어, Box 클래스를 사용하면 Integer, String 등 다양한 타입을 처리할 수 있습니다.
  3. 타입 제한이 필요한 경우:
    • 특정 타입이나 그 하위 타입에 대해서만 작동하도록 제네릭을 사용할 때 타입 제한을 두어, 보다 강력한 타입 안전성을 유지할 수 있습니다.
     
  4. API 설계:
    • 제네릭을 사용하면 클래스나 메서드의 재사용성을 높이기 위해, 라이브러리나 프레임워크를 설계할 때 유용합니다. 예를 들어, Java의 ArrayList는 다양한 타입을 받을 수 있도록 제네릭을 사용합니다.
public <T extends Number> void printNumber(T num) {
    System.out.println(num);
}

제네릭의 단점

  • 타입 불일치: 컴파일 타임에 타입을 지정하므로 런타임에 타입을 변경할 수 없습니다.
  • 다형성 제한: 제네릭 타입은 **원시 타입(primitive type)**을 사용할 수 없습니다. 예를 들어, int 대신 Integer와 같은 래퍼 클래스를 사용해야 합니다.
  • 복잡성: 제네릭을 사용할 때 코드가 다소 복잡해질 수 있습니다.

1. 제네릭 클래스

// 제네릭 클래스를 정의할 때 타입 파라미터 <T>를 사용
class Box<T> {
    private T item;

    public void setItem(T item) {
        this.item = item;
    }

    public T getItem() {
        return item;
    }
}

public class Main {
    public static void main(String[] args) {
        Box<Integer> intBox = new Box<>();
        intBox.setItem(10);
        System.out.println(intBox.getItem());  // 10

        Box<String> strBox = new Box<>();
        strBox.setItem("Hello");
        System.out.println(strBox.getItem());  // Hello
    }
}

 

2. 제네릭 메서드

// 제네릭 메서드는 메서드 레벨에서 타입 파라미터를 지정
public class Main {
    public static <T> void printArray(T[] array) {
        for (T element : array) {
            System.out.print(element + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        Integer[] intArray = {1, 2, 3};
        String[] strArray = {"Hello", "World"};

        printArray(intArray);  // 1 2 3
        printArray(strArray);  // Hello World
    }
}

 

3. 제네릭 인터페이스

interface Pair<K, V> {
    K getKey();
    V getValue();
}

class KeyValuePair<K, V> implements Pair<K, V> {
    private K key;
    private V value;

    public KeyValuePair(K key, V value) {
        this.key = key;
        this.value = value;
    }

    public K getKey() {
        return key;
    }

    public V getValue() {
        return value;
    }
}

public class Main {
    public static void main(String[] args) {
        Pair<Integer, String> pair = new KeyValuePair<>(1, "One");
        System.out.println(pair.getKey() + ": " + pair.getValue());  // 1: One
    }
}

 

 

★static

📌 Java에서 클래스나 객체의 특정 구성 요소에 대한 정적(Static) 특성을 정의하는 키워드입니다. 이를 사용하면 해당 구성 요소가 클래스에 속하게 되며(객체가 아닌 클래스의 변수, 메소드 선언 가능), 객체의 인스턴스화 없이 접근할 수 있습니다.

 

 

★추상 클래스 (Abstract Class)

📌 구현되지 않은 메서드(즉, 추상 메서드)를 포함할 수 있는 클래스입니다. 추상 클래스는 직접 인스턴스를 생성할 수 없으며, 다른 클래스에서 상속받아 사용하도록 설계됩니다.

 

정의:

  • 추상 클래스abstract 키워드로 선언되며, 구현되지 않은 메서드를 포함할 수 있습니다.
  • 인스턴스를 생성할 수 없다는 특징이 있으며, 이를 상속받은 자식 클래스에서 추상 메서드를 구현해야 합니다.

사용처:

    • 공통된 속성과 동작을 여러 클래스에서 공유해야 할 때 사용합니다.
    • 공통된 기본 기능을 부분적으로 구현하고, 그 외의 구체적인 구현은 자식 클래스에서 하도록 유도할 때 유용합니다.

  • 저 인터페이스 공통된 기능을 다른 클래스들에게 강제 한다는 말은 인터페이스에서 사용된 변수, 메소드는 반드시 인터페이스를 구현할 클래스에서 반드시 구현되어야만 한다. (추상 클래스는 안해도 상관없다.)
  • 이런 일이 발생하는 이유는 객체의 청사진이 클래스라면, 클래스의 청사진이 인터페이스이기 때문

 

★인터페이스

📌 클래스의 청사진으로, 인터페이스를 구현할 클래스는 반드시 인터페이스에서 사용된 변수, 메소드를 반드시 구현해야한다.

 

  • implements 키워드를 사용하여 인터페이스를 구현할 수 있습니다. 
public class 클래스명 implements 인터페이스명 { 
			// 추상 메서드 오버라이딩
			@Override
	    public 리턴타입 메서드이름(매개변수, ...) {
			       // 실행문
	    }
}

 

  • 인터페이스 간의 상속은 implements 가 아니라 extends 키워드를 사용합니다.
public class Main extends D implements C {

    @Override
    public void a() {
        System.out.println("A");
    }

    @Override
    public void b() {
        System.out.println("B");
    }

    @Override
    void d() {
        super.d();
    }

    public static void main(String[] args) {
        Main main = new Main();
        main.a();
        main.b();
        main.d();
    }
}

interface A {
    void a();
}

interface B {
    void b();
}

interface C extends A, B {
}

class D {
    void d() {
        System.out.println("D");
    }
}

 

 

This

📌 현재 객체 자신을 참조하는 키워드로, 객체 내부에서 객체의 멤버(필드, 메서드, 생성자)를 명확히 참조하기 위해 사용됩니다.

정의 객체의 현재 인스턴스를 참조하는 키워드로, 객체 내부에서 멤버 변수와 메서드를 호출하거나 생성자 호출에 사용.
특징 ✔ 객체 자신의 주소를 나타냄
✔ 인스턴스 멤버에 접근할 때 사용
✔ 메서드나 생성자에서 주로 활용됨
✔ 정적(static) 맥락에서는 사용 불가

 

  • 위 경우 입력값 model이 객체의 model이 아닌 매개변수 model에 입력됨

 

  • 위 경우 입력값 model이 객체의 model에 입력됨
  • 매개변수, 지역 변수, 클래스 변수의 이름이 동일할 경우 구분을 위해 사용
  • this. = 현재 객체의 변수
  • this() = 현재 객체 생성자

 

final

📌 현재 클래스, 변수를 더이상 변경 불가하게 만들어 버린다. 상속도 막힌다.

 

Object

📌 Java 내 모든 클래스들의 최상위 부모 클래스, 다양한 기능 제공

 


 

★객체지향 프로그래밍

class Car {
    String model;
    String color;
    
    // 기본 생성자
    public Car(String model, String color) {
        this.model = model;
        this.color = color;
    }
    
    // gasPedal 메서드: 속도를 설정하는 메서드로 kmh 값을 speed 필드에 저장하고 반환
    public double gasPedal(double kmh) {
        speed = kmh; // 자동차의 현재 속도를 kmh 값으로 설정
        return speed; // 설정된 속도 반환
    }
}

public class Main {
    public static void main(String[] args) {
        // 인스턴스화 과정
        Car car1 = new Car("Sedan", "Red"); // Car 클래스로부터 car1 객체 생성
        Car car2 = new Car("SUV", "Blue");  // Car 클래스로부터 car2 객체 생성
        
        System.out.println(car1.model);  // Sedan 출력
        System.out.println(car2.model);  // SUV 출력
    }
}

Car car1 = new Car("Sedan", "Red");는 Car 클래스를 사용하여 "Sedan" "Red"라는 속성값을 가지는 새로운 Car 객체를 생성하고, 그 객체를 car1이라는 참조형 변수에 참조하도록 하는 코드

인스턴스(객체) car1, car2
인스턴스화 new
메서드 public double gasPedal(double kmh)
클래스 class Car
생성자 public Car(String model, String color)    /     생성자는 메서드와 다르게 클래스와 이름이 같다

 

 

★오버라이딩

 🐳 부모 클래스로부터 상속받은 메서드의 내용을 재정의 하는 것을 오버라이딩이라고 합니다.

 

  1. 선언부가 부모 클래스의 메서드와 일치해야 합니다.
  2. 접근 제어자를 부모 클래스의 메서드 보다 좁은 범위로 변경할 수 없습니다.
  3. 예외는 부모 클래스의 메서드 보다 많이 선언할 수 없습니다

오버라이딩 사용 상황:

  • 부모 클래스의 메서드를 자식 클래스에서 새롭게 정의하고자 할 때.
  • 상속 구조에서 특정 메서드를 변경하고자 할 때.
  • 다형성을 활용하여, 자식 클래스의 특성에 맞는 기능을 구현하고자 할 때.

 

★오버로드

 🐳 오버로딩은 하나의 클래스 내에서 동일한 이름을 가진 메서드를 여러 개 정의하는 것입니다. 하지만 오버로딩된 메서드는 매개변수의 개수나 타입이 달라야 합니다.

  • 즉, 메서드 이름은 같지만 매개변수의 타입, 개수, 순서가 다르면 컴파일러가 어떤 메서드를 호출할지 구분할 수 있습니다. 반환 타입만 달라서는 오버로딩이 발생하지 않습니다. 컴파일 시점에 메서드가 결정됩니다

오버로딩 사용 상황:

  • 하나의 메서드 이름으로 다양한 입력을 처리하고자 할 때.
  • 매개변수의 개수나 타입이 다른 경우에도 같은 작업을 처리하고 싶을 때.
  • 메서드를 다수 정의해야 하는 경우, 메서드 이름을 통일하고 코드의 가독성을 높이기 위해.

 

 

다형성 & 추상화

동일한 메서드 이름이지만 다른 방식으로 동작할 수 있게 함

  • sound를 한 부모에서 상속받았지만 내용은 다름 = 다형성은 오버라이딩으로 구현됨
// 부모 클래스
class Animal {
    public void sound() {
        System.out.println("Animal makes a sound");
    }
}

// 자식 클래스 1
class Dog extends Animal {
    @Override
    public void sound() {
        System.out.println("Dog barks");
    }
}

// 자식 클래스 2
class Cat extends Animal {
    @Override
    public void sound() {
        System.out.println("Cat meows");
    }
}

 

참조형 자료구조 

 

 

클래스 & 객체 & 인터페이스

 

 

인스턴스 맴버와 클래스 맴버

 

 

생성자

항목 내용
정의 객체 생성 시 초기화 작업을 수행하는 특수한 메서드. 클래스 이름과 동일한 이름을 가지며 반환 타입이 없음.
(초기화의 이유 : 안정적이고 예측 가능한 상태에서 객체를 사용할 수 있도록 보장하기 위해서 )
특징 ✔ 클래스 이름과 동일
✔ 반환 타입이 없음 (void도 사용하지 않음)
✔ 객체 생성 시 자동 호출
✔ 오버로딩 가능
사용처 ▶ 객체 초기화 시 필수 데이터를 설정하거나 특정 작업 수행
객체를 생성하면서 동시에 원하는 상태로 설정해야 할 때 사용
종류 - 기본 생성자: 매개변수가 없는 생성자 (컴파일러가 자동 생성, 명시적 정의 가능).
- 매개변수 생성자: 원하는 값으로 객체 초기화
기본값 - 생성자를 정의하지 않으면 컴파일러가 기본 생성자를 자동으로 제공.
- 생성자를 정의하면 기본 생성자는 제공되지 않음.

 

 

< 접근 제어자 정리표 >

접근 제어자 같은 클래스 같은 패키지 (클래스 폴더) 자식 클래스 외부 클래스
public O O O O
protected O O O X
default O O X X
private O X X X

 

 

접근 제어

< 접근 제어자 정리표 >

접근 제어자 같은 클래스 같은 패키지 (클래스 폴더) 자식 클래스 외부 클래스
public O O O O
protected O O O X
default O O X X
private O X X X

 

< 사용 가능한 접근 제어자  >

클래스 public, default
메서드 & 멤버 변수 public, protected, default, private
지역변수 없음

 

 

'Back-End (Web) > JAVA' 카테고리의 다른 글

[JAVA] HASH란 무엇인가  (1) 2024.11.21
[JAVA] 자바의 정렬  (0) 2024.11.21
[JAVA] NULL  (0) 2024.11.13
[JAVA] 쓰레드 & 람다 함수 & 스트림  (3) 2024.11.13
[JAVA] Generic  (3) 2024.11.12