본문 바로가기
Backend

06월 05일 수 | OOP 15 - JAVA의 Abstract클래스와 Interface

by 구라미 2019. 6. 5.

10. 객체지향 프로그래밍 Ⅱ

Abstract클래스 (추상클래스)

추상클래스는 객체를 생성할 수 없다.

-> new연산자를 사용할 수 없다.

추상클래스 = 일반메소드 + 추상메소드

클래스 추상메소드가 하나라도 있으면 추상클래스이다.

하나 이상의 추상메소드를 포함하는 클래스를 추상클래스라고 한다.

이러한 추상클래스는 객체지향프로그래밍에서 중요한 특징인

다형성을 가지는 메소드의 집합을 정의할 수 있도록 해준다.

 

인터페이스는 오직 추상메소드만 있는 것이다. 인터페이스에서 많이 사용

인터페이스는 추상메소드만 선언가능하다.

 

추상메소드

메소드의 구현부 body{}가 없음. 메소드의 머릿말만 존재한다.

형식: 리턴형 메소드명();

 

abstract class Animal { //추상클래스
	
	String name;
	void view(){}//일반메소드
	abstract void disp(); //추상메소드
	
}//class end

 

위와 같이 선언부만 있고 구현하는 부분이 없는 것이 추상메소드다.

선언만 되어있고 기능이 없는

Animal클래스가 추상메소드를 포함하고 있으므로 Animal클래스는 추상클래스이다.

 

추상클래스는 new 연산자로 객체생성이 불가하다.

추상메소드는 자식클래스에서 반드시 오버라이딩해야만 사용할 수 있는 메소드이다.

추상메소드를 선언하여 사용하는 목적은

추상메소드가 포함된 클래스를 상속받는 자식클래스가 반드시 추상메소드를 구현하도록 하기 위해서 이다.

 

추상클래스 예제 1) 

package oop0605;

abstract class Animal { //추상클래스
	
	String name;
	void view(){}//일반메소드
	abstract void disp(); //추상메소드
	
}//class end
//추상클래스 : 누군가의 부모역할만 한다. (extends만)
//추상클래스를 상속받은 자식클래스는 반드시 추상메소드를 완성해야 한다.

class Elephant extends Animal {
	@Override
	void disp() {
		System.out.println("점보...");
	}
}

class Tuna extends Animal {

	@Override
	void disp() {
		System.out.println("니모...");
	}	
}



public class Test01_Abstract {

	public static void main(String[] args) {
		// 추상클래스 abstract class
		
		Elephant jumbo = new Elephant();
		jumbo.disp();
		
		Tuna nemo = new Tuna();
		nemo.disp();
		
//----------------------------------------------------------------------------------------
		
		//추상클래스의 다형성
		Animal ani = new Elephant(); //자식에 들어갈 때 부모는 자식의 모양대로 변경.
		ani.disp();
		

	}//main end
}//class end

추상클래스의 다형성 중요

▶ 풀이

1. Animal이라는 추상클래스를 만들고 

멤버변수 name

void view()라는 리턴형이 없는 일반메소드

abstract void disp 리턴형이 없는 추상메소드를 선언하였다.

2. Animal클래스에서 상속받은 Elephant클래스가 내부에서 disp추상메소드를 오버라이드(재정의)하였다.

3. Animal클래스에서 상속받은 Tuna클래스가 내부에서 disp추상메소드를 오버라이드(재정의)하였다.

4. main메소드에서 Elephant클래스와 Tuna 객체를 new연산자로 생성하고 disp를 호출하였다.

5. Animal클래스도 Elephant객체로 만들어서 다형성을 줄 수 있다.

 

shift + alt + s + v  -> 오버라이드 단축키

 

추상클래스 예제 2) 

package oop0605;

abstract class Travel {
	void view(){} //일반메소드
	abstract String travelWhere(); //추상메소드
}//class end

class TypeA extends Travel {

	@Override
	String travelWhere() {
		// TODO Auto-generated method stub
		return "제주도 올레길";
	}
	
}//class end
class TypeB extends Travel {

	@Override
	String travelWhere() {
		return "여의도 불꽃축제";
	}
	
}//class end
class TypeC extends Travel {

	@Override
	String travelWhere() {
		return "지리산 둘레길";
	}
	
	
}//class end


public class Test02_Abstract {

	public static void main(String[] args) {
		//추상클래스
		
		//추상클래스는 자신의 클래스 이름으로 객체생성불가.
		//Travel tour = new Travel(); //에러
		Travel tour = new TypeA(); //정상작동.
		System.out.println(tour.travelWhere());
		
		tour = new TypeB();
		System.out.println(tour.travelWhere());
		
		tour = new TypeC();
		System.out.println(tour.travelWhere());
		

	}//main end
}//class end

추상클래스는 오버라이딩 해서 사용한다. 

▶ 풀이

1. 추상클래스 Travel에 일반메소드 view()와 문자열을 리턴하는 추상메소드 travelWhere을 선언하였다.

2. Travel으로 부터 상속받는 TypeA,B,C 클래스를 생성하고 추상메소드 travelWhere을 오버라이드(재정의)하였다.

3. main메소드에서 추상클래스 Travel을 자식클래스 TypeA를 통해 tour라는 이름의 TypeA객체를 생성하였다.

4. tour를 new 연산자로 TypeB, TypeC로도 객체생성할 수 있다.

 

Interface

인터페이스는 추상메소드로만 구성되어있다.

추상클래스보다 더 추상화 되어있다.

일반메소드를 사용할 수 없다.

 

package oop0605;

interface Parent {
	
	//어차피 인터페이스 내 메소드는 다 추상메소드이므로
	//abstract라는 말 생략 가능하다.
	abstract void kind();
	void breathe();
}

public class Test03_Interface {
	public static void main(String[] args) {
		//인터페이스 interface
		//추상메소드로만 구성되어 있다.
		//추상클래스보다 더 추상화 되어있다.
		
	}//main end
}//class end

 

클래스 입장에서 부모가 클래스: extends 확장
// 부모가 인터페이스: implements 구현

인터페이스 자신으로 직접 객체생성은 불가하다.

implements한 자식이 오버라이드가 되지 않으면 에러가 뜬다.

 

인터페이스 다형성!

- 다형성: 자식이 부모에 들어갈 수 있음.

- 같은 자료형에 여러가지 객체를 대입하여 다양한 결과를 얻어내는 성질

 

다형성의 효과는 하나의 타입으로 다양한 실행결과를 얻을 수 있어 객체를 부품화해 유지보수 용이하게 한다.

 

인터페이스를 활용해서
개발프로젝트에서 발생하는 여러 페이지들을 표준화, 구조화 할 수도 있다.

인터페이스는 메뉴판을 보는 개념.

 

인터페이스 예제 1)

package oop0605;

interface Parent {
	
	//어차피 인터페이스 내 메소드는 다 추상메소드이므로
	//abstract라는 말 생략 가능하다.
	abstract void kind();
	void breathe();
}//interface end

class Son implements Parent { //구현, 클래스입장에서 부모가 인터페이스

	@Override
	public void kind() {
		System.out.println("아들");
	}

	@Override
	public void breathe() {
		System.out.println("허파숨쉬기");
	}
	
}//class end


class Daughter implements Parent { //구현, 

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

	@Override
	public void breathe() {
		System.out.println("허파숨쉬기");		
	}
	
	
	
}//class end


public class Test03_Interface {
	public static void main(String[] args) {
		//인터페이스 interface
		//추상메소드로만 구성되어 있다.
		//추상클래스보다 더 추상화 되어있다.
		//클래스 입장에서 부모가 클래스: extends 확장
		//				  부모가 인터페이스: implements 구현
		
		
		
		//인터페이스 자신으로 직접 객체생성불가
		//Parent pa = new Parent();
		
		Son son = new Son();
		son.kind();
		son.breathe();
		
		Daughter daut = new Daughter();
		daut.kind();
		daut.breathe();
		
		//-----------------------------------------------------------------
		
		//인터페이스에서의 다형성.
		Parent parent = new Son();
		parent.kind();
		parent.breathe();
		
		parent = new Daughter();
		parent.kind();
		parent.breathe();
		
		
	}//main end
}//class end

▶ 풀이

1. interface 클래스 Parent를 선언하고 추상메소드 kind와 breathe를 선언하였다.

2. Son클래스는 implemets키워드로 추상클래스Parent로부터 상속받는 클래스이다.

3. Son클래스 안에 추상메소드 kind와 breathe를 오버라이드 하였다.

4. Daughter클래스도 Son클래스와 마찬가지로 상속받고 오버라이드 하였다.

5. main 메소드 안에 new연산자로 son이라는 Son객체를 생성하고,

   Son객체 son의 kind메소드와 breath메소드를 호출한다.

6. Daughter클래스도 같은 방식으로 진행한다.

7. 다형성을 드러내는 부분이다. Parent클래스 parent를 new연산자로 Son객체로 생성한다.

8. Daughter객체로도 테스트.

 

결과값:

아들
허파숨쉬기

허파숨쉬기
아들
허파숨쉬기

허파숨쉬기

 

 

인터페이스 예제 2)

package oop0605;

interface ICalc { //산술연산 + - * / %
	
	public int add();
	public int sub();
	public int mul();
	public int div();
	public int mod();
	
}//interface end

class CalcImp implements ICalc { //구현
	
	private int x, y;
	
	public CalcImp(){}
	public CalcImp(int x, int y){
		this.x = x;
		this.y = y;
	}
		
	@Override
	public int add() {
		return x+y;
	}

	@Override
	public int sub() {
		return x-y;
	}

	@Override
	public int mul() {
		return x*y;
	}

	@Override
	public int div() {
		return x/y;
	}

	@Override
	public int mod() {
		return x%y;
	}

}


public class Test04_Interface {
	public static void main(String[] args) {
		//인터페이스를 활용해서
		//개발프로젝트에서 발생하는 여러 페이지들을 표준화, 구조화 할 수도 있다.
		
		//다형성
		ICalc calc = new CalcImp(5,3);
		System.out.println(calc.add());
		System.out.println(calc.sub());
		System.out.println(calc.mul());
		System.out.println(calc.div());
		System.out.println(calc.mod());		
		

	}//main end
}//class end

▶ 풀이

1. ICalc라는 interface클래스를 선언하고 안에

   정수를 리턴하는 public 추상메소드를 add,sub,mul,div,mod라는 이름으로 선언

2. ICalc를 상속받는 CalcImp클래스를 선언하고 public 추상메소드를 add,sub,mul,div,mod를 오버라이드 한다.

3. 정수 x, y는 private 접근제한자로 선언, public CalcImp(){} 생성자메소드를 만들어 초기화하고

4. 매개변수 int x, int y를 받는 public Calclmp메소드를 (오버로딩) 만들어 this.x = x, this.y = y 해줌

   *this - 자기자신을 직접 참고할 수 있는 참조변수이다.

5. public 추상메소드를 add,sub,mul,div,mod를 x와 y의 산술연산한 것을 리턴하는 메소드로 오버라이드한다.

6. main 메소드에서 ICalc클래스 calc를 CalcImp객체로 생성하고 5와 3을 인자로 넣어준다.

7. calc로 메소드를 호출할 때 x에는 5, y에는 3이 들어가서 연산하는 메소드가 출력된다.

 

결과값:

8
2
15
1
2

 

인터페이스 예제 3)

인터페이스간 상속은 extends를 이용한다.

인터페이스는 다중상속이 가능하다.

클래스가 인터페이스를 끌어올 때는 implements

인터페이스가 인터페이스를 extends

package oop0605;


class Unit {
	int currentHP; //유닛의 체력
	int x, y; //유닛의 x,y 좌표위치
	
}//class end

interface Movable {
	void move (int x, int y);
}//interface end

interface Attackable {
	void attack (Unit u);
}//interface end

interface Fightable extends Movable, Attackable { 
	//인터페이스간에도 상속 가능. //인터페이스가 인터페이스를 상속받을 때는 extends
}


public class Test05_Interface {

	public static void main(String[] args) {
		//클래스와 인터페이스간의 상속 및 구현
		

	}//main end
}//class end

▶ 풀이

1. 인터페이스간의 상속이 가능하다.

2. 인터페이스가 인터페이스를 상속받을 때 extends키워드를 사용하고 다중상속이 가능하다.

 

클래스와 인터페이스

새로 클래스를 만들 때도 이런 차이가 있다.

인터페이스는 여러개를 가져올 수 있기 때문에 영역이 넓다.

 

 

Format 클래스

 

 

Anonymous클래스 (익명클래스)

익명클래스는 클래스지만 이름이 없는 클래스이다. 

익명내부클래스이다. 메모리라는 것은 정적이다. 

스마트폰 터치할 때만 반응이 오는 것처럼

필요한 곳에서 일시적으로 실행되는 것이다.

이벤트가 발생할 때만 실행

안드로이드 자바, JavaScript, JQuery에서 많이 활용.

click, drag, scroll, hover 등의 개념인 거 같음.

 

익명클래스 예제 1)

package oop0605;

interface IMessage {
	public void msgPrint();
	
}//interface end

class Message implements IMessage {

	@Override
	public void msgPrint() {
		System.out.println("Message 클래스");
	}
	
}


public class Test06_Anonymous {

	public static void main(String[] args) {
		
		//에러. 인터페이스는 객체 생성할 수 없다.
		//IMessage mgs = new IMessage();
		
		//1) 구현클래스
		Message msg = new Message();
		msg.msgPrint();
		
		//2) 다형성
		IMessage imsg = new Message();
		imsg.msgPrint();
		
		//3) 익명클래스 - 브라켓없으면 에러, 오버라이드 안하면 에러 
		IMessage mess = new IMessage(){ //new 객체

			@Override
			public void msgPrint() {
				System.out.println("Anonymous");
			}
			
		}; //추상메소드 때문에
		
	}//main end
}//class end

▶ 풀이

1. 인터페이스는 추상클래스기 때문에 객체생성할 수 없다.

2. 그러나 익명클래스 형태로 만들면 생성할 수 있다.

3. 인터페이스 IMessage를 new연산자로 IMessage객체를 만드려면 오버라이드를 반드시 해주어야한다.

4. msgPrint()메소드를 오버라이드 해주었다.

 

 

내부클래스

내부클래스는 클래스 안의 클래스이다.

자주 쓰이지는 않지만 안드로이드 자바 코딩시 알아두어야할 개념. (R클래스)

클래스내부에서 선언된 클래스다.

내부에서 사용하려고 만든 클래스기 때문에 외부에서도 사용할 순 있지만..권장은 안하는

package oop0605;

import javax.security.auth.callback.LanguageCallback;

import oop0605.WebProgram.Language; //import를 해야됨.
import oop0605.WebProgram.Smart;

class WebProgram {
	String title = "Java Program";
	
	class Language{ //inner class
		String basic = "JAVA, HTML, CSS, Javascript";
		void display(){
			System.out.println("기초수업: " + basic);
		}
	}//class end
		
	class Smart{ //inner class
		String basic = "Objective-C, Java OOP, C#";
		void display(){
			System.out.println("기초수업: " + basic);
		}
		
	}//class end
	
	void print(){
		Language lang = new Language();
		lang.display();
		
		Smart sm = new Smart();
		sm.display();
		
	}
	
}//class end

//안드로이드 기반 자바
class R {
	static class id{
		static String btn = "버튼";
	}
}//class end


public class Test07_Inner {

	public static void main(String[] args) {
		//내부클래스 inner class
		//클래스내부에서 선언된 클래스이다.
		
		WebProgram web = new WebProgram();
		web.print();
		
		//내부클래스는 외부에서 단계적으로 접근할 수는 있다.
		Language lang = new WebProgram().new Language();
		Smart sm = new WebProgram().new Smart();
		lang.display();
		sm.display();
		
		
		System.out.println(R.id.btn);
		
		
	}//main end
}//class end

▶ 풀이

1. WebProgram이라는 클래스 안에 Language와 Smart라는 클래스를 또 선언했다.

2. main메소드에서 WebProgram클래스 안의 Language와 Smart를 호출하려면 단계적으로 접근해야한다.

3. new연산자로 WebProgram().new Language(); 이렇게 객체 생성하고 호출해야한다.

 

내부클래스는 직접 접근할 수 없고 내부클래스를 감싸고 있는 클래스를 불러와야 한다.

외부에서 단계적으로 접근할 수는 있다.

어제 프로그래머스에서 본 메소드체인 기능?

 

 

 

 

 

 

 

 

 

 

 

 

 

 

댓글