본문 바로가기
Programming Language/Java

[국비] Java 내용정리 Day14

by tpleehan 2021. 11. 24.

인터페이스

  • 인터페이스는 객체들의 표준 사용방법을 제시한다.
  • 인터페이스는 객체들을 충실하게 추상화, 캡슐화할 수 있게 도와준다.

  • 인터페이스는 선언시 class 자리에 interface라는 키워드를 넣어서 선언한다.
  • 인터페이스에는 인스턴스 필드를 선언할 수 없고, 상수만 선언할 수 있다. static final을 생략해도 자동으로 붙어서 처리된다.
  • 인터페이스에는 추상 메서드, 정적 메서드, 디폴트 메서드(jdk 1.8 이후)를 선언할 수 있다.

  • 인터페이스 자체로는 객체를 생성할 수 없다.
  • 인터페이스에서 명세한 기능을 구체화할 클래스가 필요하며, implements라는 키워드를 사용하여 인터페이스를 명시한다.
  • 인터페이스를 구현한 클래스는 인터페이스의 추상메서드들을 모두 오버라이딩해야 한다.

  • 인터페이스는 클래스간 상속과 달리 여러 개의 인터페이스를 다중 구현할 수 있다.
  • implements 키워드 뒤에 구현할 인터페이스들을 콤마로 나열한다.
  • 나열된 인터페이스의 모든 추상메서드를 전부 오버라이딩 해야 한다.

  • 공통된 속성이 여러가지일 경우 상속을 통해 클래스를 설계하는 것이 좋다.
  • 클래스 상속과 인터페이스 구현을 동시에 할 수 있고, 상속 키워드인 extends를 먼저 선언하며 순서를 주의해야 한다.
  • 상속 부모클래스가 추상 클래스일 경우 내부의 추상메서드를 반드시 오버라이딩해야 한다.

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

  • 추상클래스는 인스턴스 필드, 정적 필드, 상수를 모두 가질 수 있고 인스턴스 메서드, 정적 메서드, 파이널 메서드, 추상 메서드도 모두 가질 수 있다.
  • 추상클래스는 클래스이기 때문에 상속을 통한 새로운 클래스 확장을 위한 의도를 가지고 설계하는 것이다.
  • 인터페이스는 기능을 명세하여 객체를 규격화하는 것에 의의를 둔다. 상속에서 막아둔 다중 구현을 인터페이스에서 열어두어 설계의 유연성을 제공한다.

인터페이스 사용

  1. 인터페이스를 작성한 후 Class를 생성해서 인터페이스에 명세된 내용을 구현한다.
  2. 인터페이스의 구현 키워드는 implements 상속과 같이 클래스 이름 뒤에 구현하고자 하는 인터페이스 이름을 작성한다.
  3. 인터페이스에 선언된 추상 메서드는 반드시 구현 클래스에서 오버라이딩을 진행해야 한다.
  4. 인터페이스는 하나의 클래스에서 여러 개의 인터페이스를 동시에 다중 구현할 수 있다.
  5. 인터페이스들끼리 서로 상속이 가능하며, 다중 상속도 허용된다.
package inter.basic;

public interface Inter {

	void method3(); // abstract
}
package inter.basic;

public interface Inter1 extends Inter {

	// 인터페이스 내에 변수를 선언하면 자동으로 상수로 취급한다.
	double PI = 3.14;
	
//	Inter1() {} 인터페이스는 생성자를 가질 수 없다.
	
	// 인터페이스 내에 메서드를 선언하면 자동으로 추상 메서드가 된다.
	public void method1();
	
	public static void staticMethod() {
		System.out.println("사용 가능");
	}

}
package inter.basic;

public interface Inter2 extends Inter {
	
	int i = 5; // static final
	
	void method2(); // abstract
	
}

 

package inter.basic;

public class ImplClass1 implements Inter1, Inter2 {
	
	@Override
	public void method1() {
		System.out.println("Inter1의 추상메서드 구현");
	}

	@Override
	public void method2() {
		System.out.println("Inter2의 추상메서드 구현");
		
	}

	@Override
	public void method3() {
		System.out.println("부모 인터페이스의 추상메서드 구현");
		
	}

}
package inter.basic;

public class ImplClass2 implements Inter1 {

	@Override
	public void method3() {
		
	}

	@Override
	public void method1() {
		
	}
	
}
package inter.basic;

public class ImplClass3 implements Inter2 {

	@Override
	public void method3() {

	}

	@Override
	public void method2() {

	}
	
}
package inter.basic;

public class MainClass {

	public static void main(String[] args) {

		// 인터페이스는 객체를 생성할 수 없는 추상적인 개념이다.
//		Inter1 i1 = new Inter1(); (x)

		System.out.println("원주율: " + Inter1.PI);
		Inter1.staticMethod();

		ImplClass1 i1 = new ImplClass1();
		i1.method1();
		i1.method2();
		i1.method3();

		Inter1 it1 = new ImplClass1();
		it1.method1();
		it1.method3();
		((ImplClass1) it1).method2();
		((Inter2) it1).method2();

		Inter2 it2 = new ImplClass1();
		it2.method2();
		it2.method3();
		((Inter1) it2).method1();

		Inter1 it3 = new ImplClass2();
		Inter2 it4 = new ImplClass3();

		Inter[] inters = {it1, it2, it3, it4};

	}

}
  • 다형성은 상속이 전제되어야 하는 것이 원칙이지만 예외로 인터페이스와 클래스간의 구현 관계에서도 다형성 발생을 허용한다.
    • 인터페이스 변수 = new 객체();
  • 인터페이스의 다형성도 클래스의 다형성처럼 정보가 없다면 메서드 호출이 불가능하기 때문에 형 변환이 필요하다.
  • 구현하는 클래스가 서로 다른 인터페이스들을 동시에 구현하고 있다면 구현하는 인터페이스들끼리 서로 즉시 형변환이 가능하다.
package inter.basic2;

// 클래스의 사용 방법을 정의해 놓은 클래스의 틀 역할을 한다.
public interface Printer {

	void turnOn();
	void turnOff();
	void print(String document);
	void colorPrint(String document, String color);
	int copy(int n);
	
}
package inter.basic2;

public class Samsung implements Printer {

	String name = "Samsung";
	
	@Override
	public void turnOn() {
		System.out.println(this.name);
		System.out.println("전원을 켭니다.");
	}

	@Override
	public void turnOff() {
		System.out.println(this.name);
		System.out.println("전원을 끕니다.");	
	}

	@Override
	public void print(String document) {
		System.out.println(this.name);
		System.out.println(document);
	}

	@Override
	public void colorPrint(String document, String color) {
		System.out.println(this.name);
		System.out.println(color + "색 출력: " + document);
	}

	@Override
	public int copy(int n) {
		for (int i = 1; i <= n; i++) {
			System.out.println(i + "장 복사 완료");
		}
		return n;
	}

}
package inter.basic2;

public class LG implements Printer {

	@Override
	public void turnOn() {
		System.out.println("Life's Good");
		System.out.println("전원이 켜집니다.");
	}

	@Override
	public void turnOff() {
		System.out.println("Life's Good");
		System.out.println("전원을 끕니다.");
	}

	@Override
	public void print(String document) {
		System.out.println("Life's Good");
		System.out.println("문서 내용: " + document);
	}

	@Override
	public void colorPrint(String document, String color) {
		System.out.println("Life's Good");
		System.out.println("색상: " + color);
		System.out.println("문서 내용: " + document);
	}

	@Override
	public int copy(int n) {
		System.out.println("Life's Good");
		System.out.println(n + "장 복사를 시작합니다.");
		return n;
	}

}
package inter.basic2;

public class MainClass {

	public static void main(String[] args) {
		
		Printer p = new Samsung();
		p.turnOn();
		p.print("안녕하세요.");
		p.colorPrint("가나다라", "Green");
		p.copy(10);
		p.turnOff();
		
		System.out.println("------------------------------");
		
		p = new LG();
		p.turnOn();
		p.print("반갑습니다.");
		p.colorPrint("abcd", "빨강");
		p.copy(3);
		p.turnOff();	
	}

}

bad Example

package inter.bad;

public class Join {
	
	public Join() {
		System.out.println("회원 가입 요청");
	}
	
	public void join() {
		System.out.println("회원가입 로직 ~~~....");
		System.out.println("DB접속도 하고, 입력값도 받고, 값을 집어넣고 등등...");
	}

}
package inter.bad;

public class Login {
	
	public Login() {
		System.out.println("로그인 요청");
	}
	
	public void login() {
		System.out.println("사용자의 id, pw를 받고, 데이터베이스랑 비교 등등....");
	}

}
package inter.bad;

public class Update {
	
	public Update() {
		System.out.println("회원 정보 수정 요청");
	}
	
	public void update() {
		System.out.println("수정 정보를 입력받아서 데이터베이스 수정 조치...");
	}

}
package inter.bad;

public class Delete {
	
	public Delete() {
		System.out.println("회원 탈퇴 요청");
	}
	
	public void delete() {
		System.out.println("사용자의 아이디를 받아 데이터베이스에 삭제 조치...");
	}

}
package inter.bad;

import java.util.Scanner;

public class MainClass {

	public static void main(String[] args) {
		
		Scanner sc = new Scanner(System.in);
		
		System.out.println("진행할 번호를 입력하세요.");
		System.out.println("1.가입 2.로그인 3.수정 4.삭제");
		System.out.print("> ");
		int menu = sc.nextInt();
		
		if (menu == 1) {
			Join j = new Join();
			j.join();
			
		} else if (menu == 2) {
			Login log = new Login();
			log.login();
	
		} else if (menu == 3) {
			Update update = new Update();
			update.update();
		
		} else if (menu == 4) {
			Delete del = new Delete();
			del.delete();
		}

	}

}

Good Example

package inter.good;

public interface IUserService {

	void execute(); // 추상메서드 선언.

}
package inter.good;

public class Join implements IUserService {

	@Override
	public void execute() {
		System.out.println("회원가입 로직 ~~~....");
		System.out.println("DB접속도 하고, 입력값도 받고, 값을 집어넣고 등등...");
	}

}
package inter.good;

public class Login implements IUserService {

	@Override
	public void execute() {
		System.out.println("사용자의 id, pw를 받고, 데이터베이스랑 비교 등등....");
	}

}
package inter.good;

public class Update implements IUserService {

	@Override
	public void execute() {
		System.out.println("수정 정보를 입력받아서 데이터베이스 수정 조치...");
	}

}
package inter.good;

public class Delete implements IUserService {

	@Override
	public void execute() {
		System.out.println("사용자의 아이디를 받아서 데이터베이스에 삭제 조치...");
	}

}
package inter.good;

import java.util.Scanner;

public class MainClass {

	public static void main(String[] args) {
		
		Scanner sc = new Scanner(System.in);
		
		//다형성 적용을 위해 인터페이스 타입의 변수를 하나 선언.
		IUserService sv;
		
		System.out.println("진행하실 번호를 입력하세요.");
		System.out.println("1.가입 2.로그인 3.수정 4.삭제");
		System.out.print("> ");
		int menu = sc.nextInt();
		
		if (menu == 1) {
			sv = new Join();
			sv.execute();
		} else if (menu == 2) {
			sv = new Login();
			sv.execute();
		} else if (menu == 3) {
			sv = new Update();
			sv.execute();
		} else if (menu == 4) {
			sv = new Delete();
			sv.execute();
		}
		
		sc.close();

	}

}

예외(Exception)

  • Exception이란 실행 중 발견 된 오류이다.
  • 예외 처리(Exception Handling)는 오류 발생에 대한 대처 방법 중 하나이다.
  • 예외 처리는 시스템 스스로 오류를 복구하는 것이 아닌, 오류 발생 가능성이 있는 부분에 대한 처리를 미리 프로그래밍하는 것이다.
  • 예) 예외처리를 해야 할 필요가 있는 부분
    • 파일을 다룰 때 파일이 없거나 쓰기 금지로 인한 오류
    • 데이터베이스 프로그래밍 시 제약조건 등에 의한 데이터베이스 서버 오류
    • 네트워크 프로그래밍 시 네트워크 연결 실패로 인한 오류
    • 배열의 인덱스를 벗어난 참조로 인한 오류
  • 예외는 2가지 종류가 있다.
    • 일반 예외(Exception)
    • 실행 예외(Runtime Exception)
  • 일반 예외는 컴파일러 체크 예외라 하며, 자바 소스를 컴파일 하는 과정에서 예외처리가 필요한지 검사하기 때문이다. 만약 해당 과정에서 예외처리 코드가 없다면 컴파일 오류가 발생한다.
  • 실행 예외는 컴파일 과정에서 예외처리 코드를 검사하지 않는 예외를 말한다.

예외 책임 전가

  • 메서드 내부에서 예외가 발생할 수 있는 코드르 작성할 때 try ~ catch 블록으로 예외를 처리하는 것이 기본이지만, 경우에 따라 메서들르 호출한 곳으로 예외를 떠넘길 수 있다.
  • throws라는 키워드를 사용하며, 메서드 선언부 끝에 작성되어 내부에서 처리되지 않은 예외를 호출부로 던진다.

package exception.basic;

import java.util.Scanner;

public class TryCatchExample {

	public static void main(String[] args) {
	
		Scanner sc = new Scanner(System.in);
		
		System.out.print("정수1: ");
		int i = sc.nextInt();
		System.out.print("정수2: ");
		int j = sc.nextInt();
		
		System.out.println("나눗셈 시작");
		
		try {
			// try블록에는 예외 발생 가능성이 있는 코드를 작성한다.
			System.out.printf("%d / %d = %d\n", i, j, i/j);
		} catch (Exception e) {
			// catch블록에는 try블록에서 실제 예외가 발생했을 경우에 실행할 코드를 작성하면 된다.
			System.out.println("0으로 값을 나눌 수 없습니다.");
			System.out.println("에러 메시지: " + e.getMessage());
		}

		sc.close();
		
		System.out.println("프로그램 정상 종료");
		
	}
	
}
  • 다중 catch문은 실제 에러가 발생하면 위에서부터 순서대로 catch문을 검색하면서 내려오기 때문에 부모 타입의 예외를 자식 타입의 예외보다 위에 작성하면 안된다.
  • catch 괄호에 예외 타입을 여러 개 작성하고 싶은 경우에는 |(or) 기호를 사용하여 타입을 나열해주면, 하나의 catch 블록으로 여러 타입의 예외를 동시에 처리할 수 있다. (java 7버전부터 가능한 문법)
    예) catch (InputMismatchException | ArithmeticException e)
package exception.basic;

import java.util.InputMismatchException;
import java.util.Scanner;

public class MultiCatchExample {

	public static void main(String[] args) {
		
		Scanner sc = new Scanner(System.in);
		int[] arr = new int[5];

		try {
			System.out.print("정수: ");
			int n = sc.nextInt();
			
			int result = 100 / n;
			
			System.out.println(arr[result]);
			
			String s = null;
			s.equals("안녕");
		} catch (InputMismatchException e) {
			System.out.println("정수를 정확하게 입력해주세요.");
		} catch (ArithmeticException e) {
			System.out.println("0으로 나눌 수 없습니다.");
		} catch (ArrayIndexOutOfBoundsException e) {
			System.out.println("인덱스 범위를 벗어났습니다.");
		} catch (NullPointerException e) {
			System.out.println("주소값에 null이 있습니다.");
		} catch (Exception e) {
			System.out.println("알 수 없는 에러가 발생했습니다.");
		}
		
		System.out.println("프로그램 종료");
		
		sc.close();
	
	}

}

Exception Quiz01

1. 스캐너를 통해서 정수 2개를 입력받는다.
2. 입력받은 값이 정수라면, 단순히 정수의 합을 출력하고 반복문을 종료시킨다.
3. 입력받은 값이 에러를 발생시키는 값이라면 "정수로만 입력하세요" 라고 출력한 후에 다시 입력받을 수 있도록 작성한다.
4. 반복문을 탈출하면 프로그램 정상 종료 문장을 띄운다.
package exception.basic;

import java.util.Scanner;

public class MainClass {

	public static void main(String[] args) {

		Scanner sc = new Scanner(System.in);
		
		while (true) {
			try {
				System.out.print("정수1: ");
				int num1 = sc.nextInt();
				System.out.print("정수2: ");
				int num2 = sc.nextInt();
				
				int result = num1 + num2;
				System.out.printf("%d + %d의 합계: %d\n", num1, num2, result);
				break;
				
			} catch (Exception e) {
				System.out.println("정수로만 입력해주세요.");
				sc.nextLine();
			}
			
		}
		System.out.println("프로그램 종료");
		sc.close();
		
	}

}​

Exception Quiz02

1. 난수 2개 생성해서 덧셈 문제를 만들기 (1~100)
2. 만약 정답을 입력하는 곳에 정수가 아닌 문자열 등을 입력했을 시 잘못 입력했다고 출력을 하고 잘못 입력한 횟수를 센다.
3. 사용자가 0을 입력하면 프로그램이 종료되고 종료 시 정답 횟수와 오답 횟수, 잘못 입력한 횟수도 출력
package exception.basic;

import java.util.Scanner;

public class MainClass2 {

	public static void main(String[] args) {

		Scanner sc = new Scanner(System.in);
		int cCount = 0;
		int iCount = 0;
		int eCount = 0;
		
		System.out.println("*** 연산 퀴즈 ***");
		System.out.println("종료하시려면 0을 입력하세요.");
		
		while (true) {
			int rn1 = (int) ((Math.random() * 100) + 1);
			int rn2 = (int) ((Math.random() * 100) + 1);
			
			int correct = rn1 + rn2;
			
			System.out.printf("%d + %d = ???\n", rn1, rn2);
			
			int answer;

            try {
				System.out.print("> ");
				answer = sc.nextInt();
			} catch (Exception e) {
				System.out.println("잘 못 입력했습니다.");
				eCount++;
				sc.nextLine();
				continue;
			}

			if (answer == 0) {
				System.out.println("종료합니다.");
				break;
			} else if(answer == correct) {
				System.out.println("정답입니다.");
				cCount++;

			} else {
				System.out.println("오답입니다.");
				iCount++;
			}
				
		}
		
		System.out.println("-------------------------");
		System.out.println("정답 횟수: " + cCount + "회");
		System.out.println("오답 횟수: " + iCount + "회");
		System.out.println("잘못 입력한 횟수: " + eCount + "회");
		
		sc.close();
	}

}​
package exception.throws_;

import java.io.FileInputStream;
import java.io.FileNotFoundException;

public class ThrowsExample {

	static String[] greetings = {"안녕하세요.", "Hello", "你好"};

	static void greet(int idx) throws Exception {
		System.out.println(greetings[idx]);
	}
	
	public static void main(String[] args) {
		
		try {
			greet(3);
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		System.out.println("프로그램 정상 종료");

		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
			new FileInputStream("C:/temp/new.jpg");
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		try {
			new FileInputStream("C:/temp/new.jpg");
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}

	}

}

 

'Programming Language > Java' 카테고리의 다른 글

[국비] Java 내용정리 Day16  (0) 2021.11.28
[국비] Java 내용정리 Day15  (0) 2021.11.25
[국비] Java 내용정리 Day13  (0) 2021.11.23
[국비] Java 내용정리 Day12  (0) 2021.11.21
[국비] Java 내용정리 Day11  (0) 2021.11.20

댓글