
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();
}
- Test1의 function2()는 미구현된 메서드이므로, 서브클래스인 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 |
댓글