Q1. 거스름돈 구하는 문제

지불한 금액을 나타내는 파라미터1, 물건의 가격을 나타내는 파라미터2
이렇게 두 개의 파라미터를 받아 가장 적은 수의 지폐를 거슬러 주는 메소드를 만들어 주세요.
(단위는 50000, 10000, 5000, 1000 원입니다.)
   
 예) change(100000, 23000);
 출력결과 -> 50000원 지폐 : 1장
 10000원 지폐 : 2장 
 5000원 지폐 : 1장
 1000원 지폐 : 2장

 

 

 

A1-1. 내가 짰던 코드

public class MKY_ChangeMoney {

	public static void main(String[] args) {
		changeMoney(100000, 23000);
	}
	
	public static void changeMoney(int money, int price) {
		int cal = money - price;	// 거스름돈 구하기
		int cal2 = 0, cal3 = 0, cal4 = 0;	// 각 지폐별 변수 생성
		
		// 최소한의 지폐를 거슬러 주기 위해 5만원 단위부터 로직 구성
		if (cal>50000) {	// 거스름돈이 5만원보다 크다면 5만원 지폐를 거슬러줘야 한다.
			int bill = cal/50000;	// 5만원 몇 장이 필요한지 계산
			System.out.println("50000원 권 : " + bill + "장");
			cal2 = cal - (50000*bill);	// 거슬러줄 5만원 지폐를 제외하고 나머지 금액을 구한다.
		} 
		
		// 나머지도 같은 형식으로 진행됨
		// 거슬러 줄 지폐가 있다면 if문 안으로 들어가서 문장을 실행한다.
		if (cal2>10000) {
			int bill = cal2/10000;
			System.out.println("10000원 권 : " + bill + "장");
			cal3 = cal2 - (10000*bill);
		} 
		
		if (cal3>5000) {
			int bill = cal3/5000;
			System.out.println("5000원 권 : " + bill + "장");
			cal4 = cal3 - (5000*bill);
		} 
		
		if(cal4>1000) {
			int bill = cal4/1000;
			System.out.println("1000원 권 : " + bill + "장");
		}
	}
}

< console >----------------------------------------------------------------------------------
50000원 권 : 1장
10000원 권 : 2장
5000원 권 : 1장
1000원 권 : 2장

▶ 코드가 너무 길어져서 짜면서도 간단하게 할 방법이 있을 것 같았는데, 아래 다른 조원분이 해결해주셨다.

 

 

 

A1-2. 다른 조원이 짠 코드

package methodStudy;

public class JSH_ChangeMoney {

	public static void main(String[] args) {
		f1(100000, 23000);
	}
	
	 public static void f1(int x, int y){
	        int [] money = {50000, 10000, 5000, 1000};	// 지폐를 배열로 묶어줌
	        int div = 0, result = 0;
	       
	        result = x - y;
	        for(int i = 0; i<money.length; i++){	
	            div = result / money[i];	// 거슬러줘야하는 지폐 수
	            System.out.println(money[i] + "원 지폐: " + div + "장" );
	            result = result % money[i];	// 남은 거스름돈
	        }
	    }
}

▶ 각 단위의 지폐를 배열로 묶어주고 for 반복문을 돌림으로써 코드의 길이가 간결해졌다.

▶ %(나머지)로 남은 거스름돈을 알 수 있는 것도 생각지도 못했던 부분

 

 

 

A1-3. 다른 조원이 짠 코드2

public class CHH_ChangeMoney {

	public static void main(String[] args) {
		change(100000, 23000);
		
	}

	public static void change(int pay,int cost) {
		int changeMoney = pay - cost;
		
		int fifty_thousand = changeMoney / 50000;				
		int ten_thousand = (changeMoney % 50000) / 10000;	
		int five_thousand = (changeMoney % 10000) / 5000;	
		int one_thousand = (changeMoney % 5000) / 1000;		
		
		System.out.println("50000원 지폐 : " + fifty_thousand);
		System.out.println("10000원 지폐 : " + ten_thousand);
		System.out.println("5000원 지폐 : " + five_thousand);
		System.out.println("1000원 지폐 : " + one_thousand);
	}
}

▶ 나는 변수를 따로 설정하고 if문을 만들어 돌렸지만, 변수를 설정하면서 바로 로직이 가능하다.

▶ 로직을 짠 후 어떻게 더 간단하게 할 수 있을지 연구해봐야겠단 걸 많이 느낀 문제

728x90
1. 클래스

1-1. 객체(Object)

프로그래밍에서의 객체는 프로그램에서 표현하고자 하는 기능을 묶기 위한 단위

 

1-2. 객체를 구상하는 단위

  • 객체를 이루는 것은 데이터와 기능이다.
  • (프로그래밍을 한다는 건 데이터를 어떻게 조작할 지에 대해 컨트롤 하는 것)
  • 데이터는 변수로 표현된다.
  • 객체 안에 포함된 변수를 '멤버변수' 혹은 '프로퍼티'라 한다.
  • 기능은 메서드(=함수)로 표현된다.

 

1-3. 클래스와 객체의 관계

  • 객체를 생성하기 위해서 객체의 설계도가 필요하다.
  • 객체의 설게도 역할을 하는 프로그램 소스 = 클래스(Class)
  • 공장에서 하나의 설계도를 사용하여 여러 개의 제품을 생산할 수 있는 것처럼, 하나의 클래스를 통해 동일한 구조를 갖는 객체를 여러 개 생성할 수 있다.

  • 자동차의 엔진, 문, 바퀴 등은 멤버변수로 존재할  수 있다.
  • 전진, 후진 등은 메서드의 형태로 표현된다.

 

1-4. 자동차 클래스의 예

  • 동일한 설계로 만들어진 자동차라 하더라도 각각의 자동차를 구성하는 부품들은 그 형태만 같을 뿐 실제로는 각각 존재하게 된다.
  • 클래스를 작성하면서 그 안에 생성되는 멤버변수들은 여러 개의 객체 간에 서로 동일한 이름으로 존재하지만 실제로는 서로 다른 값이라는 의미

 

1-5. 클래스의 기본 작성 방법

class 클래스이름{
	멤버변수;
	void 메서드이름(){
	}
}
  • 'class'라는 예약어와 클래스의 이름을 명시하고 블록{...}을 구성한다.
  • 멤버변수는 여러 개 존재할 수 있다. 이 때, 값을 선언과 동시에 할당할 수도 있고, 객체를 통해 간접적으로 할당할 수 도 있다.
  • 메서드는 여러 개 존재할 수 있다.
  • 클래스 안에 포함된 멤버변수와 메서드를 특성에 따라 그룹화하기 위한 기법이 클래스를 작성하는 것이라고 이해할 수 있다.

 

1-6. 객체의 생성 방법

  • 객체의 선언
클래스이름 객체이름;
  • 객체의 할당
객체이름 = new 클래스이름();
  • 선언과 할당의 통합
클래스이름 객체이름 = new 클래스이름();

 

1-7. 객체의 사용

객체 안에 포함된 변수나 메서드는 점(.)으로 연결하여 접근한다.

  • 객체 안에 포함된 변수의 값을 다른 변수에 복사하는 경우
변수 = 객체이름.멤버변수;
  • 객체 안에 포함된 변수의 값에 다른 값을 대입하는 경우
객체이름.멤버변수 = 값;
  • 객체 안에 포함된 메서드를 호출하는 경우
객체이름.메서드이름();
  • 객체 안에 포함된 메서드에 파라미터를 전달하는 경우
객체이름.메서드이름(값1, 값2, ..., 값n);

 

1-8. 클래스를 정의하면서 멤버변수에 값을 직접 대입하는 경우

  • 위 예제는 객체를 생성함과 동시에 객체 안에 name변수와 age변수가 할당된 값을 포함하게 된다.
  • 같은 클래스로 객체를 여러 개 생성할 경우, 모든 객체가 동일한 값을 갖게된다.
  • 동일한 Student 클래스
    std.name = "자바학생" / std.age = 19
    std2.nave = "자바학생" / std2.age = 19

  • 같은 클래스를 통하여 생성된 객체라 할 지라도 서로 다른 값을 대입하면 서로 독립적인 형태로 존재하게 된다.

 

1-9. 값이 대입되지 않은 멤버변수를 갖는 클래스

  • 클래스란 객체를 위한 틀을 제공하는 것이기 때문에 클래스 작성과정에서 멤버변수에 대입된 값은, 객체를 통하여 멤버변수의 값을 지정하기 전까지 사용될 "기본값"으로서의 의미이다.
  • 객체를 통하여 새로운 값이 대입되면 클래스 작성시에 멤버변수에 대입한 값은 의미를 잃어버리게 된다.
  • 때문에 일반적으로 클래스 작성 시에는 멤버변수에 값을 지정하지 않는다.

 

1-10. 메서드를 포함하는 클래스

  • 메서드란 프로그램에서 하나의 동작 단위를 의미한다.
  • 두 개 이상의 메서드가 서로 동일한 대상을 위해서 존재할 경우, 이 메서드들을 클래스에 포함시켜 그룹화 할 수 있다.
  • 클래스에 멤버변수와 메서드가 공존할 경우, 멤버변수는 모든 메서드가 공유하는 전역변수로 존재하게 된다.
  • 변수의 종류
    멤버변수(전역변수)
        클래스 안에서 선언된 변수로서, 클래스 블록{...} 범위 안에서 유효하다.
    지역변수
        메서드 안에서 선언된 변수로서, 메서드의 블록{...}을 빠져나가지 못한다.
        그러므로 다른 메서드는 해당 변수를 인식하지 못한다.
        이 규칙은 조건문, 반복문처럼 블록{...}을 형성하는 모든 경우에 해당된다.

    *** 참고 ***
    - 지역변수와 전역변수가 선언되는 메모리 영역이 다르다.
    - 지역변수(멤버변수)는 Heap 영역에 저장
    - 지역변수는 Stack영역에 저장 > 자동으로 초기화되지 않는다.
    - Heap : 프로그래머가 원하는 방식으로 쓸 수 있는 공간. 긴 생명주기를 가진 데이터들이 저장됨

    - Stack : 아주 잠깐 사용하고 삭제할 데이터의 저장공간

 

 

1-11. 메서드만을 포함하는 클래스

  • 객체 안에 멤버변수(=데이터)가 포함되지 않는다.
  • 객체 안에 포함된 메서드를 호출하여 결과를 만들기 위한 목적이므로 굳이 여러 개의 객체를 생성할 필요가 없다.
    → 계산 기능을 갖는 클래스의 예
class Calc{
	int sum(int x, int y){
		return x+y;
	}
}

      → 기능의 활용 : 두 개의 값을 위하여 객체를 각각 생성하는 경우

Calc c1 = new Calc();
int a = c1.sum(100, 200);
System.out.println(a);		// 300

Calc c2 = new Calc();
int b = c2.sum(200, 300);
System.out.println(b);		// 500
  • 파라미터에 의해 결과를 리턴하는 경우, 서로 다른 값을 위하여 객체를 여러 개 생성할 필요가 없다.
  • 자체적으로 데이터를 갖는 형태가 아니라 외부적인 요인인 파라미터에 의해서 결과가 생성되므로, 하나의 객체를 재사용하는 것이 바람직하다.
Calc c1 = new Calc();
int a = c1.sum(100, 200);
System.out.println(a);
int b = c1.sum(200, 300);
System.out.println(b);

 


파라미터를 받아 계산 후 리턴해주는 사칙연산 메소드 만들기

메소드 생성
Calc클래스 객체 생성해서 메소드 사용하기

 


 

 

 

2. this

2-1. 자기 자신을 의미하는 키워드

클래스 안에서 this를 사용하여 "자기자신"을 표현한다.

 

2-2. this를 사용하여 지역변수와 멤버변수(전역변수) 구분하기

  • 멤버변수와 지역변수가 동일한 이름으로 공존할 경우, 유효성 범위가 작은 변수(▶지역변수)가 우선적으로 인식된다.
class Student{
	String name;			// 멤버변수(전역변수)
	
	public void setName(){
		String name;		// 지역변수    
		name = "자바학생";	// 지역변수로 인식됨
	}
}
  • this를 사용하여 지역변수와 구분해준다.
class Student{
	String name;			// 멤버변수(전역변수)
	
	public void setName(){
		String name;		// 지역변수    
		name = "자바학생";	// 지역변수로 선언된 name
		this.name = "JSP학생";	// 멤버변수로 선언된 name
	}
}
  • this를 사용하여 파라미터와 멤버변수 구분하기
    → 파라미터도 해당 메서드 안에서만 유효한 지역변수의 일종
class Student{
	public void setname(Stirng name){	// name은 지역변수. setname안에서만 사용 가능
    
	}
}

      → 파라미터를 사용하여 멤버변수의 값을 간접적으로 설정하고자 할 경우, 이름은 동일하게 지정하고

           this 키워드를 사용하여 멤버변수와 파라미터를 구별하는 것이 java 언어의 일반적인 처리 방식이다.

class Student{
	String name;
	public void setname(Stirng name){	// 지역변수 name
		this.name = name;		// 멤버변수 name    
	}

}
  • 모든 멤버변수 앞에는 this 키워드를 사용하여 멤버변수임을 직관적으로 표시하는 것이 소스코드의 가독성을 위하여 바람직하다.

 


▶ 파라미터와 같은 이름의 멤버변수를 사용하려면 this.를 반드시 붙여주어야 한다. 하지만 파라미터나 지역변수와 같은 이름이 아니라면 subject 처럼 그냥 써도 멤버변수로 사용 가능하다.

 


 

 


▶ 메서드를 만들어줄 때 void 앞에 public을 붙일 때도 있고 아닐 때도 있는데, 왜 그런지 찾아봐야겠다.

728x90

와우 5시간씩 꾹꾹 눌러 배워서 정리가 안 끝나는 매직...★ 살려주세오...

 


 

1. 예외처리

컴파일 에러 : 컴파일 할 때 문법적으로 오류가 발생

런타임 에러 : 실행은 되지만 프로그램에서 문제가 발생

  • 에러(error) : 코딩으로 해결할 수 없는 심각한 오류
    ex. OOME(Out Of Memory Error) > 메모리 부족으로 인한 에러
  • 예외(exception) : 코딩으로 해결할 수 있는 오류

컴파일 에러는 빨갛게 표시가 되고, 런타임 에러는 실행은 되지만 에러가 남(콘솔창에 에러 이유가 출력됨)

 

 

예외처리를 사용하는 이유?

1) 프로그램이 강제종료 되는 것을 막기 위해

2) 제어문으로는 처리할 수 없는 경우

 

 

Exception 클래스

모든 예외들의 부모클래스

사용자의 실수와 같은 외적인 요인이 발생하는 예외

어떤 예외가 발생하든지 Exception 타입으로 잡을 수 있다.

 

 

RuntimeException 클래스

프로그래머의 실수로 발생하는 예외

컴파일러가 예외처리 여부를 체크하진 않지만, 실행 시 프로그램 종료

 

 

Exception 계층도

 

 

try ~ catch ~ finally

try {

         예외가 발생할 수 있는 문장

} catch(예외클래스명 객체명) {

         예외가 발생시 수행할 문장

} catch(예외클래스명 객체명) {

         예외 발생 시 수행할 문장

         (catch블럭은 여러 개 사용 가능)

}

...

finally {

         예외 발생 유무에 상관없이 무조건 실행할 문장(생략가능)

        ***주로 외부 장치와 연결했을 경우 다시 닫을 때 사용한다.

         ex. printWrite open()과 close()

}

 

 

try에서 예외가 발생했을 경우

1) 해당 예외와 일치하는 catch로 가서 예외처리를 한다. 만약 일치하는 catch가 없다면 예외처리가 되지 않고 프로그램이 비정상 종료된다.
2) catch에 있는 전체 문장을 수행한 후, try ~ catch문을 탈출하여 나머지 로직을 수행한다. 따라서 try에 예외발생한 문장 이후의 나머지 문장이 남아있어도 수행되지 않는다. finally를 사용하여 나머지 문장을 실행하면 된다

 

 

try에서 예외가 발생하지 않았을 경우

catch를 거치지 않고 try ~ catch문을 탈출하여 나머지 로직을 수행한다.

 

 

예제

 

 

실습

▶ try ~ catch문으로 실행해 언제 예외가 발생하는지 확인한다.

▶ 예를 들어, num1 = 10, num2 = 5를 입력하면 정상적으로 출력되지만 num1 = 10, num2 = 0을 입력하면 런타임에러 중 ArithmeticException이 발생한다.(나눗셈에서 0으로 나누는 것은 불가능하기 때문)

예외처리

▶ 예외 찾는 과정을 계속한다.

▶ 정수가 아닌 것을 입력했을 때 예외 발생(InputMismatchException) > 입력받는 과정 역시 예외가 발생할 수 있다는 걸 알 수 있다.

예외가 발생할 수 있는 문장들을 try ~ catch문 안으로 옮겨주고, 예외처리(InputMismatchException은 import처리 필수)&amp;nbsp;
더 이상 어떤 에러가 나올지 모르겠으므로 혹시 에러가 발생할 때를 대비해 Exception 사용

▶ 나가기 기능 추가하기

 

 

throws

메소드 실행 시 발생할 수 있는 예외를 선언하여 호출하는 쪽에 알리는 것

직접 예외처리를 하지 않고 메소드 호출한 곳으로 떠넘겨서, 메소드를 호출한 곳에서 예외처리를 하겠다는 뜻

throw와 전혀 다름

 

리턴타입 메소드명() throws 예외1, 예외2, ...{

         // 메소드 내용

}

 

 

throws 예제

 


 

2. API

개발에 필요한 주요 기능들을 제공하는 라이브러리들의 집합

선배 개발자들이 JAVA에서 코딩을 쉽게 할 수 있도록 미리 만들어 놓은 부품들

 

 

JAVA API

자바 시스템을 제어하기 위해서 자바에서 제공하는 기능(명령어)

JDK 설치 시 제공해주는 기본 API

 

 

java.lang

자바 프로그래밍을 위한 가장 기본적인 패키지와 핵심적인 클래스들을 포함

 

 

외부 API

선배 개발자들이 개발한 패키지 및 클래스들을 의미

보통 jar파일로 배포하며 자바 프로젝트에 import하여 사용할 수 있다.

 

 

*** API의 종류는 굉장히 많고 다양하기 때문에 모두 외우는 것은 절대 불가능하다.

그래서 처음 보는 API라도 설명을 잘 읽고 맞는 목적으로 사용하는 방법을 알아야 한다. ***

 

 

javadocs

클래스, 메소드에 대한 도움말 문서

java API 문서는 JAVADOCS 프로그램으로 만들어진 문서로 볼 수 있다.

 

 

API 사용하는 이유?

개발 비용과 시간이 획기적으로 줄어든다.

누군가 만들어 놓은 API를 이용하면 해당 서비스가 구현되는 원리는 모르더라도 API를 통해 서비스를 그대로 사용이 가능하다.

 

 

어노테이션 주석

/*

    내부에 javadocs 문서에 대한 내용을 작성한다.

 */

@author        개발자

@param        메소드에서의 매개변수

@return        메소드에서의 리턴값

@exception   메소드에서 발생하는 예외

@throws        throws에 대한 설명

@see             참고할만한 링크

@since          사용 가능한 JDK버전

@version       클래스의 버전 정보

 


 

3. Object 클래스

모든 클래스들의 최상위 클래스

 

toString() : 객체를 문자열로 바꿔서 반환해주는 메소드

                  주로 오버라이딩을 통해 인스턴스의 정보를 알기 쉽게 출력하기 위해 사용

 

equals() : 두 객체의 주소값을 비교하는 메소드(boolean)

                equals()를 오버라이딩할 경우 주소값이 아닌 인스턴스 변수(iv)를 비교할 수 있도록 한다.

 

hashCode() : 객체의 해시값(주소값과 관련된 어떤 값)을 int로 바꿔서 반환하는 메소드

 

*** equals를 재정의하면 hashCode()도 재정의 해야한다.

equals()와 hashCode() 모두 초기에는 객체의 주소값으로 작업을 하는 공통점이 있다.

만약 equals()가 재정의를 통해 인스턴스변수(iv)로 작업을 한다면, hashCode()도 마찬가지로 iv를 이용해서 작업하도록 오버라이딩 해야한다.

따라서 equals()의 결과가 true라면 두 객체의 hashCode()도 같다.

 

 

예제1

▶️toString이 주소값 보는 용도가 아니기 때문에 오버라이딩 해준다.

우리가 만들지 않은 메소드이지만 최상위클래스인 Object의 메소드이기 때문에 가져다 쓸 수 있다
toString() 오버라이딩 후 data값 초기화 뒤 "Hello" 출력

 

 

예제2

user1과 user2의 주소값이 다르기 때문에 equals 비교에서 false 출력
user name끼리 비교했으므로 true 출력됨

▶️ equals가 true인데 hashCode의 주소값은 다름으로 false인 상태 > 즉, 모순되는 상황이다.

▶️ 따라서 equals를 재정의해주면 hashCode도 재정의 해주어야 한다.

주소값도 같아짐

 

 

실습

 


 

4. String 클래스

char[]과 관련 메소드들로 이루어져 있다.

내용을 변경할 수 없는 불변 클래스

 

String data1 = "pine"

String data2 = "apple"

data1 = data1 + data2   // pineapple

> pineapple이라는 새로운 문자열 객체가 생기고 문자열 값끼리 비교한다.

 

equals() : String 클래스 안의 equals는 Objects 클래스의 equals와 다름. 매개변수로 받은 문자열과 비교하기 때문에 문자열 값끼리 비교한다. 따라서 문자열이 다르거나 매개변수가 String이 아닐 경우 false 반환

 

 

예제

문자열 리터럴과 String 객체의 주소값이 다른 이유

 


 

5. Wrapper Class(래퍼 클래스)

기본 자료형 값을 클래스로 감싸는 것

기본형 타입의 값을 객체로 다뤄야 할 때, 객체로서 사용 가능하게 해주는 클래스

 

ing > Integer

char > Character

double > Double

boolean > Boolean

 

 

boxing

기본형을 클래스형으로 바꿔주는 것

 

 

unboxing

클래스형을 기본형으로 바꿔주는 것

 

 

예제

int를 Integer로 바꿔줌으로써 객체로 다룰 수도 있고 Integer 클래스 안의 메소드들을 사용가능하다는 이점이 있다.

 

수동

Wrapper 클래스명 참조변수 = new Wrapper생성자(기본형 값)   // 박싱

기본자료형 변수명 = 객체.형타입Value();   // 언박싱

 

 

자동

jdk 1.5버전부터는 오토를 지원하기 때문에 컴파일러가 자동으로 형변환을 해준다.

Wrapper클래스명 참조변수 = 기본자료형 값;   // 오토박싱

기본자료형 변수명 = 객체;   // 오토언박싱

 

 

Wrapper 클래스 사용 이유?

1) 기본형 타입의 값을 객체로 다루어야 할 때

2) 매개변수로 객체를 넘길 때(특히 Object에는 객체를 넘겨주어야 하므로 래퍼클래스 사용)

3) 기본 자료형 타입을 (오토)박싱하면 래퍼클래스의 다양한 메소드를 사용 가능하다.

 

 

실습

 

728x90

1. 접근 권한 제어자

다른 패키지 혹은 다른 클래스에서 해당 필드에 접근할 수 있는 범위(권한)을 설정해주는 키워드들

접근 제어자 4개 중 하나만 사용 가능

 

같은 클래스 < 같은 패키지 < 다른 패키지의 자손 클래스 < 전체

제어자 같은 클래스 같은 패키지 자손 클래스 전체
public O O O O(접근제한 없음)
protected O O O 다른 패키지에 있으면 X
default O O 같은 클래스, 같은 패키지에서만 사용 가능
private O 같은 클래스에서만 사용 가능(사용 범위가 가장 좁음)

 

접근 제어자의 역할

1) 외부로부터 데이터를 보호하기 위해

2) 외부에 불필요한 정보를 노출시키지 않고 내부적으로만 사용되는 부분을 감추기 위해

3) 따라서 접근 제어자의 범위는 좁을수록 좋다.

 

private?

접근 제어자가 private로 설정된 필드는 직접 접근할 방법이 하나도 없기 때문에 무조건 public으로 설정된 getter(), setter() 메소드를 통해서 간접 접근한다. (값 사용 : getter(), 값 대입 : setter())

private를 이용하여 외부에서 직접 접근을 못하도록 막고 setter를 통해 간접 접근한다.

 


 

2. 추상클래스

구현이 안된 메소드가 선언되어 있는 클래스

구현이 안된 메소드를 추상메소드라고 부르며, 추상메소드는 바디{}가 없고, 리턴타입에 abstract를 붙인다.

ex. public abstract class Electronics{   // 추상클래스 

               abstract void on();   // 추상메소드 > ()뒤에 {}가 없음

               abstract void off();   // 추상메소드

}

추상클래스에 abstract를 붙여 추상메소드를 가지고 있다는 표시를 한다.

추상메소드가 하나라도 있으면 추상클래스이다.

 

 

추상 클래스 선언

abstract class 클래스명 {

         abstract 리턴타입 메소드명(매개변수, ...);

         * 일반메소드도 선언 가능

}

1) 일반메소드도 추상클래스 내부에 선언 가능

2) 추상클래스는 미구현 클래스이기 때문에 구현 후 객체화를 할 수 있다.

3) 따라서 상속을 통해 자식클래스에서 반드시 재정의해야 객체를 생성할 수 있다.

4) abstract 키워드가 붙으면 자식클래스에서 꼭 필수적으로 재정의해야 한다.

 

 

추상 메소드의 사용 목적

1) 꼭 필요하지만 자식마다 다르게 구현할 것이라고 예상되는 경우

2) 기존 클래스의 공통 부분만 뽑아내서 추상클래스를 만드는 경우

> 선언부는 같고 구현부가 다를 경우 추상메소드를 만들어 코드의 중복을 제거한다.

 

 

예제

메소드 선언
자식클래스에서 추상메소드 재정의
자식클래스에서 추상메소드 재정의2
새로운 클래스에서 객체 생성

 

 

실습

추상클래스(추상메소드, 일반메소드) 생성
추상메소드 구현1
추상메소드 구현2
추상메소드 구현3
새로운 클래스에서 객체 사용(doSomething();은 자식클래스에 있기 때문에 다운캐스팅 하여 사용)

 


 

3. 인터페이스(interface)

추상메소드의 집합으로 오직 "추상메소드"만 존재한다.

따라서 구현된 것이 아무것도 없는 틀이다.

 

 

인터페이스의 선언

interface 인터페이스명{

         public static final 타입 상수명 = 값;

         public abstract 리턴타입 메소드이름(매개변수, ...);

}

1) 인터페이스의 모든 메소드는 public이고, abstract이므로 전부 생략 가능

2) 마찬가지로 모든 상수는 public, static, final이므로 전부 생략 가능

 

 

인터페이스의 구현

class 클래스명 implements 인터페이스명{

         // 인터페이스에서 선언한 추상메소드 전부 구현

}

1) implements 키워드를 사용해 다른 클래스에 인터페이스를 지정하여 구현시킨다.

2) 지정받은 클래스는 인터페이스가 가지고 있는 모든 추상 메소드를 반드시 재정의 해야한다.

3) 인터페이스도 타입으로 구현된 클래스의 부모역할을 한다.

 

 

추상클래스와 인터페이스의 차이?

1) 추상클래스는 인스턴스 멤버와 생성자를 가질 수 있다. 인터페이스는 오로지 추상메소드(+상수)만 가질 수 있다.

2) 추상클래스는 상속(extends)을 통해 추상메소드를 구현시킨다. 인터페이스는 implements를 통해 추상메소드를 구현시킨다.

3) 공통점 : 추상클래스와 인터페이스 모두 추상메소드를 가지고 있다.

 

 

interface 강제성 소멸 : Adapter

인터페이스를 클래스에 바로 지정하면 모든 메소드에 강제성이 부여되어 전부 다 구현해야 한다.

하지만 일반적인 상황에서는 모든 것이 아닌 필요한 메소드만 골라서 재정의 해야하는 경우가 생긴다.

이때 특정 클래스에 인터페이스를 지정한 후 바디만 만들어 놓아 구현시켜서 강제성을 소멸시킨다.

그럼 다른 클래스들은 Adapter클래스를 상속받아서 필요한 메소드만 골라서 재정의 할 수 있게 된다.

 

 

인터페이스의 장점

1) 선언과 구현이 분리되어 있기 때문에 코드가 유연해진다.

     > 만약 변경사항이 생길 경우 선언과 구현이 분리되어 있기 때문에 구현부분만 바꿔주면 된다.

2) 관계없는 클래스들을 서로 관계를 맺어줄 수 있다.

3) 다중상속처럼 사용이 가능하다.

 

 

예제

인터페이스 구현
Adapter 클래스
Adapter 클래스 지정 -필요한 메소드만 재정의
인터페이스 지정 - 모든 메소드에 강제성 부여
인터페이스 지정 - 모든 메소드에 강제성 부여

 

 

다중상속

여러 부모 클래스를 상속하는 것

java는 모호성 때문에 다중상속을 지원하지 않는다.

하지만 인터페이스는 여러 개를 지정할 수 있기 때문에 다중상속이 가능하다.

 

 

모호성

하나의 자식이 여러 부모를 상속 받을 때 부모 필드에 동일한 이름의 필드가 있으면 어떤 부모의 필드인지 알 수가 없다.

class A{int data = 100;}

class B{int data = 200;}

class child extends A, B{}

Child ch = new Child();

ch.data; > A의 data인지 B의 data인지 판별불가

 

 

인터페이스는 다중상속처럼 사용 가능한 이유

인터페이스의 메소드는 전부 추상메소드이기 대문에 선언부만 있고 구현부가 없다.

만약 두 개의 인터페이스가 같은 이름과 같은 매개변수 개수의 메소드를 가지고 있어도 두 개의 인터페이스를 모두 구현한 클래스에서는 해당 메소드를 재정의하기 때문에 충돌이 나지 않는다.

 

 

모호성 해결 예제

인터페이스 A
인터페이스 B
인터페이스 A와 B에 동일하게 있는 printData()의 재정의를 통해 모호성 해결

 

 

default 메소드(=인스턴스 메소드)

JDK1.8버전부터는 인터페이스에 dfault 메소드 선언가능

why? 인터페이스를 구현한 클래스들이 있을 때, 인터페이스에 새로운 메소드를 추가하게 되면 기존에 구현한 클래스들도 모두 새로 추가한 메소드를 구현해야 한다. 하지만 디폴트 메소드는 구현부가 있기 때문에 기존에 구현한 클래스들에게 영향을 끼치지 않는다. 인터페이스에서 디폴트 메소드를 사용할 경우 꼭 default 키워드를 붙여야 한다.

위에서 만든 인터페이스A에 default 메소드를 추가한 모습

 

 

마커인터페이스(marker interface)

클래스들을 하나의 카테고리처럼 그룹화하기 위한 목적으로 사용한다.

인터페이스는 지정한 클래스의 부모나 다름없고, 다형성으로 모든 자식은 부모의 타입이다.

그래서 마커인터페이스를 지정받은 클래스들이 하나의 타입으로 묶이게 된다.

부모클래스 Movie
인터페이스 Action
자식클래스 Venom이 부모클래스만 상속받은 상태
자식클래스 Venom이 Action으로 그룹화됨
자식클래스 SpiderMan도 Movie를 상속하면서 Action으로 그룹화됨

 


 

4. 내부 클래스(inner class)

클래스 안에 클래스가 있는 중첩클래스

밖에 있는 클래스를 '외부 클래스', 안에 선언된 클래스를 '내부 클래스'라고 한다.

외부 클래스가 먼저 메모리에 할당되어야 내부 클래스를 객체화 할 수 있다.

 

 

내부 클래스의 장점

내부 클래스는 외부 클래스의 필드이기 때문에 외부 클래스의 필드를 자신의 필드처럼 가져다 사용할 수 있다.

class A{

         ...

         class B{

                  ...

         }

}

1) class B 안에서 class A의 멤버에 쉽게 접근 가능(객체 생성 없이도 A의 멤버 접근)

2) class B는 class A의 멤버이다.

3) 캡슐화 : 외부 클래스가 없다면 내부 클래스도 존재할 수 없기 때문에 다른 클래스에서 접근하지 못하도록 내부 클래스를 숨길 수 있다.(캡슐화 용도로 많이 쓰임)

4) 코드의 복잡성을 줄일 수 있다.

 

 

내부 클래스의 사용

외부클래스명 외부참조변수 = new 외부클래스 생성자();

외부클래스명.내부클래스명 내부참조변수 = 외부참조변수.new 내부클래스 생성자();

 

 

예제

클래스 세 개 생성. 객체를 생성해서 자유롭게 다른 클래스 필드 사용 가능
다른 클래스 안에 넣어줘서 내부클래스로 만들어줌(캡슐화)

 


 

5. 익명 클래스

이름이 없는 클래스로 딱 한 번만 사용할 클래스. 사용하면 사라진다(일회용)

클래스의 구현과 객체생성을 동시에 한다.

어떤 클래스를 상속받거나 인터페이스를 구현해야지 익명 객체 생성이 가능하다.

 

class Child extends Parents{...}   // 구현

Child ch = new Child();   // 객체 생성

             ↓(위 두 과정을 동시에)

new Parents(){...};   // 구현 + 객체 생성

 

class Rabbit implements Animals{...}   // 구현

Rabbit ra = new Rabbit();   // 객체 생성

                 ↓

new Animal(){...};   // 구현 + 객체 생성

 

 

익명 클래스 사용

new 부모클래스이름(){

         // 구현(인스턴스 멤버 선언)

};

 

new 구현인터페이스이름(){

         // 구현(인스턴스 멤버 선언)

};

 

 

예제

인터페이스 생성
new 구현인터페이스이름(){} 통째로 객체. 방법 1처럼 '.'으로 필드 사용가능하고 방법 2처럼 참조변수도 사용 가능

 

 

실습

인터페이스 생성
익명 클래스 사용

728x90
1. 배열

1-1. 2차 배열

2차원 배열의 선언, 크기 할당, 값의 대입에 대한 일괄처리

→ 2차원 배열의 경우 블록{...}을 2중으로 겹쳐서 2차원 배열을 표현한다.

→ 행과 열의 구분에는 콤마(,)가 사용된다.

→ 컴파일러가 블록{...}의 요소를 파악하면 행, 열의 크기가 산출될 수 있으므로 배열의 크기 설정을 위한 [][]에는 배열의 크기를 명시하지 않는다.

→ 데이터형[][] 배열이름 = new 데이터형[][]{

            {0행0열의 값, 0행1열의 값, ... ,0행n열의 값},
            {1행0열의 값, 1행1열의 값, ... ,1행n열의 값},
                                      ...
            {n행0열의 값, n행1열의 값, ... ,n행n열의 값}

     };

 

1-2. 2차원 배열에 대한 값의 대입 방법

  • 행, 열에 대한 인덱스를 통하여 값을 대입한다.
    → 배열이름[행][열] = 값;
    → int[][] grade = new int[3][3]
        grade[0][0] = 75;
        grade[0][1] = 82;
        grade[0][2] = 91;
                  ...
        grade[2][2] = 90;
  • 일괄지정하는 경우
    → int[][] grade = new int[][]{
                 {75, 82, 91},
                 {88, 64, 50},
                 {100, 100, 90}
        };

 

1-3. 2차원 배열의 길이

  • 2차원 배열의 길이는 행에 대한 측면과 열에 대한 측면을 나누어서 생각해야 한다.
  • 행의 길이
    → 1차 배열의 길이는 2차 배열에서는 행의 크기로 조회가 된다.
        int rows = grade.length;
  • 열의 길이
    → 열의 길이는 각 행에 대하여 개별적으로 조회해야 한다.
        int cols = grade[행].length;

// 성적표에 대한 2차 배열 생성
// 학급 성적을 위한 배열
int[][] grade = new int[3][3];
		
// 둘리의 과목별 점수
grade[0][0] = 75;
grade[0][1] = 82;
grade[0][2] = 91;
		
// 도우너의 과목별 점수
grade[1][0] = 88;
grade[1][1] = 64;
grade[1][2] = 50;
		
// 또치의 과목별 점수
grade[2][0] = 100;
grade[2][1] = 100;
grade[2][2] = 90;
		
// 2차 배열을 탐색하여 총점과 평균점수 구하기
for(int i=0; i<grade.length; i++) {
	// 반복문 안에서 선언된 변수는 매 실행시마다 새로 생성된다.
	int sum = 0;
	int avg = 0;
		
	for(int j=0; j<grade[i].length; j++) {
		// i번째 행의 j번째 열의 데이터를 누적처리
		sum += grade[i][j];
	}
    
	// i번째 위치의 평균점수 구하기 = 총점 / 과목수
	// i번째 학생의 과목수는 grade 배열의 i번째에 대한 길이
	avg = sum / grade[i].length;
	
	System.out.println("총점 = " + sum + ", 평균 = " + avg);
}



// 콘솔창 출력결과
총점 = 248, 평균 = 82
총점 = 202, 평균 = 67
총점 = 290, 평균 = 96

// 문제 1. num 배열에 저장된 요소의 합을 구하시오.
int[] num = new int[]{22, 3, 8, 12}

int sum = 0;
for(int i = 0; i < num.length; i++){
	sum += num[i];
}
System.out.println(sum);	// 45
// 문제 2. num2 배열에 저장된 요소의 합과 평균을 구하시오.
int[] num2 = new int[] {60, 95, 88};
		
int sum2 = 0;
for (int i = 0; i < num2.length; i++) {
	sum2 += num2[i];
}
int avg = sum2/num2.length;
System.out.println("합 : " + sum2 + ", 평균 : " + avg);	// 합 : 243, 평균 : 81
// 문제3. num3 배열에 저장된 요소의 최대값을 출력하시오.
int[] num3 = {94, 85, 95, 88, 90};
		
int max = num3[0];	// 첫번째 수를 기준으로 삼고
for(int i = 1; i < num3.length; i++) {	// 배열 안 나머지 숫자들과 비교
	if(max<num3[i]) {
		// 첫 번째 숫자보다 크면 max가 되고, 반복문이 도는 동안 계속 비교해서 가장 큰 수가 max가 된다.
		max = num3[i];
	}
}
System.out.println(max);	// 95



// 아래는 어떻게 푸는지 몰라서 무식하게 풀어본 거
int max = 0;
int a = num3[0];
int b = num3[1];
int c = num3[2];
int d = num3[3];
int e = num3[4];

if(a>b) {
	max = a;
} else {
	max = b;
}
if(max<c) {
	max = c;
} else if(max<d) {
	max = d;
} else {
	max = e;
}
System.out.println("최대값 : " + max);
// 문제 4. num4 배열에 저장된 요소의 홀수와 짝수의 합을 각각 구하시오
int[] num4 = new int[] {22, 3, 8, 12};
		
int oddsum = 0, evensum = 0;
for (int i = 0; i < num4.length; i++) {
	if(num4[i]%2==0) {
		evensum += num4[i];
	} else {
		oddsum += num4[i];
	}
}
System.out.println("홀수 합 : " + oddsum + ", 짝수 합 : " + evensum); // 홀수 합 : 3, 짝수 합 : 42

 

 

 

2. 메서드

2-1. 프로그램의 시작점

public static void main(String[] args){}

java 프로그램이 시작되는 시작점을 의미하는 main은 public, static, void, main, (String[] args) 라는 키워드로 구성된 하나의 블록{...}이다.

 

2-2. 다른 이름의 메서드 만들기

→ f(x) = x + 1

    f : 함수이름

    x : 매개변수

    x + 1 : 식→ f(1) = 2
    f(10) = 11
    f(5) = 6

 

2-3. 프로그램의 함수 = 메서드특정 기능(=연산)을 그룹화해서 재사용하기 위한 단위→ public static void 메서드이름(){             ...수행할 연산식...    }

 

2-4. 메서드의 호출정의된 메서드는 다른 메서드를 구성하는 {...} 안에서 다음의 형식으로 사용될 수 있으며, 이를 메서드를 호출한다고 한다.→ 메서드 이름();

 


public static void main(String[] args){
	// 여러 번 호출 가능
	f();	// 101
	f();
	f();
	f();
	f();
}

public static void f(){
	int x =100;
	int y = x+1;
	System.out.println(y);
}

 

2-5. 메서드 파라미터java 프로그램의 메서드(=함수)는 자신이 실행되는데 필요한 조건값을 메서드 이름 뒤의 괄호 안에서 변수 형태로 선언한다. 이를 메서드 파라미터라고 한다.→ public static void 메서드이름(변수형 변수이름){

 

    }

 

2-6. 다중 파라미터메서드가 연산을 수행하는데 두 개 이상의 파라미터가 필요하다면 콤마(,)로 구분하여 선언할 수 있다.→ public static void 메서드이름(변수형 변수이름, 변수형 변수이름, 변수형 변수이름){

 

    }

 

2-7. 파라미터를 갖는 메서드의 호출메서드를 정의하면서 파라미터가 명시되어 있다면 해당 메서드를 호출하면서 파라미터를 전달해 주어야 한다.→ 메서드이름(값1, 값2, 값3);

 


public static void main(String[] args){
	f1(100);		// 110
	plus(2, 5);		// 7
	minus(11, 9);		// 2
}

public static void f1(int a){
	int b = 10;
	System.out.println(a+b);
}

public static void plus(int x, int y) {	// 메서드 이름도 관련 있게 지을 것!
	System.out.println(x+y);
}

public static void minus(int x, int y){
	System.out.println(x-y);
}

 

2-8. 메서드의 리턴값

  • 메서드가 연산 결과를 자신이 호출된 위치에 반환하는 것을 "리턴"이라고 하며, 반환되는 값을 "리턴 값"이라고 한다.
  • 메서드 안에서 값을 리턴하기 위해서는 "return"이라는 키워드가 사용된다.
  • 값을 리턴하는 메서드는 선언시에 "void" 키워드 대신, 리턴하는 값에 대한 변수형이 명시된다. void는 리턴값이 없다는 의미이다.
  • → public static 리턴형 메서드이름(변수형 파라미터, ...){
                 return 리턴값;
        }

 


public static void main(String[] args){
	// 메서드의 리턴값을 변수에 저장
	int z = f1(5);
	System.out.println(z);	// 6
    
	boolean result = f2(10);
	System.out.println(result);	// true
	// 리턴값을 출력에 바로 사용 가능
	System.out.println(f2(2));	// false
}

public static int f1(int x){
	int y = x + 1;
	return y;
}

public static boolean f2(int x){
	if(x>5){
		return true;
	} else{
		return false;
 	}
}

 

2-9. 메서드 간의 상호 호출

  • 두 개의 함수를 연립하여 사용하기
    → f1(x) = x + 1
    → f2(y) = f1(y) + 10
    → k = f2(5);   // f1(5) + 10 > 5 + 1 + 10 > 16
  • java의 메서드 역시 서로 호출하는 것이 가능하다. 호출된 메서드가 값을 리턴하는 경우, 리턴받은 값을 다른 연산에 사용할 수 있다.
public static void main(String[] args){
	System.out.println(f2(100));	// 102
}

public static int f1(int x){
	return x+1;
}

public static int f2(int x){
	// 다른 메서드 호출
	return f1(x)+1;
}

 


// 문제 1. "Hello World~", "메서드가 호출되었습니다."를 출력하는 메서드를 각각 만들어 호출하세요.

public static void main(String[] args){
	helloWorld();	// Hello World~
	callMethod();	// 메서드가 호출되었습니다.
}

public static void helloWorld(){
	System.out.println("Hello World~");
}

public static void callMethod(){
	System.out.println("메서드가 호출되었습니다.");
}
// 문제 2. 
// 반환값이 없고 받는 인자값(매개변수, 파라미터)이 2개 있는 덧셈 메서드를 구현하여 인자값의 결과값을 출력하여라.

public static void main(String[] args){
	add(10, 10);	// 20
}

public static void add(int x, int y){
	System.out.println(x+y);
}
// 문제 3. 반환 값이 있고 받는 인자값(매개변수, 파라미터)이 없는 메서드를 구현하세요.

public static void main(String[] args){
	int b = a();
	System.out.println(b);	// 365
}

public static int a(){
	return 365;
}
// 문제 4. 반환값이 있고, 받는 인자값(매개변수, 파라미터)이 있는 메서드를 구현해보세요.

public static void main(String[] args){
	double result = div(41, 20)
	System.out.println(result)	// 2.0
}

public static double div(int a, int b){
	return a/b;
}

 

728x90

+ Recent posts