5회차. 클래스

KIMA·2023년 1월 21일
0
post-thumbnail

목표

자바의 Class에 대해 학습하기

학습할 것

클래스와 객체

클래스와 객체의 관계는 붕어빵 틀과 슈크림/팥 붕어빵의 관계와 같다.

  • 클래스 : 객체의 설계도
  • 객체 : 클래스를 바탕으로 만들어진 것, 사물과 같은 유형적인 것과 개념이나 논리와 같은 무형적인 것
    • 예) 책상, 프로그램 에러 등

클래스 정의하는 방법

  1. 소스파일을 생성한다.
    클래스명.java

    • 명명 규칙
      • 첫 번째 글자에 숫자 ❌
      • $, _외의 특수문자 ❌
      • 자바 키워드 ❌
        • 예) String, for
      • PascalCase로 적자
        • 예) EarPhone
  2. 클래스를 선언한다.

    public class Tv {
      // 필드
      private String color;
      private boolean power;
      private int channel;
    
      // 생성자
      public Tv(String Color) {
        this.color = color;
      }
    
      // 메소드
      public void power() { power = !power; }
      public void channelUp() { channel++; }
      public void channelDown() { channel--; }
      public void setColor(String Color) { this.color = color; }
    }
  • 필드 : 클래스의 속성
    • 보통 외부에 노출시키지 않으며, 외부에서 메소드를 통해 해당 변수에 접근하도록 한다.
      • 예) 위의 예시에서 powerprivate으로 설정해 외부에서 접근하지 못하도록 막았다. `
        • 그대신 외부에선 power()를 통해 power를 변경해줄 수 있다.
  • 메소드 : 클래스의 기능
  • 생성자 : 필드의 값을 초기화해준다.
  • 하나의 소스파일에 다수의 클래스를 정의할 수 있으나, public 키워드가 붙은 클래스는 단 하나만 존재해야하며 이 클래스는 소스 파일 이름과 동일한 이름을 가져야 한다.
    • 되도록 하나의 파일에는 하나의 클래스만 정의하자.

객체를 만드는 방법 (new 키워드)

클래스명 변수명 = new 클래스명();
  • new 키워드를 통해 클래스 정의를 바탕으로 객체를 생성한다.
    • 이러한 과정을 인스턴스화라고 하며, 이때 생성된 객체를 인스턴스라고 부른다.
  • 생성된 객체는 힙 메모리에 저장되며, 해당 객체의 메모리 주소가 변수에 저장된다.
  • 객체를 생성하면서, 객체 생성자를 호출한다.
    • 생성자에서 필드 초기화를 수행한다.

메소드 정의하는 방법

[접근 제어자] [반환 자료형] [메소드명] ([매개변수]) { ... }

접근 제어자

: 클래스, 멤버변수, 메서드 그리고 생성자에 사용되어, 외부에서 접근하지 못하도록 제한하는 역할을 한다.

  • 종류(접근할 수 있는 범위에 따라 나뉨)

    public > protected > (default) > private

    • private : 같은 클래스 내
      • 클래스의 내부에 선언된 데이터를 외부로부터 보호하기 위해 사용된다.
        • 예) 비밀번호
      • 클래스의 외부가 아닌 내부에서만 사용될 때 사용된다.
        • 예) 카운터
      • 이 둘은 객체지향 개념에서 은닉화(information hiding)로 불린다.
      • 객체 생성자 호출을 막기 위해 생성자에 붙이기도 한다.
    • default : 같은 패키지 내
      • 따로 접근 제어자를 명시하지 않으면 default가 적용된다.
    • protected : 같은 패키지 내 그리고 다른 패키지의 자손 클래스 내
    • public : 모든 곳
  • 사용가능한 접근 제어자

    대상접근 제어자
    클래스public, (default)
    메소드public, protected, (default), private
    멤버 변수public, protected, (default), private
    지역 변수없음

반환 자료형

: 사용자는 해당 메소드를 실행한 후 어떤 자료형의 값을 반환받는지 확인할 수 있다.

  • return 키워드를 사용해서 반환하는 값의 자료형이 메소드의 반환 자료형과 일치해야 한다.

메소드명 컨벤션

  • CamelCase로 적자.
  • 동사 형태로 적자.
  • 예) setColor()

매개변수

: 메소드 안에서 필요한 값들을 메소드 외부로부터 전달받을 수 있다.

생성자 정의하는 방법

class 클래스명 {
  클래스명() { ... } // 기본 생성자
}

: 클래스명과 동일한 이름의 메소드를 선언한다.

  • 생성자는 객체를 생성할 때 필드 초기화 목적으로 호출된다.
  • 생성자는 매개변수 개수와 종류를 달리하여 여러개 선언할 수 있다.
    • 이를 생성자 오버로딩이라 불린다.
  • 반환이 따로 존재하지 않는다.
  • 매개변수가 없는 생성자를 기본 생성자라하며, 자동으로 생성해준다.
    • 매개변수가 존재하는 생성자만 있을 경우, 자동으로 생성해주지 않으니 조심하자.
    • 자손 클래스에서 부모 클래스의 기본 생성자를 자동으로 호출해주는데 위의 상황에서 문제가 발생하므로, 기본 생성자는 직접 생성해주는 것이 좋다.

this 키워드

: 객체 자기자신을 의미한다.

  • this.필드 사용
    : 객체의 필드라는 것을 강조하기 위해 쓰인다.

    class Car {
      private String color;
    
      Car(String color) {
        this.color = color;
      }
    }
    • 생성자 안의 블록에서 color 변수를 사용한다면 가장 가까운 스코프인 매개변수의 color가 호출이 된다.
    • 따라서, 객체 필드로서의 color를 사용하고 싶다면 this키워드를 사용하자.
  • 생성자안에서 this() 사용
    : 자신이 속한 클래스의 다른 생성자를 호출하기 위해 사용한다.

    class Car {
      private String color;
      
      Car() {
        this("black");
      }
      
      Car(String color) {
        this.color = color;
      }
    }
    • 생성자 블록의 최상단에서만 사용가능하다.
  • 객체 자신으로서의 this 사용
    : 객체의 참조값을 전달하기 위해 사용한다.

    // in StringBuilder class
    @Override
    public StringBuilder append(String str) {
      super.append(str);
      return this;
    }
    
    // in Main class
    StringBuilder stringBuilder = new StringBuilder();
    builder.append("A").append("B");
    • 메소드 체이닝을 위해 객체의 참조값을 this 키워드로 반환하고 있다.

과제

이진 트리란

: 자식 노드 수가 두 개 이하인 트리

  • 분류

    • 완전 이진 트리(complete binary tree) : 왼쪽에서부터 채워져 있는 이진 트리
    • 정이진 트리(full binary tree) : 자식 노드가 0 또는 2개인 이진 트리
    • 포화 이진 트리(perfect binary tree) : 모든 노드가 꽉 차 있는 이진 트리
    • 변질 이진 트리(degenerated binary tree) : 모든 노드의 자식 노드가 하나밖에 없는 이진 트리
    • 균형 이진 트리(balanced binary tree) : 왼쪽과 오른쪽 노드의 높이 차이가 1이하인 이진 트리

💡 트리란?
: 순환 구조가 없는 그래프

  • 트리 구조로 배열된 일종의 계층적 데이터의 집합이다.
  • 임의의 두 노드 사이의 경로는 유일무이하게 존재한다.
  • 구성
    • 루트 노드 : 가장 위에 있는 노드
    • 리프 노드 : 자식 노드가 없는 노드
    • 내부 노드 : 루트 노드와 리프 노드 사이에 있는 노드
  • 깊이와 높이
    • 깊이(= 레벨) : 루트 노드부터 특정 노드까지 최단 거리로 갔을 때의 거리
    • 높이 : 루트 노드부터 리프 노드까지의 거리 중 가장 긴 거리

int 값을 가지고 있는 이진 트리를 나타내는 Node 클래스 정의

🧐 요구사항

  • int value, Node left, Node right 필드를 가져야함
public class Node {
    private Node left;
    private Node right;
    private int value;

    public Node(Node left, Node right, int value) {
        this.left = left;
        this.right = right;
        this.value = value;
    }

    public Node getLeft() {
        return left;
    }

    public void setLeft(Node left) {
        this.left = left;
    }

    public Node getRight() {
        return right;
    }

    public void setRight(Node right) {
        this.right = right;
    }

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }
}

BinaryTree라는 클래스 정의

🧐 요구사항

  • 주어진 노드를 기준으로 출력하는 bfs(Node node)dfs(Node node) 메소드 구현
    • DFS는 왼쪽, 루트, 오른쪽 순으로 순회
  • BinaryTree 구현

    import java.util.LinkedList;
    import java.util.Objects;
    import java.util.Queue;
    
    public final class BinaryTree {
    
        private BinaryTree() {
        }
    
        public static void bfs(Node root) {
            Queue<Node> queue = new LinkedList<>();
            queue.offer(root);
            while (!queue.isEmpty()) {
                Node node = queue.poll();
                System.out.print(node.getValue() + " ");
                if (!Objects.isNull(node.getLeft())) {
                    queue.add(node.getLeft());
                }
                if (!Objects.isNull(node.getRight())) {
                    queue.add(node.getRight());
                }
            }
            System.out.println();
        }
    
        public static void dfs(Node root) {
            if (Objects.isNull(root)) return;
    
            dfs(root.getLeft());
            System.out.print(root.getValue() + " ");
            dfs(root.getRight());
        }
    }
  • BinaryTree 테스트

    import org.junit.jupiter.api.BeforeEach;
    import org.junit.jupiter.api.DisplayName;
    import org.junit.jupiter.api.Test;
    
    class BinaryTreeTest {
        private static Node root;
    
        @BeforeEach
        void setUp() {
            Node node10 = new Node(null, null, 10);
            Node node9 = new Node(null, null, 9);
            Node node8 = new Node(node10, null, 8);
            Node node7 = new Node(null, node9, 7);
            Node node6 = new Node(node8, null, 6);
            Node node5 = new Node(null, null, 5);
            Node node4 = new Node(node7, null, 4);
            Node node3 = new Node(node5, node6, 3);
            Node node2 = new Node(node4, null, 2);
    
            root = new Node(node2, node3, 1);
        }
    
        @Test
        void bfs() {
            BinaryTree.bfs(root);
        }
    
        @Test
        void dfs() {
            BinaryTree.dfs(root);
        }
    }
    • bfs

      1 2 3 4 5 6 7 8 9 10 
    • dfs

      7 9 4 2 1 5 3 10 8 6 

Reference

profile
안녕하세요.

0개의 댓글