개인/풀이

220103 과제 보강

jumphare 2022. 1. 3. 22:29
회원정보를 클래스(MemberInput)에 입력받고 클래스(MemberInfo)의 멤버변수에 저장시킨 후 출력하는 프로그램
(2명 이상의 회원 정보를 입력받는다.)

 

1. 설명 및 목표

  • 키보드를 이용해 각 회원들의 정보를 입력받는 클래스(MemberInput)를 작성한다 
  • 입력한 회원의 정보를 클래스(MemberInfo)의 private 멤버변수에 저장한다.
  • 클래스(MemberInfo)의 메소드를 이용해 출력한다.

 

2. 이론

 접근제어자(Access Modifier)는클래스 및 클래스의 구성 멤버에 대한 접근을 제한하는 역할을 한다. 클래스, 필드, 메소드, 생성자의 범위를 제한해줄 수 있다. 

 멤버변수(Field)란 메소드 바깥에 정의되는 변수로, 값이 heap 메모리 영역에 저장된다. 동일 클래스(생성자, 메소드) 안에서는 모두 사용이 가능하고, 다른 클래스에서 사용하고자 할 때는 참조형(클래스, 배열, 인터페이스)을 이용해 new 연산자로 객체를 생성하고 생성자로 값을 초기화한 뒤 heap 영역에 새로운 공간을 할당받는다. 이때 생성한 변수를 이용해 접근할 수 있다.

 물론 여기에 static이 붙으면 정적 멤버변수이므로 heap이 아니라 static 영역에 할당되므로 그때엔 new 연산자로 할당할 필요 없이 클래스명.연산자로 곧바로 접근할 수 있다. 또, static이 붙더라도 private가 붙어버리면 접근제어자에 의해 동일 클래스 내에서만 사용이 가능하므로 메소드를 이용해 접근하는 방식을 취해야 한다.

 this. 연산자는 매개변수와 필드명이 동일할 때 객체의 필드임을 명확히 하기 위해 사용한다.

 

3. 세부 내용

class MemberInfo {

	private String[][] input = new String[5][4];
	int i;

	public void Member(String name, String age, String email, String address) {
		input[i][0] = name;
		input[i][1] = age;
		input[i][2]  = email;
		input[i][3] = address;
		i++;
	}

회원 정보를 저장할 MemberInfo 클래스이다. 임의로 5명의 정보를 받기로 하였으므로 [5][4] 크기의 2차원 배열을 private로 만든다. 회원 정보는 Member 메소드를 이용해 MemberInput 클래스에서 입력받을 것이고, 입력받은 값은 2차원 배월의 첫 행에 차례로 들어간다. 멤버변수 i는 초기값이 0이므로 따로 0으로 지정해주지 않아도 되고, Member 메소드 실행이 끝나면 마지막에 값이 하나 증가해 다음으로 또 매개변수로 값이 들어오게 되면 두 번째 행으로 들어가도록 처리한다.

	public void print() {
		for (int j = 0; j < i; j++) {
			System.out.println((j + 1) + "번 회원님의 정보");
			System.out.println("이름: " + input[j][0]);
			System.out.println("나이: " + input[j][1]);
			System.out.println("이메일: " + input[j][2]);
			System.out.println("주소: " + input[j][3]);
			System.out.println();
		}
	}
}

MemberInfo 클래스의 print 메소드이다. 회원정보가 저장되어 있는 배열값을 for문을 이용해 출력할 건데, 위의 Member 메소드에서 i가 입력받은 회원 수만큼 증가했을 것이므로 (3명 받았을 때 3) 값을 받은 만큼만 출력시키기 위해 for문이 돌아가는 범위를 0<=j<i로 지정해준다.

	public static void main(String[] args) {
		String a;
		String name, age, email, address;
		Scanner sc = new Scanner(System.in);
		System.out.println("정보를 입력하세요(최대 5명)");

		MemberInfo info = new MemberInfo();

		for (int i = 0; i < 5; i++) {
			System.out.print("이름: ");
			name = sc.next();
			System.out.print("나이: ");
			age = sc.next();
			System.out.print("이메일: ");
			email = sc.next();
			System.out.print("주소: ");
			address = sc.next();

			info.Member(name, age, email, address);

MemberInput2 클래스의 main 메소드이다. for문 밖에서 MemberInfo 클래스에 접근하기 위해 객체를 생성해준다. 그리고 for문을 통해 name, age, email, address 값을 받아 info.Member로 Member 메소드에 매개변수 값을 리턴시켜준다.

			if (i == 4) {
				System.out.println("다섯 명 입력 완료");
				System.out.println();
				info.print();
				break;
			}

			System.out.println("더 입력하시겠습니까? (현재" + (i + 1) + "명) Y/N");
			a = sc.next();
			if (a.equals("N") || a.equals("n")) {
				info.print();
				break;
			}
		}

i==4인 경우 5명이 전부 입력된 상태이므로 다섯 명의 정보를 출력한 뒤 break로 for문을 빠져나간다.

5명이 전부 채워지지 않은 경우 현재 인원수와 더 입력하겠냐는 문구를 보여준다. Y를 입력한 경우 다시 for문이 실행되고 N을 입력한 경우 지금까지 채워진 n명의 정보를 출력한 후 for문을 빠져나간다.

 

 

4. 실행 결과

세 명의 정보를 입력했을 때의 출력 화면. 저장된 값이 제대로 출력되었다.
다섯 명의 정보를 입력했을 때의 출력 화면. 마지막에 '다섯 명 입력 완료' 문구 뒤로 입력된 회원들의 정보가 출력된다.

 

5. 고찰

 일단 한 명의 정보를 저장해 출력할 때랑 차이가 많이 났다. 처음엔 한 명을 받았을 때처럼 생성자로 매개변수 값을 멤버변수 값으로 초기화시키는 방법을 시도해봤는데 계속 마지막에 입력한 회원 정보값이 배열의 첫 행에 들어가고 그 뒤로는 배열에 값이 들어가지 않았다. 생성자 내에서 i값을 변화시켜도 결과값은 똑같았다. 추측컨대 생성자에서는 매개변수가 지정되지 않은 i의 값을 따로 변경시킬 권한이 없고? 그래서 배열도 i의 초기값인 0이 들어간 첫 행으로만 입력받는 게 아닐까 싶다. 이 글을 쓰면서 그럼 i를 매개변수로 지정하면 어떨까? 싶어 시도하고 왔는데 아예 null값이 나온다. 도대체 왜 안 되는 건지 알 수가 없다. 과제를 제출하며 질문을 적었으니 아마 내일이면 이유를 알 수 있지 않을까 싶다. 만약 알게 되면 이 아래에 추가하도록 하겠다. 아무튼, 그런 이유로 생성자 대신 메소드를 이용해 i값을 변화시키며 각 배열에 회원 정보 값을 입력하였고 문제없이 저장되어 출력되는 것을 확인할 수 있었다. 또, 몇 명을 입력시키든 끝에 '더 입력하시겠습니까?' '이름: ' 문구가 자꾸 추가되는 것을 확인했는데, 이건 if문 끝에 break;를 붙여 할 일이 끝나면 for문을 빠져나가게 만드는 것으로 간단히 해결할 수 있다. 이와 별개로 내가 만드는 코드는 굉장히 비효율적인 것처럼 느껴지는데, 다른 사람들이 해결하는 것처럼 깔끔하게 만들고 싶다는 욕구가 자꾸 생긴다. 배운 게 더 많아진다면 효율적인 방식을 선택해서 쓸 수 있을까, 나 하기에 달린 일이니 열심히 공부해야겠다.

 

0104 과제 확인

1.

나: 필드에 2차원 배열을 선언함 String [][] input=new String[5][4];
답: 메인 메소드에 객체 배열을 변수로 클래스에 접근함 MemberInfo[] m=new MemberInfo[5];
-> 메인 메소드에 객체 배열을 변수로 선언, new 연산자로 각 배열마다 영역을 할당하고, 입력받은 값을 생성자로 필드에 넘겨 초기화시켜 저장하게 됨 
각 배열마다 새 영역을 할당해 필드의 값을 각자 집어넣을 수 있음
+ 메소드로 값을 받을 필요 없고 생성자만 이용하면 됨
+ 서로 다른 자료형의 값을 집어넣을 수 있음 (필드의 자료형은 변하지 않으니까)
이렇게 메모리 값을 일시적으로 저장해주는 클래스 -> DTO(Data Transfer Object)데이터 접근 객체

내 값이 가장 마지막에 선언한 값만 들어갔던 이유... new 연산자로 할당한 영역은 하나뿐이었고 그 영역의 초기값은 생성자로 넣어주는 값이기 때문에... 객체 배열로 n개 선언해주면 new로 할당하는 영역도 n개이고 각 영역마다 생성자가 값을 초기화시켜줌 -> 정보 여러개 입력 가능!

 

2.
나: MemberInfo 클래스에 print() 메소드 만들어 사용
답: 출력을 main에서 하고 getter 메소드를 사용
-> 객체 배열을 사용하는 경우 2차 배열 대신
m[i].getName()
m[i].getAge()
..... 이걸 for문 돌려서 출력하는게 좀더 효율적임! setter와 getter를 언제, 어디서, 왜 사용하는지 계속 확인하고 필요 시 응용할 수 있도록 해야함

3.
나: String 문자열 입력받을 때 .next() 사용
답: .nextLine() 사용
-> 띄어쓰기 포함된 모든 문자열을 저장하려면 nextLine()을 사용해야함. next()는 주소를 입력할 때 서울시 강서구... 에서 서울시만 값을 저장하게 됨
+ int형 nextInt() 사용 뒤 nexLine() 추가해주면 -> 숫자 입력 후 enter키 누르면 null값 리턴 (오류 없애기)

4. 정해지지 않은 n명의 정보를 입력하고 싶다면 for보다 while을 이용하는 걸 추천함

 

6. 전체 코드