추상클래스(abstructClass)

김용민·2023년 3월 28일
0

ヾ(•ω•`)o 추상클래스란?

상위 클래스로서 상속을 주기 위한 클래스로, 스스로 객체로 선언해서 인스턴스화 할 수 없고
하위 클래스에서 그 추상 클래스를 상속을 받아 그 안의 메서드나 필드를 사용하게끔 하는 클래스이다
어느정도의 틀을 제공하며 조금더 나아가서는 인터페이스의 내용과 연결되는 내용이다

특징

  • 상속시에 오버라이딩을 강제하기 위한 클래스이고 그래서 객체를 생성할 수 없다!
	abstract class Test1 {
	int num1 = 10;
	int num2 = 20;
	
	public void method1() {
		System.out.println("method1");
	}
}

	public class Ex01 {
	public static void main(String[] args) {
		// Cannot instantiate the type Test1
        // 추상 메서드는 객체를 만들 수 없다!!
		// Test1 t1 = new Test1();
	}
}
  • 추상 클래스는 추상 메서드를 포함 할 수 있다!
    (추상 메서드 : 추상 클래스내에 함수 내용을 가지지 않는 메서드
    -> 상속을 받는다면 오버라이딩 해서 쓸 수 있게끔 만드는 메서드)
abstract class Test1 {
	int num1 = 10;
	int num2 = 20;
	
	public void method1() {
		System.out.println("method1");
	}
	public abstract void method2();// {
		// 추상 메서드는 함수 내용을 가질 수 없다
	//}
}
  • 추상클래스를 상속받은 하위클래스는 클래스 내의 추상 메서드를 구현해야만 한다
    (ex. 추상 클래스의 Test1의 상속을 받은 Test2)
class Test2 extends Test1{
	// The type Test2 must implement the inherited abstract method Test1.method2()
	// Test2는 상속받은 추상 메서드 Test1.method2()를 구현해야만 합니다!
}

그래서, 두가지의 방법이 있는데
1. 추상 메서드는 추상 클래스가 가질 수 있으므로 Test2를 추상 클래스화를 하거나

abstract class Test2 extends Test1{
	
}
  1. 추상메서드를 상속 받았으니까, 오버라이딩해서 내용을 구체적으로 작성하는 방법
class Test2 extends Test1{

	@Override
	public void method2() {
		// TODO Auto-generated method stub
		
	}
}

또 다른 특징으로는

  • 하나의 추상클래스 A를 상속받은 서로 다른 클래스 B,C는 같은 형식의 메서드를 가지고 있지만
    내용은 전혀 다를 수 있다. 오버라이딩 이므로 B,C가 각각 A를 업캐스팅해도 각각의 오버라이딩 된 메서드가 실행된다
abstract class A{
	abstract void method5();
}

class B extends A {
	
	@Override
	void method5() {
		System.out.println("나는 메서드 B");
	}
}

class C extends A {
	
	@Override
	void method5() {
		System.out.println("나는 메서드 C");
	}
}

public class Practice2 {
	public static void main(String[] args) {
		A ob1 = new B();
		A ob2 = new C();
		
		ob1.method5();
		ob2.method5();
	}
}

ヾ(•ω•`)o 인터페이스

추상클래스의 한 종류이다

  • 일반적인 추상 클래스와는 달리, 일반 메서드를 포함할 수 없다
  • 인터페이스의 모든 필드는 public static final 속성을 포함한다
  • 인터페이스의 모든 메서드는 public abstract 속성을 포함한다
  • 인터페이스는 extends 대신 implements 로 상속처리한다
  • 인터페이스는 다중상속을 허용한다
interface Test3 {
	// 인터페이스의 모든 필드는 public static final 속성
	public static final int NUM1 = 10;
	
    // 인터페이스의 모든 메서드는 public abstract
	public abstract void method3();
}

// 인터페이스는 extends 대신 implements로 상속처리한다
class Test4 implements Test3 {

	@Override
	public void method3() {
		System.out.println("method3");
	}
}

public class Ex02 {
	public static void main(String[] args) {
		Test4 ob = new Test4();
		ob.method3();
 	}  
}

ヾ(•ω•`)o 익명 클래스

추상클래스를 객체로 생성하려면 추상메서드의 미구현 내용을 구현해야한다

매번 클래스를 만들어서 미구현 내용을 처리하고자 하면 가독성이 떨어지므로

이름없는 클래스를 즉석에서 만들어서 객체를 생성한다

이런 형식을 익명 내부 클래스(Anonymous Inner Class/ Type) 이라고 한다

자 그럼, 직접 익명 클래스를 만들면서 알아보자

1) 추상 클래스를 상속받아서 추상 메서드를 오버라이딩 하는 새로운 클래스를 작성한다

package abstractClass;

class Button {
	String text;
	OnClickListner listener;
	
	public Button(String text) {
		this.text = text;
	}
	void click() {				// 클릭하면
		if(listener != null) {	// 클릭했을 때 동작이 지정되어 있다면
			listener.onClick();	// 지정된 내용을 수행한다
		}
		else {
			System.err.printf("%s : 클릭에 연결된 동작(기능, 함수)이 없습니다\n", text);
		}
	}
	void setOnClickListener(OnClickListner listener) {
		this.listener = listener;
	}
	public String toString() {
		return String.format("[%s]", text);
	}
}

abstract class OnClickListner {
	abstract void onClick();
}

// 1) 추상 클래스를 상속받아서 추상 메서드를 오버라이딩 하는 새로운 클래스를 작성한다
class HelloWorld extends OnClickListner {

	@Override
	void onClick() {
		System.out.println("Hello, world !!");
	}
}

public class Ex03 {
	public static void main(String[] args) {
		
		Button btn1 = new Button("Hello");
		
		// 2) 1번에서 만든 클래스를 활용하여 객체를 생성한다
		HelloWorld listener1 = new HelloWorld();
		
		// 3) 2번에서 생성한 객체를 버튼에 전달한다 (1번만 쓰고 더이상 사용되지 않는 클래스)
		btn1.setOnClickListener(listener1);
		
		System.out.println(btn1);
		btn1.click();
		
		Button btn2 = new Button("그냥 버튼");
		btn2.click();
		
		// Hello, World 가 아닌 다른 텍스트를 출력하거나, 다른 기능을 구현하려면
		// 매번 새로운 클래스를 작성하여, OnClickListner를 상속받고, 메서드를 오버라이딩 한 이후
		// 객체를 생성하여 버튼에 연결시켜주어야 한다
		
		Button btn3 = new Button("JAVA");

		// 객체를 생성하면서, 즉석에서 함수 내용만 지정하면 미구현 내용이 사라지므로, 객체를 생성할 수 있다
		OnClickListner listener3 = new OnClickListner() {
			@Override
			void onClick() {
				System.out.println("자바는 수다스럽다");
			}
		};
		btn3.setOnClickListener(listener3);
		btn3.click();
		
		
		Button btn4 = new Button("Python");
		btn4.setOnClickListener(new OnClickListner() {
			@Override
			void onClick() {
				System.out.println("Life is too short, you need python");
			}
		});
		btn4.click();
		
//		함수의 객체화
		
//		자바의 기본단위는 클래스이다. 그래서 자바에서 함수는 변수에 저장할 수 없다
//		(자바에서 함수는 일급객체가 아니다)
//		함수를 전달하려면, 함수를 포함하는 객체를 생성해서 전달해야만 한다
//		함수의 내용을 자유롭게 작성하려면, 추상 메서드로 형식을 지정해두어야 한다
//		추상메서드로 형식이 지정된 함수를 오버라이딩하여 내용을 작성하고, 그 함수를 포함하는 객체를 전달한다
		
	}
}

ヾ(•ω•`)o 인터페이스 실습!

class PC {
	// PC는 USB타입의 장치를 연결할 수 있다
	void connect(USB device) {
		device.onConnect();	// 연결된 장치마다, 연결되었을 때 수행하는 동작이 있다
	}
	// 만약 인터페이스를 사용하지 않았다면... 연결하고 싶은 장치의 개수만큼 함수 오버로딩을 수행해야 한다
	// void connect(Keyboard device) { ... }
	// void connect(DataCable device) { ... }
	// void connect(ElectricFan device) { ... }

}
interface USB {
	/*public abstract*/ void onConnect();
}
class Keyboard implements USB {
	@Override
	public void onConnect() {
		System.out.println("키보드가 연결되었습니다");
	}
}
class DataCable implements USB {
	@Override
	public void onConnect() {
		System.out.println("데이터를 전송할 준비가 되었습니다");
	}
}
class ElectricFan implements USB {
	@Override
	public void onConnect() {
		System.out.println("선풍기 충전중...27%");
	}
}

public class Ex04 {
	public static void main(String[] args) {
		PC pc = new PC();
		
		Keyboard d1 = new Keyboard();
		DataCable d2 = new DataCable();
		ElectricFan d3 = new ElectricFan();
		
		USB[] arr = { d1, d2, d3 };	// 다형성
		
		for(int i = 0; i < arr.length; i++) {
			pc.connect(arr[i]);
		}
		// 서로 다른 타입의 객체를 하나의 타입으로 묶어 줄 수 있다
		// USB 타입이 되기 위해서는 반드시 추상메서드를 오버라이딩 해야 한다
		// USB타입이면 onConnect() 함수가 있어서, PC에 connect했을때 저마다의 동작이 수행된다
		
		
		// 인터페이스가 가지는 추상메서드가 하나만 있다면, 함수형 인터페이스로 분류한다
		// 함수형 인터페이스는 람다식으로 객체를 생성할 수 있다
		// 내부 구조는 익명 클래스와 다르다 (사용은 비슷하게 할 수 있다)
		
		USB mouse = () -> System.out.println("마우스 연결됨...");
		pc.connect(mouse);
		
		// 람다식 기본 : () -> {}
		// () 에는 함수의 매개변수를 넣어준다
		// -> 는 고정으로 사용한다
		// {} 에는 함수의 내용을 작성한다
		// 함수가 하나밖에 없으니, 함수의 이름을 지정할 필요가 없다
		
		// 만약, 매개변수가 하나라면 ()를 생략할 수 있다
		// 만약, 함수의 실행 내용이 한줄이라면 {}를 생략할 수 있다
		// 만약, 함수가 특정 타입을 반환하고, 실행내용이 한줄이라면 return을 생략할 수 있다
		
		// 인터페이스도 넓은 범주에서 보면 추상 클래스이므로, 익명클래스 문법을 사용할 수 있다
		USB mic = new USB() {
			@Override
			public void onConnect() {
				System.out.println("마이크 연결됨...");
			}
		};
		pc.connect(mic);
	}
}
profile
안녕하세요

0개의 댓글