JAVA 4주차

Organ·2023년 9월 16일
0

JAVA

목록 보기
6/14

4주차 후기

이번주부터 본격적으로 객체지향에 대한 개념들을 배우기 시작했는데 확실히 이전과는 다르게 주위를 둘러보면 이해하기 어려워하는게 보이기 시작한다. 나도 마찬가지여서 수업 외 시간에 이해가지 않는 부분들을 유튜브에 검색해보며 이해하려고 노력한 것 같다. 지금 생각해보면 나도 학원 오기 전에 공부하다가 객체지향 파트에서 이해를 아예 못하고 있는 상황에서 중요하다고 하니 어떻게든 하려고 했었는데 그때는 그냥 코드만 따라치고 있었던 것 같다. 금요일 수업 끝난 저녁이랑 토요일 아침에 전에 내가 어려워 하던 강의를 다시 봤는데 그 어렵던게 이해가 되더라. 다만 그 강의 대상에는 초보자가 있었지만 지금 내가 봐도 그 강의로 자바를 처음 공부해야겠다고 생각했던 건 잘못된 선택이었다고 생각한다. 지금이라도 이해했으니 다행이지만.

15일차

가위바위보 게임

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

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

 기준 데이터 -> 1:가위, 2:바위, 3:보

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

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

 // >> 승부 최종 결과 : 컴퓨터가 이겼습니다~!!!
 // 계속하려면..		당신이 이겼습니다
 						비겼습니다
*/
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.Random;


class RpsGame
{
	String[] rps = {"가위", "바위", "보"};
	int user;				// 사용자 답변 저장할 변수
	int com;				// 컴퓨터 답변 저장할 변수

	void input() throws IOException
	{
		do
		{
			BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
			System.out.printf("1:가위, 2:바위, 3:보 중 입력(1~3) : ");
			user = Integer.parseInt(br.readLine());
		}
		while (user < 1 || user > 3);
	}

	void game()
	{
		Random rd = new Random();
		com = rd.nextInt(3); 
		user--;
		System.out.println("유저   : " + rps[user]);
		System.out.println("컴퓨터 : " + rps[com]);
	}

	void result()
	{
		if(user - com == 1 || com - user == 2)
			System.out.print("당신이 이겼습니다~!!!");
		else if(user == com)
			System.out.print("비겼습니다");
		else
			System.out.print("컴퓨터가 이겼습니다~!!!");
	}


	

		
		
}

public class Test102
{
	public static void main(String[] args) throws IOException
	{
		RpsGame rg = new RpsGame();
		rg.input();
		rg.game();
		rg.result();
	}
}
/*===============================
  ■■■ 클래스와 인스턴스 ■■■
 - 클래스와 인스턴스 활용
================================*/

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

 기준 데이터 -> 1:가위, 2:바위, 3:보

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

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

 // >> 승부 최종 결과 : 컴퓨터가 이겼습니다~!!!
 // 계속하려면..		당신이 이겼습니다
 						비겼습니다
*/
import java.util.Scanner;
import java.io.IOException;
import java.util.Random;


class RpsGame
{
	private int user;				
	private int com;				
	
	// 컴퓨터의 가위바위보
	private void runCom()
	{
		Random rd = new Random();
		com = rd.nextInt(3) + 1;				// 0 1 2 (+1) 1 2 3
	}

	// 유저의 가위바위보
	public void input()
	{
		// 사용자가 가위바위보 하기 전에... 컴퓨터(주최측) 먼저 가위바위보
		runCom();

		Scanner sc = new Scanner(System.in);

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

	}

	// 중간 결과 출력
	public void middleCalc()
	{
		String[] str = {"가위", "바위", "보"}; // 1 2 3

		System.out.println();
		System.out.println("- 유저   : " + str[user - 1]);
		System.out.println("- 컴퓨터 : " + str[com - 1]);
	}

	// 승부에 대한 최종 결과 연산
	// - 무승부 상황입니다.
	// - 당신이 승리했습니다.
	// - 컴퓨터가 승리했습니다.
	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(">> 승부 최종 결과 : %s\n", str);
	}
		
		
}

public class Test102
{
	public static void main(String[] args) throws IOException
	{
		RpsGame ob = new RpsGame();

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

메소드 오버로딩(Nethod Overloading)(103)

/*
○ 메소드 오버로딩(Method Overloading)의 개요
   메소드 오버로딩이란 메소드가 처리하는 기능은 같고,
   메소드 괄호 속에 오는 인수(인자, 매개변수, 파라미터)의 갯수가 다르거나
   자료형(Data type)이 다른 경우
   메소드의 이름을 동일한 이름으로 부여하여 메소드를 정의할 수 있도록
   문법적으로 허용하게 되는데,
   이를 메소드 오버로딩(Method Overloading)이라고 한다.
*/
public class Test103
{
	public static void main(String[] args)
	{
		/*
		Test103 ob = new Test103();
		ob.drawLine();
		*/

		// Test103.drawLine(); 클래스 메소드라 바로 인스턴스 생성 없이 부를 수 있고 Test103도 필요없다.

		drawLine();
		//== --------------------

		drawLine('=');
		//== ====================

		drawLine('\\');
		//== \\\\\\\\\\\\\\\\\\\\

		drawLine('+', 40);
		//== ++++++++++++++++++++++++++++++++++++++++

		drawLine('/', 10);
		//== //////////
	}

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

	// 선을 그리는 메소드 정의 -> 선의 형태를 바꾸어 그리는 메소드
	// public static void drawLine()
	public static void drawLine(char c)
	{
		// System.out.println("===================");
		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();
	}
}

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

/*==================================================================
  ■■■ 클래스와 인스턴스 ■■■
 - 메소드 오버로딩(Method Overloading)이 가능한 형태와 불가능한 형태
===================================================================*/

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

		print(20);

		print(3.14);

		double result = print(3.14);
	}

	public static void print() {}
	//public static void print() {}					         허용x
	public static void print(int i) {}			          // 가능
	//public static void print(int j) []			         14번과 중복 == 허용 x
	public static void print(char c) {}				      // 가능 but 자동 형 변환 조심
	public static void print(int i, int j) {}		      // 가능
	public static void print(double d) {}				  // 가능 but 자동 형 변환 조심
	//public static void print(double e) {return 10.0;}	     반환형 잘못됨
	//public static double print(double d) {return 10.0;} // 안됨
}

만년 달력(105)

내 풀이

/*=========================================
  ■■■ 만년 달력 ■■■
 - 다음과 같은 기능의 프로그램을 구현한다.
=========================================*/

/*
 실행 예)
 『연도』를 입력하세요 : 2023
 『월』을 입력하세요   : 9

 [ 2023년 9월 ]

 일 월 화 수 목 금 토
=====================
                 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
=====================
계속하려면 아무 키나 누르세요
*/
import java.util.Scanner;
import java.io.IOException;

public class Test105
{
	public static void main(String[] args) throws IOException
	{
		Test105 ts = new Test105();
		ts.input();
		ts.dayCal();
		ts.print();
	}


	private int y,m;
	private int[] months = {31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
	int daySum = 1;

	public void input() throws IOException
	{
		Scanner sc = new Scanner(System.in);
		System.out.print("『연도』를 입력하세요 : ");
		y = sc.nextInt();

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

	public void dayCal()
	{
		
		daySum += (y-1) * 365 + (y-1) / 4 - (y-1) / 100 + (y-1) / 400;

		if (y % 4 == 0 && y % 100 != 0 || y % 400 == 0)				// 윤년
			months[1] = 29;
		else														// 평년
			months[1] = 28;

		for(int i = 0; i < (m - 1); i++)
			daySum += months[i];

		d = weekNames[daySum % 7];	
	}

	public void print()
	{
		System.out.printf("    [%d년 %d월]\n\n", y, m);
		System.out.println(" 일  월  화  수  목  금  토");
		System.out.println("============================");
		int dNum = 1;

		for(int i = 1; i <= months[m-1]+daySum % 7 ; i++) 
// 공백 출력해야 하기 때문에 i 값과 dNum값이 다르다
		{
			if(i <= daySum % 7)
				System.out.printf("    ");
			else
			{
				System.out.printf("%4d",dNum);
				dNum++;
			}

			if((daySum + dNum) % 7 == 1 || dNum == months[m-1]+1)
// dNum을 1로 시작하기 때문에 == 1이 되는 것
				System.out.println();
		}
		System.out.println("============================");
	}
}

수업

/*=========================================
  ■■■ 만년 달력 ■■■
 - 다음과 같은 기능의 프로그램을 구현한다.
=========================================*/

/*
 실행 예)
 『연도』를 입력하세요 : 2023
 『월』을 입력하세요   : 9

 [ 2023년 9월 ]

 일 월 화 수 목 금 토
=====================
                 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
=====================
계속하려면 아무 키나 누르세요
*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Test105
{
	public static void main(String[] args) throws IOException
	{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		int[] days = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

		// 주요 변수 선언
		int nalsu, y, m, w;			// 날 수, 년, 월, 요일
		do
		{
			System.out.print("『연도』를 입력하세요 : ");
			y = Integer.parseInt(br.readLine());
		}
		while (y < 1);

		do
		{
			System.out.print("『월』을 입력하세요   : ");
			m = Integer.parseInt(br.readLine());
		}
		while (m < 1 || m > 12);

		if (y % 4 == 0 && y % 100 != 0 || y % 400 == 0)				
			days[1] = 29;

		// 1년 1월 1일 ~ 입력받은 연도의 이전 년도 12월 31일 까지의 날 계산
		nalsu = (y-1) * 365 + (y-1) / 4 - (y-1) / 100 + (y-1) / 400;

		// 입력받은 연도(해당 연도) 1월 1일 ~ 입력한 월의 이전 월까지의 날 수 계산
		for(int i = 0; i < (m-1); i++)
		{
			nalsu += days[i];
		}
		
		// 입력받은 월의 1일을 날 수 누적 연산
		nalsu += 1;			// ++nalsu

		//------------------여기까지 수행하면 모든 날 수에 대한 종합 처리 완료

		// 요일 확인
		//-- 입력받은 연의 입력월의 1일이 무슨 요일인지 확인하기 위한 연산
		w = nalsu % 7;
		//-- w:0   -> 일요일
		//   w:1   -> 월요일

		// 확인
		// System.out.println("W : " + w);
//『연도』를 입력하세요 : 2024
//『월』을 입력하세요   : 5
// W : 3         // 2024년 5월 1일은 수요일(3)이라는 의미

		// -------------여기까지 수행하면 해당 연도 해당 월의 1일이 무슨 요일인지 확인 완료

		// 출력(달력 그리기)
		System.out.println();									// 개행
		System.out.printf("\t[ %d년 %d월 ]\n", y, m);
		System.out.println();									// 개행
		System.out.println("  일  월  화  수  목  금  토");		// 하루 4칸
		System.out.println("============================");

		// 특정 요일부터 1일이 출발할 수 있도록 공백 발생(지정)
		for(int i = 1; i <= w; i++)
		{
			System.out.print("    ");
		}

		// 해당 월(입력한 월)의 날짜만 출력될 수 있도록 반복문 구성
		for(int i = 1; i <= days[m - 1]; i++)
		{
			System.out.printf("%4d", i);
			w++;
			// 반복문을 통해 날짜를 처리하는 동안 
			// 그만큼의 요일도 함께 증가할 수 있도록 처리

			// 일요일을 구성하려는 경우...
			// (즉, 이번에 출력하고자 하는 날짜가 일요일인 경우...)
			if(w % 7 == 0)
			{
				// 개행
				System.out.println();
			}
		}

		// 달의 마지막 날짜가 출력 형식을 모두 채웠을 경우
		// (즉, 토요일까지 라인 전체 출력이 이루어졌을 경우)
		// 이미 일요일 개행이 이루어졌기 때문에
		// 이 경우에는 추가 개행을 하지 않도록 처리

		if(w % 7 != 0)
		{
			System.out.println();
		}

		System.out.println("============================");

/*
『연도』를 입력하세요 : 2023
『월』을 입력하세요   : 9

        [ 2023년 9월 ]

  일  월  화  수  목  금  토
============================
                       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
============================
계속하려면 아무 키나 누르십시오 . . .
*/

	}
}

주민번호 유효성 검사(106)

/*
○ 주민등록번호 검증 공식

   1. 마지막 자리를 제외한 앞자리 수를 규칙에 맞게 곱한다.

      123456-1234567 (주민번호)
	  ****** *******  ------------- 각 자릿수에 곱하기
	  234567 892345  (각 자릿수에 곱해질 수)

   2. 규칙에 맞게 곱셈 연산을 수행한 결과를 모두 더한다.
   750615-1862133
   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
	   ---------------------------
	   -> 14 + 15 + 0 + 30 + 6 + 35 + 8 + 72 + 12 + 6 + 4 + 15 == 217

   3. 더해진 결과값을 11로 나누어 나머지를 취한다.
      217 % 11

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

	  3의 처리 과정에서 나머지가 0인 경우 -> 11 - 0 -> 11
	  3의 처리 과정에서 나머지가 1인 경우 -> 11 - 1 -> 10

	  이를 다시 10으로 나누어 나머지를 취한다. 11 -> 1
	  										   10 -> 0

   5. 4의 연산 결과가 주민번호를 구성하는 마지막 숫자와 일치하는지의 여부를 비교하여 확인한다.

      일치    -> 유효한 주민번호
	  불일치  -> 잘못된 주민번호


 실행 예)
 주민번호입력(xxxxxx-xxxxxxx) : 123456-12345678			// 입력 갯수 초과
 >> 입력 오류
 계속하라면...

 주민번호입력(xxxxxx-xxxxxxx) : 123456-123456			// 입력 갯수 미달
 >> 입력 오류
 계속하라면...

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

 주민번호입력(xxxxxx-xxxxxxx) : 750615-1252085			// 잘못된 주민번호
 >> 잘못된 주민번호

 문제 해결을 위한 추가 팁

 배열.length			    -> 배열의 길이(배열방의 갯수) 반환
 문자열.length()		    -> 문자열의 길이 반환
 문자열.substring(m, n)		-> 문자열 추출
 문자열 m번째 위치에서 n-1 번째 위치까지 추출(인덱스는 0부터)

 문자열.substring(m)
 문자열 m번째 위치에서 문자열의 끝까지 추출(인덱스는 0부터)
*/

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class Test106
{
	public static void main(String[] args) throws IOException
	{
		// 테스트
		/*
		String strTemp = "홍길동";
		System.out.println(strTemp.length());
		//== 3

		strTemp = "홍길동가나다라마바";
		System.out.println(strTemp.length());
		//== 

		strTemp = "동해물과 백두산이 마르고 닳도록";
		System.out.println(strTemp.length());
		//== 17
		
		strTemp = "study-hard";
		System.out.println(strTemp.length());
		//== 10
		*/
		//---------------------------------------------
		
		String strTemp = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
		System.out.println(strTemp.substring(13, 17));
		//== NOPQ

		//System.out.println(strTemp.substring(13, 53));
		//== 에러 발생(런타임 에러)
		//	 StringIndexOutOfBoundsException

		//System.out.println(strTemp.substring(13)); // 13 ~ 끝까지
		//== NOPQRSTUVWXYZ

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

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

		String cd = br.readLine();
		int sum = 0;
		
		// 전체 14자리 확인
		if(cd.length() != 14)
		{
			System.out.println("입력 오류");
			return;
		}

		int[] num = new int[13];

		for(int i = 0; i < 6; i++)
		{
			num[i] = Integer.parseInt(cd.substring(i,i+1));
		}

		for(int i = 6; i < 13; i++)
		{
			num[i] = Integer.parseInt(cd.substring(i+1,i+2));
		}



		for(int i = 2; i <= 9; i++)
		{
			sum += num[i - 2] * i;
		}
		//System.out.print(sum);

		for(int i = 8; i <= 11; i++)
		{
			sum += num[i] * (i - 6);
			//System.out.printf("%d  %d  %d", i, num[i], sum);
		}
		System.out.print(sum % 11);
	
				

		if(num[12] == 11 - (sum % 11) || num[12] == sum % 11 - 10)
			System.out.print("유효한 주민번호\n");
		else
			System.out.print("잘못된 주민번호\n");
	}
}

16일차

주민번호 유효성 검사(수업)


import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class Test106
{
	public static void main(String[] args) throws IOException
	{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		
		// 입력받을 주민번호(문자열 형태)를 담아둘 변수 선언
		String str;

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

		// 곱셈 연산 후 누적합 -> 각 곱셈의 결과를 더해나가라..
		//               ----
		int tot = 0;

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

		if(str.length() != 14)
		{
			System.out.println("입력 오류");
			return;			// 메소드 종료
		}

		// 테스트
		// System.out.println(">> 자릿수 적합");

		// ex) "750615-1252085"
		for(int i = 0; i < 13; i++)			// i -> 0 1 2 3 4 5 6 7 8 9 10 11 12
		{
			// 테스트
			//System.out.print(i + " ");
			//== 0 1 2 3 4 5 6 7 8 9 10 11 12

			// i가 6일 때에는 continue
			if(i == 6)
				continue;		// 뒷부분 무시하고 계속해라

			tot += chk[i] * Integer.parseInt(str.substring(i, i + 1));
		}

		// 테스트
		System.out.println(tot);
		// 주민번호입력(xxxxxx-xxxxxxx) : 750615-1862133
		//==217

		//----------------------------- 여기까지 하면 1과 2를 모두 끝낸 상황이며
		//								규칙에 맞게 곱셈 연산을 수행한 결과를 모두 더한 값은
		//								변수 tot에 담겨있는 상태가 된다.

		int su = 11 - tot % 11;

		// ------------ 여기까지 수행하면 검증 공식의 3과 5를 모두 끝낸 상황이며
		//				su 에 대한 연산 결과가 두 자리의 정수로 나올 경우
		//				주민번호 마지막 자리의 숫자와 비교를 수행할 수 없는 상황.

		su = su % 10;		// == su %= 10

		// 주민번호의 마지막 자리와 비교한 결과가 같다면 -> 정확한 주민번호
		//									    아니라면 -> 잘못된 주민번호
		if(su == Integer.parseInt(str.substring(13)))
		{
			System.out.println(">> 정확한 주민번호");
		}
		else
		{
			System.out.println(">> 잘못된 주민번호");
		}
// 실행결과
/*
주민번호입력(xxxxxx-xxxxxxx) : 121212-1234567
136
>> 정확한 주민번호
*/

	}
}

정렬 알고리즘(107~110)

선택 정렬

/*=================================
  ■■■ 정렬(Sort) 알고리즘 ■■■
=================================*/

/*
○ 정렬
   : 데이터를 특정한 규칙(기준)에 맞게 순서대로 나열(오름차순, 내림차순)

○ 정렬의 목적
   : 데이터 처리 과정의 편의성이나 가독성을 높이기 위함
     -> 보기 좋게, 찾기 좋게, 검색이 편하게

○ 정렬의 종류
   : 선택 정렬, 삽입 정렬, 버블 정렬, 힙 정렬, 퀵 정렬, 쉘 정렬...


 선택 정렬(Selection Sort)

 실행 예)
 Source Data : 52 42 12 62 60
 Sorted Data : 12 42 52 60 62
 계속하려면..

 향상된 for 문
 int[] marks = {75, 60, 56}
 for(int i:marks){
     sum = sum + i;
 }

	 자료형 변수명 : 자료구조
  i를 marks가 끝날때까지 반복 but 배열 수정 불가
*/
public class Test107
{
	public static void main(String[] args)
	{
		int[] a = {52, 42, 12, 62, 60};

		System.out.print("Source Data : ");
		for(int i : a)
			System.out.printf("%d ", i);
		System.out.println();

		int temp;
		/*
		   0 과 1234 비교하면서 0이 더 크면 자리 바꿈 -> 완료하면 0값에 가장 작은 값
		   1 과  234 비교하면서 1이 더 크면 자리 바꿈 -> 완료하면 1값에 두번째로 작은 값
		   반복하면 정렬 완료됨.
		*/
/*		
		for(int i = 0; i < 5; i++)
		{
			for(int j = i + 1; j < 5; j++)
			{
				if(a[i] > a[j])
				{
					temp = a[i];
					a[i] = a[j];
					a[j] = temp;
				}
			}
		}
*/
		for(int i = 0; i < a.length - 1; i++)			// 비교 기준 데이터 0    1   2   3
		{
			for(int j = i + 1; j < a.length; j++)		// 비교 대상 데이터 1234 234 34  4
			{
				if(a[i] > a[j])							// 오름차순 
			//  if(a[i] < a[j])							// 내림차순
				{
					a[i] = a[i] ^ a[j];
					a[j] = a[j] ^ a[i];
					a[i] = a[i] ^ a[j];
				}
			}
		}

		System.out.print("Sorted Data : ");
		for(int i : a)
			System.out.printf("%d ", i);
		System.out.println();

// 실행 결과
/*
Source Data : 52 42 12 62 60
Sorted Data : 12 42 52 60 62
계속하려면 아무 키나 누르십시오 . . .
*/
	}
}

버블 정렬

/*=================================
  ■■■ 정렬(Sort) 알고리즘 ■■■
=================================*/
/*

 버블 정렬(거품 정렬, Bubble Sort)


 실행 예)
 Source Data : 52 42 12 62 60
 Sorted Data : 12 42 52 60 62
*/
public class Test108
{
	public static void main(String[] args)
	{
		int[] a = {52, 42, 12, 62, 60};
		/*
		 0 1 -> 1 2 -> 2 3 -> 3 4 한 사이클 끝나면 가장 큰 수가 오른쪽 끝에 위치한다(오름차순 기준)
		 0 1 -> 1 2 -> 2 3		  한 사이클 끝 -> 두번째 큰 수가 오른쪽 두번째에 위치(오름차순 기준)
		 0 1 -> 1 2				  한 사이클 끝
		 0 1 비교
		반복
		*/

		System.out.print("Source Data : ");
		for(int n : a)
			System.out.printf("%d ", n);
		System.out.println();
/*
		for(int i = 0; i < a.length - 1; i++)
		{
			for(int j = 0; j < a.length - 1 - i; j++)		// j와 j + 1을 비교하므로 j 끝나는 조건 바꿔줌
			{
				if(a[j] > a[j + 1])
				{
					a[j] = a[j] ^ a[j + 1];
					a[j + 1] = a[j + 1] ^ a[j];
					a[j] = a[j] ^ a[j + 1];
				}
			}
		}
*/
		// 정렬--------------------------------------------------------------------------
		// Bubble Sort  수업
		int i,j;
		for(i = 1; i < a.length; i++)			 // i 뒤에서 비교 대상을 줄여주는 역할
		{										 //	  1     2    3   4
			for(j = 0; j < a.length - i; j++)	 // j 비교기준 인덱스
			{									 //   0123  012  01  0
				if(a[j] > a[j + 1])				 // 오름차순
				{
					a[j] = a[j] ^ a[j + 1];
					a[j + 1] = a[j + 1] ^ a[j];
					a[j] = a[j] ^ a[j + 1];
				}
			}
		}


		System.out.print("Sorted Data : ");
		for(int n : a)
			System.out.printf("%d ", n);
		System.out.println();
	}
}

향상된 버블 정렬

/* 향상된 버블 정렬(Bubble Sort)

   앞에서 본 Selection Sort(Test107.java)나 Bubble Sort(Test108.java)의 성능은 같다.
   (성능에 대한 추정 근거 : 반복문을 수행한 횟수)
   하지만, 향상된 Bubble Sort는 대상 데이터의 구조에 따라서
   일반 Bubble Sort 나 Selection Sort 에 비해 성능이 좋을 수 있다.

   원본 데이터 : 61 15 20 22 30     
			     15 20 22 30 61     	01 12 23 34 1회전 -> (스왑 발생 -> true) 다음 회전 진행 
				 15 20 22 30         	01 12 23 1회전 -> (스왑 발생 -> false) 다음 회전 진행 X

	2회전에서 스왑(자리바꿈이) 전혀 일어나지 않았기 때문에
	불필요한 추가 연산은 무의미한 것으로 판단하여
	수행하지 않는다.

 실행 예)
 Source Data : 10 50 20 30 40
 Sorted Data : 10 20 30 40 50
*/
public class Test109
{
	public static void main(String[] args)
	{
		int[] a = {10, 50, 20, 30, 40};
		//int[] a = {52, 42, 12, 62, 60};
		

		System.out.print("Source Data : ");
		for(int n : a)
			System.out.printf("%d ", n);
		System.out.println();
/*      내 풀이
		boolean flag = false;
		int i,j;
		for(i = 1; i < a.length; i++)			 
		{										 
			for(j = 0; j < a.length - i; j++)	 
			{									 
				if(a[j] > a[j + 1])	
				{
					a[j] = a[j] ^ a[j + 1];
					a[j + 1] = a[j + 1] ^ a[j];
					a[j] = a[j] ^ a[j + 1];
					flag = true;
				}
			}
			System.out.println("a");
			if(flag == false)
				break;

			flag = false;
		}
*/
		boolean flag;
		int pass = 0;

		do
		{
			flag = false;			// 이번 회전에서 자리바꿈이 발생하지 않을 것이다.
			pass++;

			for(int i = 1; i < a.length - pass; i++)
			{
				if(a[i] > a[i + 1])				// 오름차순
				{
					a[i] = a[i] ^ a[i + 1];
					a[i + 1] = a[i + 1] ^ a[i];
					a[i] = a[i] ^ a[i + 1];
					flag = true;				// 한 번이라도 자리바꿈이 발생하게 되면
												// flag 변수는 true로 변경
				}
			}
		}
		while (flag);				// while() 안에 true면 반복된다.
		// flag변수가 false라는 것은
		// 회전이 구분적으로 발생하는 동안 스왑이 일어나지 않은 경우로
		// 더 이상의 반복문 수행은 무의미한 것으로 판단 가능
		
		System.out.print("Sorted Data : ");
		for(int n : a)
			System.out.printf("%d ", n);
		System.out.println();


	}
}
/*=================================
  ■■■ 정렬(Sort) 알고리즘 ■■■
=================================*/
/*
○과제
  사용자로부터 여러 학생의 성적 데이터를 입력받아
  점수가 높은 학생부터 낮은 순으로 등수를 부여하여
  결과를 출력하는 프로그램을 구현한다.
  단, 배열과 정렬 알고리즘을 활용하여 작성할 수 있도록 한다.

 실행 예)
 인원 수 입력 : 5
 이름 점수 입력(1, 공백 구문) : 홍길동 90
 이름 점수 입력(2, 공백 구문) : aaa 80
 이름 점수 입력(3, 공백 구문) : bbb 85
 이름 점수 입력(4, 공백 구문) : ccc 75
 이름 점수 입력(5, 공백 구문) : ddd 95

 ----------------------
 1등 ddd 95
 2등 홍길동 90
 3등 bbb 85
 4등 aaa 80
 5등 ccc 75
 ----------------------
계속하려면...

*/

import java.io.InputStreamReader;
import java.io.BufferedReader;
import java.io.IOException;

public class Test110
{
	public static void main(String[] args) throws IOException
	{
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		System.out.print("인원 수 입력 : ");
		int N = Integer.parseInt(br.readLine());				// 입력받은 값 변수N에 저장
	
		String[] arrSt = new String[N];							// 입력받은 전체를 담을 문자열 배열
		int[] arrSc = new int[N];								// 성적만 빼서 담을 정수형 배열

		for(int i = 0; i < N; i++)							
		{
			arrSt[i] = br.readLine();							// 입력 받은 전체를 arrSt 배열에 담는다
			arrSc[i] = Integer.parseInt(arrSt[i].substring(4)); // 입력 받은 전체에서 숫자만 arrSc 배열에 담는다.
		}
		
		String str;									
		boolean flag;
		int pass = 0;

		do
		{
			flag = false;										// 이번 회전에서 자리바꿈이 발생하지 않을 것이다.	

			for(int i = 1; i < arrSc.length; i++)
			{
				if(arrSc[i - 1] < arrSc[i])						// 내림차순
				{
					str = arrSt[i];								// 문자열 전체를 바꿔준다
					arrSt[i] = arrSt[i - 1];					// i가 1로 시작하고 01 비교해야하기 때문에 i - 1해준다.
					arrSt[i - 1] = str;				

					arrSc[i] = arrSc[i] ^ arrSc[i - 1];			// 성적만 따로 뺀 배열을 바꿔준다
					arrSc[i - 1] = arrSc[i - 1] ^ arrSc[i];
					arrSc[i] = arrSc[i] ^ arrSc[i - 1];
					flag = true;				
				}
			}
			System.out.println("a");
		}
		while (flag);		
		
		for(int i = 0; i < N; i++)
		{
			System.out.println(arrSt[i]);						// 정렬이 완료된 문자열 배열 순서대로 출력
		}
	}
}

상속(111 ~ 112)

/*
○ 상속(Inheritance)
   
   새로 설계(생성)하고자 하는 클래스가
   이미 설계되어 있는 다른 클래스의 기능과 중복되는 경우
   이미 설계된 클래스의 일부분이나 전체 구조를 공유할 수 있도록 하는 기능을 의미한다.

   즉, 상속은 객체를 좀 더 쉽게 만들 수 있는
   고수준의 재사용성(reusablility)를 확보하고
   객체 간의 관계를 구성함으로써
   객체 지향의 또 다른 특징인 다형성의 문법적 토대가 된다.

   상속은 기존 프로그램의 클래스 내용을 공유함으로써
   중복된 코드들을 재작성할 필요 없이
   반복적이고 세부적인 작업을 처리하지 않기 때문에
   프로그램을 작성하는 시간을 절약할 수 있고
   유지보수를 편리하게 할 수 있으며,
   프로그램의 길이도 짧아지게 된다.

   또한, 이미 작성된 프로그램들은 앞서 테스트되었기 때문에
   오류를 줄일 수 있어 현재 작성 중인 프로그램에만 전념할 수 있다.

   주의할 점

   자바는 다중상속을 지원하지 않기 때문에
   두 개 이상의 클래스로부터 상속받을 수 없다.

   즉, 자바는 단일상속만 지원한다.
*/
// protected라는 접근제어지시자는 상속을 염두에 두고 사용하는 것 

// 부모 클래스 == 상위 클래스 == 슈퍼(super) 클래스 == 물려주는 클래스 == 상속하는
class SuperTest111
{
	protected double area;
	

	SuperTest111()
	{
		System.out.println("Super Class...");
	}
	
	void write(String title)
	{
		System.out.println(title + " - " + area);
	}

	
}

// 자식 클래스 == 하위 클래스 == 서브 클래스 == 물려받는 클래스 == 상속받는
public class Test111 extends SuperTest111 // SuperTest112, SuperTest113 다중상속 불가능
										  // 그러나 한 부모 클래스로부터 여러개의 서로 다른 클래스로 상속은 가능
{
/* 부모 클래스의 생성자는 상속 대상에서 제외됨
	protected double area;									부모로부터 상속받은 area
	
	void write(String title)								부모로부터 상속받은 write() 메소드
	{
		System.out.println(title + " - " + area);
	}
*/	
	// 컴파일 과정에서 자동으로 삽입되는 default 생성자
	/*
	Test111()
	{
		 생성자 내부에서 또 다른 생성자 호출
		 -> 가능하다. 단, 생성자 내부에서 가장 먼저 실행되어야 한다.
		 디폴트 생성자는 비어있는 것이 아니라 
		 부모 클래스의 생성자 호출 구문이 들어있다 == super()
		 // 그러면 super는 사용자 정의 생성자때문에 디폴트가 없는 경우에 사용하는 것?
		 // -> 사용자 정의 생성자도 super()가 자동 삽입 되어있다.
    }
	*/
	Test111()
	{
		// super() 자동 삽입 == SuperTest111() == System.out.println("Super Class...")
		System.out.println("Sub Class...");

		// super() -> 생성자 안에 다른 생성자를 호출하려면 맨 위에 있어야함 -> 컴파일 오류
	}

	public void actionCircle()
	{
		int r = 10;		
		area = r * r * 3.141592;
		write("원");		
	}
	
	public void actionRect()
	{
		int w = 20, h = 5;
		area = w * h;
		write("사각형");
	}

	public static void main(String[] args)
	{
		// Test111 클래스(자식) 기반 인스턴스 생성
		Test111 ob = new Test111();
		//== Super Class... 부모 먼저 나옴
		//   Sub Class...

		ob.actionCircle();
		//== 원 - 314.1592

		ob.actionRect();
		//== 사각형 - 100.0
	}
}
/*=========================
  ■■■ 클래스 고급 ■■■
  - 상속(Inheritance)
==========================*/

/*
 super
  static으로 선언되지 않은 메소드에서 사용되며
  현재 클래스가 상속받은 상위 클래스의 객체를 가리킨다.
  super는 상위 클래스의 생성자를 호출하거나
  상위 클래스의 멤버 변수 또는 메소드를 호출할 때 사용할 수 있다.

  하위 클래스의 생성자에서 상위 클래스의 생성자를 호출할 때에는
  하위 클래스의 생성자 정의 구문에서 맨 처음에만 위치할 수 있다.

 생성자와 클래스 상속간의 관계
  하위 클래스는 상위 클래스의 멤버를 상속받지만,
  생성자는 상속 대상에서 제외된다.
  그리고, 하위 클래스의 생성자를 호출할 때
  자동으로 상위 클래스의 생성자를 호출하게 된다.
  이 때, 상위 클래스의 생성자는
  인수가 없는 생성자(default 생성자 형태)가 호출된다.

  상위 클래스 및 하위 클래스(즉, 상속관계에 있는 클래스)를 설계하는 과정에서
  상위 클래스의 생성자를 정의하지 않거나 == default 생성자만 있는 경우
  인수가 없는 생성자만을 정의한 경우
  명시적으로 하위 클래스에서 상위 클래스의 생성자를 호출하지 않아도
  아무런 문제가 발생하지 않지만
  상위 클래스에 인자가 있는 생성자만 존재하는 경우
  주의해야 한다.

  예를 들어
class Aclass
{
	Aclass(int n)
	{
	}
}

class Bclass extends Aclass
{
	Bclass()
	{
		super();
	}
}

  하위 클래스인 Bclass 의 생성자에서
  명시적으로 Aclass 의 생성자를 호출하지 않으면
  자동으로 인자 없는 생성자를 호출한다.
  하지만, Aclass 에는 인자가 있는 생성자만 존재하고
  인자가 없는 생성자는 존재하지 않기 때문에 에러 발생한다.
  따라서, Bclass 생성자의 선두에
  다음처럼 명시적으로 상위 클래스의 생성자 호출 구문을 작성해야 한다.

class Aclass
{
	Aclass(int n)
	{
	}
}

class Bclass extends Aclass
{
	Bclass()
	{
		super(10);  // Aclass에서 생성자에 int n 이라는 매개변수가 필요하므로 10을 넣어서 Bclass 생성자를 정의해준다
		...;
		...;
	}
}


상속 시 주의할 사항
  하위 클래스에서 선언된 멤버 변수의 이름과
  하위 클래스에서 선언된 멤버 변수의 이름이 같으면
  상위 클래스의 멤버 변수는 무시된다.
  이 때, 상위 클래스의 멤버 변수를 사용하기 위해서는
  super 키워드를 이용한다. ex) super.변수명

  동일한 이름의 멤버 변수나 동일한 이름의 메소드가
  한 클래스 안에 선언되거나 정의되는 경우 기본적으로 에러 발생한다.
  단, 메소드의 경우에는 매개변수의 갯수나 타입이 다른 경우
  에러 발생하지 않고 이들을 서로 다른 메소드로 취급하게 된다.
*/
// Rect112 클래스와 Circle112 클래스의 부모 클래스
class SuperTest112
{
	protected double area;
	private String title;

	public SuperTest112()
	{
		System.out.println("SuperTest112... 인자 없는 생성자");
	}

	public SuperTest112(String title)
	{
		this.title = title;
		System.out.println("SuperTest112... 문자열을 넘겨받는 생성자");
	}

	public void write()
	{
		System.out.println(title + " - " + area);
	}
}
// SuperTest112 클래스를 상속받는 자식 클래스(단일 상속)
class Rect112 extends SuperTest112
{
	/* 상속으로 물려받는다
	protected double area;

	// private 멤버는 접근 자체가 불가능
	private String title;

	// 생성자는 상속 대상에서 제외
	//public SuperTest112()
	//{
	//	System.out.println("SuperTest112... 인자 없는 생성자");
	//}
	
	// 생성자는 상속 대상에서 제외
	//public SuperTest112(String title)
	//{
	//	this.title = title;
    //	System.out.println("SuperTest112... 문자열을 넘겨받는 생성자");
	//}

	public void write()
	{
		System.out.println(title + " - " + area);
	}
	*/

	private int w,h;

	public Rect112()
	{
		// super();
	}

	public void calc(int w, int h)
	{
		this.w = w;
		this.h = h;
		area = (double)this.w + this.h;
		write();
	}
	
	@Override		//-- 어노테이션(annotation) - metadata -> JDK 1.5 ~
	public void write() // Supertest112 클래스에서 상속받은 메소드를 재정의함 == overriding
	{
		System.out.println("w : " + w + ", h : " + h);
		System.out.println("사각형 - " + area);
	}

	// 메소드 오버라이딩(Method Overriding)

	// 상위 클래스를 상속받은 하위 클래스에서
	// 상위 클래스에 정의된 메소드를 다시 정의하는 것으로(재정의)
	// 객체 지향 프로그래밍의 특징인 다형성을 나타낸다.
	// 재정의(Overriding)는 반드시 상속 관계에 있어야 하며,
	// 메소드 이름, 리턴 타입, 매개변수의 갯수나 타입이
	// 모두 완전히 일치해야 한다.
}
// SuperTest112 클래스를 상속받는 자식 클래스(단일 상속)
class Circle112 extends SuperTest112
{
	/* 상속으로 물려받는다
	protected double area;

	// private 멤버는 접근 자체가 불가능
	private String title;

	// 생성자는 상속 대상에서 제외
	//public SuperTest112()
	//{
	//	System.out.println("SuperTest112... 인자 없는 생성자");
	//}
	
	// 생성자는 상속 대상에서 제외
	//public SuperTest112(String title)
	//{
	//	this.title = title;
    //	System.out.println("SuperTest112... 문자열을 넘겨받는 생성자");
	//}

	public void write()
	{
		System.out.println(title + " - " + area);
	}
	*/

	public Circle112(String title)
	{
		// super();
		super(title);
	}

	public void calc(int r)
	{
		area = r * r * 3.141592;
		write();
	}
}

// ----------------------------------------------------------------

// main() 메소드를 포함하는 외부의 다른 클래스
public class Test112
{
	public static void main(String[] args)
	{
		// Rect112 클래스(자식 클래스) 기반 인스턴스 생성
		Rect112 ob1 = new Rect112();
		//== SuperTest112... 인자 없는 생성자

		// Circle112 클래스(자식 클래스) 기반 인스턴스 생성
		// Circle112 ob2 = new Circle112(); 
		// 컴파일 에러
		// Circle112 클래스에는 매개변수를 필요로하는 사용자정의 생성자가 만들어저 있으며
		// 이로 인해 default 생성자가 자동으로 삽입되지 않는 상황

		// Circle112 클래스(자식 클래스) 기반 인스턴스 생성
		Circle112 ob3 = new Circle112("원");
		//== SuperTest112... 인자 없는 생성자					super(title); 넣기 전
		//== SuperTest112... 문자열을 넘겨받는 생성자			super(title); 넣은 후

		ob1.calc(10, 5);
		//== w : 10, h : 5
		//== 사각형 - 15.0

		ob3.calc(10);
		//== 원 - 314.1592

/*======================================================================
상위 클래스   | 하위 클래스        | 결과
------------------------------------------------------------------------
생성자를      |생성자 정의 안함    | → 가능(둘 다 디폴트 생성자)
정의하지      |인수가 없는 생성자  | → 가능
않음          |인수가 있는 생성자  | → 가능
------------------------------------------------------------------------
인수가        |생성자 정의 안함    | → 가능
없는          |인수가 없는 생성자  | → 가능
생성자만 정의  |인수가 있는 생성자  | → 가능
------------------------------------------------------------------------
인수가        |생성자 정의 안함    | → 에러
있는          |인수가 없는 생성자  | → 상위 클래스의 해당 생성자를 호출하지 않으면 에러 == super(10); 이런식으로 하지않으면
생성자만 정의  |인수가 있는 생성자  | → 상위 클래스의 해당 생성자를 호출하지 않으면 에러 == super(10); 이런식으로 하지않으면
========================================================================

생성자들의 관계에서 부모클래스에 사용자 정의 생성자가 들어가고 매개변수가 필요한 생성자만 있다면 하위 클래스 생성자 주의
*/
	}
}

17일차

상속 (113)

/*
 다음과 같은 프로그램을 구현한다.
 단, 상속의 개념을 적용하여 작성할 수 있도록 한다.

 실행 예)
 임의의 두 정수 입력(공백 구분) : 20 10
 연산자 입력(+ - * /) : -
 >> 20 - 10 = 10
 계속하려면..
*/

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

class Aclass
{
	protected int x,y;
	protected char op;			//double result가 선언되어있지 않기 때문에 밑에서 선언해야 한다
	Aclass()
	{

	}

	void write(double result)
	{
		System.out.printf("\n>> %d %c %d = %.2f\n", x, op, y, result);
	}
}

// Aclass 를 상속받는 클래스로 설계
class Bclass extends Aclass
{
	/*				내 풀이
	Bclass() throws IOException
	{
		Scanner sc = new Scanner(System.in);
		System.out.print("임의의 두 정수 입력(공백 구분) : ");
		x = sc.nextInt();
		y = sc.nextInt();

		System.out.print("연산자 입력(+ - * /) : ");
		op = (char)System.in.read();
	}
	

//	void input() throws IOException
//	{
//		Scanner sc = new Scanner(System.in);
//		System.out.print("임의의 두 정수 입력(공백 구분) : ");
//		x = sc.nextInt();
//		y = sc.nextInt();
//
//		System.out.print("연산자 입력(+ - * /) : ");
//		op = (char)System.in.read();
//	}

	double cal()
	{
		double result = 0.0;

		switch(op)
		{
			case '+' : result = x + y; break;
			case '*' : result = x * y; break;
			case '-' : result = x - y; break;
			case '/' : result = (double)x / y; break;
		}
		return result;
	}
	
					수업 --------------------------------------
*/
	Bclass()
	{
		// super();
	}

	boolean input() throws IOException
	{
		// Scanner sc = new Scanner(System.in);
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		System.out.print("임의의 두 정수 입력(공백 구분) : ");  // 20 10
		String temp = br.readLine();

		// 문자열.split("구분자");
		// 문자열.split("\\s");		// 구분자 == 공백
		//
		// ex)"10 20 30 40 50".split("\\s");
		//			-> 반환 -> {"10", "20", "30", "40", "50"} -> 문자열 배열
		// ex) "010-1234-5678".split("-");
		//     -> 반환 -> {"010", "1234", "5678"}

		String[] strArr = temp.split("\\s");		// "20 10" -> String[] strArr = {"20", "10"};

		//if(temp.length() != 2)
		if(strArr.length != 2)
			return false;
		// false를 반환하며 input() 메소드 종료
		// 이 조건을 만족하여 if문을 수행하게 될 경우..
		// 아래 수행해야 할 코드가 남아있더라도
		// 결과값(-> false)를 반환하며 메소드는 종료된다.

		x = Integer.parseInt(strArr[0]);
		y = Integer.parseInt(strArr[1]);
		// this.x = Integer.parseInt(strArr[0]);
		// super.x = Integer.parseInt(strArr[0]);

		System.out.print("연산자 입력(+ - * /) : ");
		op = (char)System.in.read();

		if(op != '+' && op != '-' && op != '*' && op != '/')
		{
			return false;
		}

		return true;

	} // end input()

	double calc()
	{
		double result = 0.0;
		
		switch(op)
		{
			case '+' : result = x + y; break;
			case '*' : result = x * y; break;
			case '-' : result = x - y; break;
			case '/' : result = (double)x / y; break;
		}

		return result;
	}// end calc()

	// write 상속 받았기 때문에 출력메소드 정의할 필요 없다.


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

		// ob.input(); boolean반환형이기 때문에 다른 형태로 호출하자

		boolean resp = ob.input();

		if(resp != true) // == (!resp); == (!ob.input());
		{
			System.out.println("Error...");
			return;							//프로그램 종료
		}
		
		double result = ob.calc();
		ob.write(result);

		//ob.write(ob.cal());
	}
}

상속 (114)

/*=========================
  ■■■ 클래스 고급 ■■■
  - 상속(Inheritance)
==========================*/
/*
 메소드 오버라이딩(Method Overriding)의 특징

 - 메소드 이름, 리턴 타입, 파라미터 수나 타입이 완전히 일치해야 한다.
 - 반드시 상속 관계가 있어야 한다.
 - 재정의된 하위 클래스의 메소드 접근제어지시자는
   상위 클래스의 메소드 접근제어지시자보다 범위가 크거나 같아야 한다.
   예를 들어, 상위 클래스 메소드의 접근제어지시자가 protected인 경우
   하위 클래스가 이 메소드를 오버라이딩(Overriding)하는 경우
   접근제어지시자는 public 또는 protected 이어야 한다.
 - static, final, private 메소드는
   오버라이딩(Overriding)할 수 없다.
 - Exception 의 추가가 불가능하다.
   즉, 상위 메소드가 가지고 있는 기존의 예외 사항에
   새로운 Exception 을 추가하는 것은 불가능하다는 것이다.
*/

// 부모 클래스(상위 클래스, super class)
class SuperTest114
{
	private int a = 5;
	protected int b = 10;
	public int c = 20;

	public void write()
	{
		System.out.println("Super Write() 메소드 : " + a + " : " + b + " : " + c);
	}
}

// 자식 클래스(하위 클래스, sub class)
class SubTest114 extends SuperTest114
{
	/*
	protected int b = 10;
	public int c = 20;

	public void write()
	{
		System.out.println("Super Write() 메소드 : " + a + " : " + b + " : " + c);
	}
	*/

	protected int b = 100;

	public void print()
	{
		// System.out.println("Sub print() 메소드 : " + a + " : " + b + " : " + c);
		// 에러 발생(컴파일 에러)
		// 슈퍼클래스에서 선언된 변수 a 에는 접근할 수 없다
		// -> private 변수이기 때문
		System.out.println("Sub print() 메소드 : " + b + " : " + c);
		//== Sub print() 메소드 : 100 : 20      100 20 이 나오는 이유? -> SubTest114클래스에서 선언된 b가 덮어쓰기 함

		System.out.println("Sub print() 메소드 : " + b);			//== 100
		System.out.println("Sub print() 메소드 : " + this.b);		//== 100  == SubTest114.b
		System.out.println("Sub print() 메소드 : " + super.b);		//== 10   == SuperTest114.b
		// 변수 b는 접근 방법에 따라 다른 b로 접근 및 출력이 이루어진다
		// 슈퍼클래스에서 선언된 b, 서브클래스에서 선언된 b
		
		System.out.println("Sub print() 메소드 : " + c);			// 20
		System.out.println("Sub print() 메소드 : " + this.c);		// 20
		System.out.println("Sub print() 메소드 : " + super.c);		// 20
		// 변수 c는 접근하는데 아무런 제약과 제한이 없다
		// 슈퍼클래스에서 선언된 c
	}// end print()

	@Override
	public void write()
	{
		// System.out.println("Super Write() 메소드 : " + a + " : " + b + " : " + c);
		// 에러 발생(컴파일 에러)
		// 슈퍼클래스에서 선언된 변수 a 에는 접근할 수 없다
		// -> private 변수이기 때문

		System.out.println("Sub print() 메소드 : " + b + " : " + c);
	}
}

// main() 메소드를 포함하는 외부의 다른 클래스
public class Test114
{
	public static void main(String[] args)
	{
		// 하위 클래스(SubTest114) 인스턴스 생성
		SubTest114 ob = new SubTest114();

		ob.print();

		ob.write();
		//== Super Write() 메소드 : 5 : 10 : 20    오버라이딩 하기 전
		//== Sub print() 메소드 : 100 : 20         a를 출력구문에서 지운 후

		System.out.println("--------------------------------구분선");

		System.out.println(ob.b); //== 100
		System.out.println(((SuperTest114)ob).b); //== 10
		// SubTest114(하위 클래스) 자료형인 ob를 SuperTest114(상위 클래스)자료형으로 형변환하여 b를 부르면
		// 상위 클래스에서 선언된 대로 출력된다 == 슈퍼 부름
		// 반드시 괄호 ((SuperTest114)ob) 이런식으로 해야함!!!!!!

		ob.write();					//== Sub print() 메소드 : 100 : 20
		((SuperTest114)ob).write(); //== Sub print() 메소드 : 100 : 20 
		// 메소드는 변형되면 되돌릴 수 없다 == 메소드는 슈퍼 콜 불가능
		

	}
}

상속 (115)

/*==========================
  ■■■ 클래스 고급 ■■■
  - 추상 클래스(abstract)
===========================*/

/*
○ 추상 클래스(abstract)는
   
   선언만 있고 정의가 없는 하나 이상의 메소드(추상 메소드)를 갖는 클래스로
   하위 클래스(자식 클래스)에서 오버라이딩(Overriding)할 것으로 예상되는 메소드에 대해
   메모리 낭비 없이 미리 호출 계획을 세워두기 위해 만든다.

○ 형식 및 구조
   [접근제어지시자] abstract class 클래스명
   {
	   [접근제어지시자] abstract  자료형 메소드명([매개변수], ...);
   }
○ 특징
   
   클래스가 적어도 하나 이상의 추상 메소드를 포함할 때
   그 클래스는 클래스 앞에 abstract 키워드를 붙여
   추상 클래스로 명시해야 하며,
   추상 클래스로 선언한 경우에는
   불완전한 형태의 클래스이므로 객체를 생성할 수 없다.
   추상 메소드가 존재하지 않는 추상 클래스마저도
   객체를 생성할 수 없는 것이다.

   즉, 추상 클래스는 독립적으로 존재할 수 없기 때문에
   상속을 위해서만 존재하며
   추상 클래스를 상속받은 하위 클래스에서는
   반드시 추상 메소드를 오버라이딩(Overriding) 해야 한다.

   abstract 키워드는
   클래스와 메소드에서만 사용할 수 있으며
   멤버 변수나 로컬 변수에서는 사용할 수 없다.

*/	

// class SortInt115
abstract class SortInt115
{
	private int[] value;

	protected void sort(int[] value)
	{
		this.value = value;
		sorting();
	}
	
	// 추상 메소드
	//protected void sorting();
	protected abstract void sorting();

	protected int datalength()
	{
		return value.length;
	}

	// final 키워드로 인해
	// 이 클래스(SortInt115)를 상속받는 클래스에서
	// 이 메소드를 재정의(Nethod Overriding)할 수 없다
	protected final int compare(int i, int j)
	{
		int x = value[i];
		int y = value[j];

		if(x == y)
			return 0;
		else if(x > y)
			return 1;
		else
			return -1;
	}

	// final 키워드로 인해
	// 이 클래스(SortInt115)를 상속받는 클래스에서
	// 이 메소드를 재정의(Nethod Overriding)할 수 없다
	protected final void swap(int i, int j)
	{
		int temp = value[i];
		value[i] = value[j];
		value[j] = temp;
	}

}//end SortInt115

//public class Test115
//public class Test115 extends SortInt115 추상클래스를 상속받는 순간
//public abstract class Test115 extends SortInt115 // Test115도 추상클래스가 된다 -> 추상메소드 재정의 -> 일반 정상 클래스
public class Test115 extends SortInt115
{
/*
	protected void sort(int[] value)
	{
		this.value = value;
		sorting();
	}

	// 추상메소드
	protected abstract void sorting();

	protected int datalength()
	{
		return value.length;
	}
	protected final int compare(int i, int j)
	{
		int x = value[i];
		int y = value[j];

		if(x == y)
			return 0;
		else if(x > y)
			return 1;
		else
			return -1;
	}
	protected final void swap(int i, int j)
	{
		int temp = value[i];
		value[i] = value[j];
		value[j] = temp;
	}
*/

	int i,j;

	static int[] data = {7, 10, 3, 28, 7};
/*	
	@Override
	protected void sorting()
	{
		for(i = 0; i < datalength(); i++)
		{
			for(j = i + 1; j < datalength(); j++)
			{
				if(compare(i,j) == 1)
				{
					swap(i,j);
				}
			}
		}
	}
*/	@Override
	protected void sorting()
	{
		// 선택정렬
		for(i = 0; i < datalength() - 1; i++)
		{
			for(j = i + 1; j < datalength(); j++)
			{
				if(compare(i, j) == 1)
				{
					swap(i, j);
				}
			}
		}
	}



	public static void main(String[] args)
	{
		System.out.print("Source Data : ");
		for(int n : data)
			System.out.print(n + " ");
		System.out.println();

		Test115 ob = new Test115();
		ob.sort(data);

		System.out.print("Source Data : ");
		for(int n : data)
			System.out.print(n + " ");
		System.out.println();
	}

}

18일차

상속 (116)

/*=======================================
  ■■■ 클래스 고급 ■■■
  - 상속 관계에 있는 클래스들 간의 캐스팅
    (업 캐스팅, 다운 캐스팅)
=======================================*/

// super class, 부모 클래스, 상위 클래스
class SuperTest116
{
	public int a = 10, b = 20;

	public void write()
	{
		System.out.println("슈퍼클래스 write() 메소드...");
	}

	public int hap()
	{
		return a + b;
	}
}

// sub class, 자식 클래스, 하위 클래스
class SubTest116 extends SuperTest116
{
	public int b = 100, c = 200;

	@Override
	public int hap()
	{
		return a + b + c;
	}

	public void print()
	{
		System.out.println("서브클래스 print() 메소드...");
	}
}


// main() 메소드를 포함하는 외부의 다른 클래스
public class Test116
{
	public static void main(String[] args)
	{
		// 하위 클래스 기반 인스턴스 생성
		SubTest116 ob1 = new SubTest116();

		System.out.println("ob1.b : " + ob1.b);
		//== ob1.b : 100 // 덮어쓰기
		
		// ○ 업 캐스팅
		SuperTest116 ob2 = ob1;
		// SuperTest116 ob2 = (SuperTest116)ob1; 과 동일한 코드
		/*
		학생 홍길동 = new 학생();

		포유류 사람 = 홍길동;		// 포유류 사람 = (사람)홍길동; 과 동일한 코드

		학생도 포유류

		class 포유류			class 학생 extends 포유류
		{						{
		}						}

		*/

		System.out.println("ob2.b : " + ob2.b);
		//System.out.println("ob2.b : " + ((SuperTest116)ob1).b);
		//== ob2.b : 20
		// 메모리 그림판에서 변수는 객체별로 따로 할당되기 때문에
		// 변수 b는 ob2(부모객체)의 변수이다.
		
		System.out.println("합	: " + ob2.hap());
		//== 합      : 310
		// hap() 메소드는 오버라이딩(Overriding) 되어 있고
		// ob2(부모)는 ob1(자식)을 업캐스팅한 상태의 객체이므로
		// SuperTest116의 hap() 메소드를 호출하는 것이 아니라
		// SubTest에서 재정의한 hap() 메소드를 호출하게 된다.
		// 즉, 메소드는 
		// 업 캐스팅이 되더라도 
		// 재정의(덮어쓰기)한 이상 원래의 기능으로 되돌릴 수 없다.

		ob2.write(); // 오버라이딩안해서 부모설계도 write나온다
		//== 슈퍼클래스 write() 메소드...

		// ob2.print();         부모자료형으로 업캐스팅된 상황이라 자식설계도에 있는 메소드 못쓴다.
		//== 컴파일 에러


		// ○ 다운 캐스팅
		((SubTest116)ob2).print();			//자식자료형으로 다운캐스팅
		// 서브클래스 print() 메소드...

		// 추가 관찰 ------------------------------------------------------------------------
		// 다운 캐스팅 가능 여부
		
		// 상위 클래스 기반 인스턴스 생성
		SuperTest116 ob3 = new SuperTest116();
		
		SubTest116 ob4;

		//System.out.println(ob3.c);	// 상위 클래스에는 c가 없다 == 하위 클래스가 있다는 걸 모른다
		//== 컴파일 에러
		// 상위 객체는 하위 객체의 멤버에 접근하는 것이 불가능하다.
		// (상위 객체 입장에서는 어떤 하위 객체가 존재하는지도 알 수 없음)

		//ob4 = ob3;
		//== 컴파일 에러
		// 상위 객체는 하위 객체에 담을 수(참조할 수) 없다.

		//ob4 = (SubTest116)ob3;
		//== ClassCastException 런타임에러
		// 자식클래스 인스턴스 생성시 상속받는 부모클래스도 메모리에 올라가지만 
		// 부모클래스 인스턴스 생성시 자식클래스는 메모리에 올라가지 않는다(자식클래스가 한두개가 아닐 가능성이 크기 때문)
		// 그렇기 때문에 상위클래스 객체를 강제로 하위 클래스로 형 변환을 하게되면 컴파일은 되지만 런타임에러가 난다.

		// 작성된 구문의 문법적인 구조만 봤을 때 이 구문은 다운 캐스팅이 이루어지는 상황이다.
		// 하지만, 정상적인 캐스팅이 이루어지지 않는다. 현재 SubTest116 객체에 대한 메모리 할당은 이루어지지 않은 상태이기 때문
		// 그러므로, 이 상황에서 다운 캐스팅은 불가능하다.




	}
}

인터페이스(117)

/*
○ 인터페이스(Interface)란

   완전히 미완성된 채로 남겨져
   인터페이스 안에 존재하는 그 어떤 메소드도
   몸체(정의부)가 없기 때문에 사실상 실행 부분이 존재하지 않는다.
   클래스를 위한 템플릿으로써의 기능을 수행하는
   추상 클래스의 한 종류이다.

○ 인터페이스는 클래스와 달리 다중 상속이 가능하며
   인터페이스 자체도 상속된다.
   기존의 C++ 언어 등에서 지원되는 다중 상속이
   사용 과정에서 많은 문제점을 노출시켰기 때문에
   자바에서는 다중 상속의 개념을 인터페이스라는 개념으로 변형하여
   인터페이스를 통해 다중 상속을 구현하는 방법을 지원한다.

○ 인터페이스는 상수와 추상 메소드만 가질 수 있으며
   인터페이스 안의 메소드들은 접근제어지시자를 명시하지 않아도
   public 으로 설정되어 클래스에서 구현(implements)함으로써
   바로 접근이 이루어질 수 있다.

○ 특징
   - 추상 클래스의 일종으로 선언만 있고 정의가 없다.
   - final 변수는 가질 수 있다. (상수의 개념)
   - 인터페이스는 public static final 상수만 만들 수 있다.
   - 인터페이스를 구현하기 위해서는 extends 대신에
     inplements 를 이용한다
   - 하나 이상의 인터페이스를 implements 할 수 있다.
   - 인터페이스를 implements 한 클래스는
     인터페이스의 모든 메소드를 Overriding 해야 한다.
   - 인터페이스가 다른 인터페이스를 상속받을 수 있으며
     이 때, extends 키워드를 사용한다.
	 또한, 클래스와 달리 인터페이스는 다중 상속이 가능하다.

*/

// 인터페이스
interface Demo
{
	public static final double PI = 3.141592;
	
	// 인터페이스의 멤버 변수는
	// static final 을 별도로 명시하지 않더라도 자동으로 붙여준다.
	public int a = 10;
	
	// 인터페이스의 메소드는 선언만 가능(정의 불가)
	// 자동으로 abstract 인 상태
	// public abstract void print();
	public void print();
	/* 선언만 해야 함
	{
		System.out.println("PI : " + PI);
	}
	*/
}

// 클래스
// class DemoImpl
// class DemoImpl extends Demo     // x
// class DemoImpl implements Demo

// 추상 클래스 - 인터페이스를 구현하는 추상 클래스
// abstract class DemoImpl implements Demo
// 클래스 - 인터페이스를 구현하는 클래스 ( print() 메소드 재정의)
class DemoImpl implements Demo
{
	@Override
	public void print()
	{		
		System.out.println("인터페이스 메소드 재정의...");
	}

	public void write()
	{
		System.out.println("클래스에 정의된 메소드...");
	}
}


// main() 메소드를 포함하는 외부의 다른 클래스
public class Test117
{
	public static void main(String[] args)
	{
		// Demo ob = new Demo();		// 생성 불가
		// 인터페이스는 인스턴스를 생성할 수 없음(추상클래스도 안되는데)

		// DemoImpl ob = new DemoImpl();
		//-- 인터페이스를 implements 만 한 상태에서는 불가
		// print() 메소드(-> 추상 메소드)를 재정의한 후
		// abstract 상태에서 벗어난 후 가능

		//DemoImpl obTemp = new DemoImpl();
		//Demo ob = (Demo)obTemp; == //Demo ob = obTemp;

		// ○ 업 캐스팅
		// 인터페이스 객체는 상위 객체
		Demo ob = new DemoImpl();
		ob.print();
		//== 인터페이스 메소드 재정의...




		// ob.write();			상위 객체에는 하위 객체 멤버가 없다
		//== cannot find symbol 컴파일 에러


		// 다운 캐스팅
		((DemoImpl)ob).write();
		//== 클래스에 정의된 메소드...

		System.out.println(Demo.PI);  // static이어서 접근 가능
		//== 3.141592  

		System.out.println(Demo.a);	  // 자동으로 static 붙여짐
		//== 10

		// Demo.a = 300;
		//== cannot assign a value to final variable a  == final 한번 값들어가면 변경 불가

	}
}

인터페이스(118)

// 인터페이스
interface ADemo
{
	public void write();
}

// 인터페이스
interface BDemo
{
	public void print();		
}

// 인터페이스는 2개 이상을 구현(implements)할 수 있다.
// -> 클래스에서 다중 상속이 되지 않는 부분을 보완(보충)하는 개념

// 클래스
// class DemoImpl
// class DemoImpl extends ADemo, BDemo   // x
// class DemoImpl implements ADemo, BDemo

// 추상 클래스 - 두 인터페이스를 구현하는 추상 클래스
//abstract class DemoImpl implements ADemo, BDemo

// 클래스 - 두 인터페이스를 구현한 후 -> 두 인터페이스의 모든 메소드를 Overriding -> 일반 클래스
class DemoImpl implements ADemo, BDemo
{
	// JDK 1.5(5.0)에서는 인터페이스 메소드를 오버라이딩(Overriding)할 때 @Override 어노테이션을 사용할 수 없다.
	// JDK 1.6(6.0) 이후부터 적용 가능한 문법이다. 단, 상속받은 클래스의 메소드를 오버라이딩(Overriding)할 때에는
	// JDK 1.5(5.0)에서도 어노테이션(anotation) 사용이 가능하다.
	@Override
	public void write()
	{
		System.out.println("ADemo 인터페이스 메소드 write()...");
	}

	@Override
	public void print()
	{
		System.out.println("BDemo 인터페이스 메소드 print()...");
	}
}


// main() 메소드를 포함하는 외부의 다른 클래스
public class Test118
{
	public static void main(String[] args)
	{
		// ADemo ob = new ADemo(); 인터페이스로 인스턴스 생성 불가능(추상클래스도 안되는데)
		// BDemo ob = new BDemo(); 인터페이스로 인스턴스 생성 불가능(추상클래스도 안되는데)
		
		// ADemo, BDemo 인터페이스를 구현(implements)한
		// 클래스(-> DemoImpl) 기반의 인스턴스 생성
		DemoImpl ob1 = new DemoImpl();	// 이상 없음

		ob1.write();
		//== ADemo 인터페이스 메소드 write()...

		ob1.print();
		//== BDemo 인터페이스 메소드 print()...
		

		// 둘 다 업 캐스팅
		ADemo ob2 = new DemoImpl();
		BDemo ob3 = new DemoImpl();

		//ob2.print();		//ob2에는 print메소드가 없다
		//==  cannot find symbol 컴파일 에러
		//ob3.write();		//ob3에는 write메소드가 없다
		//==  cannot find symbol 컴파일 에러

		ob2.write();
		ob3.print();
		// ADemo 인터페이스 메소드 write()...
		// BDemo 인터페이스 메소드 print()...

		((BDemo)ob2).print();
		//== BDemo 인터페이스 메소드 print()...
		((ADemo)ob3).write();
		//== ADemo 인터페이스 메소드 write()...
		// DemoImpl 클래스가 두 인터페이스(ADemo, BDemo)를 모두 구현했기 때문에
		// 이와 같은 처리가 가능하다.
		// 만약, DemoImpl 클래스가 두 인터페이스들 중 한 인터페이스만 구현했다면
		// 이 구문은 런타임 에러가 발생하는 구문이 된다.
		

		// 다운 캐스팅
		((DemoImpl)ob3).write();


	}
}

// 각각의 인터페이스에 같은 이름의 메소드가 있을 때 구별해서 Overriding하는 방법이 있는지 컴파일 오류가 생기는지

인터페이스 (119)


// 인터페이스
interface Demo
{
	public void write();
	public void print();
}

// 클래스
// class DemoImpl
// 인터페이스를 구현하는 추상 클래스
abstract class DemoImpl implements Demo
{
	@Override
	public void write()
	{
		System.out.println("write() 메소드 재정의...");
	}
	// abstract public void print();
}

// 클래스
// class DemoImplSub
// class DemoImplSub extends DemoImpl
// 추상 클래스를 상속받은 추상 클래스
// abstract class DemoImplSub extends DemoImpl
// 추상 클래스를 상속받은 클래스
class DemoImplSub extends DemoImpl
{	/*
	public void write()
	{
		System.out.println("write() 메소드 재정의...");
	}
	// abstract public void print();
	*/
	@Override
	public void print()
	{
		System.out.println("print() 메소드 재정의...");
	}
}

// main() 메소드를 포함하는 외부의 다른 클래스
public class Test119
{
	public static void main(String[] args)
	{
		//Demo ob1 = new Demo();
		// 인스턴스 생성 불가 -> 인터페이스

		// DemoImpl.ob2 = new DemoImpl();
		//-- 인스턴스 생성 불가 -> 추상 클래스

		DemoImplSub ob3 = new DemoImplSub();

		ob3.write();
		ob3.print();

		// write() 메소드 재정의...
		// print() 메소드 재정의...
	}
}

인터페이스(120)

/*==========================
  ■■■ 클래스 고급 ■■■
  - 인터페이스(Interface)
==========================*/

/*
○ extends  vs implements
   클래스 extends 클래스
   클래스 extends 추상클래스

   인터페이스 extends 인터페이스
   인터페이스 extends 인터페이스, 인터페이스, ...
   
   추상클래스 implements 인터페이스
   추상클래스 implements 인터페이스, 인터페이스, ...

   클래스 implements 인터페이스
   클래스 implements 인터페이스, 인터페이스, ...

※ 인터페이스는 클래스와는 달리 다중 상속이 가능하며,
   인터페이스 자체도 상속된다.

※ 인터페이스의 멤버 변수인 데이터는
   접근제어지시자를 별도로 명시하지 않더라도
   기본 상수(primitive constant)인 public static final 의 변경자로 설정된다.
   클래스에서 인터페이스를 추가하여(implements) 사용할 경우
   인터페이스 안에서 선언된 모든 메소드를 구현해 주어야 하며
   인터페이스를 구현하는 클래스는
   인터페이스의 상위 인터페이스가 제공하는 추상 메소드를 포함한
   모든 메소드를 구현하지 않을 경우
   추상(abstract) 클래스로 선언해야 한다.

※ 형식
   - 인터페이스는 메소드를 선언만 하고 정의는 없다.
   - 인터페이스를 implements 할 겨우 반드시 하위 클래스는
     인터페이스의 모든 메소드를 오버라이딩(Overriding)해야 한다.
   - 인터페이스는 자동적으로 다음과 같이 처리된다.
       멤버 변수 : public static final
	   메소드    : public abstract
   - 다중 상속은 콤마(,)로 구분되며
     여러 개의 인터페이스를 상속할 수 있다.
   - 인터페이스끼리 상속할 경우는 extends 키워드를 사용한다.


※ 인터페이스의 선언

   인터페이스는 클래스의 내부 구현을 제외한 참조형만 선언한 것이므로
   메소드를 선언만 하고 정의는 할 수 없다.
   또한, 클래스에서의 변수는 값이 변할 수 있지만
   인터페이스에서의 변수는 상수처럼 값이 변할 수 없기 때문에
   선언 시에 미리 값을 할당해 놓아야 한다.

※ 인터페이스의 구현

   인터페이스는 클래스를 위한 템플릿이기 때문에
   사용 가능한 인터페이스가 되기 위해서는
   자바 프로그램에서 인터페이스를 구현해 주어야 하는데
   이러한 기능을 수행하는 것이 implements 예약어이다.

※ 클래스는 동시에 두 개 이상의 인터페이스를
   implements 할 수 있다.
*/

// 인터페이스
interface ADemo
{
	public void write();
}

// 인터페이스
interface BDemo
{
	public void print();
}

// 인터페이스
// interface CDemo
// 두 인터페이스(ADemo, BDemo)를 상속받은 인터페이스
interface CDemo extends ADemo, BDemo
{	
	// public void write();
	// public void print();
	public void test();
}

// 클래스
// class DemoImpl
// abstract class DemoImpl implements CDemo
// 두 인터페이스(ADemo, BDemo)를 상속받은 인터페이스(CDemo)를 구현한 후 모든 메소드를 재정의한 클래스
class DemoImpl implements CDemo
{
	@Override
	public void test()
	{
		System.out.println("test()...");
	}

	@Override
	public void write()
	{
		System.out.println("write()...");
	}

	@Override
	public void print()
	{
		System.out.println("print()...");
	}
}

public class Test120
{
	public static void main(String[] args)
	{
		// 두 개의 인터페이스(ADemom BDemo)를 상속받은 인터페이스(CDemo)를 구현하고
		// 해당 인터페이스(CDemo)의 메소드 뿐 아니라 상속받은 인터페이스(ADemo, BDemo)의
		// 모든 메소드를 재정의(Overriding)한 DemoImpl 클래스 기반의 인스턴스 생성
		DemoImpl ob = new DemoImpl();

		ob.test();
		ob.write();
		ob.print();

		//test()...
		//write()...
		//print()...
	}
}

인터페이스 실습(121)

/*
○ 실습 문제
   성적 처리 프로그램을 구현한다.
   단, 인터페이스를 활용할 수 있도록 한다.


 실행 예)
 인원 수 입력(1~10) : 11
 인원 수 입력(1~10) : 0
 인원 수 입력(1~10) : 2

 1번째 학생의 학번 이름 입력(공백 구분) : 2309123 aaa
 국어 영어 수학 점수 입력   (공백 구분) : 90 100 85
 2번째 학생의 학번 이름 입력(공백 구분) : 2309125 bbb
 국어 영어 수학 점수 입력   (공백 구분) : 85 70 60

 2309123 aaa   90 100  85   총점   평균.xx
 				  수  수  우
 2309125 bbb   85  70  60   총점   평균.xx
 				  우  미  양

 계속하려면...

 90 이상	     수
 80 이상 90 미만 우
 70      80      미
 60		 70		 양
 				 가
*/
import java.util.Scanner;
import java.io.IOException;

// 속성만 존재하는 클래스 -> 자료형 활용
class Record
{
	String hak, name;			// 학번 이름
	int kor, eng, mat;			// 국어 영어 수학
	int tot;					// 총점
	double avg;					// 평균
}



interface Sungjuk
{
	public void set();			// 인원 세팅
	public void input();		// 데이터 입력
	public void print();		// 결과 출력
}



// 문제 해결 과정에서 설계해야 할 클래스 -> Sungjuk 인터페이스를 구현하는 클래스
class SungjukImpl implements Sungjuk
{
	private int inwon;
	private Record[] rec;

	@Override
	public void set()
	{
		Scanner sc = new Scanner(System.in);
		do
		{
			System.out.print("인원 수 입력(1~10) : ");
			inwon = sc.nextInt();

		}
		while (inwon > 10 || inwon < 1);

		rec = new Record[inwon];
	}

	@Override
	public void input()
	{
		for(int i = 0; i < inwon; i++)
		{
			rec[i] = new Record();

			Scanner sc = new Scanner(System.in);
			System.out.printf("%d번째 학생의 학번 이름 입력(공백 구분) : ", i + 1);
			rec[i].hak = sc.next();
			rec[i].name = sc.next();

			System.out.print("국어 영어 수학 점수 입력   (공백 구분) : ");
			rec[i].kor = sc.nextInt();
			rec[i].eng = sc.nextInt();
			rec[i].mat = sc.nextInt();

			rec[i].tot = rec[i].kor + rec[i].eng + rec[i].mat;
			rec[i].avg = rec[i].tot / 3.0;
		}
	}

	@Override
	public void print()
	{
		for(int i = 0; i < inwon; i++)
		{
			System.out.printf("%s %s   %d %d %d   %d   %.2f\n", rec[i].hak, rec[i].name, rec[i].kor, rec[i].eng, rec[i].mat, rec[i].tot, rec[i].avg);
			System.out.printf("%14s %s %s\n", panJung(rec[i].kor), panJung(rec[i].eng), panJung(rec[i].mat));
		}
	}

	// 내부적으로 등급에 대한 판정을 수행할 메소드

	private String panJung(int Score)
	{
		if(Score >= 90)
			return "수";
		else if (Score >= 80)
			return "우";
		else if(Score >= 70)
			return "미";
		else if(Score >= 60)
			return "양";
		else
			return "가";

	}

}


// main() 메소드를 포함하는 외부의 다른 클래스
public class Test121
{
	public static void main(String[] args) throws IOException
	{
		//Sungjuk ob;
		Sungjuk ob = new SungjukImpl();

		// 문제 해결 과정에서 작성해야 할 ob 구성 및 객체 생성

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

		// 판정이 public 일때
		// System.out.print(((SungjukImpl)ob).panJung(90));

		// 이렇게도 가능
		// ((SungjukImpl)ob).set();
		// ((SungjukImpl)ob).input();
		// ((SungjukImpl)ob).print();
	}

/*
인원 수 입력(1~10) : 11
인원 수 입력(1~10) : 0
인원 수 입력(1~10) : 2
1번째 학생의 학번 이름 입력(공백 구분) : 2309123 김다슬
국어 영어 수학 점수 입력   (공백 구분) : 90 100 85
2번째 학생의 학번 이름 입력(공백 구분) : 2309125 김동민
국어 영어 수학 점수 입력   (공백 구분) : 85 70 60
2309123 aaa   90 100  85   275   91.67
                   수 수  우
2309125 bbb   85 70  60   215   71.67
                   우 미  양
*/
}

중첩 클래스(122~124)

/*==========================
  ■■■ 클래스 고급 ■■■
       - 중첩 클래스
==========================*/

/*
○ 중첩 클래스

   중첩 클래스란 클래스 안에 다른 클래스가 설계되어 있는 형태로
   클래스 내부에서만 사용할 보조 클래스가 필요한 경우
   클래스를 중첩하여 프로그램의 구조를 보다 더 간단하고 알아보기 쉽도록
   만들 수 있는데 이러한 클래스를 중첩 클래스라 한다.
   이는, 특정 클래스를 자신의 클래스 내부적인 용도로만 사용할 목적으로 쓰이는데
   특정 클래스를 마치 자신의 멤버 변수나 메소드처럼 사용할 수 있게 한다.

○ 중첩 클래스의 종류(4가지)

   1. static 중첩 클래스(중첩 내부 클래스)
      -> 클래스 내부에... public static class 클래스명

	  중첩 클래스를 감싸는 외부 클래스의 {} 안에
	  static 을 붙인 새로운 클래스를 설계하는 것으로
	  모든 접근제어지시자를 사용할 수 있다.
	  static 중첩 클래스가 포함하고 있는 메소드에서는
	  외부 클래스의 인스턴스 변수나 인스턴스 메소드에는 접근할 수 없고,
	  (외부 클래스의 객체를 생성하지 않은 상태)
	  클래스 변수와 클래스 메소드만 접근할 수 있다.

	  - 프로그램의 구조를 보다 더 간단하고 알아보기 쉽게 구성할 수 있다.
	  - static 으로 선언된 내부 클래스이다.
	  - 중첩 클래스의 객체는 중첩 클래스를 포함하고 있는
	    외부 클래스의 객체와 동등핟.
	  - 외부 클래스의 클래스 변수와 클래스 메소드는
	    바로 접근하여 사용하는 것이 가능하다.
	  - 중첩 클래스와 중첩 클래스를 포함하고 있는 외부 클래스의
	    인스턴스 변수와 인스턴스 메소드는
		객체를 생성하여 서로 접근하는 것이 가능하다.
	  - 중첩 클래스를 외부에서 단독으로 사용하는 것이 가능하다.
   2. 내부 클래스(inner class)
      ->클래스 내부에... public class 클래스명

	  - static 중첩 클래스와 마찬가지로 프로그램 구조를 보다 더 간단하고
	    알아보기 쉽도록 하기 위해 구성한다.
      - 외부 클래스의 메소드에서 내부 멤버 클래스를 사용하기 위해서는
	    반드시 내부 멤버 클래스 객체를 생성해 주어야 한다.
	  - 외부 클래스의 멤버 변수와 메소드를
	    객체 생성 없이 바로 사용하는 것이 가능하다.
	  - 내부 멤버 클래스는 외부에서 단독으로 객체를 생성하여 사용할 수 없다.
	    즉, 내부 멤버 클래스는 외부 클래스의 인스턴스 생성이 선행되어야 한다는 것이다.
	  - static 으로 선언된 변수 또는 메소드를 가질 수 없다.
   
   3. 지역 클래스(로컬 클래스, local class)
      -> 메소드 내부에.. class 클래스명
	                또는 static class 클래스명

	  - 클래스의 메소드 안에서 클래스를 정의하는 것으로
	    내부 멤버 클래스와 유사한 성격을 가지고 있긴 하지만
		접근제어지시자는 붙일 수 없다.

   4. 무명 클래스(익명 클래스, annonymous class)
   	  -> 이름 없는 클래스

	  - 클래스 또는 인터페이스에 대한 객체를 생성하면서
	    바로 클래스 또는 인터페이스를 정의하는 클래스.
	  - 정의하는 부분과 생성하는 부분이 하나로 묶여져
	    new 수식이 있는 곳에서 바로 클래스 또는 인터페이스를
		정의하는 것을 의미한다.

		new 기능()
		{
			...
		};

*/
// outer
class Test
{
	static int a = 10;								// static
	int b = 20;
	
	// inner
	public static class StaticNested				// static
	{
		int c = 30;

		void write()
		{
			System.out.println("write()...");
			System.out.println("a : " + a);
			//System.out.println("b : " + b);		// static 없다
			System.out.println("c : " + c);
		}
	}

	void print()
	{
		// StaticNested 기반 인스턴스 생성(-> inner)
		StaticNested sn = new StaticNested();
		sn.write();
	}
}

// main() 메소드가 포함된 클래스
public class Test122
{
	public static void main(String[] args)
	{
		// 밖에서 Test 기반 인스턴스 생성(-> outer)
		Test ob1 = new Test();
		ob1.print();
		//== write()...
		// a : 10
		// c : 30

		// 밖에서... StaticNested 기반 인스턴스 생성(inner)
		// StaticNested ob2 = new StaticNested();
		// 컴파일 에러

		// 중첩 내부 클래스는 외부에서 단독으로 객체를 생성한다.
		// 단, 위와 같은 방법으로 객체를 생성해서는 안되고,
		// 클래스 변수 접근이나 클래스 메소드를 호출하는 것과 같은 방식을 통해
		// 접근하여 인스턴스를 생성할 수 있도록 처리해야 한다.
		
		// Test.a

		Test.StaticNested ob2 = new Test.StaticNested();
		ob2.write();
		// write()...
		// a : 10
		// c : 30
	}
}
/*==========================
  ■■■ 클래스 고급 ■■■
       - 중첩 클래스
==========================*/

// outer
class Test2
{
	static int a = 10;
	int b = 20;

	void write()											// 첫 번째 write() 메소드
	{
		System.out.println("write()... 1");
		final int c = 20;
		int d = 40;
		
		// inner class
		// 메소드 안에 존재하는 또다른 클래스(로컬 클래스, local class, 지역 클래스)
		class LocalTest
		{
			void write()									// 두 번째 write() 메소드
			{
				System.out.println("write()... 2");
				System.out.println("a : " + a);
				System.out.println("b : " + b);
				System.out.println("c : " + c);
				//System.out.println("d : " + d); 컴파일에러
			}
		}
		d++;

		// 변수 c 와 변수 d 는 둘 다 지역변수이지만(첫 번째 write() 메소드에서 선언된 변수이므로)
		// c 는 final 변수이기 때문에 두 번째 write() 메소드에서 언제접근하더라도 
		// 고정된 값 20이 담겨있음을 보장받을 수 있다. 반면에 d 는 그 값이 수시로 변화될 수 있는 상황이므로
		// LocalTest 클래스의 인스턴스 생성 시점이 언제가 될지 알 수 없기 때문에
		// 이로 인해 인스턴스 생성 시점에 d 에 어떤 값이 담겨있는지를 보장받을 수 없게 된다.
		// 변수 d에 접근하는 것은 피할 수 있도록 문법적으로 처리하는 것이다

		// LocalTest 클래스 기반 인스턴스 생성(-> inner)
		LocalTest lt = new LocalTest();
		lt.write();											// 두 번째 write()메소드 출


	}
}
public class Test123
{
	public static void main(String[] args)
	{
		// Test2 클래스 기반 인스턴스 생성(-> outer)
		Test2 ob = new Test2();
		ob.write();										   // 첫번째 write() 메소드 호출
		// 컴파일 에러
		// d도 인스턴스 변수고 두 번째 write도 인스턴스 변수이지만 final 이 붙은 c와는 다르게 변동 가능성이 크기때문에 에러
	}
}
/*==========================
  ■■■ 클래스 고급 ■■■
       - 중첩 클래스
==========================*/

class InnerOuterTest
{
	static int a = 10;
	int b = 20;

	class InnerNested
	{
		int c = 30;

		void write()
		{
			System.out.println("inner 의 write()...");
			System.out.println("a : " + a);
			System.out.println("b : " + b);
			System.out.println("c : " + c);
		}
	}

	void write()
	{
		System.out.println("outer 의 write()...");
		
		// InnerNested 클래스 기반 인스턴스 생성(->inner)
		InnerNested ob1 = new InnerNested();
		ob1.write();					// inner 의 write()메소드 호출
	}
}

public class Test124
{
	public static void main(String[] args)
	{
		// InnerOuterTest 클래스 기반 인스턴스 생성(-> outer)
		InnerOuterTest ob2 = new InnerOuterTest();
		ob2.write();								// outer 의 write() 메소드 호출

		//== outer 의 write()...
		//   inner 의 write()...
		//	 a : 10
		//	 b : 20
		//   c : 30

		// InnerNested 클래스 기반 인스턴스 생성(-> inner)
		// InnerNested ob3 = new InnerNested();
		// 컴파일 에러
		
		// Test122.java 파일과 비교
		// InnerOuterTest 클래스 기반 인스턴스 생성(inner)
		// InnerOuterTest.InnerNested ob4 = new InnerOuterTest.InnerNested();
		//== 컴파일 에러

		// 중첩 내부 클래스(static 중첩 클래스)와는 달리 외부 클래스의 인스턴스(객체)를 사용하지 안고
		// 단독으로 내부 클래스의 인스턴스를 생성하는 것은 불가능하다.
		// -> 단, 외부 클래스의 객.체. 를 사용하면
		// 내부 클래스의 객체를 생성하는 것이 가능하다.

		// check - > Test122.java 와 비교
		InnerOuterTest.InnerNested ob5 = ob2.new InnerNested();
		ob5.write();
		// inner 의 write()...
		// a : 10
		// b : 20
		// c : 30

		// check - > Test122.java 와 비교
		InnerOuterTest.InnerNested ob6 = new InnerOuterTest().new InnerNested();
		ob6.write();

		// outer클래스명.inner클래스명 참조변수명 = new outer생성자().new inner생성자();

		// cf) static -> 중첩 내부 클래스
		// outer클래스명.inner클래스명 참조변수명 = new outer클래스명.inner생성자();
		
	}
}

19일차

자바의 주요 클래스들(126)

/*
○ 개요

   일반적으로 클래스는 하나만 존재하는 것이 아니라
   같은 조류의 클래스를 여러 개 묶어서 사용하게 되는데
   이러한 클래스나 인터페이스의 묶음을 패키지(package)라고 한다.
   Sun(Oracle)사에서는 자바 프로그램을 효율적으로 작성할 수 있도록 자바 표준 패키지를 제공하며,
   자바 표준 패키지에는 그래픽, 네트워크, 데이터베이스 등의 다양하고 유용한 클래스들이 포함되어 있다.

○ improt 구문

   자바 표준 패키지나 사용자에 의해 외부에서 만들어진 패키지를 사용하기 위해서는 컴파일을 수행하기에 앞서 프로그램에 포함시키는
   과정이 필요한데, 이 때 import 문을 이용하여 패키지 또는 클래스를 프로그램에 포함시키게 된다.
   하지만, java.lang.* 패키지는 자바 프로그램에 기본적으로 inport 되어 있기 때문에 이 패키지의 클래스들은 import 하지 않고
   바로 사용하는 것이 가능하다.

   import 문은 반드시 클래스 설계 구문 전에 선언되어 있어야 하며
   형식은 다음과 같은 두 가지가 있다.

   import [static] 패키지.클래스;
   import [static] 패키지.*;

   ※ JDK1.5 부터는 import 다음에 static 키워드를 사용할 수 있게 하였고
      정적으로 패키지를 import 할 수 있는 기능을 제공하게 되었다.
	  만약 패키지를 정적으로 import 한 경우라면 모든 접근 가능한 메소드와 멤버 변수들은
	  접두사 (ex -> ob, br, sc 처럼)를 붙이지 않고 사용하는 것이 가능하다.


○ Object 클래스
   
   java.lang.Object 클래스는 자바 클래스의 최상위 클래스로
   자바 표준 패키지의 클래스나 사용자에 의해 작성된 모든 클래스는 기본적으로 이 클래스로부터
   상속받는다. 따라서, 자바의 모든 클래스는 java.lang.Object 클래스의 메소드를 가지고 있으며,
   바로 사용하는 것이 가능하다.
*/

// import java.lang.*;

public class Test126 // extends Object
{
	/*
	Object 클래스로부터 상속받은 멤버들
	...
	...

	...toString()
	{
		...;
	}
	*/

	public static void main(String[] args)
	{
		Test126 ob = new Test126();

		// 객체.xxx();
		// 해당 객체를 생성시키는데 사용된 클래스의 메소드 xxx() 호출

		// Circle ob = new Circle();
		// ob.input();
		// ob 객체를 생성시키는데 사용된 클래스 -> Circle
		// Circle 클래스에 정의되어 있는 input() 메소드 호출

		// 객체.yyy();
		// 해당 객체를 생성시키는데 사용된 대상 클래스에
		// yyy() 메소드가 존재하지 않을 때...
		//== 에러 발생(컴파일 에러)

		// System.out.println(ob.action());
		//== 컴파일에러 cannot find symbol
		// ob객체를 생성시키는데 사용된 Test126 클래스에
		// action 메소드가 존재하지 않기 때문에 에러 발생하는 상황

		System.out.println(ob.toString());	// Object클래스로부터 상속받은 메소드
		//== Test126@15db9742
		//-- 메모리 주소가 아니라
		//   자바가 객체를 구분하기 위해 임의로 부여하는 식별번호
		//-- Test126 클래스에 toString() 메소드가 존재하지 않음에도 불구하고
		//   에러가 발생하지 않는 상황
		//   -> Object 로 부터 상속받음

		System.out.println(ob);
		//== Test126@15db9742
		// println(Object ob)
		// Object ob = new Test126();		object - system - test126 이런식으로 내려오기때문에 업캐스팅이 자동으로 되는것
		// Sungjuk ob = new SungjukImpl(); 와 똑같다

	}
}

자바의 주요 클래스(127)

// Test126.java 파일과 비교

// import java.lang.*;
// import java.lang.Object 를 포함하는 구문

public class Test127	// extends Object
{
	/*
	Object 클래스로부터 상속받은 멤버들
	...
	...

	public String toString()
	{
		...;
	}

	..
	*/

	@Override
	public String toString()
	{
		return "재정의한 toString()...";
	}

	public static void main(String[] args)
	{
		Test127 ob = new Test127();

		System.out.println(ob.toString());
		//== 재정의한 toString()...  // 클래스명의 해쉬코드 아님

		System.out.println(ob);
		//== 재정의한 toString()...
	}
}

Object 클래스(128)

class Test
{
	private int a = 10;

	public void write()
	{
		System.out.println("a : " + a);
	}
}

public class Test128
{
	public static void main(String[] args)
	{
		Test ob1 = new Test();
		Test ob2 = new Test();

		System.out.println("10 == 9 : " + (10 == 9));
		//== 10 == 9 : false

		int a = 10;
		int b = 20;
		System.out.println("a == b : " + (a == b));
		//== a == b : false

		// ※ == 비교 연산자는 피연산자의 크기를 비교함을 확인(관찰)

		System.out.println("ob1 == ob2 : " + (ob1 == ob2));
		//== ob1 == ob2 : false

		// ※ 객체(object)들을 비교하는 과정에서 사용하는 == 연산자는
		//    크기를 비교하는 것이 아니라 대상 객체의 주소를 비교

		System.out.println();
		System.out.println("--------------------------------------------------");
		System.out.println();

		System.out.println("ob1 : " + ob1);
		System.out.println("ob1.toString() : " + ob1.toString());
		// ob1			  : Test@15db9742
		// ob1.toString() : Test@15db9742

		System.out.println("ob2 : " + ob2);
		System.out.println("ob2.toString() : " + ob2.toString());
		// ob2			  : Test@6d06d69c
		// ob2.toString() : Test@6d06d69c

		// 클래스명@해시코드

		// ※ 해시코드(hashcode)
		//    : 자바 내부적으로 객체를 구분하기 위해 사용하는 것.
		//	    메모리의 주소값으로 생각하면 절대로 안된다.


		// ※ 객체가 같으면 hashcode(해시코드)가 같지만
		//    hashcode(해시코드)가 같다고 같은 객체는 아니다.


	}
}

Object 클래스(129)

class NewCar
{
	private int velocity;		// 자동차의 속도
	private int wheelNum;		// 자동차의 바퀴 갯수
	private String carName;		// 자동차의 이름

	NewCar(int speed, String name, int wheel)
	{
		velocity = speed;
		carName = name;
		wheelNum = wheel;
	}
}

public class Test129
{
	public static void main(String[] args)
	{
		NewCar nCar1 = new NewCar(250, "벤츠", 4);
		NewCar nCar2 = new NewCar(150, "아우디", 4);

		// equals()
		System.out.println("1-1 : " + nCar1.equals(nCar2));
		System.out.println("1-2 : " + (nCar1 == nCar2));
		//== 1-1 : false	객체의 주소값으로 비교
		//   1-2 : false

		NewCar nCar3 = nCar1;	// 객체 복사 -> 얕은 복사(참조형) -> 주소값 복사

		System.out.println("2-1 : " + nCar1.equals(nCar3));
		System.out.println("2-2 : " + (nCar1 == nCar3));
		//==2-1 : true		equals는 객체가 들어간 경우 주소값으로 비교하기 때문
		//  2-2 : true

		// toString() 주소값
		System.out.println("3-1 : " + nCar1.toString());
		System.out.println("3-2 : " + nCar2.toString());
		System.out.println("3-3 : " + nCar3.toString());

		// 3-1 : NewCar@15db9742
		// 3-2 : NewCar@6d06d69c
		// 3-3 : NewCar@15db9742

		// hashCode() 주소값 16진수 형태
		System.out.println("4-1 : " + nCar1.hashCode());
		System.out.println("4-2 : " + nCar2.hashCode());
		System.out.println("4-3 : " + nCar3.hashCode());
		// 4-1 : 366712642
		// 4-2 : 1829164700
		// 4-3 : 366712642

		// 결과값을 16진수 형태로 바꾸게되면 toString 메소드가 반환한 결과값 확인 가능

		// getClass() 어떤 클래스의 객체냐?
		System.out.println("5-1 : " + nCar1.getClass());
		System.out.println("5-2 : " + nCar2.getClass());
		System.out.println("5-3 : " + nCar3.getClass());
		// 5-1 : class NewCar		
		// 5-2 : class NewCar
		// 5-3 : class NewCar
		//-- 생성된 객체를 통해
		//   해당 객체의 기반 설계도(클래스)를 확인할 수 있는 기능을 가진 메소드

		// clone()    객체복사

		// finalize() 객체 직렬화

		// 기타 나머지 메소드는 스레드 처리와 관련이 있다.
	}
}

Wrapper 클래스(130)

/*===========================================
       ■■■ 자바의 주요 클래스 ■■■
 - 자바에서 기본적으로 제공하는 주요 클래스들
 - Wrapper 클래스
============================================*/

/*
○ Wrapper 클래스
   
   1. 자바에서는 언어 수준에서 제공하는 기본형 데이터를 제외한
      나머지는 클래스로 설계하여 객체 단위로 처리한다.
	  따라서 자바에서는 이러한 기본형 데이터를 객체 단위로 처리할 수 
	  있도록 클래스를 제공할 수 밖에 업슨데 일한 클래스들을 가리켜 Wrapper클래스라 한다.

   2. 기본 자료형인
      byte, short, int,     long, float, double, char,      boolean 형에 대응하는
	  Byte, Short, Integer, Long, Float, Double, Character, Boolean 의
	  Wrapper 클래스 및 큰 숫자들을 다루기 위한
	  java.math.BigInteger 와 java.math.BigDecimal 클래스를 제공한다.

	  Wrapper 클래스는 java.lang 패키지에 포함되어 있으므로
	  별도의 import 과정 없이 바로 사용하는 것이 가능하며 기본형과 마찬가지로
	  Wrapper 클래스도 내부 메소드를 통해 형 변환이 가능하고, 동등 비교와 같은 연산도 가능하다.

	  ex) java.lang.Integer 클래스
	      int 기본 자료형의 Wrapper 클래스로
		  정수를 다루는데 필요한 상수나 메소드, 진수 변환 등에 필요한 
		  메소드 등을 포함하고 있다.

		  static Integer valueof(int i)
		  int 형을 Integer 형으로 변환한다.

		  static int parseInt(String s)
		  문자열 형식으로 저장된 숫자를 정수 형태로 변환하여 반환한다.

		  byte byteValue(), int intValue(),
		  short shortValue(), long longValue(),
		  float floatValue(), double doubleValue()
		  해당 기본 자료형으로 형 변환한 값을 반환한다.

※ 오토 박싱(Auto-Boxing)과 오토 언박싱(Auto-Unboxing)

   일반적으로 래퍼런스 형과 기본 자료형은 호환되지 않으며
   이 경우 발생하는 문제 해결을 위해 자바에서는 Wrapper 클래스를 제공하게 되었다.
   하지만, JDK 1.5부터 래퍼런스 형과 기본 자료형이 다음과 같이 형 변환이 가능하도록
   문법적인 지원이 이루어지게 되었다.

   int a = 10, b;
   Integer ob;
   ob = a; 
    기본 자료형(int)이 Integer 형으로 자동 변환(오토 박싱)
	실제로는 ob = new Integer(a); 

   b = ob; 
    Integer(객체)가 기본 자료형 int 형으로 자동 변환(오토 언박싱)
	실제로는 b = ob.intValue();

   이는 JDK 1.5 이후 추가된 오토 박싱 / 오토 언박싱이라는
   기능으로 인해 가능해진 것이다.
*/
public class Test130
{
	public static void main(String[] args)
	{
		int a = 10, b;			// 기본자료형은 참조변수가 아니기 때문에 참조시켜주기 위해서 객체화를 시키는 것
		Integer c;
		Object d;

		b = a;					// int 형 데이터(자료)     -> int 형 변수
		c = new Integer(0);		// 객체 생성

		// ※ 기본적으로 래퍼런스 형(참조 타입)과 기본 자료형(기본 타입)은 호환되지 않는다.

		b = c;					// Integer 형 데이터(객체) -> int 형 변수   ==   오토 언박싱
		b = c.intValue();		// 객체의 메소드 호출을 통해 결과값 반환    ==        언박싱

		d = new Object();		// 객체 생성
		System.out.println("d.toString() : " + d.toString());
		//== d.toString() : java.lang.Object@15db9742			Object가 가지고 있는 toString

		d = new Integer(10);	// 업캐스팅   Integer 클래스에서 Object클래스로부터 상속받은 toString을 overriding해 덮어쓰기 된 것
		System.out.println("d.toString() : " + d.toString());
		//== d.toString() : 10

		d = new Double(12.345); // 업캐스팅
		System.out.println("d.toString() : " + d.toString());
		//== d.toString() : 12.345
		
		// Object d = 10
		d = 10;					// int 형 변수 -> Integer 형 데이터(객체) ==   오토 박싱 & d = new Integer(10);와 같은 업캐스팅
		System.out.println("d.toString() : " + d.toString());
		//== d.toString() : 10
	}
}

Wrapper 클래스(131)

public class Test131
{
	public static void main(String[] args)
	{
		boolean bi = true;
		Boolean wrapBi = new Boolean(bi);
		Boolean wBi = bi;					// 오토   박싱

		int n = 300;
		Integer wrapN = new Integer(n);
		int n2 = wrapN;						// 오토 언박싱

		float f = 300.3f;					
		Float wrapF = new Float(f);

		System.out.println(wrapBi.toString());
		System.out.println(wrapN.toString());
		System.out.println(wrapF.toString());
		// true
		// 300
		// 300.3

		System.out.println(wrapBi);
		System.out.println(wrapN);
		System.out.println(wrapF);
		// true
		// 300
		// 300.3

		// Integer 클래스
		String sn = "12";
		int ni = Integer.parseInt(sn);
		System.out.printf("ni : %3d\n", ni);
		//== ni :  12

		ni = Integer.parseInt("0101", 2);
		System.out.printf("ni : %3d\n", ni);
		//== ni :   5

		ni = Integer.parseInt("12", 8);
		System.out.printf("ni : %3d\n", ni);
		//== ni :  10

		ni = Integer.parseInt("A", 16);
		System.out.printf("ni : %3d\n", ni);
		//== ni :  10

		sn = Integer.toBinaryString(20);
		System.out.printf("sn : %s\n", sn);
		//== sn : 10100

		sn = Integer.toOctalString(31);
		System.out.printf("sn : %s\n", sn);
		//== sn : 37

		sn = Integer.toHexString(31);
		System.out.printf("sn : %s\n", sn);
		//== sn : 1f


		Integer num = new Integer(50);
		System.out.println("num.toString() : " + num.toString());
		//== num.toString() : 50			String타입으로 출력된 것임

		int n3 = 345;
		Integer n4 = Integer.valueOf(n3);
		System.out.println("n4 : " + n4);
		//== n4 : 345


	}
}

BigInteger 클래스(132)

import java.math.BigInteger;

public class Test132
{
	public static void main(String[] args)
	{
		// 불가능
		//int a1 = 123456789123456789;
		//System.out.println(a1);
		
		// 불가능
		//long b1 = 123456789123456789;
		//System.out.println(b1);

		// 가능
		long c1 = 123456789123456789L;
		System.out.println(c1);
		//== 123456789123456789

		// 불가능
		// long d1 = 123456789123456789123456789L;
		//System.out.println(d1);

		BigInteger a = new BigInteger("123456789123456789");
		BigInteger b = new BigInteger("123456789123456789");

		//BigInteger c = a + b;
		//System.out.println(c);

		// 더하기
		BigInteger c = a.add(b);
		System.out.println("덧셈 결과 : " + c );
		//== 덧셈 결과 : 246913578246913578

		// 빼기
		BigInteger d = a.subtract(b);
		System.out.println("뺄셈 결과 : " + d );
		//== 뺄셈 결과 : 0

		// 곱하기
		BigInteger e = a.multiply(b);
		System.out.println("곱셈 결과 : " + e );
		//== 곱셈 결과 : 15241578780673678515622620750190521

		// 나누기
		BigInteger f = a.divide(b);
		System.out.println("곱셈 결과 : " + f );
		//== 곱셈 결과 : 1
		
		// 지수승
		BigInteger g = new BigInteger("2");
		System.out.println("2의 3승 : " + g.pow(3));
		//== 2의 3승 : 8

	}
}

BigDecimal 클래스(133)

/*===========================================
       ■■■ 자바의 주요 클래스 ■■■
 - 자바에서 기본적으로 제공하는 주요 클래스들
 - BIgDecimal 클래스
============================================*/

import java.math.BigDecimal;

public class Test133
{
	public static void main(String[] args)
	{
		BigDecimal a = new BigDecimal("123456789.123456789");

		// movePointLeft() : 소수점을 왼쪽으로 이동
		BigDecimal b = a.movePointLeft(3);
		System.out.println("처리 결과 : " + b);
		//== 처리 결과 : 123456.789123456789
		
		// 나눗셈 연산
		BigDecimal c = a.divide(b);
		System.out.println("처리 결과 : " + c);
		//== 처리 결과 : 1E+3

		BigDecimal d = a.divide(b, BigDecimal.ROUND_DOWN);	//public static final int ROUND_DOWN(BigDecimal 클래스 안 모습)
		System.out.println("처리 결과 : " + d);// 반올림을 하지 않는다. -> 절삭
		//== 처리 결과 : 1000.000000000

		// BigInteger 객체로 변환
		System.out.println(a.toBigInteger());
		//== 123456789



	}
}

Wrapper클래스(134)


public class Test134
{
	public static void main(String[] args)
	{
		byte b = 3;
		int i = 256;

		Byte b2 = new Byte(b);
		Integer i2 = new Integer(i);

		System.out.println(b2);
		System.out.println(i2);
		//== 3
		//   256

		print(b2);
		print(i2);
	}

	static void print(Number a) // Number가 Integer Byte 등의 상위 클래스라서 모두 받을 수 있다.
	// java.lang.Number 클래스는 모든 숫자형 Wrapper 클래스의 부모 클래스이다.
	// b2, i2 에 해당하는 자료형이 Number 에 넘어오면서 업 캐스팅이 일어나게 된다.
	{	
		System.out.println(a);

		/*
		if(n instanceof Integer) // n 이 Integer기반으로 만들어진 객체라면
		{
			System.out.println(n.intValue());
		}

		else if(n instanceof Double)
		{
			...
		}

		...
		*/
	}

	// Number n = new Integer(); Number가 추상 클래스이므로 Integer 객체를 업캐스팅해서 만들 수 있다.

}

0개의 댓글