국비 수업 15일차

김성수·2022년 11월 5일
0
post-thumbnail

1. 추상 클래스를 사용하는 목적

일반적인 클래스는 오직 객체를 생성하기 위한 목적으로 작성된다.
그러나 추상적인 내용이 포함되면 객체화 할 수 없다는 단점이 있는데 이를 보완하기 위해 추상 클래스를 사용한다.

※ 추상클래스는 생성자를 통하여 직접 객체를 생성할 수 없다는 특징이 있다.

package abstractClass;


abstract class Test1 {
	
	Test1() {
		System.out.println("Test1 생성자 호출 !!");
	}
	
	public void funcion1() {
		System.out.println("내용을 포함하는 구체적인 메서드");
	}
	
	public abstract void funcion2();	// 추상 메서드는 오직 추상 클래스 안에서만 생성 가능하다
}


class Test2 extends Test1 {		// 추상 클래스를 상속 받으면 미구현된 추상클래스를 만들거나 자신이 추상 클래스가 되야한다

	@Override	// 형식은 그대로 유지하면서, 내용을 새로 작성하여 덮어쓴다
	public void funcion2() {
		System.out.println("미구현 메서드를 구현한 내용");
	}
}

public class Ex01 {
	// 추상화 : 실제 객체의 몇몇 특성만 추출하여 프로그램 내에 반영한다
	// 필드는 속성을 작성하고, 메서드는 기능을 표현하는데, 메서드의 구체적인 내용이 담기지 않을 수도 있다
	
	// 추상 메서드 : 형식은 정의되어 있으나, 내용은 정의되지 않은 메서드
	// 추상 클래스 : 추상 메서드를 포함할 수 있는 클래스 (일반 메서드도 포함 가능하다)
	
	
	
	public static void main(String[] args) {
//		Test1 ob1 = new Test1();	 ※ 추상 클래스의 생성자는 직접 호출할 수 없다(객체화가 불가능하다) 말 그대로 추상적이라 객체화가 불가능하다.
		Test2 ob2 = new Test2();
		ob2.funcion1();		// 반드시 생성자가 한번은 호출된다 만약 funcion1이 존재하지 않더라도 funcion2에서 실행된다
		ob2.funcion2();
	}
}

2. 추상 클래스를 이용하여 윈도우 실행창에 접근하기

1. 추상 클래스의 특징 몇가지

  • abstract 메서드는 반드시 상속받아서 써야하기 때문에 private로 지정할 수 없다
  • 접근 제한자는 반드시 protected 혹은 public으로 설정해야한다
  • protected : 패키지가 달라도 상속관계에 있으면 접근 가능
  • public : 패키지나 상속여부에 상관없이 누구나 접근 가능
package abstractClass;

abstract class Button {
	
	protected abstract void onclick();
	
	public void click() {
		this.onclick();
	}
}

class MessageButton extends Button {
	
	@Override
	protected void onclick() {
		System.out.println("Hello, world !!");
	}
}

class NotepadButton extends Button {
	
	@Override
	protected void onclick() {
		try {
			Runtime rt = Runtime.getRuntime();		// 운영체제 런타임을  객체로 받아온다
			String cmd = "notepad";					// 실행할 명령어
			Process pro = rt.exec(cmd);				// 명령어를 실행하여 생성된 프로세스를 저장
			Thread.sleep(2000);						// 2초 기다렸다가
			pro.destroy();							// 프로세스를 강제로 종료한다
			
		} catch (Exception e) {}
	}
}


public class Ex02 {
	public static void main(String[] args) {
//		Button btn1 = new Button();
		
		MessageButton btn2 = new MessageButton();
		btn2.click();
		
		NotepadButton btn3 = new NotepadButton();	// 서브 클래스의 객체를 슈퍼 클래스로 참조한다
		btn3.click();
		
		// 추상 클래스가 직접 객체를 생성할 수는 없지만, 자료형으로써 참조변수를 사용하는 것은 가능하다
		
		Button btn5 = new Button() {	// 이름 없이 만들어 낸 클래스 익명 내부 클래스
			// 바로 실행되는 것 처럼 보이나 클래스를 생성하는 형식이다.		Ex02$1.class 형태의 이름으로 생성된다
												//	Ex02 클래스 내부의 $(이름이 없는) 1번째 클래스
			private String cmd = "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe";
			private String url = " https://www.naver.com/";
			
			@Override	// 바로 실행하는 것 처럼 보이지만
			protected void onclick() {	
				try {
					Runtime rt = Runtime.getRuntime();
					cmd += url;
					System.out.println(cmd);
					rt.exec(cmd);
				}	catch (Exception e) {
					e.printStackTrace();
				}
			}
		};
		btn5.click();
		
	}
}

3. 다중 상속을 지원하는 인터페이스

1. 인터페이스의 특징 몇가지

  • interface 는 추상 클래스의 일종이다
  • interface의 모든 필드는 public static final이다 ( 외부 접근은 가능하나 한번 지정되면 변경 불가 )
  • interface의 모든 메서드는 public abstract 이다
  • interface 는 extends 가 아니라, implement 키워드로 상속처리한다 (인터페이스를 구현한다 라고 표현함)
  • interface 는 자바에서 유일하게 다중 상속을 허용하는 형식이다
  • interface 는 오로지 추상 클래스만 표현 가능하다 (추상 클래스와의 차이점) 추상 클래스는 일반 클래스도 표현이 가능하다

package abstractClass;
interface Test3 {
	int n1 = 10;
	public static final int n2 = 20;	// n1과 n2의 형태는 같다
	// static이므로 어떤 객체에서 접근해도 동일한 값이다
	// final이므로 한번 지정된 값은 변경할 수 없으며, 반드시 초기값을 지정해야만 한다

	void method1();	// public abstract이므로 body를 작성할 수 없다
//	void method2() {} 바디 생성 불가 static을 붙히면 객체 생성에 관여가 되질 않아서 가능하긴 하다
	static void method2() {
		System.out.println("static은 객체 생성 여부에 상관없이 호출할 수 있으니 바디 생성 가능함");
	}
}

class Test4 implements Test3 {

	@Override
	public void method1() {
		System.out.println("인터페이스 Test3의 추상메서드를 구현한 메서드1");
	}
	
}

public class Ex03 {
	public static void main(String[] args) {
//		Test3 ob = new Test3();	// 인터페이스는 추상 클래스이므로, 생성자를 통한 객체 직접 생성이 불가능하다
		Test4 ob1 = new Test4();	// implements는 extends 대신에 인터페이스 전용으로 사용하는 상속문 "구현한다" 라고 표현 인터페이스는 미구현 덩어리
		ob1.method1();
		
		// 인터페이스는 추상클래스이므로, 익명 내부 클래스를 활용하여 객체를 생성할 수 있다
		Test3 ob2 = new Test3() {
			@Override
			public void method1() {
				System.out.println("익명 내부 클래스 !!");
			}
		};				
		ob2.method1();		
	}
}

4. 인터페이스의 용도와 람다식으로 구현된 함수형 인터페이스의 구조

package abstractClass;

interface USB {	// 인터페이스는 추상클래스, 추상 클래스는 클래스, 클래스는 자료형
	void action();
}
						// 인터페이스는 슈퍼클래스가 정의되어 있어도 씌울수가 있다.
class PowerChargeCable extends Object implements USB {

	@Override
	public void action() {
		System.out.println("전원 충전 중...");
	}	// 전력 전송
	
}

class PortableSSD implements USB{

	@Override
	public void action() {
		System.out.println("E: 연결됨. 용량 1TB");
	}	// 데이터 입출력
	
}

class Speaker implements USB {

	@Override
	public void action() {
		System.out.println("스피커 연결됨. 현재 볼륨 20");
	}	// 음성 데이터 전송
	
}

class PC {
	// 컴퓨터에 외부 장치를 연결하기 위해서는 USB 인터페이스 규격을 만족하면 된다
	// => 자료형이 USB이면 가능하다 (다형성)
	void connect(USB device) {
		device.action();
	}
}

public class Ex04 {
	public static void main(String[] args) {
		// 서로 다른 자료형의 3가지 장치가 모두 하나의 함수에 의해 컴퓨터와 연결될 수 있다
		PC pc = new PC();
		
		PowerChargeCable cable = new PowerChargeCable();
		PortableSSD ssd = new PortableSSD();
		Speaker sp = new Speaker();
		
		pc.connect(cable);		// 케이블 연결 시의 반응이 정상적으로 호출됨
		pc.connect(ssd);		// SSD 연결 시의 반응이 정상적으로 호출됨
		pc.connect(sp);			// 스피커 연결 시의 반응이 정상적으로 호출됨
		
		
		// 자바 8 이후 함수형 인터페이스 형식이 추가되었음
		// 함수형 인터페이스란, 단 하나의 추상 메서드만 가지는 인터페이스를 말한다
		// 함수형 인터페이스는 람다식에 의해 객체를 생성할 수 있다
		// 익명 클래스에 의한 객체 생성보다 식이 간편하고, 내부 작동도 다르다
		
		USB mouse = () -> System.out.println("마우스 연결됨...");	// 미구현된 함수의 객체만 적어주면 출력 가능 익명 클래스 방식이다
						// 실행하는 코드가 한줄이면 {} 중괄호 생략가능 (if처럼)
		pc.connect(mouse);
		
		// 위 코드의 람다식 구조
		// (매개변수) -> { 실행할 내용 };
		
		USB keyboard = () -> {
			System.out.println("키보드 연결됨...");
		};
		
		pc.connect(keyboard);
		
		// 1) 함수의 내용이 한줄이면 {} 생략 가능
		// 2) 함수의 매개변수가 하나이면 () 생략 가능	알아보기 쉽게 하기 위해 왠만하면 넣어준다
		// 3) 함수의 반환형이 void가 아니고, 한줄만에 값을 반환한다면 return 생략 가능

		// Interface ob = a -> a > 0 ? a : -a;			// a를 매개변수로 받고 (하나이면 괄호 생략가능)
														// 삼항연산자 a > 0 ?    return을 생략한 a : -a  반환
		
		// Interface ob = (a) -> { return a > 0 ? a : -a }; 위 람다식을 생략하지 않은 코드
	
	}
}

위와 같이 모든 클래스를 인터페이스 자료형으로 받아줄 수 있고 오버라이드를 이용하여 원하는 반환값이나 출력값을 얻을 수 있다.

profile
다들 잘하는데 나만 못해?

0개의 댓글