개발 일기

250910 자바 본문

TIL

250910 자바

종현종현 2025. 9. 10. 19:12

printStream.println()이 아닌 System.out.println()으로 사용하는 이유는?

이유는 개발자 편의성 때문이라고 하셨다.

실제로 System.out.println()은 printStream.println()을 호출한다.

out 이라는 static final 변수가 PrintStream 객체를 참조하고 있기 때문이다.

장점은 한 줄로 어디서든 호출가능하다는 것이다. 그래서 개발자 편의성 때문인 것 같다.

 

자바의 static

자바의 static이라는 키워드를 사용해 static 변수와 static 메소드를 만들 수 있다. 

static 키워드를 통해 생성된 정적멤버들은 Heap 영역이 아닌 Static 영역에 할당된다. Statiic에 할당된 메모리는 모든 객체가 공유하여 하나의 멤버를 어디서든지 참조할 수 있는 장점을 가지지만 GC의 관리 영역 밖에 존재하기에 Static 영역에 있는 멤버들은 프로그램의 종료시까지 메모리가 할당된 채로 존재하게 된다. 그렇기에 static을 너무 남발하면 안된다.

 

 

static 변수

// static 사용 전
public class Test {

	public static void main(String[] args) {
    	A a1 = new A();
        a1.i++;
        A a2 = new A();
        a2.i++;
        
        System.out.println(a1.i); // 11
        System.out.println(a2.i); // 11
	}
}

class A {
	int i = 10;
}

// static 사용 후
public class Test {

	public static void main(String[] args) {
    	A a1 = new A();
        a1.i++;
        A a2 = new A();
        a2.i++;
        
        System.out.println(a1.i); // 11
        System.out.println(a2.i); // 12
        
        // 생성자를 호출하지 않고 static에 접근
        System.out.println(A.i); // 12
	}
}

class A {
	static int i = 10;
}

 

static 메서드

// static 메서드가 없는 경우
public class Test {
    public static void main(String[] args) {
        A a1 = new A();
        a1.print();  // 객체를 만들어야만 호출 가능
        
        A a2 = new A();
        a2.print();
    }
}

class A {
    int i = 10; // 인스턴스 변수
    
    void print() { // 인스턴스 메서드
        System.out.println("i = " + i);
    }
}

// static 메서드 있는 경우
public class Test {
    public static void main(String[] args) {
        A a1 = new A();
        a1.i++;
        
        // 객체 없이 클래스 이름으로 직접 호출 가능
        A.print();  
        
        A a2 = new A();
        a2.i++;
        
        A.print();  // 역시 클래스 이름으로 호출
    }
}

class A {
    static int i = 10; // 클래스 변수
    
    static void print() { // static 메서드
        System.out.println("i = " + i);
    }
}

 

싱글톤 패턴

 

싱글톤 패턴은 특정 클래스가 단 하나만의 인스턴스를 생성하고, 해당 인스턴스에 대한 전역적인 접근 지점을 제공하는 디자인 패턴이다. 메모리 절약과 같은 장점이 있지만, 코드의 의존성이 높아지고 테스트가 어려워지는 단점도 있어 신중하게 사용해야 한다.

public class Test {

	public static void main(String[] args) {
		A a1 = A.getInstance();
		A a2 = A.getInstance();
		
		System.out.println(a1 == a2);
	}

}

// 싱글톤 디자인 패턴
class A {
	private static A instance; // 1. 자신 타입의 변수를 선언
	static int i = 10; // 공유하는 데이터가 됨
	
	private A() { // 2. private 생성자
		
	}
	
	public static A getInstance() { // 3. 자신의 객체를 리턴하는 메소드
		if (instance == null) {
			instance = new A();
		}
		
		return instance;
	}
}

 

a1과 a2가 같은 주소를 가리키는 것을 볼 수 있다. 그래서 객체가 하나만 존재하도록 보장하고 new로 여러 번 만들 필요 없이 전역에서 같은 객체를 재사용할 수 있게 한다.

 

final

final은 불변성을 확보할 수 있도록 한다. 클래스나 변수, 메서드에 final을 붙이면 처음 정의된 상태가 변하지 않는 것을 보장한다.

 

final 변수

public class Test {
    public static void main(String[] args) {
        final int num = 10;   // 상수처럼 동작
        // num = 20; // 컴파일 에러 (값 변경 불가)
    }
}

 

final 메서드

class Parent {
    public final void printHello() {
        System.out.println("안녕");
    }
}

class Child extends Parent {
    // 오버라이딩 불가능
    // public void printHello() {
    //     System.out.println("자식 클래스에서 변경");
    // }
}

 

final 클래스

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

// 상속 불가
// class Dog extends Animal {}

 

상수를 만들기 위해 많이 쓰이는 데 그 키워드들은 public, final, static으로 이루어진다.

final은 관리자 클래스에 많이 쓰인다고 한다.

abstract

일반적인 클래스는 구체적으로 데이터를 담아 인스턴스화 하여 직접 다루는 클래스이다. 그 반대로 추상 클래스는 구체적이지 않은 추상적인 데이터를 담고 있는 클래스이다. 그래서 추상 클래스는 일반 클래스와 달리 인스턴스 화가 불가능한 클래스이며, 추상 클래스를 선언할 때는 abstract 키워드를 사용한다는 차이점이 있다.

 

추상 클래스는 많은 프레임워크에서 지금도 사용되고 있는 구현방식이라고 한다.

내 수준에서 이해를 해보자면 for문과 while문이 비슷한 것 같다. 반복 기능을 해주는 코드를 내가 원하는 대로 작성해서 마음껏 쓰기 때문에 이런 시스템이 있는 것 같다.

 

Interface와 자바로 메모장 만들기

Interface

자바에서 클래스는 단일 상속만 가능하다. 인터페이스는 다중 구현을 가능하게 해 단일 상속의 한계를 보완하는 프로그램 단위이다.

 

예를 들어,

여러 클래스가 비슷한 역할을 수행하지만 직접 상속 구조로 묶기는 어렵거나 불가능한 경우가 있다.

Bird, Person, Superman, Airplane 같은 서로 다른 계층 구조 클래스

이들 중에서 날 수 있는 클래스라는 공통 기능을 묶고 싶일 때 공통 행동을 정의하는 인터페이스를 만들면 클래스 계층과 관계 없이 구현 가능하다.

public interface Flyer {
	public void fly();
}

public class Bird extends Animal implements Flyer {
	
	public void eat() {
		System.out.println("벌레를 잡아 먹는다.");
	}
	
	public void fly() {
		System.out.println("날개를 펄럭이며 난다.");
	}
}

public class Superman extends Person implements Flyer {
	
	public void fly() {
		System.out.println("망토를 펄럭이며 난다...");
	}
	
	@Override
	public void eat() {
		super.eat();
		System.out.println("샌드위치도 좋아한다.");
	}
}

class Show {
	public static void airShow(Flyer f) {
		f.fly();
	}
}

public class Test {

	public static void main(String[] args) {
		
		Bird b = new Bird();
		Superman s = new Superman();
		
		Show.airShow(b);
		Show.airShow(s);
		
	}
}

// 결과
날개를 펄럭이며 난다.
망토를 펄럭이며 난다...

 

메모장 만들기

메모장을 만들기 위한 코드가 왜 이렇게 작성되었는 지 최대한 이해해보려고 했다.

 

import java.awt.*;

public class NotepadFrame extends Frame {
    
    public NotepadFrame(String title) {
        super(title);                 // Frame 클래스 생성자 호출해서 창 제목 설정
        setSize(500, 400);            // 창 크기 설정

 

Frame을 상속 윈도우 창을 만들 수 있다.

super(title)  -> 부모(Frame) 생성자를 호출 해 창 제목을 설정한다.

setSize(500, 400) 창의 크기 설정

 

        MenuBar mb = new MenuBar();
        Menu fileMenu = new Menu("File");
        Menu EditMenu = new Menu("Edit");
        MenuItem openItem = new MenuItem("open");
        MenuItem saveItem = new MenuItem("save");
        TextArea ta = new TextArea();

 

MenuBar, Menu, MenuItem -> GUI 메뉴 구성 요소

TextArea 여러 줄 입력 가능한 텍스트 영역

 

        setMenuBar(mb);
        mb.add(fileMenu);
        mb.add(EditMenu);
        fileMenu.add(openItem);
        fileMenu.add(saveItem);
        add(ta);

 

메뉴바를 프레임에 붙이고 메뉴와 메뉴 아이템을 추가한다.

add(ta) 텍스트 영역을 창에 추가한다.

 

	MyOpenHandler handler = new MyOpenHandler(this, ta);
        openItem.addActionListener(handler);

 

핸들러 객체를 생성하고 버튼, 메뉴 클릭 이벤트를 처리한다.

 

이 부분이 가장 어려웠다.

ActionListener는 인터페이스다. MyOpenHandler가 ActionListener를 구현한다. (implements)

인터페이스를 구현하면 actionPerformed라는 메서드를 강제로 만들어야 한다. 이는 GUI 인벤트와 연결가능하다.

 

public class MyOpenHandler implements ActionListener {
    Frame frame;
    FileDialog openDialog;
    TextArea ta;
    
    public MyOpenHandler(Frame frame, TextArea ta) {
        this.frame = frame;
        this.ta = ta;
        openDialog = new FileDialog(frame, "open", FileDialog.LOAD);
    }

 

생성자에서 Frame과 TextArea를 받아서 핸들러가 UI와 연결된다.

FileDialog의 생성자로 파일 열기 창 준비를 한다. 3번째 인자가 int값을 받는데 상수로 LOAD 상태를 의미한다.

 

@Override
    public void actionPerformed(ActionEvent e) {
        try {
            openDialog.setVisible(true); // 파일 다이얼로그 열기
            
            String filePath = openDialog.getDirectory() + openDialog.getFile();
            FileReader fr = new FileReader(filePath);
            BufferedReader br = new BufferedReader(fr);
            StringBuilder sb = new StringBuilder();
            
            String oneLine = "";
            while ((oneLine = br.readLine()) != null) {
                sb.append(oneLine).append("\n");
            }
            
            ta.setText("");                  // 기존 텍스트 초기화
            ta.append(sb.toString());        // 파일 내용 추가
            
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

 

위 코드는 메뉴 클릭시 실행되는 핸들러 동작이다.

파일을 읽는 과정은 FileDialog -> FileReader -> BufferedReader -> TextArea에 출력된다.

StringBuilder는 문자열을 반복해서 합칠 때 + 보다 성능이 좋다고 한다. (다음 시간에 다룬다고 함)

 

import com.rjh.proj1.ui.NotepadFrame;

public class Main {
    public static void main(String[] args) {
        NotepadFrame f = new NotepadFrame("나의 메모장");
        f.setVisible(true);
    }
}

 

Frame을 상속해서 만든 NotepadFrame을 만들어 창을 띄운다.

setVisible을 true로 바꾸지 않으면 창이 보이지 않는다.

 

느낀 점

오늘은 자바의 static, final, abstract에 대해 배웠다. 이에 연계된 싱글톤 패턴, interface 등을 배우고 이를 활용한 메모장을 직접 만드는 실습을 했다.

 

어떤 느낌인지는 이해를 했지만 완벽한 이해는 아니었다. 그래서 각각의 코드 자체는 이해가 됐지만 왜 이런식으로 코드가 짜여지는 지에 대한 이해가 많이 부족했다. 그래서 배웠던 개념과 연결해서 이해해보려고 했다.

그냥 코더가 되지 않기 위해 코드 작성보다 왜 이렇게 작성하는 지에 대한 고민을 더 해야겠다.

'TIL' 카테고리의 다른 글

20250915 정렬 알고리즘  (0) 2025.09.15
250911 자바 (StringBuilder, 람다식, I/O, Thread)  (0) 2025.09.11
20250909 자바 및 과제  (0) 2025.09.09
20250908 OOP 3대 concept  (1) 2025.09.08
20250907 자바스크립트 V8 엔진  (0) 2025.09.07
Comments