09_다형성(Polymorphism) : 추상


package edu.kh.poly.ex2.model.vo;
public abstract class Animal {
// 추상 클래스 (abstract class)
// 1. 미완성 메소드(추상 메소드)를 보유하고있는 클래스
// 2. 객체로 만들면 안되는 클래스
// -> 여러 타입들을 관리하기 위한 상위 타입의 목적
// 객체로 생성하여 사용하기 위한 목적이 아니다
// 필드
private String type; // 종/과 구분
private String eatType; // 식성(초식, 육식, 잡식)
// 생성자
public Animal() {} // 기본생성자
// - 추상 클래스는 new 연산자를 통해 직접적인 객체 생성은 불가능하지만
// 상속받은 객체 생성 시 내부 부모 부분이 생성될 때 사용된다.
public Animal(String type, String eatType) { // 매개변수 생성자(오버로딩 적용)
this.type = type;
this.eatType = eatType;
}
// getter / setter
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getEatType() {
return eatType;
}
public void setEatType(String eatType) {
this.eatType = eatType;
}
// toString() 오버라이딩
@Override // 오버라이딩이 되었음을 컴파일러에게 알려주는 어노테이션
public String toString() {
return type + " / " + eatType;
}
// 동물의 공통 기능 추출(추상화)
// -> 동물은 공통적으로 먹고, 숨쉬고, 움직이지만
// 어떤 동물이냐에 따라 그 방법이 다름!
// -> 해당 클래스에 메소드를 정의할 수 없다!
// --> 그럼 어떡할까?
// 미완성 상태로 두어 상속받은 자식이 해당 메소드를 정의 하도록
// 오버라이딩 강제화 시킴 --> 추상(abstract) 메소드로 작성
// 먹다
public abstract void eat(); // 추상 메소드
// 숨쉬다
public abstract void breath();
// 움직이다
public abstract void move();
}
package edu.kh.poly.ex2.model.vo;
public class Person extends Animal{
// Animal의 추상 메서드를 오버라이딩 하지 않으면 오류 발생
private String name;
public Person() {}
public Person(String type, String eatType, String name) {
super(type, eatType);
this.name = name;
}
// getter / setter
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void eat() {
System.out.println("숟가락, 젓가락 등 도구를 이용해서 먹는다.");
}
@Override
public void breath() {
System.out.println("코와 입으로 숨쉰다.");
}
@Override
public void move() {
System.out.println("두발로 걷는다.");
}
// toString() 오버라이딩
@Override
public String toString() {
return "Person : " + super.toString() + " / " + name;
}
}
package edu.kh.poly.ex2.model.vo;
public class Fish extends Animal{
public Fish() {}
public Fish(String type, String eatType) {
super(type, eatType);
}
@Override
public void eat() {
System.out.println("입을 뻐끔 뻐끔 거리면서 먹는다.");
}
@Override
public void breath() {
System.out.println("아가미 호흡을 한다.");
}
@Override
public void move() {
System.out.println("꼬리로 헤엄치며 움직인다.");
}
@Override
public String toString() {
return "Fish : " + super.toString();
}
}
package edu.kh.poly.ex2.model.service;
import edu.kh.poly.ex2.model.vo.Animal;
import edu.kh.poly.ex2.model.vo.Fish;
import edu.kh.poly.ex2.model.vo.Person;
public class AbstractService {
public void ex1() {
//Animal a1 = new Animal();
// Cannot instantiate the type Animal (객체화 할수없음)
// 클래스 : 객체의 속성, 기능을 정의한 것(일종의 설계도)
// 추상 클래스 : 미완성 메서드를 포함한 클래스(미완성 설계도)
// -> 미완성 설계도로는 객체를 만들 수 없다! -> 오류발생
// 해결 방법 : Animal을 상속받아 미완성 부분을 구현한
// 클래스를 이용해 객체 생성
// 추상클래스를 상속받은 자식 객체 생성
Person p1 = new Person();
p1.setName("홍길동");
// 상속받은 기능 호출
p1.setType("척추동물");
p1.setEatType("잡식");
// 오버라이딩한 메서드 호출
p1.eat(); // 숟가락, 젓가락 등 도구를 이용해서 먹는다.
p1.breath(); // 코와 입으로 숨쉰다.
Fish f1 = new Fish();
f1.eat(); // 입을 뻐끔 뻐끔 거리면서 먹는다.
f1.breath(); // 아가미 호흡을 한다.
}
public void ex2() {
// * 추상 클래스와 다형성 + 바인딩
// - 추상클래스는 객체로 만들수 없다!!!
// --> 하지만 "참조 변수"로는 사용할 수 있다!
//Animal a1 = new Animal(); (X)
// 사람 -> 동물 / 물고기 -> 동물
//Animal a1 = new Person(); (O)
//Animal a2 = new Fish(); (O)
Animal[] arr = new Animal[2];
// Animal 참조변수 배열 선언 및 할당
arr[0] = new Person("사람", "잡식", "김사람");
// Animal 부모 = Person 자식(다형성 중 업캐스팅)
arr[1] = new Fish("물고기", "잡식");
// Animal 부모 = Fish 자식(다형성 중 업캐스팅)
// 바인딩 확인
for(int i = 0; i < arr.length; i++) {
// arr[i] == Animal 참조변수
arr[i].eat();
arr[i].breath();
System.out.println(arr[i].toString());
// void edu.kh.poly.ex2.model.vo.Animal.eat() - 정적바인딩
System.out.println("-------------------------------");
// 프로그램 실행 시
// 참조하고 있는 자식 객체의 오버라이딩된 eat() 메서드 수행
// - 동적 바인딩
// --> 부모 타입 참조 변수로 메소드를 호출했지만
// 자식 타입의 오버라이딩된 메소드가 수행된다.
}
}
}
package edu.kh.poly.ex2.run;
import edu.kh.poly.ex2.model.service.AbstractService;
public class AbstractRun {
public static void main(String[] args) {
AbstractService service = new AbstractService();
//service.ex1();
service.ex2();
}
}
09_다형성(Polymorphism) : 인터페이스
- 인터페이스 : 더 추상화된 개념(접점) = 추상메소드 외에 사용불가
- 추상클래스 : 추상메소드 + 멤버변수, 일반메소드 사용가능
** 자바에서 인터페이스란? 클래스간의 접점!
-> 클래스가 공통적으로 가져야하는 필드, 메소드 모아두고 상속

package edu.kh.poly.ex2.model.service;
// 계산기 인터페이스
// -> 모든 계산기에 대한 공통 필드, 기능명을 제공하는 접점(interface)의 용도
public interface Calculator {
// 인터페이스 : 추상클래스의 변형체 (추상클래스보다 추상도 높음)
// - 추상클래스 : 일부만 추상 메서드(0개 이상)
// - 인터페이스 : 모두 추상메서드
// 필드(묵시적으로 public static final ==> 상수)
public static final double PI = 3.14;
static final int MAX_NUM = 100000;
public int MIN_NUM = -100000;
int ZERO = 0;
// 메서드 (묵시적으로 public abstract)
public abstract int plus(int num1, int num2);
public abstract int minus(int num1, int num2);
public abstract int multiple(int num1, int num2);
public abstract int divide(int num1, int num2);
}
package edu.kh.poly.ex2.model.service;
public class LYJCalculator /*extends Animal */implements Calculator{
// 클래스, 인터페이스 동시 상속 가능
// 인터페이스는 다중 상속 가능
// extends : 확장하다 , implements : 구현하다
// (부)클래스 - (자)클래스 : extends (추상클래스 포함)
// (부)인터페이스 - (자)클래스 상속 시 implements
@Override
public int plus(int num1, int num2) {
int result = num1 + num2;
return result;
}
@Override
public int minus(int num1, int num2) {
int result = num1 - num2;
return result;
}
@Override
public int multiple(int num1, int num2) {
int result = num1 * num2;
return result;
}
@Override
public int divide(int num1, int num2) {
int result = num1 / num2;
return result;
}
}
package edu.kh.poly.ex2.run;
import edu.kh.poly.ex2.model.service.AbstractService;
import edu.kh.poly.ex2.model.service.LYJCalculator;
public class AbstractRun {
public static void main(String[] args) {
LYJCalculator cal = new LYJCalculator();
System.out.println("합 : " + cal.plus(20, 15));
System.out.println("차 : " + cal.minus(20, 15));
System.out.println("곱 : " + cal.multiple(20, 15));
System.out.println("몫 : " + cal.divide(20, 15));
// 인터페이스 == 미완성 설계도 == 객체생성 불가능
// -> 추상클래스처럼 참조 변수로는 사용 가능
// 코드의 큰 수정 없이
// 객체 생성 코드만 바꾸면 새로운 클래스 코드를 수행할 수 있다.
// 인터페이스 특징
// 1) 인터페이스를 부모 참조변수로 사용하면
// 다형성 중 업캐스팅이 적용되서
// 상속받은 모든 클래스를 자식 객체로 참조할 수 있다.
// -> 이를 이용하여 중요한 메인코드의 수정을 최소화 할 수 있다.
// ex) Run에 작성된 합, 차, 곱, 몫을 출력하는 코드의 수정 없이
// 객체 생성 코드 한 줄만 수정하여 다르게 작성된 기능을 수행할 수 있다.
// 2) 자식 클래스에 공통된 메서드 구현을 강제하기 때문에
// 모든 자식 클래스가 동일한 형태를 띄게 된다.
// -> 이를 이용하여 공동 작업(팀 프로젝트)에 필요한
// 개발 환경을 조성할 수 있다.
}
}


10_예외 처리



package edu.kh.exception.test;
import java.util.Scanner;
public class ExceptionTest {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while(true) {
System.out.print("정수 입력(0 입력시 종료) : ");
int input= sc.nextInt();
// 컴파일 에러 => 개발자가 코드 잘못쓴것.
// 자료형이 맞지않아 연산을 못해서 "컴파일 에러"가 발생(코드 틀림)
//int a = 99.9;
int a = (int)99.9; // 코드로 수정 가능!
if(input == 0) {
break;
}
}
// 런타임에러 예제
// 런타임 에러 : 프로그램 수행 중 발생하는 에러
// 주로 if문으로 처리가 가능하다.
int[] arr = new int[3]; // 길이 3 : 인덱스 0,1,2 까지
arr[0] = 10;
arr[1] = 20;
arr[2] = 30;
//arr[3] = 40;
//java.lang.ArrayIndexOutOfBoundsException : 배열 범위 초과 예외
if( 3 >= arr.length) { // 배열 인덱스 범위 초과 시
System.out.println("배열 범위를 초과했습니다.");
} else {
arr[3] = 40;
}
}
}
package edu.kh.exception.model.service;
import java.io.IOException;
import java.util.InputMismatchException;
import java.util.Scanner;
public class ExceptionService {
// 예외(Exception) : 소스 코드의 수정으로 해결 가능한 오류
// 예외는 두 종류로 구분됨
// 1) Unchecked Exception : 선택적으로 예외 처리
// 2) Checked Exception : 필수적으로 예외 처리
private Scanner sc = new Scanner(System.in);
public void ex1() {
System.out.println("두 정수를 입력받아 나누기한 몫을 출력");
System.out.print("정수 1 입력 : ");
int input1 = sc.nextInt();
System.out.print("정수 2 입력 : ");
int input2 = sc.nextInt();
try {
System.out.println("결과 : " + input1 / input2);
// ArithmeticException : 산술적예외 0으로 나눌 수 없다.
} catch(ArithmeticException e) {
// try 에서 던져진 예외를 catch문 매개변수 e로 잡음.
System.out.println("infinity"); // 처리 코드
}
if(input2 != 0) {
System.out.println("결과 : " + input1 / input2);
} else {
System.out.println("infinity");
}
// 발생하는 예외 중 일부 예외는 try-catch 구문 사용 안해도
// 예외 상황을 방지할 수 있다!
// 일부예외 == 대부분 UncheckedException
}
public void ex2() {
// 여러가지 예외에 대한 처리 방법
try {
System.out.print("입력1 : ");
int num1 = sc.nextInt(); //java.util.InputMismatchException
System.out.print("입력2 : ");
int num2 = sc.nextInt(); //java.util.InputMismatchException
System.out.println("결과 : " + num1 / num2); // ArithmeticException
String str = null;
System.out.println( str.charAt(0) );
// java.lang.NullPointerException : 참조하지 않는 참조변수를 이용해서 코드 수행 시 발생
} catch(InputMismatchException e) {
System.out.println("타입에 맞는 값만 넣어주세요");
} catch(ArithmeticException e) {
System.out.println("0으로 나눌 수 없습니다.");
} catch(Exception e) { // 다형성 : 업캐스팅
System.out.println("뭔지 모르겠으나 예외가 발생해서 처리함.");
// 예외처리 + 다형성
// Exception 클래스 : 모든 예외의 최상위 부모
// 다형성 - 업캐스팅 : 부모타입 참조변수로 자식객체를 참조.
// ** 상위 타입의 예외 클래스를 catch문에 작성하면
// 다형성 업캐스팅에 의해 모두 잡아서 처리 가능!! **
}
}
public void ex3() {
// 1) try - catch - finally
// finally : try구문에서 예외가 발생 하든 말든 무조건 마지막에 수행
try {
System.out.println( 4 / 0 );
} catch(ArithmeticException e) {
System.out.println("예외처리됨");
// 2) catch문 매개변수 활용
// 매개변수 e : 예외 관련된 정보 + 예외 관련 기능
System.out.println( e.getClass() ); // 어떤 예외 클래스인가?
// class java.lang.ArithmeticException
System.out.println( e.getMessage() ); // 예외 발생시 출력된 내용
// / by zero
System.out.println( e ); // e.toString();
// java.lang.ArithmeticException: / by zero
e.printStackTrace();
// java.lang.ArithmeticException: / by zero
// at edu.kh.exception.model.service.ExceptionService.ex3(ExceptionService.java:96)
// at edu.kh.exception.run.ExceptionRun.main(ExceptionRun.java:13)
} finally {
System.out.println(" 무조건 수행 됨 ");
}
}
public void ex4() {
// throws : 호출한 메서드에게 예외를 던짐
// -> 호출한 메서드에게 예외를 처리하라고 위임하는 행위
// throw : 예외 강제 발생 구문
try {
methodA();
} catch(Exception e) {
// Exception : 모든 예외의 최상위 부모
// Exception이 catch 매개변수로 작성되었다
// == 예외 종류 상관없이 모두 처리
e.printStackTrace();
// 발생한 예외가 메서드와 위치에 대한 모든 내용을 출력
// 예외 발생 지점 추적
}
}
public void methodA() throws IOException{
methodB();
}
public void methodB() throws IOException{
methodC();
}
public void methodC() throws IOException{
// 예외 강제 발생 구문
throw new IOException();
}
}
package edu.kh.exception.run;
import edu.kh.exception.model.service.ExceptionService;
public class ExceptionRun {
public static void main(String[] args) {
ExceptionService service = new ExceptionService();
//service.ex1();
//service.ex2();
//service.ex3();
service.ex4();
}
}




