🦁멋쟁이사자처럼 백엔드 부트캠프 13기 🦁
TIL 회고 - [4]일차
🚀4일차에서는 객체지향프로그래밍에서 객체를 활용하여 어떤 것들을 만들어낼 수 있는지 배웠습니다.
자바에서는 객체의 개념이 매우 중요하기때문에 더 자세히 다룬 4일차였습니다.
저의 경우는 객체에 익숙해지기위해 객체를 활용할 수 있는 실습을 여러가지 진행하였습니다.
<객체지향프로그래밍>
❓Arrays.binarySearch() 메소드
이진 검색은 요소가 오름차순 또는 내림차순으로 정렬된 배열에서 검색하는 알고리즘 입니다.
이진 검색은 선형 검색보다 좀 더 빠르게 검색할 수 있다는 장점이 있습니다.
Arrays.sort()를 통해 정렬을 한 후 정렬된 배열을 토대로
Arrays.binarySearch(검색할 배열, 검색할 값); 의 인자를 넣어주면 검색이 가능합니다.
public static void main(String[] args) {
int[] arr = {5, 3, 1, 4, 2};
Arrays.sort(arr);
int findIndex = Arrays.binarySearch(arr, 4);
System.out.println("찾고자 하는 값이 배열 arr의 [" + findIndex + "]번째에 존재합니다.");
}
❓Arrays.compare() 메소드
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5};
int[] arr2 = {1, 2, 3, 4, 5};
int result = Arrays.compare(arr, arr2);
// 두 배열이 일치하면 0, 일치하지 않으면 -1을 리턴
System.out.println(result);
}
compare(첫번째 배열, 두번째배열) 메소드는 각 두 배열의 값을 비교하여 같으면 0, 다르면 -1을 리턴합니다.
❓명령행 아규먼트
// 명령행 아규먼트에 입력된 값이 없다면
if (args.length == 0) {
System.out.println("사용법 : (java CommandLineArgumentExam 값 값 값 ...처럼 넣어주세요.)");
System.exit(0); // (=return)
}
// 명령행 아규먼트에 입력된 값이 있다면
for(String arg : args){
System.out.println(arg);
}
3일차에서 진행했던 내용처럼 명령행 아규먼트는
1) 터미널 창에서 "java 클래스이름 넣을값, 넣을값, 넣을값..."
처럼 지정해주면, main함수의 String타입 배열 args에 값이 들어감을 확인할 수 있었습니다.
2) IntelliJ에서도 Edit Configuration 창을 통해 그 기능을 제공하는데 Program Argument 블록에 값을 "공백 기준"으로 삽입하면 args에 값이 들어감을 확인할 수 있었습니다.
위 코드는 명령행 아규먼트에 입력된 값이 있으면, for each문으로 배열을 순회하며 출력하고,
명령행 아규먼트에 입력된 값이 없으면, "명령행 아규먼트의 사용법"을 출력한 후
System.exit(0)을 통해 프로그램을 종료하는 것을 확인할 수 있습니다.
System.exit()메소드는 System클래스에서 제공하는 exit() 메소드로
(현재 실행중인 프로그램이나 JVM 인스턴스를 종료해야할때 사용됩니다.)
여기서 System.exit() 메소드는 exit()안의 인자로 status값을 받는데, int 정수형타입으로 값을 받고있습니다.
ex. 0을 넣으면 프로그램 종료
System.exit(0) : 프로그램 종료
(=return : 프로그램 종료)
ex. 0이 아닌 상태인 경우
System.exit(1) : JVM의 비정상적인 종료를 의미합니다.
❓배열을 복사하면 값이 유지될까
먼저 기본형타입일때 값이 유지되는지 확인해볼 수 있습니다.
// i = 10이 있다고 할때,
int i = 10;
// k에 i의 값 10을 대입하고
int k = i;
// i의 값은 10을 증가시킨다.
i += 10;
// 이 코드 이후의 값 : i = 10 -> i = 20
System.out.println("i의 값 = " + i);
System.out.println("k의 값 = " + k);
// 결과값으로 i = 20, k = 10이 출력된다.
이제 배열에서 값이 유지되는지 확인을 해봅니다.
// arr배열에는 1칸짜리 공간이며, 그 1칸에는 10이 들어가있다.
int[] arr = {10};
// arr2배열은 arr의 공간과 똑같이 만들어지며 10이 복사된다.
int[] arr2 = arr;
// arr배열의 10을 10증가시킨다
arr[0] += 10
// 이 코드 이후 : arr[0] = 20
System.out.println("arr[0] = " + arr[0]);
System.out.println("arr2[0] = " + arr2[0]);
// 각각 출력해보면 (arr[0] = 20, arr2[0] = 20) 이 나오는 것을 확인할 수 있습니다.
정리하자면)
1. arr은 10, arr2는 arr의 값이 들어감
2. arr을 +10해주어 arr는 20이됨
3. arr2는 arr의 값이 들어가있지만, "arr은 참조형타입이었으므로 주소를 복사한 것"
4. 자연스럽게 arr2도 arr의 같은 주소값으로 같은 공간을 가리키고 있으므로 값이 20이 됨
기본 데이터 타입은 스택에 들어가있는 것이 값이기때문에 실제 값을 그대로 전달해줍니다.
하지만 레퍼런스 데이터타입은 스택에서 주소가 복사되어서 들어갑니다 (ex. int[] arr2 = arr)
따라서 주소값을 복사해준 arr의 값이 변경되면, 주소값이 복사된 arr2는 arr의 값을 따라갑니다.
❓main메소드 안에서 담당역할이 따로 있는 클래스 만들기
두 정수의 합을 구할때 보통
public class AddMethod01 {
public static void main(String[] args) {
System.out.println("-----숫자를 더하는 프로그램-----");
Scanner sc = new Scanner(System.in);
System.out.print("첫번째 숫자를 입력하세요 : ");
int x = sc.nextInt();
System.out.print("두번째 숫자를 입력하세요 : ");
int y = sc.nextInt();
int sum = x + y;
System.out.println("두 정수의 합은 : " + sum);
}
}
이렇게 main함수 내에 한번에 써줄 수 있지만,
클래스를 분리하여 (더하는 기능을 하는 역할)을 따로 만들어 줄 수 있습니다.
<실습 - 두 수 더하기>
: 개선된 코드 (클래스 분리)
public static void main(String[] args) {
System.out.println("-----숫자를 더하는 프로그램-----");
Scanner sc = new Scanner(System.in);
System.out.print("첫번째 숫자를 입력하세요 : ");
int x = sc.nextInt();
System.out.print("두번째 숫자를 입력하세요 : ");
int y = sc.nextInt();
// 더하는 메소드를 호출 (addNumber())
// : 정수값 2개를 받아 더해주는 기능을 구현
// : [접근제한자] [리턴타입] [메소드명](매개변수들) { 실행할 문장 }
int result = addNumber(x, y);
System.out.println("\n[합하는 메소드 실행완료] 두 숫자의 합 = " + result);
}
public static int addNumber(int x, int y) {
int sum = x + y;
return sum;
}
1. 이처럼 Scanner클래스를 이용하여 사용자에게 두 숫자를 입력
2. 그 두 숫자를 addNumber() 라는 메소드에게 두 숫자를 "매개변수"로 전달
3. 이 addNumber() 메소드에서는 return sum;을 통해 합한 결과를 반환
4. 다시 main함수에서는 그 합한 결과값(=addNumber()메소드로 부터 반환받은 sum값)을
5. int result 에 넣고, 출력하는 코드
이처럼 각각 역할을 담당하는 클래스를 분리해줄 수 있다면 코드의 가독성이 좋아질 것입니다.
❓자바의 객체지향 용어
만약 위의 코드를 개선하여 내부에 있는 (더하기 메소드)를 이용하는 것이 아닌
외부 클래스에서 만들어진 (더하기 메소드)를 사용하고 싶을때는 사용하고자 하는 곳(main)에서
이 외부 클래스의 객체를 생성해주어야합니다.
Pen클래스가 있고, 이 Pen클래스를 main메소드에서 사용하고 싶다면
public static void main(String[] args){
Pen p = new Pen();
}
이렇게 써주어야하는 것입니다. 이렇게 만들어진 것을 "객체"라고 합니다.
💡객체지향에서의 객체(=클래스)는 스스로 자기의 속성(=필드)을 알고 행위(=메소드)를 할 수 있습니다.
(= 클래스는 자기의 필드를 알고 메소드를 수행합니다.)
객체지향에서는 각각의 객체들이 “무생물”이 아닌 각자가 무엇을 할 수 있는지에 대한 기능을 수행합니다.
자바는 객체를 어떻게 도출할것인지, 기능들이 있을때 이 기능을 어떤 객체가 갖고있는것이 좋을지
충분히 고민하고 설계해야합니다.
💡=오브젝트를 무엇을 만들지, 메소드는 무엇을 만들지, 어떤 클래스가 이러한 메소드들을 갖는 것이
좋을지를 고민하고 설계
💡객체지향프로그램은 설계하는데 더 정성을 들여야하는 프로그래밍 입니다.
다시 말해 객체지향은 독립된 객체가 존재한다고 믿고,
객체들이 각각 행위를 잘 할 수 있게 담당해서 동작할 수 있는 프로그래밍기법입니다.
또 다른 대표적인 용어로)
(클래스(class) / 오브젝트(object) / 인스턴스(instance) / 참조형 변수(Reference Variable) 가 있습니다.
<클래스>
= 단지 설계도, 틀
: 클래스만 있어서는 아무것도 할 수 없습니다.
: 필드와 메소드를 가진다 = 속성과 행위를 가진다.
필드 : 클래스의 속성
메소드 : 클래스의 기능
<클래스 선언 방법>
- 첫 문자가 문자나 ‘_’ ‘$’의 특수문자로 시작되어야하고, 숫자로는 불가능하다.
첫문자가 아니라면, 문자나 ‘_’, ‘$’의 특수문자 그리고 숫자로 구성될 수 있다.
- 자바의 예약어는 식별자로 사용할 수 없다.
- 자바의 식별자는 대소문자를 구분한다.
- 식별자 길이는 제한이 없고 공백을 포함할 수 없다.
<클래스 선언 방법 - 프로그래머들간의 관례>
- 클래스 명은 대문자로 시작
- 단어와 단어가 만날 경우 두번째 단어의 시작은 대문자
- ex. class HelloWorld ←
<오브젝트>
= 객체를 뜻합니다.
<이 객체를 다른 객체와 어떻게 관계를 맺으며 이용될 수 있을까?>
콘센트 ↔ 케이블 ↔ 스마트폰
- 앨런 커티스 케이 :
객체지향 프로그래밍과 사용자 인터페이스 디자인 분야의 선구자
”객체지향의 핵심은 “메시징” 모듈 내부의 속성과 행동이 어떤가보다는 모듈이 어떻게 커뮤니케이션 하는지” - 객체는 자율적인 책임을 가진다.
- 자율적인 객체란 스스로 정한 원칙에 따라 판단하고 스스로의 의지를 기반으로 행동하는 객체이다.
- 객체가 어떤 행동을 하는 유일한 이유 = 다른 객체로부터 요청을 받았기때문이다.
- 요청을 처리하기 위해 객체가 수행하는 행동 = 책임
<메시지와 메소드>
[요청이라는 메시지] → 객체
<메소드 선언 방법>
[접근제한자] [static] 리턴타입 [메소드이름] (매개변수) {
실행문
}
: static은 생략가능
<인스턴스>
= 실체 (클래스를 이용해서 실체(진짜 펜)를 만들어낸다)
> 실체를 이용해서 설계도를 만들어냅니다.
new Pen();
// new는 실체를 만들 수 있다. 만들어진 실체를 “인스턴스”라고 부른다.
// new를 통해 메모리 공간에 실제로 올라가게 됩니다.
💡new Pen() = 인스턴스라고 합니다.
<참조형 변수>
=레퍼런스 변수
int[] arr 에서 arr은 레퍼런스 변수
Pen p
Pen p : Pen을 가리킬 수 있는 변수 p 선언 (=참조형 변수 p 선언)
Pen p = new Pen();
펜을 쓰기 위해선 레퍼런스 변수를 통해 인스턴스(실체)를 선언합니다.
<인스턴스를 특별한 이름으로 불러주고싶다면?>
참조형 변수를 선언한다.
<가비지 컬렉터 - 사용되지 않는 인스턴스 처리>
참조되지 않은 인스턴스는 쓰레기(가비지).
가비지 컬렉터가 자동으로 사용되지 않는 인스턴스들을 치워주게됩니다.
<실습 - 세 수 더하기 (외부 클래스 사용)>
// 3개의 숫자를 입력받아 합을 리턴해주는 객체
public class AddMethod02_Add {
public int tripleAdd(int a, int b, int c){
return a + b + c;
}
}
이렇게 클래스를 따로 만들어주고,
import java.util.Scanner;
// 세 개의 숫자를 입력받아 외부 클래스로부터 메소드를 호출하여 값을 리턴해주는 실습
public class AddMethod02 {
public static void main(String[] args) {
AddMethod02_Add add = new AddMethod02_Add();
Scanner sc = new Scanner(System.in);
System.out.println("-----객체로 만드는 합 프로그램-----");
System.out.print("첫번째 숫자를 입력하세요 : ");
int o1 = sc.nextInt();
System.out.print("두번째 숫자를 입력하세요 : ");
int o2 = sc.nextInt();
System.out.print("세번째 숫자를 입력하세요 : ");
int o3 = sc.nextInt();
int result = add.tripleAdd(o1, o2, o3);
System.out.println("[생성된 객체의 메소드로부터 실행완료] 세 숫자의 합 = " + result);
}
}
1. main메소드가 있는 곳에서는 Scanner클래스로 사용자에게 입력을 받아
2. 세 개의 숫자를 입력받고
3. AddMethod02_Add 처럼 생성된 객체로
4. add.tripleAdd(o1, o2, o3) : 그 클래스의 메소드에 접근할 수 있게된다.
5. 세 개의 수를 tripleAdd() 메소드에 전달하고, 그 메소드는 세 개의 수를 더하여 result로 반환한다.
6. 결과값 출력
위와 같은 실습을 활용하면, 계산기 프로그램을 간단히 만들 수 있다.
<실습 - 간단한 계산기 프로그램>
<연산을 수행할 외부 클래스>
// @@**@@
public class Calculator {
public int result(int x, int op, int y){
int calculation = 0;
switch (op){
case 1 :
calculation = x + y;
break;
case 2 :
calculation = x - y;
break;
case 3 :
calculation = x * y;
break;
case 4 :
calculation = x / y;
break;
default :
System.out.println("올바르지 않은 연산입니다.");
return (calculation = -1);
}
return calculation;
}
}
- switch문의 default처리로 덧셈, 뺄셈, 곱셈, 나눗셈의 숫자 1, 2, 3, 4를 제외한 값이 들어오게 된다면
경고문 출력을 하고, -1을 리턴하게끔 하였다.
<계산기 프로그램>
import java.io.BufferedReader;
import java.io.InputStreamReader;
// @@**@@
// 객체를 사용한 계산기 프로그램 실습
public class CalculatorMain {
public static void main(String[] args) throws Exception{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
Calculator cal = new Calculator();
System.out.println("----------계산기----------");
System.out.print("\n첫번째 숫자 입력 : ");
int x = Integer.parseInt(br.readLine());
System.out.println("\n---수행할 연산을 선택하세요---");
System.out.print("(1:덧셈, 2:뺄셈, 3:곱셈, 4:나눗셈) : ");
int op = Integer.parseInt(br.readLine());
System.out.print("\n두번째 숫자 입력 : ");
int y = Integer.parseInt(br.readLine());
System.out.println("\n연산 결과 = " + cal.result(x, op, y));
System.out.println("-------------------------");
}
}
- Scanner 클래스도 사용자로부터 입력받을 수 있지만,
- BufferedReader 클래스도 사용자에게 입력받을 수 있는 기능을 한다.
Integer.parseInt(br.readLine()); : 입력받은 값을 Integer 객체를 활용하여 정수형으로 형변환한다.
br.readLine()은 기본적으로 문자열의 값을 받기때문에 Integer 객체를 활용하여 정수형으로 바꿔줘야한다. - Calculator cal = new Calculator();
위에서 만든 외부 클래스를 main메소드에서 사용할 수 있게 객체(=인스턴스)로 만든다. - cal.result(x, op, y);
첫번째 숫자, 연산자, 두번째 숫자를 매개변수로 전달하여 외부클래스 Calculator에서 연산을 수행 후 반환한다.
❓제한없는 아규먼트 Unlimited Arguments
⭐메소드에 전달할 인자(아규먼트)로 "개수에 상관없이" 받아낼 수 있게함
[리턴타입] [메소드이름] (타입… 변수명){
…
}
public static void main(String[] args) {
int result = addInt(4, 1, 3, 2);
System.out.println("- 수행결과 1) : " + result);
System.out.println("- 수행결과 2) : " + addInt(4, 1));
System.out.println("- 수행결과 3) : " + addInt(5, 3, 1, 2, 3));
System.out.println("- 수행결과 4) : " + addInt(1, 1, 1, 1, 1, 1, 1, 1, 1));
System.out.println("- 수행결과 5) : " + addInt(3, 1, 4, 3, 1, 2, 5));
}
public static int addInt(int... values){
int sum = 0;
for(int x : values){
sum += x;
}
return sum;
}
이처럼 main메소드 안에 더하는 역할을 담당할 addInt()메소드를 만들어주고, 그 메소드는
아규먼트의 개수에 상관없이 입력받고 있으므로, 다양한 매개변수를 전달해보았다.
⭐만약 제한없는 아규먼트의 메소드(addInt)보다, 같은 기능을 하는 정의된 똑같은 addInt메소드가 있을때는
우선순위는 제한없는 아규먼트의 메소드보다 구체적으로 선언해놓은 메소드들이 우선순위를 가진다.
💡이처럼 자바는 메소드 오버로딩을 지원하기때문에 이렇게 활용할 수 있다.
👀간혹 메소드 오버로딩이 안되는 다른 언어들은 메소드마다 다 이름을 다르게 주진 않을 것이기때문에
이렇게 배열의 형태로 받아들여서 그것에 따라 실행을 달리하도록 구현을 하기도합니다.
<추상화>
객체들이 보일때, 객체들이 중요한 부분이 무엇일지 판단하고 그려내는 과정
어떤 목적으로 사용이 될것이냐에 따라 추상화를 하는 기준이 달라질 수 있습니다.
객체에서 필요한 것들만 남기고, 필요없는 것들은 버리는 작업
▶️실습 - 도서 키오스크 프로그램
만약 Book이라는 클래스가 주어지면, 필드로 {책의 이름, 책의 저자, 책의 가격, 책의 저작권, 책의 출판사, 책의 페이지 수 ... 등등}이 모두 담길텐데
추상화를 하게되면, 필요한 것들만 남기게되므로 {책의 이름, 책의 저자, 책의 가격} 정도만 추상화 할 수 있게된다.
public class Book {
String title;
String author;
int price;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
}
- 필드 {title, author, price}에 대해 Getter메소드와 Setter메소드를 만들고,
- 이 필드들을 main메소드에서 객체 인스턴스를 생성하여 접근할 수 있게 만들어본다.
<BookShelf클래스>
static BufferedReader br;
static StringBuilder sb;
static Book b;
static int bookCount = 0;
- BufferedReader : 사용자에게 입력을 받는다.
- StringBuilder : 문자열과 같은 결과값을 누적하여 가지고 있는다. (책의 목록 출력에 필요)
- Book b : Book타입의 참조형 변수 b를 만든다.
- bookCount : 책의 개수를 판단할 Count 변수를 만든다.
위의 변수들은 main메소드뿐만 아니라 BookShelf클래스 안에 있는 다른 메소드에서도 활용이 되어야하므로,
static키워드를 사용하여 다른 메소드에서도 이 변수들이 쓰일 수 있게 선언해주었다.
public static void main(String[] args) throws Exception{
br = new BufferedReader(new InputStreamReader(System.in));
sb = new StringBuilder();
b = new Book();
...
}
- 그 이후 이 변수들이 main메소드에서 활용되므로 "객체(인스턴스)"를 main메소드 안에 생성해준다.
while(true){
System.out.println("---------------[도서 키오스크]---------------");
System.out.println("1:책 등록하기 | 2:책 목록 출력하기 | 3:프로그램 종료");
int button = Integer.parseInt(br.readLine());
switch (button){
case 1:
uploadBook();
br.close(); // BufferdReader의 사용을 종료
continue;
case 2:
if(b.getTitle() != null){
System.out.println("------------------[책 장]------------------");
System.out.println(sb);
}
else{
System.out.println("책장에 책이 비어있습니다.\n");
}
continue;
case 3:
System.out.println("[도서 키오스크]를 종료합니다.");
System.exit(0);
}
}
- while(true) 문을 통해 도서 키오스크 시스템을 출력합니다.
- button으로 명령을 입력받아 switch문에서 각 명령별로 처리해줍니다.
- 책 등록하기 : uploadBook() 메소드를 호출합니다.
- 책 목록 출력하기 : StringBuilder에 담긴 (등록된 책의 정보들)을 출력합니다.
- 프로그램 종료 : System.exit(0)을 통해 전체 프로그램을 종료합니다.
public static void uploadBook() throws Exception{
System.out.print("등록할 책의 이름 : ");
b.setTitle(br.readLine());
String bookTitle = b.getTitle();
System.out.print("[" + bookTitle + "]의 저자 : ");
b.setAuthor(br.readLine());
String bookAuthor = b.getTitle();
System.out.print("[" + bookTitle + "]의 가격 : ");
b.setPrice(Integer.parseInt(br.readLine()));
int bookPrice = b.getPrice();
bookCount++;
sb.append(bookCount + ". '" + b.getAuthor() + "'의 책 [" + b.getTitle() + "] {가격 : " + b.getPrice() + "원}").append("\n");
}
- 책 등록하기 명령에 따라 기능을 하는 uploadBook() 메소드입니다.
- b.setTitle() : 사용자에게 책의 이름을 입력받아 Book클래스에 있는 title필드에 접근하여 title값을 변경합니다.
- b.setAuthor() : 사용자에게 책의 저자를 입력받아 Book클래스에 있는 author필드에 접근하여 author값을 변경합니다.
- b.setPrice() : 사용자에게 책의 가격을 입력받아 Book클래스에 있는 price필드에 접근하여 price값을 변경합니다.
- b.getTitle(), b.getPrice(), b.getAuthor() : 사용자가 입력했던 {책의 이름, 책의 저자, 책의 가격}을 가져옵니다.
- bookCount++ : 책의 목록 출력을 위해 등록된 책이 있을때마다 count를 증가시킵니다.
- sb.append() : 책의 목록 출력을 위해 사용자가 "책의 목록 출력" 명령을 요청하기 전 저장합니다.
▶️실습 - 목장 관리 프로그램
// @@**@@
// 목장 클래스
public class Ranch {
private String name;
private String location;
int numAnimals = 50;
String budget = "3,000,000";
public Ranch() { }
// 생성자로 필드 초기화
public Ranch(String name, String location, int numAnimals, String budget) {
this.name = name;
this.location = location;
this.numAnimals = numAnimals;
this.budget = budget;
}
// 목장이름 얻어내기
public String getName() {
return name;
}
// 목장이름 설정하기
public void setName(String name) {
this.name = name;
}
// 목장의 위치 얻어내기
public String getLocation() {
return location;
}
// 목장의 위치 설정하기
public void setLocation(String location) {
this.location = location;
}
// 동물의 숫자 출력하기
public void printAnimals(){
System.out.println("[" + name + "]목장에는 동물 " + numAnimals + "마리가 존재합니다.");
}
// 목장의 예산 출력하기
public void printBudget(){
System.out.println("[" + name + "]목장의 예산은 " + budget + "원 입니다.");
}
}
- 목장의 정보를 담은 클래스 Ranch
- Getter, Setter 메소드를 통해 각각의 필드를 main메소드에서 접근할 수 있도록 만들어줍니다.
- printAnimals(), printBudget() : 기본적으로 설정된 동물의 마리 수와 예산을 출력합니다.
<RanchManager - 목장관리 프로그램>
// 목장 클래스의 객체 생성 (인스턴스 생성)
Ranch rc = new Ranch();
- 목장 클래스의 객체를 생성
System.out.print("목장의 이름을 설정해주세요 : ");
String ranchName = br.readLine();
rc.setName(ranchName); // 목장이름 Setter메소드 활용
String userRanchName = rc.getName(); // 목장이름 Getter메소드 활용
System.out.print("[" + userRanchName + "]목장의 위치를 설정해주세요 : ");
String ranchLoc = br.readLine();
rc.setLocation(ranchLoc); // 목장위치 Setter메소드 활용
String userRanchLoc = rc.getLocation(); // 목장위치 Getter메소드 활용
- Getter와 Setter를 활용하여 목장 클래스의 필드들을 업데이트
받아온 값들을 println()메소드로 정리하여 실습을 출력하였습니다.
❓Math클래스
3일차에서 util 패키지의 Random클래스를 배울때 함께 알아야하는 것이
바로 java.lang패키지의 Math 클래스입니다.
java.lang패키지에 존재한다는 것은 따로 import를 사용하지 않고 사용할 수 있다는 것입니다.
- 절대값, 최대값, 최소값 등등을 구할 수 있는 유용한 기능의 메소드가 모여있는 곳이 Math클래스입니다.
Random클래스는 util패키지가 import되어야합니다.
java.util.Random;
이 Random클래스를 활용하여
Random random = new Random;
random.nextInt();
주사위를 굴리는 메소드인 roll() 메소드에서 이러한 방식으로 랜덤값을 얻어내는 방법도 있지만,
Math클래스의 random()메소드를 이용할 수도 있습니다.
// Random random = new Random;
// random.nextInt();
Math.random()
객체 Random을 사용하거나 하지 않고 static하기때문에 Math클래스에 바로 접근하여 메소드를 불러올 수 있습니다.
Math클래스의 api를 살펴보면
https://docs.oracle.com/javase/8/docs/api/java/lang/Math.html#random--
Math (Java Platform SE 8 )
Returns the value of the first argument raised to the power of the second argument. Special cases: If the second argument is positive or negative zero, then the result is 1.0. If the second argument is 1.0, then the result is the same as the first argument
docs.oracle.com
0.0부터 1.0사이의 값을 반환하는 것을 알 수 있습니다.
이제 주사위를 굴리는 것이 6까지의 경우의 수가 출력되어야하므로,
System.out.println( (Math.random() * 6) );
처럼 적어주면, 0.0부터 5.xxxxx까지만 출력됩니다. 이를 개선하기 위해 정수형으로 형변환을 하고
System.out.println( (Math.random() * 6) )
더 개선하여 0을 출력하지 않도록합니다. +1을 해주게되면 해결할 수 있습니다.
System.out.println( (Math.random() * 6)+1)
<응용 - 0부터 ~ 45까지의 랜덤 숫자 출력>
System.out.println( (int)(Math.random()*45)+1);
<주사위 굴리는 메소드>
public class Dice {
// 주사위의 속성 - 면, 눈
int face; // 주사위의 면
int eye; // 주사위의 눈
// "주사위의 면"의 개수만큼 굴려서 "주사위의 눈"에 대입
public void roll(){
System.out.println("주사위를 굴렸습니다(1 ~ 6)");
eye = (int)((Math.random()*face)+1);
}
}
<주사위를 실행하는 main 메소드>
public static void main(String[] args) {
// 주사위 실체 만들기 (new키워드로 인스턴스 생성)
Dice dc = new Dice();
// 주사위의 면은 6개라고 전달
dc.face = 6;
// 주사위를 굴려본다.
dc.roll();
// 주사위를 확인해본다.
System.out.println("굴려진 주사위의 눈 : " + dc.eye);
}
지금과 같은 경우는 “같은 패키지”이기때문에 dc.face 처럼 Dice클래스의 필드에 직접 접근하는 것이 가능합니다.
▶️실습 - 간단한 TV
대체로 전원의 파워버튼은 하나이므로 버튼 하나로 (켜기/끄기)를 같이 해야합니다.
turnOn()을 누르면 켜지고 / turnOff()을 누르면 꺼지고 로 나누기보단
public void togglePower(){
power = !power
}
이처럼 toggle 형식으로 이름을 짓는 것이 알맞을 것입니다.
power = !power : boolean power의 원래값을 반대로 바꾼다.
<TV객체>
// 간단한 TV 객체
public class TelevisionExam {
private int channel;
private int volumn;
boolean power;
public void togglePower(){
power = !power;
if(power) {
System.out.println("환영합니다! ^ㅁ^ [TV] 전원 ON\\n");
}
else{
System.out.println("---TV를 종료합니다---");
}
}
public void channelUp(){
this.channel++;
System.out.println("채널을 올립니다. " + channel + "번");
}
public void channelDown(){
this.channel--;
System.out.println("채널을 내립니다. " + channel + "번");
}
public void volumnUp(){
this.volumn++;
System.out.println("볼륨을 올립니다. " + volumn + "번");
}
public void volumnDown(){
this.volumn--;
System.out.println("볼륨을 올립니다. " + volumn + "번");
}
public void setChannel() {
this.channel = channel;
System.out.println("채널을 옮깁니다. " + channel + "번");
}
}
// 간단한 TV 실습
public class TelevisionExamMain {
public static void main(String[] args) throws Exception{
TelevisionExam tv = new TelevisionExam();
tv.togglePower();
tv.channelUp();
tv.volumnUp();
tv.togglePower();
}
}
- TelevisionExam 객체를 main메소드에서 인스턴스로 생성하고, togglePower(), channelUp(), volumnUp(), togglePower()등의 메소드를 수행해보았습니다.
▶️실습 - TV리모컨 프로그램
<TV 클래스>
//@@**@@
// TV 객체 실습
public class Television {
private int channel;
private int volumn = 10; // 기본 볼륨 값 설정
private boolean power;
public void powerTV(boolean power){
if(power) {
System.out.println("환영합니다! [TV]를 켰습니다.");
}
else{
System.out.println("---[TV]를 종료합니다---");
System.exit(0);
}
}
public void channelUp(){
this.channel++;
System.out.println("채널을 올립니다\n현재 채널 : " + channel + "번");
}
public void channelDown(){
this.channel--;
System.out.println("채널을 내립니다\n현재 채널 : " + channel + "번");
}
public void volumnUp(){
this.volumn++;
System.out.println("볼륨을 올립니다\n현재 볼륨 : [" + volumn + "]");
}
public void volumnDown(){
this.volumn--;
System.out.println("볼륨을 내립니다\n현재 볼륨 : [" + volumn + "]");
}
public void setChannel(int channel) {
this.channel = channel;
System.out.println("채널을 옮깁니다.\n현재 채널 : " + channel + "번");
}
public int getChannel() {
return channel;
}
public int getVolumn() {
return volumn;
}
}
- Getter, Setter메소드로 각 필드를 반환하거나 수정해낼 수 있습니다.
- 각 기능을 하는 메소드에서는 println()메소드로 기능을 수행한 후의 출력을 나타냅니다.
<리모컨 클래스>
//@@**@@
// TV 리모컨 프로그램
public class RemoteController {
static Television tv;
static BufferedReader br;
static int screenChannel;
static int screenVolumn;
(main)
}
- static 키워드로 RemoteController 안에서 사용할 각 메소드를 위해 사용범위를 이 클래스 내로 넓힙니다.
outter: while(true){
switch (remotePower){
case 1:
tv.powerTV(true);
watchTV();
break outter;
case 2:
tv.powerTV(false);
default:
System.out.println("잘못 누르셨습니다. 다시 눌러주세요.");
}
}
- 사용자가 전원끄기/켜기 를 입력하면, 수행하는 기능입니다.
- TV클래스의 powerTV()메소드를 수행합니다.
- watchTV()메소드를 수행합니다
- Label 사용으로 while문 밖으로 한번에 빠져나갈 수 있게 설계해줍니다.
- 잘못 입력하였을 경우의 예외처리를 default로 해주었습니다.
<watchTV() 메소드>
private static void watchTV() throws Exception{
while(true){
System.out.println("===========================");
System.out.println("1:채널이동 | 2:채널+ | 3:채널-");
System.out.println("4:볼륨+ | 5:볼륨- | 6:끄기");
System.out.println("===========================");
printScreen();
int button = Integer.parseInt(br.readLine());
switch(button){
case 1:
System.out.print("이동할 채널을 눌러주세요 : ");
tv.setChannel(Integer.parseInt(br.readLine()));
break;
case 2:
tv.channelUp();
break;
case 3:
tv.channelDown();
break;
case 4:
tv.volumnUp();
break;
case 5:
tv.volumnDown();
break;
case 6:
tv.powerTV(false);
default:
System.out.println("잘못 누르셨습니다. 다시 눌러주세요.");
}
}
}
- 리모컨의 버튼을 의미하는 출력문을 출력합니다.
- button으로 사용자에게 명령을 받아
- 각 기능별로 TV클래스의 메소드들에 접근하여 기능을 수행합니다.
<Main메소드가 없는 클래스는 실행되지 않는다>
<TV>
public class TV{
private power;
public static void main(String[] args){
System.out.println("TV클래스의 main메소드");
}
}
갖고 있을 순 있지만, 객체를 생성하여 구성요소를 불러 실행하는 다른 main메소드와는 다르다.
<TVMain>
package day04;
// 간단한 TV 실습
public class TelevisionExamMain {
public static void main(String[] args) throws Exception{
TelevisionExam tv = new TelevisionExam();
tv.togglePower();
tv.channelUp();
tv.volumnUp();
tv.togglePower();
}
}
이처럼 실제 TelevisionExam 객체를 인스턴스로 생성하여 사용하는 main메소드와는 위의 main메소드는 사뭇다르다.
(=사용처가 다르다.)
❓기본생성자
모든 클래스는 생성자를 가집니다.
클래스명 변수명 = new 클래스명();
// (=참조타입 참조변수 = new연산자 생성자)
이 생성자는 (참조타입 참조변수 = new연산자 생성자)의 구조를 가집니다.
컴파일러는 만약 정의된 클래스에 “생성자가 없다면” “기본생성자를” 자동으로 만들게 됩니다.
public class Dice{
public Dice(){ }
}
이처럼 우리는 생략해서 만들지 않았지만, 컴파일러는 기본생성자(=디폴트 생성자)를 자동으로 만듭니다.
생성자는 처음 만들어질때 초기화해주는 역할을 하는데,
기본생성자를 꾸며주면, 이 객체를 사용하는 곳에서 인스턴스로 처음 생성할때
태어날때부터 기본 값을 가지고 태어날 수 있도록 합니다.
▶️실습 - 보이는 계산기 프로그램
객체를 활용하여 만들어봅니다.
보통 클래스에는
- A 메소드
: 입력값, 리턴값이 둘다 없는 메소드
: 접근제한자 void 메소드명() {구현부} - B 메소드
: 입력을 받아서 실행하는 메소드
: 접근제한자 void 메소드명 (매개변수…) {구현부} - C 메소드
: 실행해서 결과를 리턴하는 메소드
: 접근제한자 리턴타입 메소드명() {구현부} - D 메소드
: 입력을 받아서 실행하고 리턴해주는 메소드
: 접근제한자 리턴타입 메소드명 (매개변수들…) {구현부}
이렇게 4가지 메소드의 종류에따라 만들 수 있다.
<이전에 실습했던 계산기와 예제의 계산기를 응용해서 만들어보았습니다.>
<CalculatorDetail - 계산기 객체 클래스>
private int x = 0;
private int y = 0;
private String op = "?";
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public void setOp(String op) {
this.op = op;
}
public String getOp() {
return op;
}
public int result(int x, int y, String op){
int calculation = 0;
switch (op){
case "1" :
calculation = plus(x, y);
setOp("+");
break;
case "2" :
calculation = minus(x, y);
setOp("-");
break;
case "3" :
calculation = multiply(x, y);
setOp("*");
break;
case "4" :
calculation = divide(x, y);
setOp("/");
break;
default :
System.out.println("올바르지 않은 연산입니다.");
return (calculation = -1);
}
return calculation;
}
public int plus(int x, int y){
return x + y;
}
public int minus(int x, int y){
return x - y;
}
public int multiply(int x, int y){
return x * y;
}
public int divide(int x, int y){
return x / y;
}
- Setter로 main메소드로부터 받아온 값들로 필드를 업데이트 시킵니다.
- Getter로 연산자를 main메소드에 있는 Screen에 뿌려주도록 합니다.
- switch문 : op 연산자를 통해 각각 다른 메소드로 이동하여 기능하도록 합니다.
<CalculatorScreen - 계산기 화면>
static BufferedReader br;
static CalculatorDetail cal;
static int x, y;
static String op;
static boolean resultEnd;
- main메소드 뿐만 아니라 다른 메소드에서도 쓰일 수 있도록 static으로 변수를 선언합니다.
printScreen(); // 초기 계산기 화면 출력
System.out.print("첫번째 숫자를 입력하세요 : ");
x = Integer.parseInt(br.readLine());
cal.setX(x);
printScreen();
System.out.print("두번째 숫자를 입력하세요 : ");
y = Integer.parseInt(br.readLine());
cal.setY(y);
printScreen();
System.out.print("(1:덧셈, 2:뺄셈, 3:곱셈, 4:나눗셈) : ");
op = br.readLine();
cal.setOp(op);
int result = cal.result(x, y, op);
printScreen();
System.out.println("\n=-=-=-=-=-계산중-=-=-=-=-=\n");
printScreen(result);
- 초기 아무것도 입력되지 않은 계산기 화면을 출력합니다.
- setX(), setY(), setOp() : Setter메소드로 CalculatorDetail클래스의 필드에 값을 업데이트 해줍니다.
- printScreen() : 숫자 입력, 연산자 입력이 수행될때마다 계산기의 화면을 출력하여, 사용자에게 보여줍니다.
- printScreen(int result) : printScreen()메소드를 오버로딩하여 결과를 출력하는 메소드로 분리시킵니다.
- cal.result(x, y, op); : CalculatorDetail클래스에 있는 result()메소드에 사용자에게 입력받은 변수들을 전달합니다.
- Getter메소드 : 이처럼 첫번째 숫자와 두번째 숫자를 입력받아 계산기 화면에 업데이트 시킵니다.
- 연산을 수행할 연산자까지 입력받아, 계산기 화면에 적용시킵니다.
- 실행결과를 출력하며 프로그램이 종료됩니다.
💡 4일차에는 객체를 활용한 실습을 다양하게 시도해보며 객체를 익히고자 노력하였습니다!🚀
'Recording > 멋쟁이사자처럼 BE 13기' 카테고리의 다른 글
[멋쟁이사자처럼 부트캠프 TIL 회고] BE 13기_6일차_'상속과 메소드 오버라이딩' (1) | 2024.12.09 |
---|---|
[멋쟁이사자처럼 부트캠프 TIL 회고] BE 13기_5일차_'메소드, 필드, static' (3) | 2024.12.06 |
[멋쟁이사자처럼 부트캠프 TIL 회고] BE 13기_3일차_'배열과 객체' (1) | 2024.12.04 |
[멋쟁이사자처럼 부트캠프 TIL 회고] BE 13기_2일차_'자바 기초와 문법' (0) | 2024.12.03 |
[멋쟁이사자처럼 부트캠프 TIL 회고] BE 13기_1일차_'자바 기초' (0) | 2024.12.02 |