목표
자바의 Class에 대해 학습하세요.
학습할 것 (필수)
- 클래스 정의하는 방법
- 객체 만드는 방법 (new 키워드 이해하기)
- 메소드 정의하는 방법
- 생성자 정의하는 방법
- this 키워드 이해하기
마감일시
2020년 12월 19일 토요일 오후 1시까지.
과제 (Optional)
- int 값을 가지고 있는 이진트리를 나타내는 Node라는 클래스를 정의하세요.
- int value, Node left, right를 가지고 있어야 합니다.
- BinrayTree라는 클래스를 정의하고 주어진 노드를 기준으로 출력하는 bfs(Node node)와 dfs(Node node) 메소드를 구현하세요.
- DFS는 왼쪽, 루트, 오른쪽 순으로 순회하세요.
클래스 정의하는 방법
클래스는 일반적으로 자바에서 설계도, 청사진이라고 불린다. 자동차를 생산하기 위해서는 공장이 필요한 것처럼 객체를 생성하기 위해서는 클래스가 필요하다.
객체지향 언어에서 클래스가 핵심 개념이라고 말하기에는 무리가 있다. 자바와 같은 클래스 기반 언어가 있는 반면, 같은 객체 지향언어인 자바스크립트와 같은 프로토타입 기반 언어에서는 클래스가 존재 하지 않는다.
따라서 가장 중요한 것은 클래스들의 정적 관계가 아닌 메시지를 주고받는 객체들의 동적 관계라는 것과 클래스는 단순히 객체들의 협력 관계를 코드로 옮기는 도구에 불과하다는 것을 알자.
이제부터 클래스를 정의하는 방법에 대해서 알아보려고 한다. 클래스의 이름은 다른 클래스와 구별되어야 하므로, 자바의 식별 규칙에 따라 만들어져야 한다.
번호 | 작성 규칙 | 예) |
1 | 하나 이상의 문자로 이루어져야 한다. | Item, Car, Book |
2 | 첫 번째 글자는 숫자가 올 수 없다. | 2Item, 3Car, 5Book 전부 불가능 |
3 | '$', '_' 외의 특수 문자는 사용할 수 없다. | $Item, _Item 가능, @Item(불가능) |
4 | 자바 키워드(예약어)는 사용할 수 없다. | int, for, while, true |
public class Item() {
// public class는 소문자
// Item은 첫머리글자가 대문자
}
클래스의 구성 멤버는 크게 3가지로 분리된다.
- 필드 : 필드는 객체의 상태나 정보 값 등을 저장하는 곳이다. 형태는 변수 형태와 비슷하지만 필드를 변수라고 부르지는 않는다. 변수는 생성자와 메소드 내에서만 사용되고 생성자나 메소드가 실행 종료되면 자동 소멸된다. 하지만 필드는 생성자와 메소드 전체에서 사용되며 객체가 소멸되지 않는 한 소멸되지 않는다.
- 생성자 : 생성자는 객체를 처음 생성할 때 초기화를 하는 역할을 한다. 생성자는 메소드와 비슷하게 생겼으나 클래스 이름으로 되어 있고 리턴타입이 없다.
- 메소드 : 메소드는 객체의 동작에 관해 정의한 중괄호 블록이다. 메소드를 호출하게 되면 중괄호 블록에 있는 모든 코드들이 일괄적으로 실행된다. 메소드는 필드를 읽고 수정하는 역할도 하지만, 다른 객체를 생성해서 다양한 기능을 수행하기도 한다.
public class Node {
// 필드
int value;
Node left;
Node right;
// 생성자
public Node(int value) {
this.value = value;
}
// 메소드
public void left(Node left) {
this.left=left;
}
public void rigt(Node right) {
this.right=right;
}
}
객체 만드는 방법 (new 키워드 이해하기)
(객체지향의 사실과 오해 中..)
- 객체지향이란 시스템을 상호작용하는 자율적인 객체들의 공동체로 바라보고 객체를 이용해 시스템을 분할하는 방법이다.
- 자율적인 객체란? 상태와 행위를 함께 지니며 스스로 자기 자신을 책임지는 객체를 의미한다.
- 객체는 시스템의 행위를 구현하기 위해 다른 객체와 협력한다. 각 객체는 협력 내에서 정해진 역할을 수행하며 역할은 관련된 책임의 집합이다.
- 객체는 다른 객체와 협력하기 위해 메시지를 전송하고, 메시지를 수신한 객체는 메시지를 처리하는 데 적합한 메서드를 자율적으로 선택한다.
객체지향은 객체를 현실세계를 유사하게 모방으로 표현하고 싶은 것이 목적이 아니다. 단지 현실과 비스무리한 이상한 나라를 표현하면 되는 것이다.
다시 본론으로 돌아와서..
객체를 생성할 때는 new 연산자를 이용해서 생성한다.
클래스 변수 = new 클래스();
1주 차 때 살펴본 바와 같이 힙 영역은 모든 객체 정보를 저장하고 있는 공간이며
스택 영역은 Object 타입의 데이터들, 원시 타입의 데이터들이 할당된다.
그림으로 보면 아래와 같다.
위 그림과 같이 변수는 주소 값을 참조하고 있기 때문에 단순 출력을 해보면 주소 값이 나온다.
public static void main(String[] args) {
Item item = new Item();
System.out.println(item);
}
메소드 정의하는 방법
메소드는 선언부와 실행 블록으로 나뉜다. 메소드 선언부는 메소드 시그니처(signature)라고도 부른다.
메소드 선언부는 아래와 같은 구조를 가진다. (예시)
public void methodName(int num) { .... } ;
접근 지시자 반환 값 메소드명 (파라미터)의 순서이다.
- 접근 지시자는 public, default, protected, private이 있으며 지정하지 않으면 기본값으로 default로 설정된다.
- 반환 값은 메소드를 싱행 한 후 리턴되는 값을 의미한다. 있을 수도 있고 없을 수도 있다.
- 메소드 명은 해당 메소드가 어떤 기능을 하는지 표현한다. (아래 규칙을 명심하자)
- 매개 변수는 메소드를 실행할 때, 메소드에 필요한 인자들을 전달받기 위해 선언된다.
추가적으로 접근 지시자와 반환 값 사이에 static 키워드를 붙이면
정적 메소드로 사용된다.
생성자 정의하는 방법
특징 : 생성자는 위에 설명한 바와 같이 객체를 생성할 때 초기화하는 역할을 하며 메소드와 비슷하게 생겼지만 클래스 이름으로 되어 있으며 리턴 타입이 없다.
생성자를 선언하지 않았다면 객체 생성 시 컴파일러가 빈 생성자를 만든다.
생성자 선언 구조
접근지시자 클래스 (매개변수) {
// 초기화 코드
}
생성자 오버 로딩(Overloading)
생성자는 오버 로딩이 가능하다.
생성자 오버로딩 시 주의할 점은 매개 변수의 타입과 개수 그리고 선언된 순서가 똑같을 경우 매개변수 이름만 바꾸는 것은 생성자 오버 로딩이라고 볼 수 없다.
Item(String item1, String item2) { }
Item(String item2, String item2) { }
this 키워드 이해하기
this키워드는 현재 자신의 객체(인스턴스)를 의미하며 이와 반대로 super키워드는 부모 객체를 의미한다.
this키워드는 아래 항목에서 사용될 수 있다.
필드 쉐도잉 (기본적인 구조)
public class KeywordTest {
private String name;
private int age;
public KeywordTest(String name, int age) {
this.name = name;
this.age = age;
}
}
같은 클래스의 생성자를 참조할 때
public KeywordTest() {
this("John", 27);
}
파라미터로 넘길 때
public KeywordTest() {
printInstance(this);
}
public void printInstance(KeywordTest thisKeyword) {
System.out.println(thisKeyword);
}
리턴에서의 this
코드가 중복될 때 중복되는 부분을 줄이기 위해서 사용하기 좋다. 대표적으로 빌더 패턴에서 사용된다.
public static class BankAccountBuilder {
private String name;
private String accountNumber;
private String email;
private boolean newsletter;
public BankAccountBuilder(String name, String accountNumber) {
this.name = name;
this.accountNumber = accountNumber;
}
public BankAccountBuilder withEmail(String email) {
this.email = email;
return this;
}
public BankAccountBuilder wantNewsletter(boolean newsletter) {
this.newsletter = newsletter;
return this;
}
public BankAccount build() {
return new BankAccount(this);
}
}
InnerClass에서의 this키워드
아래 코드에서 this를 통해 inner클래스에서 outer클래스에 접근 가능하다.
public class KeywordTest {
private String name;
class ThisInnerClass {
boolean isInnerClass = true;
public ThisInnerClass() {
KeywordTest thisKeyword = KeywordTest.this;
String outerString = KeywordTest.this.name;
}
}
}
www.w3schools.com/java/ref_keyword_this.asp
docs.oracle.com/javase/tutorial/java/javaOO/thiskey.html
과제 (Optional)
- int 값을 가지고 있는 이진트리를 나타내는 Node라는 클래스를 정의하세요.
- int value, Node left, right를 가지고 있어야 합니다.
- BinrayTree라는 클래스를 정의하고 주어진 노드를 기준으로 출력하는 bfs(Node node)와 dfs(Node node) 메소드를 구현하세요.
- DFS는 왼쪽, 루트, 오른쪽 순으로 순회하세요.
넓이우선탐색(Breadth First Search)
가까운 노드부터 탐색하는 알고리즘입니다. BFS는 선입선출 방식의 큐를 이용하면 효과적으로 규현 할 수 있습니다. 인접한 노드를 반복적으로 큐에 넣도록 알고리즘을 작성하면, 자연스럽게 먼저 들어온 것이 먼저 나가게 되어, 가까운 노드부터 탐색합니다.
깊이우선탐색(Depth First Search)
그래프를 탐색하는 알고리즘입니다. DFS는 최대한 멀리 있는 노드를 우선으로 탐색하는 방식으로 동작하며 스택 자료구조를 이용합니다.
Node 클래스
package choi.hyang.study.chapter5;
public class Node {
int value;
Node left;
Node right;
public Node(int value) {
this.value = value;
}
public void left(Node left) {
this.left=left;
}
public void rigt(Node right) {
this.right=right;
}
}
BFS 클래스
package choi.hyang.study.chapter5;
import java.util.LinkedList;
import java.util.Queue;
public class Bfs {
int count = 0;
public int bfs(Node root) {
if(root==null) return 0;
Queue<Node> queue = new LinkedList<>();
queue.offer(root);
while (!queue.isEmpty()) {
int size = queue.size();
for(int i=0; i<size; i++) {
Node node = queue.poll();
if(node.left != null) {
queue.offer(node.left);
}
if(node.right != null) {
queue.offer(node.right);
}
}
count++;
}
return count;
}
}
DFS 클래스
package choi.hyang.study.chapter5;
import java.util.Stack;
public class Dfs {
public int dfs(Node root) {
if(root == null) return 0;
Stack<Node> stack = new Stack<>();
Stack<Integer> countStack = new Stack<>();
stack.push(root);
countStack.push(1);
int max = 0;
while(!stack.isEmpty()) {
Node node = stack.pop();
int count = countStack.pop();
max = Math.max(max, count);
if (node.left != null) {
stack.push(node.left);
countStack.push(count + 1);
}
if (node.right != null) {
stack.push(node.right);
countStack.push(count + 1);
}
}
return max;
}
}
App 클래스(메인)
package choi.hyang.study.chapter5;
public class App {
public static void main(String[] args) {
Node root = new Node(10);
Bfs bfs = new Bfs();
Dfs dfs = new Dfs();
root.left = new Node(9);
root.left.left = new Node(7);
root.left.right = new Node(8);
root.left.left.left = new Node(5);
root.left.left.left.left = new Node(2);
root.left.left.right = new Node(6);
root.right = new Node(11);
root.right.left = new Node(12);
root.right.right = new Node(13);
System.out.println(bfs.bfs(root));
System.out.println(dfs.dfs(root));
}
}
Reference
이것이 자바다.
이것이 코딩테스트이다.
자료구조와 함께 배우는 알고리즘 입문(자바 편)
'Java' 카테고리의 다른 글
4주차 과제: 제어문(feedback, 피드백) (0) | 2020.12.22 |
---|---|
5주차 과제: 클래스(피드백, feedback) (0) | 2020.12.20 |
4주차 과제: 제어문 (0) | 2020.12.12 |
3주차 과제: 연산자(feedback, 피드백) (0) | 2020.11.29 |
3주차 과제: 연산자 (0) | 2020.11.26 |