본문 바로가기
JAVA/JAVA Note

[JAVA Note] 16. 추상클래스

by objade 2022. 11. 2.

 

1. 추상클래스

 

1) 일반클래스와 추상클래스

- 일반적인 클래스객체생성하기 위한 목적으로 작성함

- 추상적인 내용이 포함되면 객체화할 수 없음

class Test1 {
public void function1() {
	System.out.println("내용을 포함하는 구체적인 메서드");
	}
// public void function2();		
}

- 추상 클래스생성자를 통하여 직접 객체를 생성할 수 없음

abstract class Test1 {
	
	Test1() {
		System.out.println("Test1 생성자 호출!");
	}
	public void function1() {
		System.out.println("내용을 포함하는 구체적인 메서드");
	}
	public abstract void function2();
}

- Test1function2()미구현된 메서드이므로, 서브클래스Test2에서 구현해줘야 함

형식은 그대로 유지하면서 ,내용새로 작성하여 덮어쓴다.

class Test2 extends Test1 {

	@Override
	public void function2() {
		System.out.println("미구현 메서드를 구현한 내용");
	}
}

~ 메인 함수

public class Ex01 {
	public static void main(String[] args) {
		
// 	Test1 ob1 = new Test1();	
	Test2 ob2 = new Test2();
	ob2.function1();	// 상속을 통해 간접적으로 객체를 생성함
	ob2.function2();	
	
	}
}

- 추상 클래스생성자직접 호출할 수 없음 (Cannot instantiate the type Test1)

객체화불가능

→ 직접적인 객체 생성은 불가능하지만, 상속을 통한 간접적인 객체 생성은 가능

 

2) 추상화

- 실제 객체의 몇몇 특성추출하여 프로그램 내에 반영

- 필드속성을 작성하고, 메서드기능을 표현하는데, 메서드구체적인 내용담기지 않을 수도 있음      

- 추상 메서드 : 형식정의되어 있으나, 내용정의되지 않은 메서드

- 추상 클래스 : 추상 메서드포함할 수 있는 클래스 (일반 메서드 포함 가능함)

 

3) abstract

클래스 앞에 붙이면 추상 클래스

메서드 앞에 붙이면 추상 메서드

- abstract 메서드는 상속을 받아서 써야하기 때문에, private으로 지정할 수 없음

protected 혹은 public으로 설정해야 함

 

* protected : 패키지가 달라도 상속관계에 있으면 접근 가능

* public : 패키지나 상속여부에 상관없이 누구나 접근 가능

 

~ 예시) Button 클래스 만들기

abstract class Button {	
	protected abstract void onclick();
	public void click() {
		this.onclick();	// 어떻게 실행되는지만 적어놓음
	}
}

 - 클릭 했을 때에 어떤 내용을 실행할 지는 정해지지 않음

→ 서브 클래스에서 상속받아서 내용을 정할 것임

 

~ 실행 시 메모장을 켰다가 2초 후 끄도록 하는 버튼 만들기

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) {}
	}
}

~ 실행 시 계산기를 켜도록 하는 버튼 만들기

class CalcButton extends Button {
	@Override
	protected void onclick() {
	try {
		Runtime rt = Runtime.getRuntime(); // 운영체제 런타임을 객체로 받아옴
		String cmd = "calc";		// 실행할 명령어
		rt.exec(cmd);			// 명령어를 실행
						
		} catch(Exception e) {}
	}
}

 ~ 버튼을 실행할 메인함수

public static void main(String[] args) {
//	Button btn1 = new Button();
		
	MessageButton btn2 = new MessageButton();
	btn2.click();
		
	NotepadButton btn3 = new NotepadButton();
	btn3.click();
		
	Button btn4 = new CalcButton(); // 서브클래스의 객체를 슈퍼클래스로 참조함
	btn4.click();

- 상속없이는 객체 생성 불가능

- 추상클래스가 직접 객체를 생성할 수는 없지만, 자료형으로써 참조변수사용하는 것가능.

Button btn5 = new Button() {
	private String cmd = "C:\\ProgramFiles\\Google\\Chrome\\Application\\chrome.exe";
	private String url = " https://search.naver.com/search.naver?query=아이유";
			
	@Override	
	protected void onclick() {
		try {
			Runtime rt = Runtime.getRuntime();		
			cmd += url;
			rt.exec(cmd);
		}catch(Exception e) {}
	}
};
	btn5.click();
	}
}

- 오버라이딩이 되었기 때문에, Button 그 자체는 아님

익명 내부 클래스 : 즉석에서 이름없이 만들어진 클래스

 

* 지역 변수에는 접근제한자붙일 수 없음

 

2. interface

1) 특징   

interface 추상클래스의 일종임

interface 의 모든 필드 public static final

interface 의 모든 메서드 public abstract

interface extends가 아니라, implements 키워드로 상속처리

  인터페이스구현한다라고 표현함

interface는 자바에서 유일하게 다중 상속허용하는 형식임

 

2) 인터페이스의 필드

interface Test3 {
	int n1 = 10;	
	public static final int n2 = 20;
}

① 인터페이스의 필드는 고정된 형식이 있기 때문에, 필드를 쓰기 힘듦.

② 형식 : public static final

필드초기값을 반드시 지정해야함

④ 따로 형식을 작성하지 않더라도, 자동으로 형식이 지정되어 있음

static 이므로 어떤 객체에서 접근해도 동일한 값

final 이므로 한번 지정된 값변경할 수 없으며, 반드시 초기값지정해야만 함

 

3) 인터페이스의 메서드

interface Test3 {
	void method1();
//	void method2() {
//
//	}
	static void method2() {		
	System.out.println("static은 객체 생성 여부와 상관없이 호출 가능");
	}
}

public abstract이므로 body작성할 수 없음

static은 객체가 생성이 되지 않아도 실행할 수 있기 때문에 body 작성 가능

 static은 객체 생성 여부에 상관없이 호출할 수 있으니 상관없음

 

~ 인터페이스 Test3의 추상메서드를 구현한 메서드1

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

- 인터페이스는 추상클래스이므로,  생성자를 통한 객체 직접 생성이 불가능.

public static void main(String[] args) {
//	Test3 ob = new Test3();	
	Test4 ob1 = new Test4();
	ob1.method1();

- 인터페이스는 추상클래스이므로, 익명 내부 클래스활용하여 객체생성할 수 있음

Test3 ob2 = new Test3() {
			
	@Override
	public void method1() {
		System.out.println("익명 내부 클래스");
	}
};
		
	ob2.method1();
   	}
}

- 인터페이스는 추상클래스, 추상클래스는 클래스

클래스자료형이므로, 인터페이스자료형처럼 쓸 수 있음

 

4) USB 인터페이스 만들기

interface USB {		
	void action();	// 추상메서드
}

~ 충전을 위해 전력을 전송하는 기능 구현

슈퍼클래스가 지정되어 있어도 상관없음 (다중상속 가능)

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 {
	void connect(USB device) {
		device.action();
	}
}

→ 컴퓨터에 외부 장치를 연결하기 위해서는 USB 인터페이스 규격을 만족하면 됨

→ 자료형이 USB이면 가능함 (다형성)

 

~ 메인 함수

public static void main(String[] args) {
	
	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);	// 스피커 연결 시의 반응이 정상적으로 호출됨

 

5) 함수형 인터페이스

① 자바 8 이후 함수형 인터페이스 형식이 추가되었음

② 함수형 인터페이스란, 단 하나의 추상메서드만 가지는 인터페이스를 말함

③ 함수형 인터페이스는 람다식에 의해 객체생성할 수 있음

익명 클래스에 의한 객체 생성보다 간편하고, 내부 작동다름

미구현된 함수내용만 적어주면 객체생성할 수 있음

USB mouse = () -> System.out.println("마우스 연결됨...");
pc.connect(mouse);

 

 

6) 람다식

- 구조

 

① 실행할 함수의 내용한줄이면 { } 생략가능

② 함수의 매개변수하나이면 ( ) 생략가능

③ 함수의 반환형 void가 아니고, 한줄만에 값을 반환한다면 return 생략 가능

 

~ 예시) 

Interface ob1 = (a) -> -a;
Interface ob2 = a -> a > 0 ? a : -a;
// 위의 식을 생략하지 않고 적으면 이렇게 됨
Interface ob3 = (a) -> { return a > 0 ? a : -a; };

- 특정 함수를 객체화하기 위해서 인터페이스를 쓰기도 함

함수형 인터페이스

 

 

3. 인터페이스 활용 연습

1) 상속 없는 클래스의 객체 생성

- Cat Dog는 개별 클래스로 작성할 것.

 

~ 메인 함수

public static void main(String[] args) {
	Human h1 = new Human("황정민");
	Cat c1 = new Cat("구름이");
	Dog d1 = new Dog("감자");
	
	h1.give(c1);	// 황정민이 구름이에게 먹이를 준다.
	h1.give(d1);	// 황정민이 감자에게 먹이를 준다.

~ 클래스 Human

public class Human {

	String name;

	public Human(String name) {
		this.name = name;
	}

	public void give(Cat ob) {
		System.out.printf("%s이 %s에게 먹이를 준다.\n", this.name, ob.name);
	}

	public void give(Dog ob) {
		System.out.printf("%s이 %s에게 먹이를 준다.\n", this.name, ob.name);
	}
}

 

~ 클래스 Cat

public class Cat {  

	String name;

	Cat(String name) {
		this.name = name;
	}
}

~ 클래스 Dog

public class Dog {  

	String name;

	Dog(String name) {
		this.name = name;
	}
}

~ 결과

 

 2) 공통 특성을 가지는 Cat Dog를 슈퍼클래스 Animal을 상속받도록 처리해보기.

- 공통의 작업은 하나의 생성자에서 처리하게 만들 것.

- 이때, Human Cat Dog를 하나의 클래스 타입으로 처리할 수 있도록 변경할 것.

 

~ 메인 함수

public static void main(String[] args) {
	Human h1 = new Human("황정민");
	Cat c1 = new Cat("구름이");
	Dog d1 = new Dog("감자");
	
	h1.give(c1);	// 황정민이 구름이에게 먹이를 준다.
	h1.give(d1);	// 황정민이 감자에게 먹이를 준다.

~ 클래스 Animal

public class Animal {

	String name;
	
	Animal(String name) {
		this.name = name;
	}
}

~ Animal을 상속받는 클래스 Cat

public class Cat extends Animal {
	Cat(String name) {
	    super(name);
	}	
}

 ~ Animal을 상속받는 클래스 Dog

public class Dog extends Animal {
	Dog(String name) {
	    super(name);
	}	
}

~ 클래스 Human

public class Human {

	String name;

	public Human(String name) {
		this.name = name;
	}

	public void give(Animal ob) {
		System.out.printf("%s이 %s에게 먹이를 준다.\n", this.name, ob.name);
	}
}

~ 결과

 

3) 슈퍼클래스 Animal을 추상클래스로 만들기

-  Animal의 서브클래스들은 타입에 맞는 먹이 종류를 지정하여 반환하는 함수 getFeed()를 가져야 함.

 

~ 메인 함수

public static void main(String[] args) {
	Human h1 = new Human("황정민");
	Cat c1 = new Cat("구름이");
	Dog d1 = new Dog("감자");
	
	h1.give(c1);	// 황정민이 구름이에게 츄르를 준다.
	h1.give(d1);	// 황정민이 감자에게 개껌을 준다.

~ 추상클래스 Animal

public abstract class Animal {

	public String name;
	
	public Animal(String name) {
		this.name = name;
	}
	
	public abstract String getFeed();
}

~ Animal 클래스를 상속받는 클래스 Cat

public class Cat extends Animal {
	Cat(String name) {
	    super(name);
	}

	@Override
	public String getFeed() {
		return "츄르를";
	}	
}

~ Animal 클래스를 상속받는 클래스 Dog

public class Dog extends Animal {
	Dog(String name) {
	    super(name);
	}

	@Override
	public String getFeed() {
		return "개껌을";
	}	
}

~ Human 클래스

public class Human {

	String name;

	public Human(String name) {
		this.name = name;
	}

	public void give(Animal ob) {
		
		String form = "%s이 %s에게 %s 준다.\n";
		String feed = ob.getFeed();
		System.out.printf(form, this.name, ob.name, feed);
		}
}

~ 결과)

 

4) Human의 서브클래스 Friend를 작성해보기.

- Cat Dog Friend는 서로 다른 슈퍼클래스를 가짐.

- Cat Dog Friend를 하나의 인터페이스로 묶어주고 필요한 작업을 처리할 것.

~ 메인 함수

public static void main(String[] args) {
	Human h1 = new Human("황정민");
		
	// Cat과 Dog는 개별 클래스로 작성하세요.
	Cat c1 = new Cat("구름이");
	Dog d1 = new Dog("감자");
	Friend f1 = new Friend("하정우");
		
	h1.give(c1);	// 황정민이 구름이에게 츄르를 준다.
	h1.give(d1);	// 황정민이 감자에게 개껌을 준다.
	h1.give(f1);	// 황정민이 하정우에게 주먹밥을 준다.

~ 인터페이스 Companion 만들기

public interface Companion {
	
	String getName();

	String getFeed();
}

~ Animal 클래스

public abstract class Animal {

	public String name;
	
	public Animal(String name) {
		this.name = name;
	}
	
	public String getName() {
		String name = this.name;
		return name;
	}
}

~ Animal 클래스와 Companion 인터페이스를 상속받는 Cat 클래스

public class Cat extends Animal implements Companion{

	public Cat(String name) {
		super(name);
	}
    
	@Override
	public String getFeed() {
		return "츄르를";
	}
}

~ Animal 클래스와 Companion 인터페이스를 상속받는 Dog 클래스

public class Dog extends Animal implements Companion{

	public Dog(String name) {
		super(name);
	}
    
	@Override
	public String getFeed() {
		return "개껌을";
	}
}

~ Human 클래스

public class Human {
	String name;
	public Human(String name) {
		this.name = name;
	}

	public String getName() {
		String name = this.name;
		return name;
	}

	public void give(Companion c) {
		String form = "%s이 %s에게 %s 준다.\n";
		String feed = c.getFeed();
		System.out.printf(form, this.name, c.getName(), feed);
	}
}

~ Human 클래스와 Companion 인터페이스를 상속받는 Friend 클래스

public class Friend extends Human implements Companion{
	
	public Friend(String name) {
		super(name);
	}
	public String getFeed() {
		return "주먹밥을";
	}
}

~ 결과

 

 

 5) give의 매개변수에 들어오는 객체의 차이에 따라 주는 '방식' 을 구별하여 출력하기

~ 메인 함수

public static void main(String[] args) {
	Human h1 = new Human("황정민");
		
	// Cat과 Dog는 개별 클래스로 작성하세요.
	Cat c1 = new Cat("구름이");
	Dog d1 = new Dog("감자");
	Friend f1 = new Friend("하정우");
		
	h1.give(c1);	// 황정민이 구름이에게 츄르를 던져 준다.
	h1.give(d1);	// 황정민이 감자에게 개껌을 던져 준다.
	h1.give(f1);	// 황정민이 하정우에게 주먹밥을 건네 준다.

~ Human 클래스의 give 메서드

public void give(Companion c) {
	String how = "";
		
	if(ob instanceof Animal) how = "던져";	
	if(ob instanceof Human) how = "건네";	
		
	String form = "%s이 %s에게 %s %s 준다.\n";
	String feed = ob.getFeed();
	System.out.printf(form, this.name, ob.getName(), feed, how);
}

→ 슈퍼 클래스 타입으로 묶어서 받아도, 필요하면 구별할 수 있음

 

~ 결과

'JAVA > JAVA Note' 카테고리의 다른 글

[JAVA Note] 18. Object  (0) 2022.11.06
[JAVA Note] 17. 추상화  (0) 2022.11.06
[JAVA Note] 15. 상속  (0) 2022.11.02
[JAVA Note] 14. 접근 제한자  (0) 2022.10.30
[JAVA Note] 13. DTO  (0) 2022.10.27

댓글