제어자 ≠ 접근 제어자 (public, protected, default, private)
제어자 final
- 변수
- 상수, 값이 변할 수 없음.
- 단, 인스턴스 변수의 경우 생성자를 통해 초기화 가능하다.
- 메서드
- 클래스
생성자를 이용한 final 멤버변수 초기화
- final이 붙은 변수는 상수이므로,
보통은 선언과 초기화를 동시에 하지만
인스턴스 변수의 경우 생성자에서 초기화할 수 있다.
- 이미 값을 넣어놨다면? ( 명시화 초기화 )
생성자에서 초기화 불가능하다!
제어자 abstract
- 클래스
-
인스턴스 생성이 불가능하다. ( new 못한다. )
-
클래스 내에 추상메서드가 선언되어 있음을 의미한다.
public abstract class AbstractClassAndMethod {
public static void myPrint() {
System.out.println("Hi");
}
public abstract void absPrint();
public static void main(String[] args) {
myPrint();
}
}
- 실행이 되는가?
- abstract 제어자는, 해당 클래스를 인스턴스화 하는 것이 불가능한 것이지,
클래스 자체가 로딩되지 않는 것이 아니다.
- 따라서, abstract 클래스 내부의 static 메서드들은 호출 가능하다.
즉, 다음과 같은 코드도 실행 가능하다.
public class OuterClass {
public static void main(String[] args) {
AbstractClassAndMethod.myPrint();
}
}
- 메서드
- 선언부만 작성하고 구현부는 작성하지 않은 추상메서드
**public abstract void absPrint();**
- Body가 없다.
- 이 안의 구현은? 해당 추상 클래스를 상속받은 클래스가 구현한다.
abstract 클래스를 왜 사용하는가?
어떨 때 abstract를 써야하는가?
- 필요한 공통 기능이 미리 구현되어 있고,
각자가 구현해야할 기능이 있는 경우.
- 각자 구현 기능을
자식 클래스에서 상황별로 각자 구현해야할 때. ( abstract로 선언된 메서드를 오버라이딩! )
- 그런데, 인터페이스의 default 메서드가 있는데..
- 추상클래스 = 공통 기능은 있음, 각 자식 클래스마다 구현을 해야하는 경우.
- 인터페이스를 써도 된다..
- 꼭 abstract 클래스를 사용하는 경우?
- 하나의 클래스의 자식 클래스로 다 관리가 되어야 하는 경우
- 관계가 중요한 경우
다중상속인 경우, 메서드를 어떻게 구별하는가?
‘인터페이스명’.’메서드명’
을 꼭 명시해주어야한다!!!!! ( 중요!!! )
부모가 추상클래스고 자식도 추상클래스라면,
반드시 추상메서드를 오버라이딩 할 필요 없다.
면접 질문 : 추상클래스 사용하는 이유
- 구조적인 이유와 기능적인 이유로 나눌 수 있을 것 같습니다.
**구조적인 이유**
PClass, CClass1, CClass2…
- CClass1, CClass2 가 반드시 PClass의 자손으로 관리되어져야 할 때,
**기능적인 이유** 다른 클래스들이 PClass에서 제공되는 메서드를 공통으로 사용하되,
일부 메서드는 자식 클래스 각자가 구현해야 하는 상황일 때 일반 비즈니스 메소드 사이 사이에
각자 구현해야할 추상 메서드들이 포함되어야 할 때 사용한다 생각합니다.
- 이런 경우가 뭐가 있을까?
- 결제 파트, 포인트 파트, 회원관리 파트
- 회원실명 / 인증 파트 개발을 내가 할 때,
**abstract void logWrite()** 함수를 만들어놓고,
각자가 로그를 남기는 기능을 구현한다.
- 그러면 기능적인 이유로 말씀하신 부분은
interface의 default 메서드로 충분하지 않을까요?
사용하는 이유가 다르다 생각합니다.
default 메서드는 Java8에 람다와 스트림 API를 추가할 때,
기존 인터페이스들을 수정하지 않고, 기능을 추가해주기 위해
즉 이미 완성된 설계에 불가피한 수정이 필요할 때, 변경의 범위를 최소화하기 위해 도입한 기능입니다.
그렇지만, 추상클래스는
부모 자식 관계가 명확한 클래스들 사이에,
부모 클래스에서 정해진 방식대로 메소드를 사용하는 가이드라인을 제시할 때
사용할 수 있다 생각합니다.
인터페이스 ( Interface )
- 추상 메서드들을 모아놓은 집합체.
- 인터페이스를 상속받은 클래스들은 인터페이스의 추상메서드들을 무조건 구현해야 한다.
- 인터페이스를 왜 사용하는가?
- 공통의 메서드를 모아놓고, 사용하기 위함이다.
- 구현체들은 해당 추상 메서드들을 각자 상황에 맞게 다르게 구현할 수 있습니다. ( 오버라이딩 )
- 추상클래스를 상속받는 자손클래스는 추상메서드를 반드시 구현해야함.
- 인터페이스의 상수는 모두
**public static final** 이 붙는다, 이를 생략할 수 있다.
인터페이스의 모든 메서드는
**public abstract**가 붙는다, 이를 생략할 수 있다.,
다같이 공통으로, 값이 변경되지 않는다.
( 일반 메서드가 추상 메서드를 호출하는 형태로 구현되어 있는 경우 )
어떤 값이던 **double PI = 3.14** 이렇게 선언해도,
그 앞에 자동적으로 접근제어자 + 제어자 **public static final** 이 붙는다.
추상클래스와 인터페이스
- 추상 클래스가 인터페이스를 상속받은 경우,
둘 다 추상이기 때문에 추상 클래스가 인터페이스를 오버라이딩할 필요 없다.
인터페이스
- 일종의 추상클래스이다.
추상 클래스(미완성 설계도)보다 추상화 정도가 높다.
- 인스턴스를 생성할 수 없고, 클래스 작성에 도움을 줄 목적으로 사용된다.
- 미리 정해진 규칙에 맞게 구현하도록 표준을 제시한다.
- 미리 정해진 규칙에 맞게 구현하도록 표준을 제시한다.
다형성
- 인터페이스를 배우고 나서 배우는 이유?
- 캐스팅이다.
- 다양한 형태의 성질
- 공통인 것 추출해서 인터페이스를 만들어라.
- 각자 그 기능을 구현한다.
- 실제 호출 시, 해당 클래스에 구현을 맡긴다. ( 오버라이딩 )
다형성은 왜 가능한가
다형성은 왜 필요한가
예시
자신의 클래스에 있는 메서드(부모에게도 있는 자식의 메서드)들을 제한적으로 사용하면서,
공통의 것을 해야할 때
오버라이딩된 메서드들만을 사용한다.
인터페이스의 장점
- 다형성을 구현하기 편하다.
- 부모클래스/인터페이스 타입 하나로, 여러 자식 타입에 접근할 수 있다.
- 유연성을 얻을 수 있다.
( 부모 타입만 나타내보면, 다른 친구들을 다 상속해서, 그 타입을 사용하면 된다. )
- 같은 메서드 호출에 대해, 각자 클래스들이 각자의 방식으로 동작하게할 수 있다.
- 코드가 구조적으로 획일화되어, 관리가 용이하다.
- 동일한 인터페이스를 구현하므로, 더 추상화되고 간결해진다.
- 코드의 유연성
- 확장이 용이하다.
배열 쓰지 말고, 유저 1000명 다루기.
~= 인터페이스 없이 공통적으로 해야하는 기능 만들기
( 개발자 각자만의 방식으로 알아서 공통 기능 메서드를 만든다. )
- 다형성 ( Polymorphism )
- 공통 기능을 빼서, 부모 클래스 / 인터페이스를 만들고,
이 타입을 활용하여 자식 클래스 타입들을 가리킨다.
C-P 관계가 안되는 이유.
Child가 가리킬 수 있는 범위가 Parent 보다 넓기 때문이다.
Child의 메소드 중 일부가 유실된다. ( 접근 불가 )
사용할 수 없다.
인터페이스화, 구조적 프로그래밍,
책임을 호출하는 쪽으로 넘긴다.
/**
- 다형성
- 다양한 형태의 성질
- 여러 타입에 접근할 수 있는 방법
- 하나의 타입에 여러 객체를 대입할 수 있는 성질
- 다형성이 뭐냐? PC! = Parent 타입으로 Child를 가리키는 것,
- Child 인스턴스로 부모 타입의 객체에 접근하는 것.
- 변수는 부모의 것이지만, 메서드는 자식의 메서드를 호출.
- 공통 성질을 추상화하고, 해당 클래스를 상속받아
- 각자의 성질을 갖도록 구현한다.
- int n = 정수
- Child c = new Child();
- Parent p = new Parent();
- Parent pc = new Child();
- /