5주차 과제: 클래스
목표
자바의 Class에 대해 학습하세요.
학습할 것 (필수)
- 클래스 정의하는 방법
- 객체 만드는 방법 (new 키워드 이해하기)
- 메소드 정의하는 방법
- 생성자 정의하는 방법
- this 키워드 이해하기
클래스 정의하는 방법
자바에서 클래스(Class)란 객체를 정의하는 틀 또는 설계도와 같은 의미로 사용됩니다. 이러한 설계도인 클래스를 가지고 여러 객체를 생성하여 사용하는데, 우리가 흔히 라이브러리를 추가하면 객체를 생성하여 사용할 수 있듯이 이 클래스는 라이브러리라고 생각해도 될 것 같습니다. String
, StringBuffer
, StringBuilder
등과 같이 java.lang
패키지의 클래스들을 모두 자바의 기본 라이브러리들입니다. 이것은 import 없이도 사용할 수 있습니다.
클래스는 객체의 상태를 나타내는 필드(field)와 객체의 행동을 나타내는 메소드(method)로 구성됩니다. (보통 필드명은 지을 때는 명사, 메소드명을 지을 때는 동사로 짓습니다.)
package com.azurealstn.sociallogin.study;
public class Car {
//필드
public String modelName;
public int modelYear;
public String color;
public int maxSpeed;
//메소드
public void accelerate() {
this.maxSpeed += 50;
}
public void carBreak() {
this.maxSpeed = 0;
}
}
public class VS class
여기서 의문점이 들 수 있습니다. class
와 public class
의 차이점은 무엇일까?
이는 자바의 문법 요소 때문입니다. 자바에서 클래스를 생성하면 앞에 public
이란 접근제어자가 붙습니다. 이 public
이 붙은 클래스가 대표 클래스를 의미합니다. 자바에서 클래스 내부에는 여러 개의 클래스를 작성할 수 있습니다. 하지만 하나의 자바 파일안에 여러 개의 클래스를 만들다보면 어떤 클래스를 대표로 컴파일해야하는지 모르기 때문에 하나의 대표 클래스를 지정하고 파일명과 동일하게 하는 것이 규칙입니다.
객체 만드는 방법 (new 키워드 이해하기)
자바에서 객체를 생성하기 위해서는 new
연산자를 사용하면 됩니다. (객체를 생성하는 이유는 해당하는 클래스의 필드 또는 메소드를 사용하기 위해서.)
public class Main {
public static void main(String[] args) {
Car car = new Car();
car.modelName = "람보르기니";
car.modelYear = 2019;
car.maxSpeed = 300;
car.color = "YELLOW";
car.accelerate();
car.carBreak();
System.out.println(car.modelName);
System.out.println(car.modelYear);
System.out.println(car.maxSpeed);
System.out.println(car.color);
}
}
객체 생성 과정
new
연산자가car
객체에 저장될 메모리 할당- 생성자가
car
객체 초기화 new
연산자가 새로 생성된 객체의 주소를car
에 할당car
을 통해Car
클래스의 필드나 메소드 접근 가능
테스트 코드
public class MainTest {
private final Car car = new Car();
@Test
@DisplayName("객체 생성 테스트")
void carTest() {
car.color = "YELLOW";
car.maxSpeed = 350;
car.modelName = "람보르기니";
car.modelYear = 2019;
car.accelerate();
car.carBreak();
assertThat(car.maxSpeed).isEqualTo(0);
assertThat(car.color).isEqualTo("YELLOW");
assertThat(car.modelName).isEqualTo("람보르기니");
assertThat(car.modelYear).isEqualTo(2019);
}
}
메소드 정의하는 방법
메소드 다른 말로 함수라고도 부르며, 메소드란 입력을 가지고 어떤 일을 수행한 다음에 결과물을 내어놓는 것을 말합니다. 그렇다면 이 메소드를 굳이 왜 사용하는 걸까?
그것은 여러 번 반복되는 로직을 줄이기 위해서입니다. 만약에 구구단을 짠 로직을 10번을 사용해야 한다면 10번 모두 그 많은 로직(실제로 적을 수 있지만 일단 heavy한 로직이라고 가정하자..ㅋ) 다 작성해야 합니다. 이러면 코드 가독성이 좋지 않습니다. 참고로 개발자는 반복되는 코드는 최대한 줄이는 것이 중요합니다. 그래서 반복되는 코드는 메소드로 빼놓는 것입니다. 그러면 그 메소드만 호출해주면 해당 로직을 수행되겠죠.
메소드 구조
public 리턴자료형 메소드명(파라미터자료형1 파라미터명1, 파라미터자료형2 파라미터명2, ...) {
...
return 리턴값 //리턴값이 필요없는 경우에는 리턴자료형이 void입니다.
}
메소드 예시
package com.azurealstn.sociallogin;
public class Calculator {
//입력값이 있고, 리턴값이 있는 메소드
public int add(int x, int y) {
return x + y;
}
public int multiply(int x, int y) {
return x * y;
}
//입력값이 없고, 리턴값이 있는 메소드
public String say() {
return "Hello!";
}
//입력값이 있고, 리턴값이 없는 메소드
public void errorPrint(String message) {
System.out.println(message + " 에러 발생!!");
}
//입력값도 없고, 리턴값도 없는 메소드
public void say2() {
System.out.println("Hello");
}
}
만약 특별한 경우에 메소드를 빠져나가기를 원한다면 return
만 써서 메소드를 즉시 빠져나갈 수 있습니다.
public void errorPrint2(String message) {
if (message.equals("success")) {
return;
} else {
System.out.println(message + " 에러 발생!!");
}
}
생성자 정의하는 방법
생성자(Constructor)는 new 연산자와 같이 사용되어 클래스로부터 객체를 생성할 때 호출되어 객체의 초기화를 담당합니다.
인스턴스 변수의 초기화 작업에 주로 사용되며, 인스턴스 생성 시에 실행되어야 할 작업을 위해서도 사용됩니다.
기본 생성자
모든 클래스는 생성자 가 반드시 존재하며, 하나 이상을 가질 수 있습니다. 만약 클래스 내부에 생성자 선언을 생략했다면 컴파일러는 기본 생성자를 바이트코드에 자동 추가시킵니다. 주의할 점은 컴파일러가 자동적으로 기본 생성자를 추가해주는 것은 클래스에 정의된 생성자가 하나도 없을 때 뿐입니다. 만약 하나라도 존재한다면 컴파일러는 기본 생성자를 추가하지 않습니다.
//생략 가능
public Car() {
}
매개변수가 있는 생성자
생성자는 메소드와 비슷한 형태를 띄고 있지만, 리턴 타입이 없고 클래스 이름과 동일해야 합니다.
생성자도 메소드처럼 매개변수를 선언하여 호출 시 값을 넘겨받아 인스턴스의 초기화에 사용할 수 있습니다.
public class Car {
//필드
public String modelName;
public int modelYear;
public String color;
public int maxSpeed;
//매개변수가 있는 생성자
public Car(String modelName, int modelYear, String color, int maxSpeed) {
this.modelName = modelName;
this.modelYear = modelYear;
this.color = color;
this.maxSpeed = maxSpeed;
}
}
말고도 Builder
라는 것이 있습니다. 직접 구글링 해보세요! 실제 웹 개발할 때는 이 Builder
패턴을 더 많이 사용합니다.
객체 생성
기본 생성자만 있을 경우에는 아래와 같이 객체를 생성하면 됐었습니다.
Car car = new Car();
하지만 매개변수가 있는 생성자가 있을 경우에는 객체를 생성할 때 매개변수를 넣어줘야 합니다.
Car car = new Car("람보르기니", 2019, "YELLOW", 350);
또한 매개변수가 없는 객체를 생성해주고 싶다면 기본 생성자를 따로 생성해주면 됩니다.
public Car() {
}
public Car(String modelName, int modelYear, String color, int maxSpeed) {
this.modelName = modelName;
this.modelYear = modelYear;
this.color = color;
this.maxSpeed = maxSpeed;
}
Car car = new Car("람보르기니", 2019, "YELLOW", 350);
Car car1 = new Car();
this 키워드 이해하기
매개변수가 있는 생성자에서 this
키워드를 사용했습니다. this
는 전혀 어렵지 않습니다.
자바에서 this
란 인스턴스 자신을 가리키는 키워드입니다. 바로 예제를 보도록 하죠.
public class Car {
//필드
public String modelName; -> 🏴
public int modelYear;
public String color;
public int maxSpeed;
public Car(String modelName -> 🚩, int modelYear, String color, int maxSpeed) {
this.modelName = modelName;
this.modelYear = modelYear;
this.color = color;
this.maxSpeed = maxSpeed;
}
}
위 코드를 보시면 modelName
이라는 변수명이 필드에 하나(검은색 깃발) 메소드 파라미터에 하나(빨간색 깃발) 있습니다.
그렇다면 this.modelName
은 어느 변수명을 가르키고 있는 것일까요?
또한 = modelName
은 어느 변수명을 가르키고 있는 것일까요?
답은 this.modelName
은 검은색 깃발,= modelName
은 빨간색 깃발을 가르킵니다.
즉, this
는 인스턴스 자신을 가리키는 참조 변수입니다. 그러면 왜 this
키워드를 굳이 사용하는 것일까요? 우리는 비슷한 변수명을 매번 다르게 짓기가 힘듭니다. 그래서 인스턴스 변수명과 메소드 파라미터의 변수명을 같게 하고 이를 구분짓기 위해서 this
를 사용하는 것입니다. static
메소드에서는 this
를 사용하지 못합니다.
this()
this()
는 생성자를 뜻합니다. 같은 클래스 내의 오버로딩된 다른 생성자 메소드를 호출할 때 사용합니다.this()
는 같은 클래스의 다른 생성자를 호출할 때 사용합니다. 바로 코드를 보도록 하죠.
public class Car {
//필드
public String modelName;
public int modelYear;
public String color;
public int maxSpeed;
//매개변수 생성자
public Car(String modelName, int modelYear, String color, int maxSpeed) {
this.modelName = modelName;
this.modelYear = modelYear;
this.color = color;
this.maxSpeed = maxSpeed;
}
public Car() {
this("람보르기니", 2019, "YELLOW", 350);
}
public Car(String color) {
this("람보르기니", 2019, color, 350);
}
}
Car()
생성자와 Car(String color)
생성자는 this()
를 통해 모두 Car(String modelName, int modelYear, String color, int maxSpeed)
생성자를 호출하고 있습니다. Main
클래스에서 출력해보면 모두 동일하게 나옵니다.
this()
를 사용함으로써 코드를 최소화시킬 수 있습니다. 하지만 신입인 저는 아직 this()
를 사용해본 적이 없네요..
public class Main {
public static void main(String[] args) {
Car car = new Car();
System.out.println(car.modelName);
System.out.println(car.modelYear);
System.out.println(car.color);
System.out.println(car.maxSpeed);
System.out.println("=================");
Car car1 = new Car("YELLOW");
System.out.println(car.modelName);
System.out.println(car.modelYear);
System.out.println(car.color);
System.out.println(car.maxSpeed);
System.out.println("=================");
Car car2 = new Car("람보르기니", 2019, "YELLOW", 350);
System.out.println(car.modelName);
System.out.println(car.modelYear);
System.out.println(car.color);
System.out.println(car.maxSpeed);
}
}
BinrayTree를 정의하고 BFS와 DFS 구현
먼저 구현 코드는 https://www.notion.so/Live-Study-5-75f857b63e524d33914a8b3ec6e1e894 블로그를 보았습니다.
Node 클래스
package com.azurealstn.sociallogin.study;
import lombok.AllArgsConstructor;
import lombok.Getter;
@Getter
@AllArgsConstructor
public class Node {
private Node left;
private Node right;
private int value;
}
BinaryTree 클래스
package com.azurealstn.sociallogin.study;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.LinkedList;
import java.util.Queue;
@Getter
@AllArgsConstructor
public class BinaryTree {
private Node root;
public 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 (node.getLeft() != null) {
queue.offer(node.getLeft());
}
if (node.getRight() != null) {
queue.offer(node.getRight());
}
}
System.out.println();
}
public void DFS(Node root) {
if (root == null) {
return;
}
DFS(root.getLeft());
System.out.print(root.getValue() + " ");
DFS(root.getRight());
}
}
테스트 코드
package com.azurealstn.sociallogin.study;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
class BinaryTreeTest {
private static Node root;
private static BinaryTree binaryTree;
@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);
Node node1 = new Node(node2, node3, 1);
binaryTree = new BinaryTree(node1);
root = binaryTree.getRoot();
}
@Test
@DisplayName("root값 가져오기")
void getRootTest() {
assertThat(binaryTree.getRoot().getValue()).isEqualTo(1);
}
@Test
@DisplayName("BFS Test -> level order")
void BFS_Test() {
binaryTree.BFS(root);
}
@Test
@DisplayName("DFS Test -> inorder")
void DFS_Test() {
binaryTree.DFS(root);
}
}
References
'Java' 카테고리의 다른 글
[자바 라이브 스터디] 07. 패키지 (0) | 2021.10.12 |
---|---|
[자바 라이브 스터디] 06. 상속 (0) | 2021.10.12 |
[자바 라이브 스터디] 04. 제어문 (0) | 2021.09.23 |
[자바 라이브 스터디] 03. 연산자 (0) | 2021.09.16 |
[자바 라이브 스터디] 02. 자바 데이터 타입, 변수와 배열 (0) | 2021.09.16 |
댓글