[Java] chapter10

Ryong·2024년 1월 15일
0

Java

목록 보기
11/12
post-thumbnail

inner class

내부 클래스(Inner Class)는 다른 클래스 내부에 선언된 클래스로서, 자신을 감싸고 있는 외부 클래스의 멤버에 접근할 수 있다. 내부 클래스는 코드를 논리적으로 그룹화하고 캡슐화하여 코드의 가독성을 높이고, 외부 클래스와 강한 결합을 형성할 수 있다.

1. 인스턴스 내부 클래스(Instance Inner Class):

  • 외부 클래스의 인스턴스가 생성된 후에 내부 클래스의 인스턴스를 생성할 수 있다.
  • 내부 클래스에서는 외부 클래스의 인스턴스 멤버와 정적(static) 멤버에 접근할 수 있다.
class OuterClass {
    private int outerVar;

    class InnerClass {
        private int innerVar;

        public void display() {
            System.out.println("Outer Variable: " + outerVar);
            System.out.println("Inner Variable: " + innerVar);
        }
    }
}

public class Main {
    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        OuterClass.InnerClass inner = outer.new InnerClass();
        inner.display();
    }
}

2. 정적 내부 클래스(Static Nested Class):

  • 정적 내부 클래스는 외부 클래스의 인스턴스에 의존하지 않고 독립적으로 생성할 수 있다.
  • 외부 클래스의 정적(static) 멤버에만 접근할 수 있다.
class OuterClass {
    private static int outerVar;

    static class StaticInnerClass {
        private int innerVar;

        public void display() {
            System.out.println("Outer Variable: " + outerVar);
            System.out.println("Inner Variable: " + innerVar);
        }
    }
}

public class Main {
    public static void main(String[] args) {
        OuterClass.StaticInnerClass inner = new OuterClass.StaticInnerClass();
        inner.display();
    }
}

3. 지역 내부 클래스(Local Inner Class):

  • 메서드나 블록 내부에서만 사용할 수 있는 클래스.
  • 외부 메서드의 지역 변수에 접근할 수 있다. (단, 해당 변수는 final 또는 effectively final이어야 함)
class OuterClass {
    private int outerVar = 10;

    public void localInnerClassExample() {
        final int localVar = 20; // effectively final

        class LocalInnerClass {
            public void display() {
                System.out.println("Outer Variable: " + outerVar);
                System.out.println("Local Variable: " + localVar);
            }
        }

        LocalInnerClass localInner = new LocalInnerClass();
        localInner.display();
    }
}

public class Main {
    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        outer.localInnerClassExample();
    }
}

4. 익명 내부 클래스(Anonymous Inner Class):

  • 이름이 없는 내부 클래스로, 주로 인터페이스나 추상 클래스의 객체를 생성할 때 사용.
  • 클래스 정의와 동시에 인스턴스를 생성.
interface Greeting {
    void greet();
}

public class Main {
    public static void main(String[] args) {
        Greeting anonymousGreeting = new Greeting() {
            @Override
            public void greet() {
                System.out.println("Hello from Anonymous Inner Class!");
            }
        };

        anonymousGreeting.greet();
    }
}

thread

쓰레드(Thread)는 프로그램의 실행 흐름을 나타내는 작은 단위로, 독립적으로 실행될 수 있는 하나의 작업 단위를 말한다. 자바에서 쓰레드를 사용하면 여러 작업을 동시에 수행하거나 특정 작업을 비동기적으로 처리할 수 있다.

쓰레드의 기본 구조:

  1. 쓰레드 생성 방법:

    • 자바에서는 Thread 클래스를 상속받거나 Runnable 인터페이스를 구현하여 쓰레드를 생성할 수 있다.
  2. 쓰레드 시작:

    • start() 메서드를 호출하여 쓰레드를 시작합니다. start() 메서드는 내부적으로 run() 메서드를 호출하며, 쓰레드의 실행 흐름을 시작한다.
  3. 쓰레드 실행 흐름:

    • run() 메서드 내부에는 쓰레드가 수행할 작업을 정의한다. run() 메서드의 실행이 끝나면 쓰레드는 종료된다.

쓰레드 생성 및 실행 예제:

class MyThread extends Thread {
    public void run() {
        for (int i = 1; i <= 5; i++) {
          System.out.println(Thread.currentThread().getId() + " - Value " + i);
        }
    }
}

public class ThreadExample {
    public static void main(String[] args) {
        MyThread thread1 = new MyThread();
        MyThread thread2 = new MyThread();

        // 각각의 쓰레드 시작
        thread1.start();
        thread2.start();
    }
}

Runnable 인터페이스를 사용한 쓰레드:

class MyRunnable implements Runnable {
    public void run() {
        for (int i = 1; i <= 5; i++) {
          System.out.println(Thread.currentThread().getId() + " - Value " + i);
        }
    }
}

public class RunnableExample {
    public static void main(String[] args) {
        Thread thread1 = new Thread(new MyRunnable());
        Thread thread2 = new Thread(new MyRunnable());

        // 각각의 쓰레드 시작
        thread1.start();
        thread2.start();
    }
}

쓰레드의 상태(State):

쓰레드는 실행 전, 실행 중, 대기 중, 종료 등 여러 상태를 가진다. Thread 클래스에서는 getState() 메서드를 통해 쓰레드의 상태를 확인할 수 있다.

쓰레드 동기화(Synchronization):

여러 쓰레드가 공유 자원을 사용할 때 데이터의 불일치 등 문제가 발생할 수 있다. 동기화는 이러한 문제를 해결하기 위해 쓰레드 간에 작업의 순서를 조절하고 데이터의 일관성을 유지하는 메커니즘을 말한다.

class Counter {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public int getCount() {
        return count;
    
}

쓰레드 풀(Thread Pool):

쓰레드 풀은 쓰레드를 효율적으로 관리하고 재사용하는 메커니즘. 자바에서는 ExecutorService 인터페이스와 Executors 클래스를 사용하여 쓰레드 풀을 구현할 수 있다.

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolExample {
    public static void main(String[] args) {
        // 쓰레드 풀 생성
        ExecutorService executorService = Executors.newFixedThreadPool(2);

        // 작업 제출
        executorService.submit(new MyRunnable());
        executorService.submit(new MyRunnable());

        // 쓰레드 풀 종료
        executorService.shutdown();
    }
}

쓰레드 그룹(Thread Group):

쓰레드 그룹은 관련된 쓰레드를 묶어서 관리하는데 사용.
ThreadGroup 클래스를 통해 쓰레드 그룹을 생성하고 관리할 수 있다.

class MyThread extends Thread {
    public MyThread(ThreadGroup group, String name) {
        super(group, name);
    }

    public void run() {
        System.out.println(Thread.currentThread().getId() + " - Running");
    }
}

public class ThreadGroupExample {
    public static void main(String[] args) {
        // 쓰레드 그룹 생성
        ThreadGroup group = new ThreadGroup("MyThreadGroup");

        // 쓰레드 생성 및 그룹에 추가
        MyThread thread1 = new MyThread(group, "Thread1");
        MyThread thread2 = new MyThread(group, "Thread2");

        // 쓰레드 시작
        thread1.start();
        thread2.start();

        // 쓰레드 그룹 정보 출력
        group.list();
    }
}

InterruptedException 처리:

InterruptedException은 쓰레드가 sleep, wait, join 등에서 대기 상태에 있을 때 다른 쓰레드에 의해 interrupt가 발생하면 발생하는 예외.
이를 처리하여 안전하게 쓰레드를 종료하거나 예외 상황을 처리할 수 있다.

class MyRunnable implements Runnable {
    public void run() {
        try {
            // 작업 수행
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            // InterruptedException 처리
       System.out.println(Thread.currentThread().getName() + " - Interrupted");
        }
    }
}

lambda

람다 표현식(Lambda Expression)은 자바 8부터 도입된 기능으로, 간결하게 익명 함수를 나타내는 방법. 주로 함수형 프로그래밍을 지원하며, 코드를 간결하게 작성할 수 있도록 도와준다.

람다 표현식의 기본 구조:

람다 표현식은 매개변수 리스트, 화살표(->), 그리고 메서드 본문으로 구성.

(parameters) -> expression

또는

(parameters) -> { statements; }

람다 표현식의 예제:

// 기존의 익명 클래스를 사용한 ActionListener
button.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        System.out.println("Button Clicked!");
    }
});

// 람다 표현식으로 변환
button.addActionListener(e -> System.out.println("Button Clicked!"));

람다 표현식의 특징:

  1. 간결성: 불필요한 코드를 제거하고 간결하게 표현.

  2. 익명 클래스 대체: 람다 표현식을 사용하면 익명 클래스를 효과적으로 대체.

  3. 함수형 인터페이스: 람다 표현식은 함수형 인터페이스에서만 사용. 함수형 인터페이스는 하나의 추상 메서드만을 가진 인터페이스.

함수형 인터페이스(Functional Interface):

람다 표현식은 함수형 인터페이스에서만 사용. 함수형 인터페이스는 하나의 추상 메서드만을 가진 인터페이스로서 @FunctionalInterface 어노테이션을 사용하여 선언.

@FunctionalInterface
interface MyFunctionalInterface {
    void myMethod();
}

public class LambdaExample {
    public static void main(String[] args) {
        // 람다 표현식으로 함수형 인터페이스 구현
        MyFunctionalInterface myFunc = () -> System.out.println("My Method");
        myFunc.myMethod();
    }
}

람다 표현식의 활용:

  1. 컬렉션의 반복 처리:
List<String> names = Arrays.asList("Alice", "Bob", "Charlie");
names.forEach(name -> System.out.println(name));
  1. 스레드 생성:
new Thread(() -> System.out.println("Thread is running")).start();
  1. GUI 이벤트 처리:
button.addActionListener(e -> System.out.println("Button Clicked!"));
  1. 함수형 인터페이스를 매개변수로 받는 메서드 호출:
public void performOperation(MyFunctionalInterface operation) {
    operation.myMethod();
}

performOperation(() -> System.out.println("Custom Operation"));
profile
새로운 시작. 그리고 도약

0개의 댓글