Java - 클래스

Lee·2020년 12월 18일
0

Java

목록 보기
4/9
post-thumbnail

자바에서 제공하는 클래스에 대해서 공부하기 ✍️

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

공부하기 전에 🚀

자바는 객체 지향 프로그래밍이 가능한 언어이다.

  • 객체란? 실제 존재하는 실체라고 생각하면 된다. 실체는 '속성'과 '기능'을 가진다.
  • 객체 지향 프로그래밍이란? 객체들의 속성과 기능을 가지고 각 객체들간의 관계를 맺음으로써 하나의 프로그램을 개발하는 기법이 객체 지향 프로그래밍이다.

클래스 정의하는 방법 ✍️

클래스란? 객체를 만들기전에 우리가 필요한 속성과 기능을 정의해놓은 하나의 설계도라고 생각하면 된다.

자바에서 제공하는 클래스는 필드(속성), 생성자, 메소드(기능)로 구성된다.

  • 필드 : 객체에서 사용하는 멤버 변수라고 생각하면 된다.
  • 생성자 : 변수를 생성하는 시점에 초기값을 대입하는 것처럼 클래스에도 마찬가지로 클래스를 생성하는 시점에 필요한 값들을 초기화 시켜주는 역할을 한다.
  • 메소드 : 객체에서 사용하는 기능이라고 생각하면 된다.
public class Car {

    // 필드 혹은 클래스의 멤버 변수라고 부른다.
    private String name;
    private String color;
    private int hp;


    // 아무것도 없는 default 생성자
    // Ex) new Car();
    public Car() {

    }

    // 파라미터를 가지고 있는 생성자
    // Ex) new Car("Benz", "white", 240);
    public Car(String name, String color, int hp) {
        this.name = name;
        this.color = color;
        this.hp = hp;
    }

    // 기능에 역할을 하는 메소드
    // Car car = new Car("Benz", "white", 240);
    // car.getName() --> "Benz"
    // car.getColor() --> "white"
    // car.getHp() --> 240
    public String getName() {
        return name;
    }

    public String getColor() {
        return color;
    }

    public int getHp() {
        return hp;
    }
}

클래스, 멤버 변수, 메소드에서 사용될 수 있는 키워드

  • 접근 지정자 : 해당하는 클래스, 멤버 변수, 메소드를 외부에서 접근하지 못하도록 제한하는 역할을 한다.
    - public, default, protected, private
    • public : 접근 제한이 전혀 없다.
    • default : 같은 패키지 내에서만 접근이 가능하다.
    • protected : 같은 패키지 내에서, 그리고 다른 패키지의 자손클래스에서 접근이 가능하다.
    • private : 같은 클래스 내에서만 접근이 가능하다.

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

클래스로부터 객체를 만드는 과정을 클래스의 인스턴화(instantiate)라고 하며, Car 클래스로부터 만들어진 객체를 Car 클래스의 인스턴스(instance)라고 한다. 객체를 만드는 과정은 매우 간단하다.

public static void main(String[] args) {
        // write your code here
        
        Car car = new Car("Benz", "white", 210);
    }

클래스명 변수명 = new 클래스명();

클래스의 객체를 참조하기 위한 참조변수를 선언한다.
변수에 new 키워드로 생성된 클래스의 주소를 참조변수에 저장한다.

메소드 정의하기 📌

메소드란 클래스내에 존재하는 함수로써 어떤 작업을 수행하기 위한 명령문들의 집합체이다. 주로 어떤 값을 입력받아서 그에 맞는 결과를 되돌려 주는 역할을 수행한다. 사용목적에 따라서 입력받는 값이 없을 수도 있고, 되돌려주는 결과 값이 없을 수도 있고, 둘다 없는 경우도 있다.

해당 객체에 기능을 담당하는 역할도 있지만 단순 반복적인 내용을 하나의 덩어리로 나타내기 위해 사용한다. tunningEngine 이라는 메소드를 보면
멤버 변수의 hs을 10씩 올려주는 메소드이다.

public void tunningEngine() {
        int tunning = 10;
        this.hp = tunning;
    }

메소드는 크게 선언부와 구현부 두 부분으로 나뉘어져있고 선언부의는 리턴타입, 메소드이름, 그리고 괄호()에 매개변수를 선언하고, 구현부에는 메소드가 호출되었을 때 수행되어야 할 코드를 넣어주면 된다.

메소드가 호출될 때 선언부에 작성되어 있는 매개변수를 통해서 메소드가 작업을 수행할 때 필요한 값들을 받아서 처리한다.
괄호()안에 있는 매개변수는 지역변수로 갅되어 메소드 내에서만 사용이 가능하며 메소드가 종료되는 순간 메모리에서 제거되어 사용할 수 없다.

리턴타입은 메소드의 결과에 따라 어떤 타입으로 반환할 것인지에 대해 작성하는 부분이다. 메소드의 반환 값이 없는 경우 선언부에 void라는 키워드를 작성하면 되고, 반환 값이 있는 경우 return 키워드를 사용하여 구현부 맨 마지막에 작성하면 된다.

	// 자동차의 엔진 마력을 가져오는 메소드.
        public int getHp() {
        return hp;
    }

getHp 메소드는 int 타입에 hp의 값을 반환해주는 역할을 하는 매소드이다.

생성자 정의하기 📌

변수를 선언하고 초기화하는 것과 같은 개념으로 객체를 생성할 때 객체를 초기화 하기 위해 사용되는 것이 생성자이다.

  • 컴파일러가 자동적으로 추가해주는 생성자 (파라미터 값을 가지지 않는 생성자를 명시적으로 작성해주지 않을 경우 자동 생성)
  • 파라미터(매개변수) 값을 가지지 않는 생성자
  • 파라미터(매개변수) 값을 가지는 생성자
public class Car {

    private String name;
    private String color;
    private int hp;


    // 아무것도 없는 default 생성자
    // Ex) new Car();
    public Car() {

    }

    // 파라미터를 가지고 있는 생성자
    // Ex) new Car("Benz", "white", 240);
    public Car(String name, String color, int hp) {
        this.name = name;
        this.color = color;
        this.hp = hp;
    }

}

생성자는 몇가지 특징을 가지고 있다.

  • 생성자는 리턴 타입을 갖지 않는다.
  • 생성자는 클래스 이름가 동일해야한다.
  • 모든 클래스는 생성자가 반드시 존재하며, 하나 이상을 가질 수 있다.
  • 클래스 내부에 생성자를 선언하지 않으면 자동으로 기본 생성자가 선언된다.

this 키워드 ⭐️

클래스가 인스턴스화 되었을때 자기자신의 메모리 주소를 담고있는 키워드이다.
한마디로 저 여기 있어요~! ⭐️ 하는 녀석인거 같다.

클래스의 멤버 변수 이름과 메소드의 매개 변수 이름이 동일한 경우 이를 구분짓기 위해 this 키워드를 이용한다.

public class Car {

	
    private String name;
    private String color;
    private int hp;


    // 메소드에서 사용하는 파라미터의 이름과 클래스의 멤버변수가 동일한 경우
    // this 키워드를 이용해 Car 객체의 자기 자신한태 있는 name, color, hp 알려준다.
    public Car(String name, String color, int hp) {
        this.name = name;
        this.color = color;
        this.hp = hp;
    }
}

this 키워드가 클래스 내에 멤버 변수를 가리킨다 하면 this()는 클래스 내부에 있는 생성자를 의미한다.
자기 자신의 클래스 생성자를 호출한다. 주의할 점은 호출하는 곳의 this() 키워드가 맨 윗줄에 있어야 하며, 파라미터가 있는 생성자인 경우 this()안에 파라미터 타입에 맞게 입력해야 한다.

public class Car {

    private String name;
    private String color;
    private int hp;

    public Car(String name, String color, int hp) {
        this.name = name;
        this.color = color;
        this.hp = hp;
    }

    public Car(int hp) {
        this("BMW", "Black", hp);
    }
}

Result : Car{engine=false, name='BMW', color='Black', hp=110}

과제

요구사항 📌

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

Node? 🤔

  • 연결 리스트에서 데이터가 저장되는 실제 공간
  • 네트워크 또는 데이터 구조를 구성하는 각각의 개체를 말한다.
  • 하나의 노드는 다른 노드와 연결된다.
  • 연결 방식에 따라 연결리스트(Linked List)와 트리(Tree) 등이 있다.

Node 구현 ✍️

  • int 값을 가지고 있는 이진 트리를 나타내는 Node 라는 클래스를 정의하세요.
  • int value, Node left, right를 가지고 있어야 합니다.
public class Node {

    private Node left;
    private int value;
    private Node right;

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

    public Node getLeft() {
        return left;
    }

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

    public int getValue() {
        return value;
    }

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

    public Node getRight() {
        return right;
    }

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

Tree? 🤔

  • 계층적인 자료구조를 나타낼때 사용한다.
  • 계층구조를 지니기 때문에 상하관계를 가지고 있다.
  • 계층구조에서 상위계층에 존재하는 자료를 parent라고 표현하고 그 하위계층을 children이라고 표현한다.
  • 최상의 parent를 root라고 표현하며, 최하위 children을 left라고 표현한다.
  • parent-children의 관계에서 parent는 다수의 children을 가질 수 있지만, children은 하나의 parent와 연결되어야 한다.
트리의 예
                (1)	 
              ↙     ↘
           (2)        (3)
         ↙    ↘     ↙
     (4)      (5) (6)

용어

  • 루트(root) 노드 : 최상위에 위치한 노드
  • 리프(leaf) 노드 : 자식이 없는 노드
  • 간선(Edge) : 노드와 노드를 연결하는 선
  • 서브트리(Sub-Tree) : 큰 트리에 속하는 작은 트리
  • 레벨(Level) : 트리의 각 층별 숫자를 매김
  • 높이(Height) : 트리의 최고 레벨

관계

  • 부모-자식(parent-child) 관계 : 루트노드를 제외한 모든 노드는 하나의 부모를 갖는것을 의미한다. 간선으로 이어진 2개의 노드 중, 위의 노드가 부모, 아래 노드가 자식이 되는 관계이다
    - (4), (5)는 (2)의 자식 노드이고, (2)는 (4), (5)의 부모 노드이다.
  • 형제(sibling) 관계 : 같은 부모 노드를 갖는 노드들을 형제 관계라고 한다.
    - (4), (5)는 같은 부모를 가지고 있기 때문에 형제 관계라고 말할 수 있다.

특징

  • 루트 노드를 제외한 모든 노드는 단 하나의 부모 노드만을 가진다.
  • 임의의 노드에서 다른 노드로 가는 경로는 유일하다.
    - (5)노드에서 (6)노드로 간다는 가정하에..유일하네..?🤔

Tree 구현 ✍️

  • 위에서 선언한 Node 클래스를 기반으로 Tree를 구현하는 테스트 코드를 작성해봤다.


public class NodeTest {

    @Test
    @DisplayName("1 ~ 6까지의 노드 생성")
    void setUp() {
        Node node6 = new Node(null, 6, null);
        Node node5 = new Node(null, 5, null);
        Node node4 = new Node(null, 4, null);

        Node node3 = new Node(node6, 3, null);
        Node node2 = new Node(node4, 2, node5);

        Node node1 = new Node(node2, 1, node3);
    }

    @Test
    @DisplayName("노드의 child value값 확인")
    void check_value_in_child_node() {
        Node node6 = new Node(null, 6, null);
        Node node5 = new Node(null, 5, null);
        Node node4 = new Node(null, 4, null);

        Node node3 = new Node(node6, 3, null);
        Node node2 = new Node(node4, 2, node5);

        Node node1 = new Node(node2, 1, node3);

        // Node1의 child node value 확인
        assertEquals(2, node1.getLeft().getValue());
        assertEquals(3, node1.getRight().getValue());


        assertEquals(4, node2.getLeft().getValue());
        assertEquals(5, node2.getRight().getValue());

        assertEquals(6, node3.getLeft().getValue());
    }

}

이진트리(Binary Tree)

  • 이진트리란 자식노드가 최대 두 개인 노드들로 구성된 트리다.

이진트리의 종류

  • Full Binary Tree
  • Perfect Binary Tree
  • Complete Binary tree

Full Binary Tree

  • 모든 노드가 0개 혹은 2개의 children을 가지고 있는 이진트리

Perfect Binary Tree

  • 모든 레벨에서 노드들이 꽉 채워진 이진트리

Complete Binary Tree

  • 마지막 레벨을 제외한 모든 레벨에서 노드들이 가득 차있고, 마지막 레벨에서 노드가 가장 왼쪽부터 채워지는 형태로 이루어진 이진트리

깊이 우선 탐색(DPS)

  • Inorder(Left, Root, Right)
    - Root 노드를 기준으로 Left -> Root -> Right 순으로 순회한다.
public void inorder(Node node) {
        if (node != null) {
            inorder(node.getLeft());
            System.out.println(node.getValue());
            inorder(node.getRight());
        }
    }
  • Preorder(Root, Left, Right)
    - Root 노드를 기준으로 Root -> Left -> Right 순으로 순회한다.
public void preorder(Node node) {
        if (node != null) {
            System.out.println(node.getValue());
            preorder(node.getLeft());
            preorder(node.getRight());
        }
    }
  • Postorder(Left, Right, Root)
    - Root 노드를 기준으로 Left -> Right -> Root 순으로 순회한다.
public void postorder(Node node) {
        if (node != null) {
            postorder(node.getLeft());
            postorder(node.getRight());
            System.out.println(node.getValue());
        }
    }

너비 우선 탐색(BPS)

  • 레벨 단위로 시작
public void bfs(Node node) {
        Queue<Node> queue = new LinkedList<>();
        queue.add(node);

        while(!queue.isEmpty()){
            Node current = queue.poll();
            System.out.print(current.getValue() + " ");
            if (current.getLeft() != null) queue.add(current.getLeft());
            if (current.getRight() != null) queue.add(current.getRight());
        }
    }

DPS & BPS 테스트 코드

public class Main {
    public static void main(String[] args) {
        Node node6 = new Node(null, 6, null);
        Node node5 = new Node(null, 5, null);
        Node node4 = new Node(null, 4, null);

        Node node3 = new Node(node6, 3, null);
        Node node2 = new Node(node4, 2, node5);

        Node node1 = new Node(node2, 1, node3);

        BinaryTree binaryTree = new BinaryTree();
        binaryTree.setRoot(node1);
        binaryTree.inorder(binaryTree.getRoot());
        binaryTree.preorder(binaryTree.getRoot());
        binaryTree.postorder(binaryTree.getRoot());

        binaryTree.bfs(node1);
    }
}

inorder : 4 2 5 1 6 3
preorder : 1 2 4 5 3 6
postorder : 4 5 2 6 3 1

bfs : 1 2 3 4 5 6

0개의 댓글