ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [live-study] 5: 클래스
    개발/Java 2021. 1. 1. 23:48

    백기선님이 진행하시는 live-study 5주차 과제
    5주차 과제

    목표

    • 자바의 Class에 대해 학습하세요.

    학습할 것 (필수)

    • 클래스 정의하는 방법
    • 객체 만드는 방법 (new 키워드 이해하기)
    • 메소드 정의하는 방법
    • 생성자 정의하는 방법
    • this 키워드 이해하기

    과제 (Optional)

    • int 값을 가지고 있는 이진 트리를 나타내는 Node 라는 클래스를 정의하세요.
    • int value, Node left, right를 가지고 있어야 합니다.
    • BinrayTree라는 클래스를 정의하고 주어진 노드를 기준으로 출력하는 bfs(Node node)와 dfs(Node node) 메소드를 구현하세요.
    • DFS는 왼쪽, 루트, 오른쪽 순으로 순회하세요.

    클래스

    • 클래스란 객체 모델을 프로그래밍 언어로 표현하기 위한 수단이다.
    • 즉, 사물이나 관념등의 공통된 특성을 추출해서 파악하는 추상화시키는 것을 모델링이라고 하고, 자바에선 그것을 클래스로 표현한다.
    • 여러개의 클래스를 작성하여 하나의 목적을 위해 협력관계를 형성한다.
    • 데이터를 저장하는 필드와 행위를 정의하는 메소드를 가질 수 있다.

    클래스 정의하는 방법

    • 클래스를 지정하기 위해 class 키워드를 사용한다.
      [접근제한자] class [Final] 클래스명 { String name; // 필드 }

    • 클래스 앞에는 final, 접근제한자등이 올 수 있다.

    • 클래스의 이름에도 규칙이 있다. (규칙을 따르지 않으면 컴파일 에러가 발생한다.)

      • 숫자로 시작할 수 없다.
      • #, $를 제외한 특수문자가 올 수 없다.
      • 자바 예약어가 올 수 없다. (if, for등)
      • 클래스 파일의 이름과 동일해야한다.

    객체를 만드는 방법 (new 키워드 이해하기)

    • (static이 아니라면)정의한 클래스를 사용하기 위해선 객체를 생성해야 한다.
    • 그렇게 생성된 객체를 클래스의 인스턴스라고 한다.
    • 객체를 생성할 땐 new 키워드를 사용한다.
    public class Train {
        String name;
    }

    위와 같은 클래스가 있을 때

    Train tomas = new Train(); 와 같이 생성할 수 있다.

    풀어서 의미를 해석해보면 다음과 같다.
    (new Train) : 의미를 풀어서 보면 새로운 Train 객체를 생성해서 그 객체의 주소를
    (Tomas tomas): Tomas 타입의 tomas라는 이름의 참조변수에 할당한다.

    객체를 생성하면 Heap 메모리에 해당 객체가 생성된다.

    객체를 참조변수에 할당하고 나면 클래스의 속성을 사용할 수 있는데
    클래스에 정의된 필드는 참조변수명.필드로 접근할 수 있다.

    메소드 정의하는 방법

    메소드는 해당 클래스가 할 수 있는 행위를 정의해놓은 것이다.
    메소드는 [접근제한자] [static] [final] 메소드명(매개변수) {} 로 정의한다.

    public static moveTrain(int distance) {
        ....
    }

    필드를 사용할 때와 마찬가지로, 참조변수명.메소드명() 으로 사용할 수 있다.
    그러나 static 메소드의 경우 클래스명.메소드명() 으로 사용할 수 있다.

    생성자 정의하는 방법

    • 생성자는 해당 클래스의 인스턴스가 생성될 때 초기값 또는 행위을 주기 위해 사용되는 메소드이다.
    • 생성자는 클래스의 이름과 동일해야 하며, 접근지정자 외에 static, final등 예약어가 올 수 없다.
    • 생성자는 리턴값을 갖지 않는다.
    • 모든 클래스는 반드시 하나 이상의 생성자를 갖는다. (작성하지 않으면 컴파일러가 자동으로 매개값이 없는 생성자를 생성함)
    public class Train {
        String name;
    
        // 생성자
        public Train(String name) {
            this.name = name;
        }
    
    }

    this 키워드 이해하기

    this 키워드는 인스턴스를 생성했을 때, 자기 자신의 메모리 주소를 가지고 자기 자신을 나타내는 키워드다.

    public class Train {
        String name = "tomas";
    
        // 생성자
        public Train(String name) {
            this.name = name;
        }
    }
    
    public class Main {
        static public void main(String[] args) {
            Train train = new Train("james");
        }
    }

    위의 예제에서 Train클래스 안에 클래스 필드 name이 있고, 생성자 내부의 name이 있다. 둘의 이름이 같은데 어떻게 구분할까?

    새 인스턴스를 생성하고 생성자가 실행되었을 때 메모리의 그림은 다음과 같다.

    메소드는 자신과 가까이 있는 지역 변수에 저장된 값을 우선시한다.

    그러므로 자신의 스택프레임 내부에 있는 지역변수 name을 우선시 한다. (james를 저장하고 있는)

    지역변수를 지칭하고 싶다면 특별한 방법이 필요없이 name(지역변수명)을 지칭하면 된다.

    그렇다면 동명의 객체 변수(클래스 필드)를 참조하고 싶다면 어떻게 할까?

    이럴때 this 키워드를 사용하면 객체 변수를 참조하게 된다.

    그래서 위의 Train 예제 생성자 내부에 있는 this.name = name;의 의미는
    매개값으로 받은 지역변수 name의 값을 객체변수 name에 할당한다.

    this()는 클래스 내부에서 생성자를 호출한다.
    this()는 메소드의 첫 라인에서 호출되어야 한다.
    생성자가 파라미터가 있는 경우 this()안에 생성자 파라미터 타입에 맞게 직접 입력하여 사용할 수 있다.

    public class Train {
        String name = "tomas";
    
        // 생성자
        public Train(String name) {
            this.name = name;
        }
        public Train(String name, String generation) {
            this(name + " " + generation);
        }
    
        public class Main {
        static public void main(String[] args) {
            Train train = new Train("james", "2세대"); // 이 기차의 이름은 james 2세대가 된다.
        }
    
    }
    

    바이너리트리 구현

    링크

    • bfs는 Level-order 방식 순회와 동일하다.
    • dfs는 in-order 방식 순회로 구현하였다.

    Node

    package week5;
    
    public class Node {
        private int value;
        private Node left;
        private Node right;
    
        public Node(int value, Node left, Node right) {
            this.value = value;
            this.left = left;
            this.right = right;
        }
    
        public Node(int value) {
            this.value = value;
        }
    
        public int getValue() {
            return value;
        }
    
        public Node getLeft() {
            return left;
        }
    
        public Node getRight() {
            return right;
        }
    
    }

    BinaryTree (DFS/BFS 구현)

    package week5;
    
    import java.util.LinkedList;
    import java.util.Objects;
    import java.util.Queue;
    
    public class BinaryTree {
    
        public static String bfs(Node root) {
            Queue<Node> q = new LinkedList<>();
            String result = "";
            LinkedList<Node> visited = new LinkedList<>();
            q.add(root);
    
            while (!q.isEmpty()) {
                Node node = q.poll();
                if(visited.contains(node)) {
                    continue;
                }
                result += node.getValue();
                if (!Objects.isNull(node.getLeft())) {
                    q.add(node.getLeft());
                }
                if (!Objects.isNull(node.getRight())) {
                    q.add(node.getRight());
                }
            }
    
            return result;
        }
    
        public static String dfs(Node root) {
            if (Objects.isNull(root)) {
                throw new NullPointerException("root가 null입니다.");
            }
            return dfs(root, "");
        }
    
        private static String dfs(Node root, String result) {
            if (Objects.isNull(root)) {
                return result;
            }
            result = dfs(root.getLeft(), result);
            result += root.getValue();
            result = dfs(root.getRight(), result);
    
            return result;
        }
    }
    

    테스트코드

    package week5;
    
    import org.junit.jupiter.api.BeforeEach;
    import org.junit.jupiter.api.Test;
    
    import java.util.Objects;
    
    import static org.junit.jupiter.api.Assertions.*;
    
    class BinaryTreeTest {
    
        Node root;
    
        @BeforeEach
        void initilize() {
            Node node1 = new Node(1);
            Node node2 = new Node(2);
            Node node5 = new Node(5, node1, node2);
            Node node3 = new Node(3);
            Node node4 = new Node(4);
            Node node6 = new Node(6, node3, node4);
            Node node7 = new Node(7, node5, node6);
            Node node8 = new Node(8);
            root = new Node(9, node7, node8);
        }
    
        @Test
        void bfs() {
            assertTrue(!Objects.isNull(root));
            assertEquals("978561234", BinaryTree.bfs(root));
    
        }
    
        @Test
        void dfs() {
            assertTrue(!Objects.isNull(root));
            assertEquals("152736498", BinaryTree.dfs(root));
        }
    
    }

    참고

    https://www.notion.so/Live-Study-5-75f857b63e524d33914a8b3ec6e1e894

    댓글

Designed by Tistory.