본문 바로가기

개발 스토리/Java live study

Java 5주차 : 클래스

목표


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

학습할 것 (필수)


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

과제 (Optional)

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

클래스란?

  • '객체를 정의해놓은 것', 또는 클래스는 '객체의 설계도 또는 틀'이라고 정의할 수 있다.
  • 클래스는 객체를 생성하는데 사용되며, 객체는 클래스에 정의된 대로 생성된다.

클래스 정의하는 방법


  • 클래스를 선언하는 방법은 접근 제어자와 함께 class 키워드를 사용하면 됩니다.
접근제이자 class 클래스이름 {
    접근제어자 필드1의타입 필드1의이름;
    접근제어자 필드2의타입 필드2의이름;
    ...
    접근제어자 메소드1의 원형
    접근제어자 메소드2의 원형
	...
}

출처 : http://www.tcpschool.com/java/java_class_declaration

 

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


클래스 객체 변수 = new 클래스();

클래스의 객체를 참조가히 위한 참조변수를 선언하고 new 연산자를 이용해서 객체를 생성한다.

new는 클래스 타입의 인스턴스를 생성해주는 역할을 담당하고 연산자 new를 통해 메모리에 데이터를 저장할 공간을 할당받고 그 공간의 참조값을 객체에게 반환하여 주고 이어서 생성자를 호출하게 된다. 인스턴스를 핸들하기 위해서는 new 연산자를 통해 참조값을 저장한 객체로만 접근이 가능하다.

 

class TV {
    String color;
    boolean power;
    int channel;
    
    void power(){
    	power = !power;
    }
    
    void channelUp(){
    	++channel;
    }
    
    void channelDown(){
    	--channel;
    }
}

class TvTest{
	public static void main(String args[]){
    	Tv t;	// 1
        t = new TV();	// 2
        t.channel = 7;	// 3
        t.channelDown();	// 4
        System.out.prinln("현재 채널은 " + t.channel + " 입니다.");
    }
}

1. TV t;

  • TV클래스에 타입의 참조변수 t를 선언한다. 메모리에 참조변수 t를 위한 공간이 마련된다. 아직 인스턴스가 생성되지 않았으므로 참조변수로 아무것도 할 수 없다.

2. t = new TV();

  • 연산자 new에 의해 TV클래스의 인스턴스가 메모리의 빈 공간에 생성된다. 주소가 0x100인 곳에 생성되었다고 가정하고 멤버변수는 각 자료형에 해당하는 기본값으로 초기화 된다. 그 다음에는 대입연산자에 의해서 생성된 객체의 주소값이 참조변수 t에 저장된다.

 

3. t.channel = 7;

  • 참조변수 t에 저장된 주소에 있는 인스턴스의 멤버변수 channel에 7을 저장한다.
  • 인스턴스의 멤버변수를 사용하러면 '참조변수.멤버변수'와 같이 하면 된다.

4. t.channelDown();

  • 참조변수 t가 참조하고 있는 Tv인스턴스의 channelDown메서드를 호출한다. channel Down메서드는 멤버변수 channel에 저장되어 있는 값을 1 감소시칸다.
  • channelDown()에 의해서 channel의 값은 7에서 6이 된다.

 

메서드 정의하는 방법


  • 메서드는 크게 두 부분, '선언부'와 '구현부'로 이루어져 있다.
  • 메서드를 정의한다는 것은 선언부와 구현부를 작성하는 것을 뜻하며 아래와 같은 형식으로 메서드를 정의한다.
반환타입 메서드 이름 (타입 변수명, 타입 변수명, ... ) { // <- 선언부

    // 메서드 호출시 수행될 코드 <- 구현부
    
}

int add (int a, int b) { // <- 선언부

    int result = a + b;
    return result; // 호출한 메서드로 결과를 반환한다. 
    
}

 

- 메서드 선언부

  •  메서드 선언부는 '메서드의 이름'과 '매개변수 선언', 그리고 '반환타입'으로 구성되어 있다.
  • 메서드가 작업을 수행하기 위해 어떤 값들을 필요로 하고 작업의 결과로 어떤 타입의 값을 반환하는지에 대한 정보를 제공한다.

- 매개변수 선언

  • 매개변수는 메서드가 작업을 수행하는데 필요한 값들을 제공받기 위한 것이다
  • 필요한 값의 개수만큼 변수를 선언하며 각 변수 간의 구분은 쉼표를 사용한다.

- 메서드의 이름

  • 메서드의 이름도 변수의 명명규칙대로 작성하면 된다.

- 반환타입

  • 메서드의 작업수행 결과인 '반환값'의 타입을 적는다. 반환값이 없는 경우 반환타입으로 'void'를 적어야한다.

- 메서드의 구현부

  • 메서드를 호출했을 때 수행될 문장들을 적는다.

- return문

  • return문은 현재 실행중인 메서드를 종료하고 호출한 메서드로 되돌아간다.

 

생성자 정의하는 방법


- 생성자란?

  • 생성자는 인스턴스가 생성될 때 호출되는 '인스턴스 초기화 메서드'이다. 따라서 인스턴스 변수의 초기화 작업에 주로 사용되며, 인스턴스 생성 시에 실행되어야 할 작업을 위해서도 사용된다.
  • 생성자 역시 메서드처럼 클래스 내에 선언되며, 구조도 메서드와 유사하지만 리턴값이 없다는 점이 다르다.
클래스이름 (타입 변수명, 타입 변수명, ... ) {
    // 인스턴스 생성 시 수행될 코드
    // 주로 인스턴스 변수의 초기화 코드를 적는다.
}
class Card {
    Card() {	// 매개변수가 없는 생성자.
    	...
    }
    
    Card(String k, int num) {	// 매개변수가 있는 생성자.
    	...
    }
}

Card c = new Card();

1. 연산자 new에 의해서 메모리(heap)에 Card클래스의 인스턴스가 생성된다.

2. 생성자 Card()가 호출되어 수행된다.

3. 연산자 new의 결과로, 생성된 Card인스턴스의 주소가 반환되어 참조변수 c에 저장된다.

 

- 기본 생성자(default constructor)

클래스이름() { }

Card() { }

 

  • 모든 클래스에는 반드시 하나 이상의 생성자가 정의되어 있어야 한다.
  • 클래스에 생성자를 정의하지 않고도 인스턴스를 생성할 수 있었던 이유는 컴파일러가 제공하는 '기본 생성자' 덕분이다.
  • 컴파일 할 때, 클래스에 생성자가 하나도 정의되지 않은 경우 컴파일러는 자동적으로 기본 생성자를 추가하여 컴파일한다.

- 매개변수가 있는 생성자

  • 생성자도 메서드처럼 매개변수를 선언하여 호출 시 값을 넘겨받아서 인스턴스의 초기화 작업에 사용할 수 있다.
class Car {
     String color;
     int door;
     
     Car() {}	// 기본 생성자
     
     Car(String color, int door) {
     	this.color = color;
        this.door = door;
     }
}

  • Car인스턴스를 생성할 때, 생성자 Car()를 사용한다면, 인스턴스를 생성한 다음에 인스턴스변수들을 따로 초기화해주어야 하지만, 매개변수가 있는 생성자를 사용하면 동시에 원하는 값으로 초기화를 할 수 있게 된다.

 

this 키워드 이해하기


  • 자바에서 this는 '객체, 자기 자신'을 나타낸다.
  • 생성자 간에 서로 호출이 가능하며 두 가지 조건이 있다.
  • 생성자의 이름으로 클래스이름 대신 this를 사용한다.
  • 한 생성자에서 다른 생성자를 호출할 때는 반드시 첫 줄에서만 호출이 가능하다.

 

1. 클래스의 속성과 생성자/메소드의 매개변수의 이름이 같은 경우

class Car {
     String color;
     int door;
     
     Car() {}	// 기본 생성자
     
     Car(String color, int door) {
     	this.color = color;
        this.door = door;
     }
}

여기에서의 this키워드는 객체 자신의 속성을 나타내게 되는 것 입니다.

 

2. 클래스에 오버로딩된 다른 생성자 호출

class Car {
     String color;
     int door;
     
     Car() {	// 기본 생성자
     	this("white", 4);
     }	
     
     Car(String color, int door) {
     	this.color = color;
        this.door = door;
     }
}

 

같은 클래스에 오버로딩된 다른 생성자를 호출할때에도 this키워드가 사용됩니다.

 

3. 객체 자신의 참조값을 전달하고 싶을 때

class Car {
     String color;
     int door;
     
     Car() {}	// 기본 생성자
     
     Car(String color, int door) {
     	this.color = color;
        this.door = door;
     }
     
     public Car getCarInstance() {
     	return this;
    }
}

 

 

과제 (Optional)

Binary Search Tree란

  • 각 노드에 값이 있다.
  • 각 노드의 키값은 모두 달라야 한다.
  • 값들은 전순서가 있다.
  • 노드의 왼쪽 서브트리에는 그 노드의 값보다 작은 값들을 지닌 노드들로 이루어져 있다.
  • 노드의 오른쪽 서브트리에는 그 노드의 값보다 큰 값들을 지닌 노드들로 이루어져 있다.
  • 좌우 하위 트리는 각각이 다시 이진 탐색 트리여야 한다.
  • 중복된 노드가 없어야 한다.

Tree를 사용하는 이유

  • 탐색, 삼입, 삭제가 빠르다.
  • 정렬 된 배열에서는 삽입, 삭제 작업이 비효율적이다.
  • 링크드리스트는 검색이 느리다.
  • 평균적으로 O(log n)의 시간복잡도를 가진다.

 

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

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

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

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

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        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;
    }
}

 

BFS vs DFS

  • 이진트리에 해당하는 검색 알고리즘은 2가지가 있다. 너비 우선탐색(bfs), 깊이 우선탐색(dfs).
  • BFS는 시작 정점으로부터 가까운 정점을 먼저 방문하고 멀리 떨어져 있는 정점을 나중에 방문하는 순회 방법이다.
  • DFS는 루트 노드에서 시작해서 다음 분기로 넘어가기 전에 해당 분기를 완벽하게 탐색하는 방법

출처 : https://younghwi.tistory.com/3

 

  • BinaryTree라는 클래스를 정의하고 주어진 노드를 기준으로 출력하는 bfs(Node node)와 dfs(Node node)메소드를 구현하세요.
  • DFS는 왼쪽, 루트, 오른쪽 순으로 순회하세요.
public class BinaryTree {

    public void bfs(Node node) {
        Queue<Node> queue = new LinkedList<Node>();
        queue.offer(node);

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

    public void dfs(Node node) {
        Stack<Node> stack = new Stack<>();
        stack.push(node);

        while (!stack.isEmpty()) {
            Node x = stack.pop();
            if (x != null) {
                System.out.print(x.getValue() + " ");
                stack.push(x.getRight());
                stack.push(x.getLeft());
            }
        }
    }
}

Test

class BinaryTreeTest {

    @Test
    void bfs() {
        Node leftNode = new Node(1, new Node(3), new Node(4));
        Node rightNode = new Node(2, new Node(5), new Node(6));
        Node node = new Node(0, leftNode, rightNode);

        BinaryTree binaryTree = new BinaryTree();
        binaryTree.bfs(node);
        // 출력 : 0 1 2 3 4 5 6
    }

    @Test
    void dfs() {
        Node leftNode = new Node(1, new Node(3), new Node(4));
        Node rightNode = new Node(2, new Node(5), new Node(6));
        Node node = new Node(0, leftNode, rightNode);

        BinaryTree binaryTree = new BinaryTree();
        binaryTree.dfs(node);
        // 출력 : 0 1 3 4 2 5 6 
    }

}

 

- 참고 자료

http://www.tcpschool.com/java/java_class_declaration

m.blog.naver.com/PostView.nhn?blogId=heartflow89&logNo=220955262405&proxyReferer=https:%2F%2Fwww.google.com%2F

library1008.tistory.com/4

yaboong.github.io/data-structures/2018/02/12/binary-search-tree/

gmlwjd9405.github.io/2018/08/14/algorithm-dfs.html

gmlwjd9405.github.io/2018/08/15/algorithm-bfs.html