티스토리 뷰
1. 인터페이스 - 디폴트 메소드
- 인터페이스만으로는 사용이 불가능하다.
- Why? 디폴트 메소드는 인스턴스 메소드로, 구현 객체가 인터페이스에 대입되어야 호출할 수 있기 때문이다.
- 모든 구현 객체가 가지고 있는 기본 메소드로 사용되지만, 필요에 따라서 재정의가 가능하다.
- 인터페이스의 모든 멤버는 public이다.
2. 다형성
- 하나의 타입에 여러 가지 객체를 대입해 다양한 실행 결과를 얻는 것이다.
- 자동 타입 변환 ( Promotion ) : 인터페이스( 부모 ) 변수 = 구현( 자식 )객체 ;
- Ex. A a1 = new b ; ( 부모인 A타입의 a라는 변수에 자식객체인 b를 넣은 것이다. )
- 자동형변환은 데이터 유실의 위험성이 없다.
- 필드의 다형성 : 다형성은 객체를 부품화시킨다.
- Ex. 타이어 인터페이스를 만들어서 타이어의 규격을 정한 후, 규격에 맞는 다양한 타이어를 구현한다.
3. 인터페이스 상속
- Public interface 하위인터페이스 extends 상위인터페이스1, 상위인터페이스2 { … }
- 다중인터페이스( implements )는 클래스에서 사용하고, 인터페이스의 상속( extends )은 인터페이스에서 사용한다.
- 하위 인터페이스는 상위 인터페이스의 규격을 모두 지켜야 한다.
- 하위 인터페이스 구현 클래스는 다음과 같은 메소드를 모두 재정의 해야 한다.
- 1. 하위 인터페이스의 추상 메소드 2. 상위 인터페이스1의 추상 메소드 3. 상위 인터페이스2의 추상 메소드
4. 예외( Exception ) 처리
- 자바에서는 컴파일할 때나 런타임에서 나타나는 오류를 예외라고 부른다.
- 오류의 종류 :
- 1 ) 에러 ( Error ) : 하드웨어의 잘못된 동작 또는 고장으로 인한 오류
- 2 ) 예외 ( Exception ) : 사용자의 잘못된 조작 또는 개발자의 잘못된 코딩으로 인한 오류
- + 에러는 정상실행 상태로 돌아갈 수 없지만, 예외는 예외 처리 추가하면 정상실행 상태로 돌아갈 수 있다.
- 예외의 종류 :
- 1 ) 일반( 컴파일 체크 ) 예외 [ checked exception ] : 예외처리 코드가 없으면 컴파일 오류 발생
- 2 ) 실행 예외 ( Runtime Exception ) : 예외 처리 코드를 생략하더라도 컴파일이 되는 예외
- 예외 클래스의 상위 클래스 : Throwable - > java.lang.Exception
5. 실행 예외 ( Runtime Exception )
- NullPointerException ( 객체 참조가 없는 상태 ) : 객체를 가지고 있지 않은데, 객체를 가지고 있는 것처럼 실행할 때 나타나는 예외
- ArrayIndexOutOfBoundException : 배열의 인덱스 범위를 초과해서 사용할 경우 발생
- ClassCastException : 타입 변환이 되지 않을 경우 발생하는 실행예외이다.
6. 예외 처리 코드 ( try – catch – finally )
- 예외 발생시 프로그램의 종료를 막고, 정상적으로 실행할 수 있도록 처리해준다!
- 일반 예외(checked exception)에서는 반드시 작성해야 컴파일이 가능하고, 실행 예외에서는 컴파일러가 체크하지 않기에 개발자 경험에 의해서 작성해야 한다.
- Try – catch – finally 블록을 이용해 예외 처리 코드를 작성해야 한다.
- Try { } catch (예외클래스 e) { } finally { }로 구성되어 있으며,
- Try { } 블록 내에서는 예외 발생 가능 코드를 작성하고
- Catch (예외클래스 e) { } 블록 내에서는 예외를 잡는 블록으로, 예외 처리를 어떻게 할지 대안 로직 코드를 작성하게 된다.
- (예외클래스 e)에서는 import문을 사용해야 한다.
- 만약 예외가 발생하지 않으면 catch 블록을 스킵된다.
- 그러나 try블록은 예외가 발생하든 발생하지 않든 무조건 실행된다.
- Finally 블록도 물론 항상 실행된다.
7. .parsexxx(String number)
- 사용자가 입력한 문자열을 지정된 타입에 맞게 변환시켜준다.
- 기본정수타입 - - - > Wrapper Type.parsexxx(String number) :
- byte - - - > Byte
- short - - - > Short
- char - - - > Character. parsexxx
- int - - - > Integer.parseInt(String number)
- long - - - > Long.parseLong(…)
- 기본실수타입 - - - > Wrapper Type.parsexxx(String number) :
- float - - - > Float
- double - - - > Double
- 기본논리타입 - - - > Wrapper Type.parsexxx(String number) :
- boolean - - - > Boolean
01. 인터페이스 - 디폴트 메소드
package Interface06;
public interface RemoteControl { // 디폴트 메소드와 정적 메소드의 오버라이드 ( 재정의 )
public static final int MAX_VOLUME = 10;
public static final int MIN_VOLUME = 0;
public abstract void turnOn();
public abstract void turnOff();
public abstract void setVolume(int volume);
// 디폴트 메소드
public default void setMute(boolean mute) {
if(mute) {
System.out.println("무음 처리합니다.");
} else {
System.out.println("무음을 해제합니다.");
} // if - else
} // default method - setMute
public static void changeBattery() {
System.out.println("건전지를 교환합니다.");
}// changeBattery
} // end class
package Interface06;
import lombok.ToString;
@ToString
public class Audio implements RemoteControl {
// 1. 인스턴스 필드
private int volume;
// -------------------- 인터페이스의 규격을 구현 ( 추상메소드 재정의 ) -----------------------
// 2. 추상 메소드의 실체 메소드
@Override // 오버라이딩을 할 때에는 반드시 @Override를 작성하자
public void turnOn() {
System.out.println("Audio를 켭니다.");
} // turnOn
@Override
public void turnOff() {
System.out.println("Audio를 끕니다.");
} // turnOff
@Override
public void setVolume ( int volume ) {
if ( volume > RemoteControl.MAX_VOLUME) {
this.volume = RemoteControl.MAX_VOLUME;
} else if ( volume < RemoteControl.MIN_VOLUME) {
this.volume = RemoteControl.MIN_VOLUME;
} else {
this.volume = volume;
} // if - else if - else
System.out.println("현재 Audio 볼륨 : " + volume );
}
// -------------------- 디폴트 ( default ) 메소드 재정의 -----------------------
@Override
public void setMute(boolean mute) {
System.out.println("Audio::setMute invoked.");
} // setVolume
// 디폴트 메소드는 인터페이스에서 선언할때 default를 작성하라는 것이지 오버라이드할 때에도 작성하면 안된다.
// 오버라이드할 때에는 default를 삭제하도록 하자!!
// -------------------- 정적 ( static ) 메소드 재정의 - 불가능 -----------------------
// @Override // xx!
// public static void changeBattery() {
//
// System.out.println("건전지를 교환합니다.");
//
// }// changeBattery
// 정적 메소드의 오버라이딩이란 개념은 없다!! 모든 정적멤버는 그 소속이 clazz이기 때문에 오버라이드가 불가능하다!!
} // end class
package Interface06;
public class Television implements RemoteControl {
// 1. 인스턴스 필드
private int volume;
// -------------------- 인터페이스의 규격을 구현 ( 재정의 ) -----------------------
// 2. 추상 메소드의 실체 메소드
@Override
public void turnOn() {
System.out.println("TV를 켭니다.");
} // turnOn
@Override
public void turnOff() {
System.out.println("TV를 끕니다.");
} // turnOff
@Override
public void setVolume ( int volume ) {
if ( volume > RemoteControl.MAX_VOLUME) {
this.volume = RemoteControl.MAX_VOLUME;
} else if ( volume < RemoteControl.MIN_VOLUME) {
this.volume = RemoteControl.MIN_VOLUME;
} else {
this.volume = volume;
} // if - else if - else
System.out.println("현재 TV 볼륨 : " + volume );
} // setVolume
// -------------------- 디폴트 ( default ) 메소드 재정의 -----------------------
@Override
public void setMute(boolean mute) {
System.out.println("Television::setMute invoked.");
} // set Mute
} // end class
package Interface06;
//클래스나 패키지를 복사하게 되다보면, 실행 클래스에서 이름 충돌이 날 수 있는데, 그때는 import문을 수정해주자!
public class RemotecontrolExample {
public static void main(String [] args) {
RemoteControl rc = null;
rc = new Television();
rc.setMute(true); // 출력 : Television::setMute invoked.
System.out.println("rc1 : " + rc);
rc.turnOn();
rc.turnOff();
rc = new Audio();
rc.setMute(true); // 출력 : Audio::setMute invoked.
System.out.println("rc2 : " + rc);
rc.turnOn();
rc.turnOff();
} // main
} // end class
02. 인터페이스의 상속
package Interface07;
public interface InterfaceA {
public abstract void methodA();
} // end interface
package Interface07;
public interface InterfaceB {
public abstract void methodB();
} // end interface
package Interface07;
public interface InterfaceC extends InterfaceA, InterfaceB { // 인터페이스의 상속
public abstract void methodC();
} // end interface
package Interface07;
public class ImplementationC implements InterfaceC {
// InterfaceC가 A와 B 모두 상속받았기 때문에, 구현 클래스는 A B C 규격 모두 지켜야 한다. (***)
@Override
public void methodA() {
System.out.println("ImplementationC::methodA() invoked.");
} // methodA
@Override
public void methodB() {
System.out.println("ImplementationC::methodB() invoked.");
} // methodB
@Override
public void methodC() {
System.out.println("ImplementationC::methodC() invoked.");
} // methodC
} // end class
package Interface07;
public class Example {
public static void main(String [] args ) {
ImplementationC impl = new ImplementationC(); // 구현 객체 생성
InterfaceA ia = impl; // 상위 인터페이스에 하위 인터페이스의 구현 객체를 받음
ia.methodA();
System.out.println();
// ===================================================================
InterfaceB ib = impl;
ib.methodB();
System.out.println();
// ===================================================================
InterfaceC ic = impl; // 인터페이스C는 A와 B모두 상속받았기 때문에 메소드 a b c 모두 사용이 가능하다.
ic.methodA();
ic.methodB();
ic.methodC();
} // main
} // end class
03. 다형성 1 - 추상메소드 오버라이드
package PracticePolymorphism03;
public interface Tire { // 다양성 - 추상메소드 오버라이드
// + 규격을 정할 때에는 추상 메소드!!
public abstract void roll(); // 규격
} // end interface
package PracticePolymorphism03;
public class HankookTire implements Tire {
@Override
public void roll() {
System.out.println("HankookTire::roll() invoked.");
} // roll
// 추상메소드는 규격의 역할을 하기에, 만약 이러한 규격을 어기면 오류가 발생하게 된다.
// 오류를 막기 위해서는 추상메소드를 지키거나 추상 클래스가 되는 수밖에는 없다.
} // end class
package PracticePolymorphism03;
public class KumhoTire implements Tire {
@Override
public void roll() {
System.out.println("KumhoTire::roll() invoked.");
} // roll
// 추상메소드도 디폴트와 같이 인터페이스에서만 abstract를 붙이지,
// 오버라이드할 때에는 abstract를 붙이지 않아야 한다!!
} // end class
package PracticePolymorphism03;
// 다형성 1에 의거해서 구현객체(자식객체)를 넣어준다.
public class Car {
// Lvalue : 부모타입 Rvalue : 자식타입
// 아래는 모두 다형성1로 필드 초기화 ( 즉, 부품 장착 )
Tire frontLeftTire = new HankookTire();
Tire frontRightTire = new HankookTire();
Tire backLeftTire = new HankookTire();
Tire backRightTire = new HankookTire();
void run() {
// 다형성2 발현 : 부모타입의 필드의 메소드 호출 (roll) - >
// 다형성 1에 의해 대입된 자식(구현)객체의 재정의된 메소드가 호출
frontLeftTire.roll();
frontRightTire.roll();
backLeftTire.roll();
backRightTire.roll();
} // run
} // end class
package PracticePolymorphism03;
public class CarExample {
public static void main (String [] args ) {
Car myCar = new Car();
myCar.run();
// ===============================================
// 부품교환
myCar.frontLeftTire = new KumhoTire();
myCar.frontRightTire = new KumhoTire();
// ===============================================
myCar.run();
// ===============================================
// 출력 : 바퀴가 4개이기에 4번씩 출력되는 것이며, 앞의 2개의 바퀴는 금호로 바뀌었기에 아래와 같이 출력된다.
// HankookTire::roll() invoked.
// HankookTire::roll() invoked.
// HankookTire::roll() invoked.
// HankookTire::roll() invoked.
// KumhoTire::roll() invoked.
// KumhoTire::roll() invoked.
// HankookTire::roll() invoked.
// HankookTire::roll() invoked.
} // main
} // end class
04. 다형성 2 - 추상메소드 오버라이드 2
package PracticePolymorphism04;
public interface Vehicle {
public abstract void run();
} // end interface
package PracticePolymorphism04;
public class Taxi implements Vehicle {
@Override
public void run() {
System.out.println("Taxi::run() invoked.");
System.out.println("택시가 달립니다.");
} // run
} // end class
package PracticePolymorphism04;
public class Bus implements Vehicle {
@Override
public void run() {
System.out.println("Bus::run() invoked.");
System.out.println("버스가 달립니다.");
} // run
} // end class
package PracticePolymorphism04;
public class Driver {
public void drive ( Vehicle vehicle ) { // 어떤 차를 몰지 선택하게 하였다.
vehicle.run();
} // drive
} // end class
package PracticePolymorphism04;
public class DriverExample {
public static void main (String[] args) {
Driver driver = new Driver(); // 객체 생성 ( 다형성 x )
Bus bus = new Bus();
Taxi taxi = new Taxi();
// ================================================
driver.drive(bus);
driver.drive(taxi);
// 출력 :
// Bus::run() invoked.
// 버스가 달립니다.
// Taxi::run() invoked.
// 택시가 달립니다.
} // main
} // end class
05. 다형성 3 - 강제형변환
package PracticePolymorphism05;
public interface Vehicle {
public abstract void run();
} // end interface
package PracticePolymorphism05;
public class Bus implements Vehicle{
@Override
public void run() {
System.out.println("Bus::run() invoked.");
} // run
public void checkFare() {
System.out.println("Bus::checkFare invoked.");
} // checkFare
} // end class
package PracticePolymorphism05;
public class VehicleExample {
public static void main(String [] args) {
Vehicle vehicle = new Bus(); // 다형성 1
vehicle.run(); // 다형성 2
// vehicle.checkFare(); // 컴파일 오류발생
// why? 겉이 부모타입으로 되어있기에 부모타입에 선언된 멤버만 사용이 가능하다!!! (***)
// ==========================================
// Bus bus = (Bus) vehicle; // 강제타입변환 - 안전하지 않은 버전
if( vehicle instanceof Bus bus ) { // 안전하게 강제형변환 할 수 있다.
bus.run(); // 다형성2는 아니다. 단순히 자식객체로 불러온 것이다.
bus.checkFare();
} // if
} // main
} // end class
06. 실행예외 1 - ArrayIndexOutOfBoundsException
package RuntimeException;
import java.util.Arrays;
public class ArrayIndexOutOfBoundsExceptionExample { // 배열의 원소의 개수보다 초과할 때 나타난다.
public static void main (String [] args) { // 메인 메소드는 JVM의 메인 쓰레드가 구동한다.
// main called by JVM "main" thread
// main은 static이기에 클래스 명.main으로 부른다.
// ex. ArrayIndexOutOfBoundsExceptionExample.main
System.out.println(Arrays.toString(args)); // 출력 : [1, 2, 34, 5, 6, 7, 8, 9, 10]
// main에 있는 문자열타입의 배열 args에 값을 넣는 방법은 런버튼에 있는
// Run Configurations에 있는 알규먼트 탭에서 값을 넣을 수 있다.
// 프로그램 알규먼트에서 값을 넣어야 한다.
if(args.length == 2 ) { // 문자열을 원소로 갖는 배열 args의 원소가 2개라면...
String data1 = args[0];
String data2 = args[1];
System.out.println("args[0] : " + data1);
System.out.println("args[1] : " + data2);
} else { // 배열 args의 원소의 개수가 2개가 아니라면...
System.out.println(" [ 실행 방법 ] ");
System.out.print("java ArrayIndexOutOfBoundsExceptionExample.");
System.out.print("값1 값2");
} // if-else
} // main
} // end class
07. 실행예외 2 - ClassCastException
package RuntimeException;
public class ClassCastExceptionExample {
public static void main (String [] args) {
Dog dog = new Dog(); // Dog 객체 생성
changeDog(dog); // 메소드 호출 ( 자식객체)
Cat cat = new Cat(); // Cat 객체 생성
changeDog(cat); // 메소드 호출 ( 자식객체 )
} // main
// 매개변수의 타입이 상속관계에서 부모타입으로 선언
public static void changeDog( Animal animal) { // 다형성1 발생
// 다형성 1의 상태에서 자식객체를 강제로 끄집어 낸다.
Dog dog = (Dog) animal; // cat이 들어올 수 있기에 ClassCastException이 발생한다.
// if(animal instanceof Dog dog) { // 이렇게 하면 강제형변환이 없어지기에 예외가 발생하지 않는다. ( 안전한 버전 )
// ;;
// } // if
// 예외가 발생하게 되면, 발생한 예외의 이름을 파악하는 것이 중요하다.
// 그 후에 예외이름 : 뒤에 있는 설명을 통해 왜 예외가 발생하고 있는지 파악하고
// at ~~ ( )안에 예외가 발생한 클래스명과 행 번호를 알려준다.
// ex. at RuntimeException.ClassCastExceptionExample.changeDog(ClassCastExceptionExample.java:20)
// - > ClassCastExceptionExample클래스 20번째 행에서 예외가 발생했다는 의미이다.
// at으로 적혀있는 예외 메세지(Stack Trace)는 아래에서 위로 읽어야 하며, 마지막 예외메세지를 확인하는 것이 좋다.
} // changeDog
} // end class
class Animal {;;}
class Dog extends Animal {;;}
class Cat extends Animal {;;}
08. 실행예외 3 - NullpointerException
package RuntimeException;
public class NullpointerExceptionExample {
public static void main (String[] args) {
String data = null; // 객체를 가지고 있지 않다.
System.out.println(data.toString());
// 실행 예외 : 객체를 가지고 있지 않은데, 객체를 가지고 있는 것 처럼 객체 메소드를 실행해서 예외가 발생했다.
} //main
} // end class
09. 실행예외 4 - NumberFormatException
package RuntimeException;
public class NumberFormatExceptionExample {
public static void main(String [] args) {
String data1 = "100"; // OK!
String data2 = "a100"; // 어, 이건 문자열에 a라는 문자와 100이라는 숫자가 같이 있는데 변환이 가능할까? -> 예외발생
// 예외 메세지 : Exception in thread "main" java.lang.NumberFormatException: For input string: "a100"
// 예외 메세지는 내가 작성한 코드 내에서 발생한 것만 확인하면 된다.
// parseInt ( " 문자열 " ) -> 정수타입으로 바꿔주는 메소드 (***)
int value1 = Integer.parseInt(data1);
int value2 = Integer.parseInt(data2);
int result = value1 + value2;
System.out.println(data1 + " + " + data2 + " = " +result);
} // main
} // end class
10. 예외처리 코드 - try - catch - finally
package try_catch_finally;
public class TryCatchFinallyExample {
public static void main (String [] args) { // 예외처리코드 : try - catch
try {
Class clazz = Class.forName("java.lang.String2");
// 문자열로 클래스 이름을 넣으면 해당하는 clazz객체를 주겠다는 메소드이다.
} catch(ClassNotFoundException e) { // e는 단순히 예외를 담는 변수이다.
// catch블록은 ( )내에 있는 예외가 발생하면 블록 내에 있는 대안 로직을 대신 실행시킨다.
System.out.println("클래스가 존재하지 않습니다."); // 대안 로직
// finally는 옵션이기에, 반드시 필요한 것은 아니다.
} // try - catch
} // main
} // end class
11. 예외처리 코드 2 - try - catch - finally
package try_catch_finally;
public class TryCatchFinallyRuntimeExceptionExample { // try - catch
public static void main(String [] args) {
String data1 = null;
String data2 = null;
try { // try 블록 내에서 예외가 발생하게 되면 catch로 간다. 예외가 발생하지 않으면 catch는 패스한다.
data1 = args[0];
data2 = args[1];
int result = Integer.parseInt(args[1]); // 문자열을 숫자로 변환시켜 준다!! (***)
System.out.println("result : " + result);
} catch(ArrayIndexOutOfBoundsException e) {
System.out.println("실행매개 값의 수가 부족합니다.");
System.out.println("[실행방법]");
System.out.println("java TryCatchFinallyRuntimeExceptionExample num1 num2");
return; // 이 문장을 만나는 즉시, 메소드의 실행을 종료시키고 (***)
// 만일 뒤의 값(리터럴, 변수, 표현식 등)이 오면, 호출자에게 반환한다.
} // try-catch
} // main
} // end class
'KH 정보교육원 [ Java ]' 카테고리의 다른 글
KH 19일차 - 제네릭 타입 (0) | 2022.03.25 |
---|---|
KH 18일차 - 예외처리코드 및 제네릭 (0) | 2022.03.24 |
KH 16일차 - 추상 클래스 및 인터페이스 (0) | 2022.03.21 |
KH 15일차 - protected 접근제한자 및 프로모션 (0) | 2022.03.18 |
KH 14일차 - 상속 (0) | 2022.03.17 |