public class Organize{
public static void main(String[] args) {
int max = 0, min = 0;
int[] num = new int [10];//난수 저장할 10개 배열
Scanner sc = new Scanner(System.in);
Random ran = new Random();
System.out.print("최소 정수를 입력하세요 : ");
min = sc.nextInt();
System.out.print("최대 정수를 입력하세요 : ");
max = sc.nextInt();
for(int i = 0; i < num.length; i++) {
num[i] = ran.nextInt(max - min + 1) + min;//배열0~9까지 난수 생성
}
Arrays.sort(num);//오른차순 정렬
for(int a : num) {//for each문으로 출력
System.out.print(a + " ");
}
}
}

화면에 밑에 친구 화살표를 누르면 다른 프로젝트를 실행시키는것을 알 수 있다. Project를 불러오고, 그 안에 Main class파일도 불러오자!!

ctrl+F3 > 원하는 클래스, 메소드 멤버를 상세하게 검색해서 찾아준다.
ctrl + O > 해당 소스의 메소드 리스트 보여
package com.test.memo;
import java.util.Arrays;
import java.util.Random;
class Lotto {
private int[] lotto;// 로또 번호를 출력할 1차원 배열
private Random ran; // 난수를 생성할
public Lotto() {// 굳이 이렇게 위에서 인스턴스을 하지 않고 하는 이유는 가독성때문에
lotto = new int[6];
ran = new Random();
}
public void execute() {
makeLotto();
sortLotto();
printLotto();
}
public boolean chkNum(int idx) {// 배열에 있는 값이 중복되는지 안되는지 검사하는 메서드
for (int i = 0; i < idx; i++) {//idx를 넣지않으니까 값이 안나
if (lotto[idx] == lotto[i]) {
return false;
}
}
return true;
}
public void makeLotto() {// 배열에 난수를 부여하는 메서드 > chkNum으로 검사
for (int i = 0; i < lotto.length; i++) {
lotto[i] = ran.nextInt(45) + 1;// 배열에 1~45 난수 넣기
if (!chkNum(i)) {// 메서드 호출해서 값이 중복되면 true로 해당 배열 삭제
i--;
}
}
}
public void sortLotto() {// 오름차순으로 정렬하는 메서드
Arrays.sort(lotto);
}
public void printLotto() {
for (int i : lotto) {
System.out.print(i + " ");
}
}
}
public class Organize {
public static void main(String[] args) {
Lotto lotto = new Lotto();
for (int i = 0; i < 5; i++) {
lotto.execute();
System.out.println();
}
}
}
마지막 메인 메소드에서 호출할 때
System.out.println(lott.execute()); 이건 호출하면서 반환값을 출력하려고 하는데, execute메소드는 void타입으로 반환값이 없기 때문에 오류가 난다.
생성하고, 배열이 겹치지 않는지 검증되는 메소드, 그 배열을 출력하는 메소드를 하나의 메소드로 모아 그 모아진 메소드를 메인에서 호출하면 한번에 되는게 굉장히 깔끔한것같다.
package com.test.memo;
import java.util.Arrays;
import java.util.Random;
class Lotto {
private int[] lotto;
private int[] number;
private Random ran;
Lotto() {
lotto = new int[6];// 배열 6개
number = new int[45];// 배열 45개
ran = new Random();
for (int i = 0; i < number.length; i++) {
number[i] = i + 1;// 1~45를 순차적으로 배열에 저장
}
}
public void execute() {
shuffle();
sortLotto();
printLotto();
}
public void shuffle() {// 배열에 있는 아무 카드끼리 막 섞게하는 메서드
// > 0~45사이의 난수를 발생시켜서, 첫카드랑 다른 카드랑 10번 섞고, 두번째 카드랑 다른 카드랑 10번 섞게 하는게 j의 역할
for (int i = 0; i < number.length; i++) {
for (int j = 0; j < 10; j++) {
int k = ran.nextInt(45);// 0~45사이에 난수
int temp = number[i];
number[i] = number[k];
number[k] = temp;
}
}
System.arraycopy(number, 0, lotto, 0, 6);// (원본배열, 원본에서 복사를 시작할 인덱스, 대상배열, 대상에서 붙여넣기할 인덱스, 복사항 요소의 수)
} // number배열의 일부를 lotto배열의 일부로 복사 > number배열 0부터 6개의 요소를 lotto배열로 복사하는것
public void sortLotto() {
Arrays.sort(lotto);
}
public void printLotto() {
System.out.println(Arrays.toString(lotto));// [1.2.3]형태로 출력되고 배열의 각 요소를 문자열로 변환해 배열 전체를 한 번에 출력 가능
}
// for(int i : lotto) { //각 배열의 요소를 개별적으로 출력하는 방식
// System.out.print(i + " ");
// }
// }
}
public class Practice2 {
public static void main(String[] args) {
Lotto lot = new Lotto();
for (int i = 0; i < 5; i++) {
lot.execute();
System.out.println();
}
}
}
배열 간의 요소를 복사하는데 사용되는 메서드
System.arraycopy(number, 0, lotto, 0, 6);
number > 복사 할 원본 배열
0 > 원본배열에서 복사를 시작할 인덱스(복사를 시작할 자리 시작점)
lotto > 붙여넣기 할 대상 배열
0 > 대상 배열에서 붙여넣기를 시작할 인덱스
6 > 복사할 요소의 수
따라서
number배열의 일부를lotto배열의 일부로 복사하고 있습니다. 따라서number배열에서0부터 시작하여6개의 요소를lotto배열로 복사하게 됩니다.
배열을 간편하게 출력하기 위한 메서드로,
배열의 각 요소를 문자열로 변환하고, 이를 "[e1, e2, ..., en]" 형식으로 반환합니다. 이를 통해배열 전체를 한 번에 출력
for(int i : lotto)는 각 요소를 개별적으로 출력하는 방식입니다. Arrays.toString()을 사용하면 더 간결하게 배열 전체를 출력할 수 있어서 선택한 방식입니다.package com.test.memo;
import java.util.Arrays;
import java.util.Random;
class Lotto {
private int[][] lotto;
private Random ran;
private final int MAX = 6;// 지정된 열
private int numOfLotto;// 입력받을 행
public Lotto(int numOfLotto) {// 몇 행을 만들것인지
this.numOfLotto = numOfLotto;
lotto = new int[numOfLotto][MAX];
this.ran = new Random();
}
public void execute() {
makeLottos();
sortLottos();
printLotts();
}
public boolean chkNum(int idx, int[] arr) {
for (int i = 0; i < idx; i++) {
if (arr[i] == arr[idx]) {
return false;
}
}
return true;
}
public void makeLotto(int[] arr) {// 한 행을 나타내는 1차원 배열받기
for (int i = 0; i < arr.length; i++) {
arr[i] = ran.nextInt(45) + 1;
if (!chkNum(i, arr)) {// 배열 중 중복되는게 있으면 다시 난수 입력받기
i--;
}
}
}
public void makeLottos() {
for (int i = 0; i < numOfLotto; i++) {
makeLotto(lotto[i]);// 2차원 배열에서 i번째 행을 나타낸것 > i번째 행을 파라미터로 넘김
}
}
public void sortLotto(int[] arr) {
Arrays.sort(arr);
}
public void sortLottos() {
for (int i = 0; i < numOfLotto; i++) {
sortLotto(lotto[i]);
}
}
public void printLotto(int[] arr) {
System.out.println(Arrays.toString(arr));
}
public void printLotts() {
for (int i = 0; i < numOfLotto; i++) {
printLotto(lotto[i]);
}
}
}
public class Practice {
public static void main(String[] args) {
Lotto lotto = new Lotto(5);// 5행을 만들것이라고
lotto.execute();
}
}
class BlockTest {
static {
System.out.println("static { }");
}
{
System.out.println("{ }");
}
public BlockTest() {
System.out.println("생성자");
}
public static void main(String args[]) {
System.out.println("BlockTest bt = new BlockTest(); ");
BlockTest bt = new BlockTest();
System.out.println("BlockTest bt2 = new BlockTest(); ");
BlockTest bt2 = new BlockTest();
}
}
정답
static { }
BlockTest bt = new BlockTest();
{ }
생성자 BlockTest bt2 = new BlockTest();
{ }
생성자
static{}- 정적 초기화 블록은 클래스가 로딩될 때 실행되는 블록으로, 클래스가 처음 사용될 때 한 번만 실행된다. main메서드 실행 전에 실행
BlockTest bt = new BlockTest();- 첫 번째 객체를 생성할 때, 먼저 인스턴스 초기화 블록이 실행되고 생성자가 실행된다.
생성자- 객체를 생성할 때 호출되는 생성자가 실행된다.
따라서 출력 순서는
static[],{},생성자,{},생성자순이다.
class InitTest{
static int cv = 1;//정적 변수
int iv = 1; //인스턴스 변수
static { cv = 2; }
{ iv = 2; }
InitTest(){
iv = 3;
}
}
정적 변수 초기화(static initialization block)
static int cv - 1; - 처음에 정적변수 cv에 1이 할당
static { cv = 2}; - 정적 초기화 블록에서 cv의 값이 2로 변경
정적 초기화 블록은 클래스가 로딩될 때 한 번만 실행
인스턴스 변수 초기화(instance initialization block)
int iv - 1; - 인스턴스 변수 iv에 할당
{ iv = 2;} - 인스턴스 초기화 블록에서 iv의 값이 2로 변경된다. 인스턴스 초기화 블록은 객체가 생성될 때마다 실행
생성자 호출
InitTest() { iv = 3; } - 생성자에서 iv의 값이 3으로 변경된다. 생성자는 객체가 생성될 때 호출되며, 인스턴스 초기화 블록 이후에 실행된다.
최종적으로 객체를 생성하면 cv = 2/ iv = 3이다.
만약 객체를 여러개 생성한다면, 인스턴스 초기화 블록과 생성자는 각 객체 생성 시에 호출된다.
객체로 나눌때 기능적인 부분들은 다 boolean을 이용해 return시키고 출력하는 FrontEnd부분의 클래스에서 return받아와서 출력하는 시스템으로 하자 - 자기들끼리 기능적으로 연동되는것은 거기서 출력해도되고..
package com.test.memo;
import java.util.Scanner;
class PhoneInfo {
private String name, num, birth;
public PhoneInfo(String name, String num, String birth) {
this.name = name;
this.num = num;
this.birth = birth;
}
public PhoneInfo(String name, String num) {
this.name = name;
this.num = num;
}
public String getName() {
return name;
}
public String getNum() {
return num;
}
public void printPhonInfo() {
System.out.print("이름: " + name + " ");
System.out.println("전화번호: " + num + " ");
System.out.println("생년월일: " + (birth != null ? birth : "없음") + " ");
}
}
class PhoneBook {// 각 PhoneBook객체마다 별도의 pInfo 배열을 가지고있다. pb는 정적변수로 한번만 초기화되고, 여러 인스턴스간의 공유된다.
// 따라서 pb변수를 통해 PhoneBooke객체에 접근할 수 있지만, pInfo배열은 각 객체마다 별도로 생성된다.
// 이를 통해 각각의 PhoneBook객체는 고유한 데이터를 저장하고 관리할 수 있는것이다.
private static PhoneBook pb;// pInfo배열이 들어가는 객체의 주소지
private PhoneInfo[] pInfo;// PhoneInfo객체들을 담아두기위한 배열 > 사용자로부터 입력받은 정보를 pInfo배열에 저장
int cnt;// 저장된 번호의 개수
public PhoneBook(int size) {// 최대 저장개수 제한
pInfo = new PhoneInfo[size];
}
public static PhoneBook single(int size) {// 정보배열을 담는 변수 하나로 제한
if (pb == null) {
pb = new PhoneBook(size);
}
return pb;
}
public boolean chkBook() {// 저장 가능한 용량 확인
if (cnt >= pInfo.length) {
return false;
}
return true;
}
public void inputNumSave(String name, String num, String birth) { // 값을 입력받으면 각 배열에 저장
pInfo[cnt++] = new PhoneInfo(name, num, birth);
}
public boolean searchNumByName(String name) {// 이름을 입력받아서 해당 정보를 검색해주는
for (int i = 0; i < cnt; i++) {
if (name.compareTo(pInfo[i].getName()) == 0) {
pInfo[i].printPhonInfo();
return true;
}
}
return false;
}
public int deleteNumByNum(String num) {// 삭제할 번호를 입력받아서 해당 번호가 배열 어디에 있는지 찾는 메서드
for (int i = 0; i < cnt; i++) {
if (num.compareTo(pInfo[i].getNum()) == 0) {
return i;
}
}
return -1;
}
public boolean deleteNum(String num) {// 배열에서 번호를 찾으면 삭제하고 배열을 한칸씩 당김 , 없으면 false반환
int searchResult = deleteNumByNum(num);
if (searchResult != -1) {
for (int i = searchResult; i < cnt - 1; i++) {// 삭제할 번호의 인덱스 이후의 배열 요소를 한 칸씩 앞으로 당긴다.
// 만약 마지막 인덱스면 for문이 실행되지 않고 넘어간다. 왜냐하면 조건이 searchResult -1 이니까
pInfo[i] = pInfo[i + 1];
}
pInfo[cnt - 1] = null;// 앞으로 당겨 삭제된 마지막 요소를 null로 초기화한다.
cnt--;
return true;
}
return false;
}
public void allPrint() {
for (int i = 0; i < cnt; i++) {
pInfo[i].printPhonInfo();
}
System.out.println();
}
}
class OpenUI {
private static PhoneBook pb = PhoneBook.single(100);// 여기서 최대 배열 100이라고 선언
static Scanner sc = new Scanner(System.in);
public static void printUI() {// 처음 사용자에게 보기 보여주기
System.out.println("선택하세요...");
System.out.println();
System.out.println("1.데이터 입력");
System.out.println("2.데이터 검색");
System.out.println("3.데이터 삭제");
System.out.println("4.모든 데이터 보기");
System.out.println("5.프로그램 종료");
System.out.print("선택 :");
}
public static void inputPhoneNum() {// 용량이 괜찮으면 입력받아서 배열에 저장하는 메서드로 보내기
String name, num, birth;
if (pb.chkBook() == true) {
System.out.println("데이터 입력을 시작합니다.");
System.out.print("이름: ");
name = sc.nextLine();
System.out.print("전화번호: ");
num = sc.nextLine();
System.out.print("생년월일: ");
birth = sc.nextLine();
pb.inputNumSave(name, num, birth);
System.out.println("데이터 입력이 완료되었습니다.");
} else {
System.out.println("더 이상 데이터를 저장할 수 없습니다. 데이터를 삭제 후 진해해주십시오.");
return; //호출한 곳으로 돌아감
}
}
public static void searchPhoneNum() {// 이름을 입력하면 번호 찾아주기
String name;
System.out.println("데이터 검색을 시작합니다.");
System.out.print("이름: ");
name = sc.nextLine();
if (pb.searchNumByName(name)) {
System.out.println("데이터 검색이 완료되었습니다.");
} else
System.out.println("해당하는 이름이 없습니다.");
}
public static void deletePhoneNumByNum() {
String num;
System.out.println("데이터 삭제를 시작합니다.");
System.out.print("번호: ");
num = sc.nextLine();
if (pb.deleteNum(num) == true) {
System.out.println("데이터 삭제가 완료되었습니다.");
}else {
System.out.println("해당하는 번호가 없습니다. 다시 입력하세요.");
}
}
public static void printAll() {
System.out.println("모든 정보를 출력합니다.");
pb.allPrint();
}
public static void closeNum() {
System.out.println("프로그램을 종료합니다.");
sc.close();
}
public static void worngInput() {
System.out.println("잘못된 입력입니다 다시 입력하세요.");
}
}
public class Practice {
private static final int INSERT_NUM = 1;
private static final int SEARCH_NUM = 2;
private static final int DELETE_NUM = 3;
private static final int PRINT_ALL_NUM = 4;
private static final int QUITE_APP = 5;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int user = 0;
while (true) {
OpenUI.printUI();
user = sc.nextInt();
sc.nextLine();
switch (user) {
case INSERT_NUM:
OpenUI.inputPhoneNum();
break;
case SEARCH_NUM:
OpenUI.searchPhoneNum();
break;
case DELETE_NUM:
OpenUI.deletePhoneNumByNum();
break;
case PRINT_ALL_NUM:
OpenUI.printAll();
break;
case QUITE_APP:
OpenUI.closeNum();
return;//break; 였었는데 OpenUI.clseNum();에서 Scanner를 close했는데 while문으로 다시 입력받으려고 하니까 오류가 난것이였다.
default:
OpenUI.worngInput();
}
}
}
}
자꾸 종료되는 부분의 메서드를 깜빡함..
nextInt();로 입력받으면 엔터값이 버퍼에 남아있어서 nextLine();으로 빼줘야하는데 깜빠꾸한다..
PhoneBook클래스에서 싱글톤으로 만들어주는 메서드를 처음 OpenUI 클래스를 만들었을때 new로 객체를 생성하는게 아니라 싱글톤으로 만들어준는 메서드로 가서 만들어주는 것이다.
PhoneBook클래스에서 deleteNum메서드는 완전히 식을 잘못썼다. (14일차 수업때 넣은건 순 엉터리였다 삭제해야지..)
마지막 종료를 할 때 Exception in thread "main" java.lang.IllegalStateException: Scanner closed 라고 계속 오류가 떴었는데, 이게 사용자에게 int로 입력받을때로 계속 오류가 났다.
알고보니 Practice 메인 클래스에서 OpenUI.closeNum();을 호출해 스캐너를 close해줬는데 현재 while문이 무한루프이므로 사용자에게 입력값을 다시 받으려고 하는것이다.
package com.test.memo;
import java.util.Random;
import java.util.Scanner;
class BaseBall {
private int[] com;
private int[] user;
private Random ran;
private int strike, ball;
public final int MAX;
public final int START_NUM;
public final int END_NUM;
public BaseBall(int num) {// 사용자에게 입력받은 자리수
this.MAX = num;
com = new int[MAX];
user = new int[MAX];
ran = new Random();
START_NUM = setStart();
END_NUM = START_NUM * 10 - 1;
makeComNum(com);// 난수 만들어주는 메서드
// printCom();// 디버깅 용도
}
private int setStart() {// 입력받은 수 에 따라 난수 시작점 정해주는 메서드
int a = 1;
for (int i = 0; i < MAX - 1; i++)
a *= 10;
return a;
}
private boolean numRange(int num) {// 적합한 범위에 있는지 확인하는 메서드
if (START_NUM > num || num > END_NUM) {
return false;
}
return true;
}
private boolean chkNum(int[] arr) {// 중복되는 배열이 없는지 확인하는 메서드
for (int i = 0; i < arr.length; i++) {
for (int j = i + 1; j < arr.length; j++) {
if (arr[i] == arr[j])
return false;
}
}
return true;
}
private void mkArr(int[] arrNum, int num) {// 숫자를 자릿수별로 나누어 배열에 저징하는 메서드
int divisor = 1;
for (int i = 0; i < arrNum.length - 1; i++) {
divisor *= 10;
}
for (int i = 0; i < arrNum.length; i++) {
arrNum[i] = num / divisor;
num %= divisor;
divisor /= 10;
}
}
private void makeComNum(int[] arr) {// 컴퓨터 값 난수로 만들어주 메서드
while (true) {
int ranNum = ran.nextInt(END_NUM - START_NUM - 1) + START_NUM;// 발생되는 난수 범위
mkArr(arr, ranNum);
if (chkNum(arr))// 중복값이 존재하면 다시 난수 발생해서 넣기
break;
}
}
private void printCom() {// 디버깅 용
for (int a : com) {
System.out.print(a);
}
System.out.println();
}
// private void inputUserNum(int num) {//사용자에게 받은 수를 배열에 넣는
// 이것도 이렇게 하드코딩 할 필요없이 위에 일반화한 메서드 사용
// for(int i = 0; i < user.length; i++) {
// user[i] = num % 10;
// num /=10;
// }
// }
public boolean userNum(int num) {// 사용자 입력값이 범위안에 있는지
boolean result = true;
if (numRange(num)) {
mkArr(user, num);// 사용자가 입력한 값을 배열에 넣고
result = chkNum(user);// 검증해서 리턴
} else
result = false;
return result;
}
public void palyGame() {// strike, ball이 몇번나오는지
int strike = 0;
int ball = 0;
for (int i = 0; i < com.length; i++) {
for (int j = 0; j < user.length; j++) {
if (com[i] == user[j]) {
if (i == j) {
strike++;
} else {
ball++;
}
}
}
}
this.strike = strike;
this.ball = ball;
}
public boolean showResult() {// 결과를 보여주고, 홈런이면 종료되고, 아니면 계속 진행
boolean result = false;
if (strike == com.length) {
System.out.println("홈런!!!");
result = true;
} else if (strike == 0 & ball == 0) {
System.out.println("아웃입니다.");
} else {
System.out.println(strike + "스트라잌" + ball + "볼");
}
return result;
}
}
class BaseBallGame {
private BaseBall computer;// 위 클래스와 연결시키는
public BaseBallGame(int numberDigits) {
this.computer = new BaseBall(numberDigits);// 사용자에게 입력받아서 넣는 자리수
}
private boolean attack(int num) {// 사용에게 값을 받아서
return computer.userNum(num);// 배열에 넣는 메서드 호출
}
public boolean playGame(int num) {
boolean result = false;
if (attack(num)) {
computer.palyGame();
result = computer.showResult();
} else {
System.out.println("숫자는 " + computer.START_NUM + "이상 " + computer.END_NUM + "이하의 겹치지 않는 수여야 합니다.");
}
return result;
}
}
public class Practice {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int numberDigits = 0;
int userNum = 0;
System.out.println("숫자 야구 게임을 시작합니다.");
while (true) {
System.out.println("원하는 자리수를 선택하세요");
System.out.println("1~9까지 선택가능");
numberDigits = sc.nextInt();
if (numberDigits >= 1 && numberDigits <= 9)
break;
System.out.println("잘못 입력하셨습니다.");
}
BaseBallGame bGame = new BaseBallGame(numberDigits);
while (true) {
boolean result;
System.out.println("자 공격하세요.");
userNum = sc.nextInt();
result = bGame.playGame(userNum);
if (result) {
System.out.println("게임을 종료합니다.");
break;
}
}
sc.close();
}
}
숫자야구에서 난수를 만들어서 배열에 넣는 로직을 일반화시켜서 값을 받아와서 하면 간편한데 하나씩 하드코딩으로 하려해서 뭔가 아다리가 안맞았던것
디버깅 용으로 출력하는 메시지에 println으로 붙여서 for문으로 돌리니까 띄어쓰기가 그렇게 많이 출력된던것
선생님이 보던 코드 같이 보면서 생각하면서 만들었는데 오류가 너무 많았다.. 아직 무슨 기능이 필요하고 어디에서 호출해서 연결 시켜야할지 메서드로 기능만드는 부분이 미숙한것같다.