오늘 수업 내용

* 클래스와 인스턴스 활용하는 여러 예제를 다룬다.

* 메소드 오버로딩(메소드 중복 정의)에 대해 배운다.

 - 메소드 오버라이딩(메소드 재정의)과 명칭이 비슷해서 헷갈릴 수 있다. 메소드 오버라이딩은 자바15(2020.0824) 에서 다룬다.

* 만년달력 예제를 다룬다.

* 주민번호 유효성 검사 예제를 다룬다. (예전에는 실무적으로 사용했지만 현재는 잘 사용하지 않는다. 연습용 예제)


메소드 오버로딩(Method Overloading, 메소드 중복 정의)

메소드가 처리하는 기능은 같고 

 - 메소드 괄호 속에 오는 인수(인자, 매개변수, 파라미터)의 갯수가 다르거나

 - 메소드 괄호 속에 오는 인수의 자료형(Data Type)이 다른 경우

메소드의 이름을 동일한 이름으로 부여하여 메소드를 정의할 수 있도록 문법적으로 허용하게 되는데 이를 메소드 오버로딩(Method Overloading)이라고 한다.

 

* 메소드 오버로딩을 사용할 때 메소드의 반환형은 같아야하며, 매개변수는 같으나 반환형은 다르다는 조건은 메소드 오버로딩에 성립되지 않는다.

   ex) ①void write(int n)  /  ②void write(String str) → write("김소소") 를 호출하면 ②메소드를 호출한 것

   ex) ①int print()  /  ②void print() → print() 메소드를 호출했을 때 둘 중 어떤 메소드를 호출한 건지 전혀 구분할 수 없으므로 메소드 오버로딩이 성립되지 않는다.

 

※ 메소드 오버로딩 : 메소드 중복 정의 (같은 이름의 메소드를 정의한다.)

※ 메소드 오버라이딩 : 메소드 재정의 (상속받은 메소드의 정의부를 새로 정의한다. 자바15 포스팅 참조)

 

예제 코드

/*=================================================
  ■■■ 메소드 중복정의(Method Overloading) ■■■
=================================================*/

public class Test106
{
	public static void main(String[] args)
	{
		drawLine();
		//--==>> ====================

		
		drawLine('+');
		//--==>> ++++++++++++++++++++

		drawLine('>');
		//--==>> >>>>>>>>>>>>>>>>>>>>
		
		drawLine('/', 50);
		//--==>> //////////////////////////////////////////////////
		
		
		drawLine('+', 30);
		//--==>> ++++++++++++++++++++++++++++++
	}


	// 선을 그리는 메소드 정의
	public static void drawLine()
	{
		System.out.println("====================");
	}

	// 선의 형태를 바꾸어 그리는 메소드 정의
	public static void drawLine(char c)
	{
		for (int i=0; i<20; i++)
		{
			System.out.print(c);
		}
		System.out.println();
	}

	// 선의 형태와 길이를 바꾸어 그리는 메소드 정의
	public static void drawLine(char c, int n)
	{
		for (int i=0; i<n; i++)
		{
			System.out.print(c);
		}
		System.out.println();
	}
}

 

메소드 오버로딩(Method Overloading) 이 가능한 형태와 불가능한 형태

 

/*===================================================
  ■■■ 메소드 중복정의(Method Overloading) ■■■
  - Method Overloading 이 가능한 형태와 불가능한 형태
===================================================*/

public class Test107
{
	public static void main(String[] args)
	{
		print('A');

		double result = print(10.0);
		print(10.0);
	}

	public static void print() {}
	public static void print(int i) {}
    	// print('A') : 매개변수 char 함수 없어도 매개변수 int 함수 불러서 컴파일 할 수 있음
	
    	//public static void print(int j) {}	//--(x)
    
	public static void print(char c) {}	//-- 자동 형 변환 규칙 check 하면서 써야함
	public static void print(int i, int j) {}
	public static void print(double d) {} 	//-- 자동 형 변환 규칙 check 하면서 써야함
    
	//public static double print(double d) {return 3.14;}	//--(x)
	//public static void print(double d) {return 3.14;}	//-- 정의 불가
	//public static void print(double e) {}			//--(x)

}

클래스와 인스턴스 활용 예제 1

학생별로 국어점수, 영어점수, 수학점수를 입력받아 총점, 평균을 계산하는 프로그램을 구현한다.
단, 클래스의 개념을 활용하여 작성할 수 있도록 한다.
또한, 이 과정에서 배열을 적극적으로 활용할 수 있도록 한다.

○프로그램을 구성하는 클래스
1. Record 클래스 → 속성만 존재하는 클래스로 설계할 것
2. Sungjuk 클래스 → 인원 수를 입력받아, 입력받은 인원 수 만큼 이름, 국어점수, 영어점수, 수학점수를 입력받고 총점과 평균을 산출하는 클래스로 설계할 것 
 · 속성 : 인원수, Record 형태의 배열
 · 기능 : 인원수 입력, 상세 데이터 입력, 총점 및 평균 연산, 결과 출력
3. Test104 클래스 → main() 메소드가 존재하는 외부 클래스로 설계할 것

/*===============================
  ■■■ 클래스와 인스턴스 ■■■
  - 클래스와 인스턴스 활용
===============================*/

// Record.java / Sungjuk.java / Test104.java 세트~!

// 1. Record 클래스

public class Record
{
	// 학생 1명을 표현할 수 있는 속성들로 구성

	String name;			//-- 이름
	int[] score = new int[3];	//-- 각 과목의 점수 → int kor, eng, mat;
	int tot;			//-- 총점
	double avg;			//-- 평균
	int rank;			//-- 등수(석차)
}
/*===============================
  ■■■ 클래스와 인스턴스 ■■■
  - 클래스와 인스턴스 활용
===============================*/

// Record.java / Sungjuk.java / Test104.java 세트~!

// 2. Sungjuk 클래스

import java.util.Scanner;

public class Sungjuk
{
	// 주요 속성 구성(주요 변수 선언)
	int inwon;	//-- 인원 수
	Record[] rec;	//-- Record 배열(학생 한 명 당 Record 배열 방 한 개 활용)
			//   Record를 기반으로 생성된 객체만 담아낼 수 있는 배열

	// 주요 메소드 구성(기능 구성 → 메소드 정의)
	// ① 인원 수 입력	
	public void set()
	{
		Scanner sc = new Scanner(System.in);

		do
		{
			System.out.print("인원 수 입력(1~100) : ");
			inwon = sc.nextInt();
		}
		while (inwon<1 || inwon>100);

		// check~!!!
		// Record 클래스를 기반으로 생성된 객체(인스턴스)를 담을 수 있는
		// 배열방을 inwon 만큼 생성한 것이지
		// Record 클래스의 인스턴스를 생성한 것은 아니다.
		rec = new Record[inwon];
	}

	// 주요 메소드 구성(기능 구성 → 메소드 정의)
	// ② 상세 데이터 입력 (이름, 국어점수, 영어점수, 수학점수 입력) + 총점 평균 산출
	public void input()
	{
		Scanner sc = new Scanner(System.in);

		String[] title = {"국어 점수 : ", "영어 점수 : ", "수학 점수 : "};

		// 인원 수 만큼 반복 → 인원 수에 기반하여 만들어진 배열의 길이만큼 반복
		for (int i=0; i<inwon; i++)	// for (int i=0; i<rec.length; i++)
		{
			// check~!!! (가장 핵심!!!★★★)
			// Record 클래스 기반의 인스턴스 생성

			//Record ob = new Record();
			//rec[i] = ob;
			rec[i] = new Record();

			//rec[i].name = "홍길동";
			System.out.printf("%d번째 학생의 이름 입력 : ", (i+1));
			rec[i].name = sc.next();


			for (int j=0; j<title.length; j++)
			{
				// 안내 메세지 출력
				System.out.print(title[j]);

				// 사용자가 입력한 데이터를 스코어(score) 배열에 담아내기
				rec[i].score[j] = sc.nextInt();	// score[0] → 국어 점수
								// score[1] → 영어 점수
								// score[2] → 수학 점수

				// 국어, 영어, 수학 점수 데이터 입력받는 동안
				// 총점 누적하기
				rec[i].tot += rec[i].score[j];
			}

			// 평균 산출하기
			rec[i].avg = rec[i].tot / 3.0;
		}
	}// end input()


	// 주요 메소드 구성(기능 구성 → 메소드 정의)
	// ③ 결과 출력
	public void print()
	{
		// 석차 산출 메소드 호출~!!! (구문 추가)
		ranking();

		System.out.println();	// 개행

		// 학생 한 명 당 반복 출력 구문 구성
		for (int i=0; i<inwon; i++)
		{
			// 이름 출력
			System.out.printf("%5s", rec[i].name);

			// 성적(국어, 영어, 수학) 반복 출력
			for (int j=0; j<3; j++)
			{
				System.out.printf("%4d", rec[i].score[j]);
			}

			// 총점, 평균 출력
			System.out.printf("%5d", rec[i].tot);
			System.out.printf("%6.2f", rec[i].avg);

			// 석차 출력구문 추가~!!! (구문 추가)
			System.out.printf("%5d", rec[i].rank);

			System.out.println();
		}
	}// end print()


	// ④ 석차 산출 메소드 추가
	// - Record 배열의 rank 속성 초기화를 수행하는 기능 → 반환 자료형 void
	// - 클래스 내부에서 활용할 메소드로 정의
	//   즉, 외부에 노출할 메소드가 아닌 형태로 정의 → 접근제어 지시자 private
	//   → 외부에서 접근(호출) 불가
	private void ranking()
	{
		// 모든 학생들의 등수(석차, rank)를 1로 초기화
		for (int i=0; i<inwon; i++)
			rec[i].rank = 1;

		// 등수 산출
		for (int i=0; i<inwon-1; i++)		// 비교 기준	0	 1	 2	3
		{
			for (int j=i+1; j<inwon; j++)	// 비교 대상	1234 234 34 4
			{
				// 기준의 평균이 대상의 평균보다 크다면...
				if (rec[i].avg > rec[j].avg)
				{
					// 대상의 rank 를 1 만큼 증가
					rec[j].rank++;
				}
				else
				{
					// 기준의 rank 를 1만큼 증가
					rec[i].rank++;
				}
			}
		}
	}// end ranking()
}// end class Sungjuk
/*===============================
  ■■■ 클래스와 인스턴스 ■■■
  - 클래스와 인스턴스 활용
===============================*/

// Record.java / Sungjuk.java / Test104.java 세트~!

// 실행 예)
// 인원 수 입력(1~100) : 102
// 인원 수 입력(1~100) : -10
// 인원 수 입력(1~100) : 3

// 1번째 학생의 이름 입력 : 윤홍준
// 국어 점수 : 90
// 영어 점수 : 80
// 수학 점수 : 70

// 2번째 학생의 이름 입력 : 김승범
// 국어 점수 : 82
// 영어 점수 : 7
// 수학 점수 : 62

// 3번째 학생의 이름 입력 : 이예슬
// 국어 점수 : 98
// 영어 점수 : 88
// 수학 점수 : 78

// 윤홍준  90  80  70  240  xx.xx	2
// 김승범  82  72  62  xxx  xx.xx	3
// 이예슬  98  88  78  xxx  xx.xx	1

// 계속하려면 아무 키나 누르세요...

public class Test104
{
	public static void main(String[] args)
	{
		Sungjuk ob = new Sungjuk();

		ob.set();
		ob.input();
		ob.print();
	}
}

클래스와 인스턴스 활용 예제 2

1 ~ 3 사이의 난수를 발생시켜서 가위, 바위, 보 게임 프로그램을 구현한다.
단, 클래스의 개념을 활용하여 처리할 수 있도록 한다.
또한, 배열을 활용하여 처리할 수 있도록 한다.
최종적으로 RpsGame 클래스를 완성할 수 있도록 한다.

/*===============================
  ■■■ 클래스와 인스턴스 ■■■
  - 클래스와 인스턴스 활용
===============================*/

// ※ 기준 데이터 → 1:가위, 2:바위, 3:보

// 실행 예)
// 1:가위, 2:바위, 3:보 중 입력(1~3) : 4
// 1:가위, 2:바위, 3:보 중 입력(1~3) : -1
// 1:가위, 2:바위, 3:보 중 입력(1~3) : 2

// - 유저   : 바위
// - 컴퓨터 : 보

// >> 승부 최종 결과 : 컴퓨터가 이겼습니다~!!!
// 계속하려면 아무 키나 누르세요...

import java.util.Scanner;
import java.util.Random;

class RpsGame
{
	// ○ 주요 속성 구성(변수 선언)
	private int user;
	private int com;
	//private String resultStr;

	// ○ 주요 기능 구성(메소드 정의)
	//	  - 사용자의 선택 내용을 입력받는 기능의 메소드
	public void input()
	{
		runCom();

		Scanner sc = new Scanner(System.in);

		do
		{
			System.out.print("1:가위, 2:바위, 3:보 중 입력(1~3) : ");
			user = sc.nextInt();
		}
		while (1>user || user>3);
	}

	private void runCom()
	{
		Random rd = new Random();
		com = rd.nextInt(3) + 1;	//-- 『+1』 : 0 1 2 → 1 2 3
	}


	// ○ 주요 기능 구성(메소드 정의)
	//	  - 중간 결과 출력(서로의 선택 내용 확인)
	public void middleCalc()
	{
		String[] str = {"가위", "바위", "보"};

		System.out.println();
		System.out.println(" - 유저   : " + str[user-1]);
		System.out.println(" - 컴퓨터 : " + str[com-1]);
		//-- 『-1』 : str[1] str[2] str[3] → str[0] str[1] str[2]
	}


	// ○ 주요 기능 구성(메소드 정의)
	//	  - 승부에 대한 연산
	public String resultCalc()
	{
		String result = "무승부 상황입니다~!!!";

		// (유저=="가위" && 컴=="보") || (유저=="바위" && 컴=="가위") || (유저=="보" && 컴=="바위")
		if ((user==1 && com==3) || (user==2 && com==1) || (user==3 && com==2))		// 당신이 승리한 상황
		{
			result = "당신이 승리했습니다~!!!";
		}
		// (유저=="가위" && 컴=="바위") || (유저=="바위" && 컴=="보") || (유저=="보" && 컴=="가위")
		else if ((user==1 && com==2) || (user==2 && com==3) || (user==3 && com==1))	// 컴퓨터가 승리한 상황
		{
			result = "컴퓨터가 승리했습니다~!!!";
		}

		return result;
	}



	// ○ 주요 기능 구성(메소드 정의)
	//	  - 최종 결과 출력
	public void print(String str)
	{
		System.out.printf("\n>> 승부 최종 결과 : %s\n", str);
	}
}


// main() 메소드를 포함하고 있는 외부의 다른 클래스
public class Test105
{
	public static void main(String[] args)
	{
		RpsGame ob = new RpsGame();

		ob.input();
		ob.middleCalc();
		String result = ob.resultCalc();

		ob.print(result);
	}
}

// 실행 결과
/*
1:가위, 2:바위, 3:보 중 입력(1~3) : 1

 - 유저   : 가위
 - 컴퓨터 : 바위

>> 승부 최종 결과 : 컴퓨터가 승리했습니다~!!!
계속하려면 아무 키나 누르십시오 . . .

1:가위, 2:바위, 3:보 중 입력(1~3) : 2

 - 유저   : 바위
 - 컴퓨터 : 바위

>> 승부 최종 결과 : 무승부 상황입니다~!!!
계속하려면 아무 키나 누르십시오 . . .

1:가위, 2:바위, 3:보 중 입력(1~3) : 3

 - 유저   : 보
 - 컴퓨터 : 가위

>> 승부 최종 결과 : 컴퓨터가 승리했습니다~!!!
계속하려면 아무 키나 누르십시오 . . .
*/

만년 달력 예제

/*======================
  ■■■ 만년달력 ■■■
======================*/

// 실행 예)
// 『연도』를 입력하세요 : 2021
// 『월』을 입력하세요   : 1

/*
	[ 2021년 1월 ]
  일  월  화  수  목  금  토
============================
		       1   2
   3   4   5   6   7   8   9
  10  11  12  13  14  15  16
  17  18  19  20  21  22  23
  24  25  26  27  28  29  30
  31
============================
계속하려면 아무 키나 누르세요...
*/

import java.util.Scanner;

public class Test108
{
	int totDay;
	int y, m;
	int[] months = {0,31,28,31,30,31,30,31,31,30,31,30,31};
	String[] weekday = {"일","월","화","수","목","금","토"};

	// 날짜 입력
	void input()
	{
		Scanner sc = new Scanner(System.in);

		System.out.print("『연도』를 입력하세요 : ");
		y = sc.nextInt();
		System.out.print("『월』을 입력하세요   : ");
		m = sc.nextInt();
	}

	// m월 1일의 요일 계산
	int firstDay()
	{
		totDay = (y-1)*365 + (y-1)/4 - (y-1)/100 + (y-1)/400;

		if (y%400==0 || (y%4==0 && y%100!=0))	//윤년의 2월달은 29
			months[2] = 29;
		else					//평년의 2월달은 28
			months[2] = 28;
		
		for (int i=1; i<m; i++)
			totDay += months[i];
		
		totDay++;	// m월 1일

		return totDay%7;
	}

	// 달력 출력
	void print(int weekday)
	{
		// 출력(달력 그리기)
		System.out.printf("\n\t[ %d년 %d월 ]\n", y, m);
		System.out.println("  일  월  화  수  목  금  토");
		System.out.println("============================");

		// 특정 요일부터 1일이 출발할 수 있도록 공백 발생(지정)
		for (int i=0; i<weekday; i++)
		{
			System.out.print("    ");
		}
		// 테스트(확인)
		//System.out.printf("%4d", 1);

		// 해당 월(입력한 월)의 날짜만 출력될 수 있도록 반복문 구성
		for (int i=1; i<=months[m]; i++)
		{
			System.out.printf("%4d", i);	//	1 2 3 4 5 6 ... 31
			weekday++;			//	7 8 9 10 ...

			if (weekday%7==0)		// 일요일에 해당하는날짜일 경우
				System.out.println();		// 개행
		}

		// 달의 마지막 날짜가 출력 형식을 모두 채웠을 경우
		// 이미 일요일 개행이 이루어졌기 때문에
		// 이 경우에는 추가 개행을 하지 않도록 처리
		if(weekday%7!=0)
			System.out.println();
		System.out.println("============================");
	}

	public static void main(String[] args)
	{
		Test108 ob = new Test108();
		ob.input();
		int weekday = ob.firstDay();
		//System.out.println(weekday);		// 테스트
		ob.print(weekday);
	}

}

주민번호 유효성 검사 예제

과거에는 실무에 사용했지만 현재는 사용되지 않는다. 하지만 제어문을 다루는 연습으로는 좋은 로직이다.

 

예제를 푸는데 도움이 되는 메소드

* 배열.length   : 배열의 길이(배열 방의 갯수)를 반환

* 문자열.length()   : 문자열의 길이 반환

* 문자열.substring(i, j)   : 문자열 index i번째에서 j-1번째 까지 반환(j는 포함되지 않는다.)

 

 

※ 주민등록번호 검증 공식

① 마지막 자리를 제외한 12개의 각 자리 수를 규칙에 맞게 곱한다.
      123456-1234567 (주민번호)
      234567 892345  (각 자리에 곱해질 수)

② 규칙에 맞게 곱셈 연산을 수행한 결과를 모두 더한다.

  ex) 7 5 0 6 1 5 - 1 8 6 2 1 3 3
       2 3 4 5 6 7   8 9 2 3 4 5
   --------------------------------

   → (7*2) + (5*3) + (0*4) + (6*5) + (1*6) + (5*7) + (1*8) + (8*9) + (6*2) + (2*3) + (1*4) + (3*5)
   → 14 + 15 + 0 + 30 + 6 + 35 + 8 + 72 + 12 + 6 + 4 + 15  = 217

③ 더해진 결과값을 11로 나누어 『나머지』를 취한다.
        217 % 11 = 8 (나머지)

④ 11에서 나머지(8)을 뺀 결과값을 구한다.
        11 - 8 = 3 (결과값) 

  ※ 만약 ③의 처리 과정에서 나머지가 0인 경우이거나 1인 경우에는

        11-0 = 11 또는 11-1 = 10
     이를 다시 10으로 나눈 나머지를 결과값으로 한다. (1 또는 0 이 결과값)

⑤ 결과값이 주민번호의 마지막 숫자와 일치하는지의 여부를 확인한다.
       일치   → 유효한 주민번호
       불일치 → 잘못된 주민번호

/*======================================
  ■■■ 주민등록번호 유효성 검사 ■■■
======================================*/

// 실행 예)
// 주민번호 입력(xxxxxx-xxxxxxx) : 123456-12345678 → 입력 갯수 초과
// >> 입력 오류~!!!
// 계속하려면 아무 키나 누르세요...

// 주민번호 입력(xxxxxx-xxxxxxx) : 123456-123456→ 입력 갯수 미달
// >> 입력 오류~!!!
// 계속하려면 아무 키나 누르세요...

// 주민번호 입력(xxxxxx-xxxxxxx) : 750615-1252085 → 유효한 주민번호
// >> 정확한 주민번호~!!!
// 계속하려면 아무 키나 누르세요...

// 주민번호 입력(xxxxxx-xxxxxxx) : 750615-1252084 → 유효하지 않은 주민번호
// >> 잘못된 주민번호~!!!
// 계속하려면 아무 키나 누르세요...


//import java.util.Scanner;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class Test109
{
	public static void main(String[] args) throws IOException
	{
    	/*
		// 문자열.length() 테스트
		strTemp = "동해물과 백두산이";
		System.out.println(strTemp.length());
		//--==>> 9
		strTemp = "study-hard";
		System.out.println(strTemp.length());
		//--==>> 10

		// 문자열.substring() 테스트
		strTemp = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
		System.out.println(strTemp.substring(3, 5));	// 3 ~ 4
		//--==>> "DE"
        
		System.out.println(strTemp.substring(13, 17));	// 13 ~ 16
		//--==>> "NOPQ"

		//System.out.println(strTemp.substring(13, 57));	// 13 ~ 56
		//--==>> 에러 발생 → StringIndexOutOfBoundsException
		
		strTemp = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
		System.out.println(strTemp.substring(15));	// 15 ~
		//--==>> "PQRSTUVWXYZ"
	*/

		// BufferedReader 인스턴스 생성
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		// 입력 받는 주민번호(문자열 형태)
		String str;

		// 주민번호의 각 자릿수에 곱하게 될 수 → 배열 형태로 구성
		//	     7  5  0  6  1  5  -  1  8  6  2  1  3  3
		//	     *  *  *  *  *  *  *  *  *  *  *  *  *
		int[] chk = {2, 3, 4, 5, 6, 7, 0, 8, 9, 2, 3, 4, 5};

		// 곱셈 연산 후 누적합
		int tot = 0;

		System.out.print("주민번호 입력(xxxxxx-xxxxxxx) : ");
		str = br.readLine();

		if (str.length() != 14)
		{
			System.out.println(">> 입력 오류~!!!");
			return;	//-- 메소드종료 → main() 메소드 종료 → 프로그램 종료
		}

		// ex) 750615-1252085
		for (int i=0; i<13; i++)
		{
			if (i==6)
				continue;

			//chk[i] * Integer.parseInt(주민번호 특정 자릿수 추출);
			tot += chk[i] * Integer.parseInt(str.substring(i, (i+1)));

			//chk[0] * Integer.parseInt("750615-1252085".substring(0, 1));
			//chk[0] * Integer.parseInt("7");
			//2 * 7
			//chk[1] * Integer.parseInt("750615-1252085".substring(1, 2));
			//chk[1] * Integer.parseInt("5");
			//3 * 5
			//  :
			//chk[6] * Integer.parseInt("750615-1252085".substring(6, 7));
			//0 * Integer.parseInt("-");

		}

		// ③ ④ 관련 연산 수행
		int su = 11 - tot%11;

		// 테스트(확인)
		//System.out.println(su);

		// 최종 결과 출력 이전에... 추가 연산 필요~!!!
		// su 에 대한 연산 결과가 두 자리로 나올 경우
		// 주민번호 마지막 자리의 숫자와 비교할 수 없는 상황
		su = su % 10;	// su %= 10;


		if (su == Integer.parseInt(str.substring(13)))
			System.out.println(">> 정확한 주민번호~!!!");
		else
			System.out.println(">> 잘못된 주민번호~!!!");

	}
}
  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기