KDT 공부 일지 - 2026.01.09

김시코·2026년 1월 9일

KDT 공부 일지

목록 보기
4/27

2026년 1월 7일 수요일


코드를 분리하고 싶을때 가장 먼저 고려할 것은 메서드.


메서드 기본 문법과 활용

Return Type

리턴 타입: 가지고 돌아갈 값의 타입을 정하는 것.
return : 값을 반환하고 탈출하는것.
리턴타입의 종류로는 8가지의 기본타입, 배열[], String, void 등이 있으며, 심지어는 클래스 이름도 들어갈 수 있다. (자기자신을 리턴)

  • 기본타입: 타입에 맞는 값을 리턴함. ex) int는 정수형을 리턴값으로 반환
  • 배열[]: 배열이 저장된 메모리의 주소를 반환
  • String: 문자열이 저장된 메모리의 주소를 반환
  • void: 리턴값이 존재하지 않다는 뜻.
  • void가 아닌 리턴타입을 가지는 메서드는 마지막에 꼭 return을 해야 함 (안쓰면 문법오류)
  • 리턴값에는 null, this, 인스턴스 생성문(new 클래스명()) 등이 들어갈 수 있다.

API 개념

API: 프로그램을 만들 때 사용할 수 있도록 미리 만들어 놓은 클래스와 메서드(기능)들의 묶음이다. Java에서 제공하는것 뿐만이 아니라, 직접 작성한 메서드 중 Public으로 풀려있는것이 API가 된다.

  • System.out.println(); : System클래스에 있는 out 필드가 참조하는 객체의 메소드 println을 호출
  • Scanner scanner = new Scanner(System.in); : Scanner 이라는 이름을 가지는 클래스가 있는것. new 키워드로 인스턴스를 생성하고 아규먼트로 System.in을 준다. 그후 Scanner 타입 참조변수 scanner에 인스턴스의 주소를 대입 그렇기 때문에 Scanner라는 문법은 없는것
  • scanner.nextLine(); : scanner가 참조하고 Scanner 인스턴스에 있는 메서드 nextLint을 호출.

매개변수의 일반화, 구체화

  • 메서드의 매개변수: 기능의 일반화를 위해 필요한 것
    일반화: 하나의 고정된 값이 아니라, 여러 값을 받아 처리할 수 있도록 만드는 것
    구체화: 실제 사용할 값을 넣어서 사용의 가능성을 제한는 것. (매개변수가 아닌 상수가 들어가면 구체화)

메서드 오버로딩

  • 메서드 오버로딩 : 같은 이름을 가지는 메서드를 여러개 만드는 것이다. 이때, 멤버변수는 타입이 다르거나, 변수의 개수가 달라야 한다. 이렇게 만들어지는 메서드는 이름만 같고, 아예 다른 메서드다. (실제 컴파일하면 이름을 바꿔서 저장한다고 함
  • 재귀 : 트리 구조의 데이터를 활용할때 사용한다. 잘 읽어보고 작동원리 이해하기. (읽어보면 그대로라고 함)

[P1]
public class P1 {
    public static void main(String[] args) {
        // 메서드
        SumCalculator sumCalculator = new SumCalculator();
        // 변수명은 보통 클래스의 이름을 그대로 쓴다. 단, 첫 문자를 소문자로
        int result = sumCalculator.calculate(10, 20);
        	// sumCalculator.calculate() 메서드에서 받아온 리턴값을
          		// int 변수 result에 넣는다.
			// 즉, int reult = 55; 가 됨. 메서드 안 for문의 연산결과가 55

        System.out.println(result);         // 리턴 값 활용

        sumCalculator.checkValue(30, 10);
        System.out.println(sumCalculator.calculate(50, 100));
        	// 문법적으로 문제 없음. 이럴때는 보통 괄호 안이 먼저 실행 되니까.
        
        System.out.println(sumCalculator.calculate(100));
        	// 메소드 오버로딩. 매개변수가 1개인 메서드 실행
        
        sumCalculator.process(5);
    }
}

class SumCalculator {
    // 리턴: 내 역할은 어디까지인가
    // 매개 변수: 일반화 => 여러 상황에 대응되는 코드
    int calculate(int start, int end) {
        // 메서드 안에서 메서드 호출 가능
        if(!checkValue(start, end)) {
        	// 정확한 문법은 this.checkValue
            return -1;      // -1은 보통 에러를 뜻한다. (관례)
        }

        int sum = 0;
        for(int i = start; i <= end; i++) {
            sum += i;
        }
	      // 여기에 출력문이 있으면 계산 뿐만 아니라 출력도 하고있기 때문에,
	      // 하나의 매서드는 하나의 역할만 해야 한다는 SRP원칙에 위배됨.
    	  // 이름에 기능을 다 명시하면 해결이 되긴 한다고 함.
          // 아니면 역할을 잘라서 다른 함수로 넘기거나.
        return sum;
    }

    // 메서드 오버로딩: 이름만 같고 아예 다른 메서드
    int calculate(int end) {
        return calculate(0, end);
    }

    // 재귀: 트리 구조의 데이터를 활용할때 사용.
    void process(int value) {
        System.out.println("재귀 앞: " + value);
        if(value >= 10) {
            return;
        }
        process(++value);
        System.out.println("재귀 코드 뒤: " + value);
    }

    boolean checkValue(int start, int end) {
        if(start < 0 || end < 0 || start > end) {     // 예외처리
        return false;
        }

        return true;
          // if문을 실행하지 않을 경우의 return값이 필요.
          // 일단 그냥 true로 주면 됨.
    }
 }

객체지향 프로그래밍 기초

static, final, 접근제한자

[static]
static은 시작부터 존재하기 때문에 인스턴스 생성과 관계가 없다. 그렇기 때문에 this 또한 사용 할 수 없다.
System.out.println("Hello World"); - System = 클래스, . = 접근 연산자, out = static 참조 변수, . = 접근 연산자, println() = 메서드 호출, "Hello World" = String 타입 아규먼트를 System클래스 내부의 println 메서드의 매개변수에 전달한다.
『println 메서드는 다양한 타입의 출럭을 위해 메서드 오버로딩을 잔뜩 해놔서 다양한 타입에 대응이 된다. 이때, 매개변수가 2개 이상인 경우의 메서드가 없기 때문에 아규먼트는 항상 한개여야 한다. 또한, 우리가 println을 사용하기 위해서 System 클래스의 인스턴스를 생성한 적이 없기 때문에 static의 개념을 알고나서 System.out.println();을 봤을때 정확히는 몰라도 static이 사용 되었을 것이라는 것을 예측할 수 있다.』

[P3] - static 예시
public class P3 {
    public static void main(String[] args) {
        // static
        SomeData1 ref1 = new SomeData1();
        SomeData1 ref2 = new SomeData1();

        SomeData1.c = 30;
        System.out.println(SomeData1.c);	// 값을 넣고 바로 출력 가능

        SomeData1.test2();	// static이라 인스턴스와 상관없이 실행가능

        ref1.a = 10;
        ref2.a = 20;
        System.out.println(ref1.a);
        System.out.println(ref2.a);
    }
}

// static 장점(?) - 글로벌 함. 아무런 제약 없이 어디서든 다이렉트로 쓸수 있다
class SomeData1 {
    // 3개 다 멤버 변수
    int a;      // 인스턴스 변수
    int b;      // 인스턴스 변수
    static int c = 50;
	// 클래스 변수(static) - 인스턴스 생성과 관계 없음. 시작부터 존재
		// 이렇게 쓰면 메모리 관리를 하지 않는거지만,
    	// 일반적으로 static은 일반 변수랑 섞이지 않아서 괜찮다.
    
    void test1() {
        System.out.println("test1 실행");
    }

    static void test2() {
        System.out.println("test2 실행");
    }
}

[final]
문법적으로 컴파일을 제한 시킴 (문법적으로 더 나쁘게 만듬) - 변수를 상수로 만드는 것.
더 이상 값을 변경하지 못하게 만드는 것이며, 개발자의 실수를 막기 위해 사용한다. 어떠한 작업에 있어, 절대로 값이 바뀌면 안되는 값(예를들면 ip주소같은 값)을 바꾸지 못하게 하는 경우에 쓰인다. 사실상 매개변수들도 값이 바뀌면 안되기 때문에 final이 붙어야 하지만 문법이 귀찮아져서 잘 쓰이지 않는다.

  • 변수: 프로그램 동작 중에 주기적으로 변하는 값
  • 상수: 프로그램 동작 중에 한번 초기화 되면 절대로 바뀌지 않는 값.

[접근 제한자]

  • public: 누구에게나 공개. (제한자 작성하지 않으면 기본으로 public)
  • private: 비공개. 클래스 내부에서만 쓸수 있음
  • protected, default는 거의 사용하지 않기 때문에 넘김

[키워드 정리]

  • 소속 지정자 : static
  • 변경 제한자 : final
  • 접근 제한자 : public / private / protected / default

setter, getter

  • setter 메서드 : write 권한을 주는것이기 때문에 위험. 리턴타입은 void. 진정한 의미의 기능은 아니다. (로직X. 문법적 메서드) setter만 주는건 입력만 가능하고 출력이 안됨. 그래서 보통 getter를 함꼐 쓴다
  • getter 메서드 : read 권한을 주는것, write는 불가. 리턴타입이 void가 아닌 다른것이 와야 하며(값을 전달하는것이기 때문), setter에 비해 비교적 안정적이다.
  • setter, getter는 정해진 코드가 있기 때문에 그냥 형식대로 쓰면 된다.

[P5]
public class P5 {
    public static void main(String[] args) {
        // 접근 제한자(중요): public. private
        // 캡슐화, 정보은닉

        SomeData3 aaa = new SomeData3();
        aaa.a = 30;
    //  aaa.b = 40; 오류인 이유: 아래 클래스의 변수 b가 private기 때문에.
    }
}

class SomeData3 {
    public int a;
    private int b;

    SomeData3() {	// 여기도 private 쓸순 있지만, 그럼 인스턴스 생성이 안됨.

    }
    

    public void test1() {
        this.b = 10;	// 여기는 b가 선언된 클래스 내부이기 때문에 사용가능
        this.test2();	// private는 내부에서만 사용 가능한거니까.
    }

    private void test2() {
        this.b = 20;
        System.out.println(b);
    }
}

[P6]
public class P6 {
    public static void main(String[] args) {
        // 정보 은닉(캡슐화) - private
        Account aaa = new Account("민수");
        Account bbb = new Account("철수");

        aaa.deposite(3000);
        bbb.deposite(5000);

        System.out.println(aaa.getName() + "님의 잔고: " + aaa.getBalance());

        int qqqq = aaa.getBalance();
        qqqq -= 100000;
        	// 이거는 값을 복사해서 바꾸는거라 원래의 값에는 영향이 없다.
        System.out.println(qqqq);
    }
}

class Account {
    private String name;
    	// 절대 꼭 private여야 함. 남들이 손을 대면 안되기 때문에 (정보은닉)
    private int balance = 0;

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

    // 입금
    public void deposite(int value) {
        if(checkBigMoney(value)) {
            return;
        }
        balance += value;
    }

    private boolean checkBigMoney(int value) {
    	// private 이유: 내부에서 작동하는 코드라서, 외부에서 알 필요가 없다.
        if(value > 100000000) {
            System.out.println("돈의 출처를 취조하는 코드");
            return true;
        }
        return false;
    }

    // 출금
    public void withdraw(int value) {
        if(value > balance) {
            System.out.println("오류: 잔액이 부족합니다.");
            return;
        }
        balance -= value;
    }

    // read 권한을 주겠다. name의 값을 주는거.
    public String getName() {
        return name;
    }

    public int getBalance() {
        return balance;
    }
}

DTO - Data Transfer Object

DTO: 코드를 짤때 우선으로 작성하는 것이다. 기능 구현이 목적이 아닌 데이터를 묶어서 전달하는 것이 목적이다. 여기에서 많은 인스턴스가 생성되기 때문에 데이터 선언의 기준이 되며, 필드는 무조건 prvate로 선언하고 getter, setter로 데이터를 다뤄야 한다.
앞으로 DTO 클래스를 만들때는 클래스이름 뒤에 DTO를 붙여서 DTO임을 알기 쉽게 한다.


[P7] - setter, getter
public class P7 {
    public static void main(String[] args) {
        // setter, getter
        Student s1 = new Student();
        s1.setName("민수");     // s1,name = "민수" 와 의미가 같음
    }
}

// DTO
class Student {
    private String name;
    private int age;
    private int score;      // 이 3개에 대한 setter, getter가 있어야 한다.

    // setter
    public void setName(String name) {
        this.name = name;
    }

    // getter
    public String getName() {
        return name;        // 정해져 있는 것
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    public void setScore(int score) {
        this.score = score;
    }

    public int getscore() {
        return score;
    }
}

Component

  • 컴포넌트: 기능 클래스(로직이 중요) 일반적으로는 여러 인스턴스가 생성될 일은 없음. 하나의 인스턴스를 생성해서 여러번 재사용 하는것

디자인 패턴

  • 싱글톤 패턴(Singleton Pattern): 인스턴스를 한번만 생성시키기 위한 디자인 패턴
[P7]
public class P8 {
    public static void main(String[] args) {
        
    }
}

// 컴포넌트
class SomeComponent {
    public void test1() {       // API가 됨
        // 중요한 로직...!
        test2();
    }

    private void test2() {
        // 중요한 로직...!
    }

    // 싱글톤 패턴(디자인 패턴의 한 종류)
    private SomeComponent() {   // 생성자
        // 필요에 따라서는 초기화
    }

/*  private static SomeComponent instance = null;

    public static SomeComponent getInstance() {
      // SomeComponent 리턴타입을 가지는 getIntance 메서드
        if(instance == null) {
            instance = new SomeComponent();
        }
        return instance;
    } */    // 이건 옛날 방식의 싱글톤

    private static final SomeComponent instance = new SomeComponent();

    public static SomeComponent getInstance() {
        return instance;
    }       // 그나마 요즘의 싱글톤 패턴
}

[기초정리] - 완벽하게 잡고 가야 하는 것

  1. 클래스 선언하는 문법
  2. 멤버 변수 선언 - 인스턴스 생성 및 접근 (.), 스택 - 힙 (this) 중요
  3. 생성자 - 메서드랑 문법이 약간 다르지만 인스턴스가 생성시 자동(직접호출 불가)으로 실행되는 "메서드"라고 생각 해도 됨 (좀 틀린부분이 있긴 하지만)
  4. 메서드 기초 - 리턴타입, 호출 문법, 매개변수

profile
취업하고싶다...

0개의 댓글