추상화
추상화는 상속, 캡슐화, 다형성 과 더불어 객체지향 프로그래밍의 핵심 개념 중 하나이다. 추상이라는 말에서 유추를 할 수 있듯이 말 그대로 추상적인 개념, 뭔가 애매모호 함을 활용한다.
상속에서 상위클래스-하위클래스를 연결했을 때 상위클래스의 멤버를 하위클래스도 상속을 받는데 상위클래스에서 정의된 멤버를 똑같이 받아 쓴다.
추상화도 상속을 받아 쓴다 라는 개념에서 보면 비슷하지만 큰 차이가 있는데 추상화의 개념에서는 "미완성 설계도"라고 불리는 추상 클래스와 시그니처만 있고 바디 가 없는 추상 메서드를 하위 클래스에서 상속받아 하위클래스에서 정의를 한다.
즉 비어있는 기본 틀만 가져와 하위클래스에서 맞게 설정한다. 따라서 코드의 중복과 유지보수 면에서 편리하다.
여럿이 개발을 하는 경우에도 추상클래스를 건들지 않는 한 공통된 속성과 기능임에도 불구하고 다른 변수와 메서드로 따로따로 정의되는 경우에 생길 수 있는 오류를 사전에 방지할 수 있다.
추상클래스 (abstract class)
abstract 제어자로 '미완성 설계도'인 추상 클래스를 만들 수 있다. 이 미완성 설계도는 쓸모없게 들릴 수 있지만
추상 클래스는 상속 관계에 있어서 새로운 클래스를 생성하는데 매우 유용하다.
추상 클래스 안의 추상 메서드 바디 부분이 상속을 받는 클래스에 따라 맞춤 제작이 가능하기 때문. 이렇게 추상 클래스를 상속받은 하위 클래스에서 메서드를 새롭게 정의해서 쓸 수 있는데 이게 전에 상속 파트에서 공부한
메서드 Overriding 이다.
오버 라이딩을 통해 하위 클래스에서 새롭게 메서드를 완성할 수 있고 해당 하위 클래스를 기반으로 해당 인스턴스를 만들 수 있다.
추상 클래스는 자바 OOP의 추상화 개념을 구현하는데 매우 중요한 역할을 한다.
추상화는 위에 정리했듯, "클래스 간 공통적인 속성을 찾아내서 공통의 상위 클래스를 만드는 것"이라 정의할 수 있는데 여기에서의 '공통의 상위 클래스'가 바로 추상 클래스가 된다. Class Hierarchy 관점으로 바라보면 높은 계층에 있을수록 추상화의 정도가 높고 (덜 구체적 - 더 공통적인 속성과 기능), 낮은 계층에 있을수록 구체화된다라고 볼 수 있다.
모호~ 하게 해 놓고 나중에 입맛에 맞게 변경 가능
제어자 abstract
추상화에서 abstract 제어자를 쓰게 된다. 주로 클래스와 메서드에 사용되는데 클래스 앞에 붙으면 추상화 클래스, 메서드 앞에 붙으면 추상 메서드가 된다.
abstract class AbstractEx //추상 메서드를 적어도 하나 이상 가지고 있는 추상 클래스
{
abstract void abMethod(); //시그니처만 있고 바디자체가 없는 추상 메서드
}
abstract의 제일 중요한 개념은 '미완성'이라는 것인데 다르게 말하면 충분히 구체적이지 않다 라는 의미이다. 즉 추상 메서드는 무슨 기능을 하는지 구체화되지 않은 메서드이고, 그 추상 메서드를 포함하는 추상 클래스는 미완성 클래스라는 의미가 된다.
추상클래스는 '미완성 클래스' 이므로 인스턴스를 생성할 수 없다.
AbstractEx abs = new AbstractEx(); //ERROR!
짚고 갈 포인트가 추가적으로 더 있는데,
1. 추상클래스는 추상 메서드를 포함하고 있다는 것을 빼곤 그냥 일반 클래스랑 전혀 다르지 않다. 따라서 추상 클래스에도 생성자가 있고, 멤버 변수와 메서드도 가질 수 있다.
2. 추상 메서드를 포함하고 있지 않은 클래스에도 abstract 제어자를 사용하면 추상 클래스로 지정이 가능하다. 추상 메서드가 존재하지 않는 완성된 클래스지만 추상 클래스로 지정이 되면 인스턴스 생성이 불가능하다.
final 키워드
인터페이스 개념을 익히기 전에 final 키워드에 대한 이해가 먼저 선행되어야 한다. 자료 타입을 배웠을 때 상수를 선언할 때 변수 앞에 final을 붙이면 그 변수의 값을 아래에서 변경할 수 없었다. 클래스와 메서드에도 final 키워드를 쓸 수 있고, 상수 선언 때와 약간의 차이가 있지만 변경과 확장이 불가능하다는 공통점도 있다.
final 키워드의 위치 | 결과 |
변수 | 값 변경 불가능 |
클래스 | 변경, 확장, 상속 불가능 |
메서드 | 오버라이딩 |
인터페이스
인터페이스는 일종의 추상 클래스이며, 추상 메서드의 집합체다.
후에 배우는 Spring 프레임워크를 이해하는 데 있어 매우 중요한 부분이다.
일종의 추상 클래스라고 했지만 추상 클래스보다 추상화의 정도가 더 높아 추상 클래스와 달리
오직 추상 메서드와 상수만을 멤버로 가질 수 있다. 그 외의 모든 요소는 포함할 수 없다.
추상 클래스를 부분적으로만 완성된 '미완성 설계도'라고 한다면 인터페이스는 밑그림만 그려져 있고 구현된 것은 아무것도 없는 깡통이라 '기본 설계도'라고 보면 될 것이다.
추상 클래스와 마찬가지로 완성된 것이 아니기 때문에 그 자체로 쓰이기보다는 다른 클래스를 작성하는데 도움을 준다.
인터페이스의 작성은 아래와 같이 한다.
interface 인터페이스_이름
{
public static final 타입 상수_이름 = 값;
public abstract 메서드_이름 (매개변수목록);
}
//보통 인터페이스의 이름은 ~able로도 많이 쓰이는데 이는 어떤 기능을 할 수 있는 이라는 뜻으로
//해당 인터페이스가 어떤 역할을 하는지 명확하게 표현 가능하다. (항상 그래야 하는건 아니다)
인터페이스의 멤버들은 조건이 있다.
1. 모든 멤버 변수는 public static final 이어야 한다. 하지만 생략이 가능하다.
2. 모든 메서드는 public abstract 이어야 한다. 하지만 생략이 가능하다.
(but JDK1.8부터 default와 static은 제외)
인터페이스에 정의된 모든 멤버들에 대해 예외 없이 적용되는 사항이라 생략이 가능한 것이다.
생략을 한다면 컴파일 단계에서 컴파일러가 자동으로 추가해준다.
public interface InterfaceTest // 인터페이스 구성 은 이런식으로..
{
public static final int num1 = 1; // 인터페이스 필드변수 정의
final int num2 = 2; // public 과 static 생략
static int num3 = 3; // public 과 final 생략
public abstract String sumOfNum(); // 바디가 비어있는 추상 메서드 정의
void swapNum(); // public abstract 생략
}
위의 interface 코드 예시를 보면 인터페이스 안에는 상수와 추상 메서드 만 포함하고 있다. 그리고 인스턴수 변수 부분의 public static final과 추상 메서드 부분의 public abstract는 생략이 가능하다.
인터페이스의 이점
1. 개발 시간의 단축 (메서드를 호출하는 쪽에서 내용에 상관없이 선언 부만 알면 된다)
2. 코드의 표준화가 가능 (기본 틀을 인터페이스로 만들어놓는다 -> 정형화를 가능하게 해 준다)
3. 서로 상속 관계가 아닌 클래스들에게 관계를 맺어줄 수 있다 (단일 상속의 아쉬움을 보완해 준다)
4. 독립적으로 프로그래밍이 가능하다 (한 클래스의 변화가 다른 클래스의 영향을 받지 않게 해준다)
인터페이스의 상속
인터페이스도 상속을 할 수 있지만 같은 인터페이스끼리만 가능하다. 그리고 단일 상속만 허용하는 클래스와는 달리 다중 상속을 허용한다. 인터페이스는 클래스와 Object의 관계처럼 최고 상위 인터페이스가 없기 때문이다. 또한 애초에
미완성된 멤버를 갖고 있기 때문에 충돌이 발생할 여지가 없다.
interface Running
{
// 지정 위치 [x,y] 까지 달리는 메서드 //
void run1 (int x, int y);
}
interface StopRunning
{
// 달리는 도중 특정 위치[a,b]에서 멈추는 메서드 //
void stop_run (int a, int b);
}
interface RunNStop extends Running, StopRunning { }
클래스의 상속처럼 인터페이스 RunNStop는 상위 인터페이스의 Running과 StopRunning에 정의된 모든 멤버를 상속받는다.
따라서 RunNStop에서는 아무 멤버가 정의되지 않았지만 상속받은 2개의 추상 메서드 run1(int x, int y) 그리고 stop_run(int a, int b)를 멤버로 갖는다.
추상클래스 VS 인터페이스
추상 클래스와 인터페이스를 공부하다가 보니 비슷한데 왜 나눠져 있지?? 하는 생각이 들었다.
일단 두 가지를 간단하게 다시 정리해보면:
추상 클래스 - 추상 메서드를 반드시 1개 이상 가지고 있는 클래스로서 abstract 키워드 사용. 다중 상속 X
인터페이스 - 상수와 추상 메서드만 가지고 있는 일종의 추상 클래스. 다중 구현 OK
공통된 사항으로 둘 다 인스턴스화를 할 수 없고 메서드 오버 라이딩을 강제한다.
결론적으로 말하면 추상 클래스를 써야 할 때와 인터페이스를 쓸 상황이 각각 나뉜다. 따라서 매우 간단한 얘기이지만
상황과 필요에 맞춰 쓰면 된다.
다중 상속이 안되고 다중 구현이 가능하다는 부분에 포커스를 맞추면 될 것 같다.
추상 클래스
>> 같은 상위 클래스를 상속하며 상위 클래스의 기능을 공통적으로 써야 할 경우
인터페이스
>> 서로 상관없고 상속 관계도 아닌 클래스이지만 같은 기능이 필요한 경우
인터페이스의 구현
'어떤 클래스가 어떤 인터페이스를 구현한다'는 그 어떤 인터페이스가 가진 모든 추상 메서드를 해당 클래스 내에서 전부 Overriding 하는 것을 의미한다. 그래야 해당 클래스에서 메서드를 완성할 수 있고 인스턴스도 생성 가능해진다.
단일 상속만을 허용하는 클래스와 다르게 인터페이스는 다중 구현을 허용한다. 즉 하나의 클래스가 여러 개의 인터페이스를 구현할 수 있다.
클래스에서 인터페이스를 구현할 때는 'implements' 키워드를 사용한다.
class 클래스이름 implements 인터페이스 이름
{
//인터페이스에 정의된 추상 메서드를 구현해야한다!
}
=========================================================
// 클래스에서 여러 인터페이스를 구현할때
class 클래스이름 implements 인터페이스명1, 인터페이스명2, 인터페이스명3 { .... }
인터페이스의 활용 예제
'programming > JAVA' 카테고리의 다른 글
[TBC]Java - Array 정리 (0) | 2022.05.15 |
---|---|
[TBC]Java - 객체지향언어 (OOP - Object-oriented Programming) (0) | 2022.05.15 |
Java - 다형성 (0) | 2022.05.13 |
Java - 캡슐화 (Encapsulation) (0) | 2022.05.12 |
Java - 상속(Inheritance) (0) | 2022.05.12 |