일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 서블릿
- 함수
- 코딩
- SQL
- 데이터베이스
- java
- Database
- Method
- web
- 오라클
- 자바스크립트
- HTML
- It
- 메소드
- JavaScript
- Servlet
- 문자열
- PL/SQL
- function
- 프론트엔드
- Python
- frontend
- 프로그래밍
- 자바
- jsp
- 파이썬
- 웹
- String
- oracle
- Programming
- Today
- Total
Untitled_Blue
[JAVA] final, abstract 제어자 본문
안녕하세요. 이번 글은 final과 abstract 제어자에 대한 설명입니다.
- final 제어자
final이란 사전적으로 해석하면 '최종적'이라는 뜻이다. 이를 프로그래밍 관점에서 보면 필드(변수)에 한 번 값이 저장되면 실행 도중이거나 다른 영역에서 값을 변경할 수 없다는 뜻이다. 즉 한 번 값이 할당되면 그걸로 끝이라고 보면 된다.
package classes;
class Firsting {
int a = 10;
final String k = "Firsting";
Firsting() {}
}
class Seconding {
int a;
final String k;
Seconding() {
a = 20;
k = "Seconding";
}
}
class Thirding {
int a = 30;
final String k = "Thirding";
//k = "Example";
Thirding() {
a = 35;
//k = "Thirding_2"; // 대입 불가 (상단에서 한 번 할당했으므로 재할당 내지 변경 불가)
}
}
public class Final_practice {
public static void main(String[] args) {
Firsting fri = new Firsting();
fri.a = 30;
//fri.k = "fri의 변수 k"; // 재할당 불가
Seconding sci = new Seconding();
sci.a = 50;
//sci.k = "sci의 변수 k"; // 생성자에서 이미 최초 할당해서 재할당 내지 변경 불가
}
}
다음 소스코드를 보면 final 제어자가 포함된 필드는 한 번 값이 할당되면 그 이후로는 절대 값을 재할당할 수 없고 단순히 해당 변수를 호출해서 값을 출력만 가능하다는 점을 확인할 수 있다. 어느 위치에 할당했는가에 관계없이 아무리 생성자에 값을 할당해도 할당했다는 것 자체는 변하지 않는 만큼 재할당할 수 없다.
package classes;
class Firsting {
void mFirstMethod_Basic() {
System.out.println("Firsting 클래스 내 일반 메서드");
}
final void mFirstMethod_Final() {
System.out.println("Firsting 클래스 내 final 메서드");
}
}
class Seconding extends Firsting {
@Override
void mFirstMethod_Basic() {
System.out.println("Override - Seconding 클래스 내 일반 메서드 (상속)");
}
//final void mFirstMethod_Final() {}
}
public class Final_practice {
public static void main(String[] args) {
Firsting fri = new Firsting();
fri.mFirstMethod_Basic();
fri.mFirstMethod_Final();
Seconding sci = new Seconding();
sci.mFirstMethod_Basic();
sci.mFirstMethod_Final();
}
}
다음은 final 메서드가 있는 클래스가 포함된 소스코드이다. 여기서 우리는 Firsting 클래스를 먼저 확인할 수 있고 그 내부에는 final 메서드가 있으며 내부에 실행 코드가 적혀있는 것을 확인할 수 있다. 그리고 이 클래스를 상속받은 자식 클래스가 Seconding이라는 점도 알 수 있다. 자식 클래스 내부에는 오버라이딩을 통해 부모 클래스의 일반 메서드의 이름을 그대로 사용해 본인의 스타일에 맞게 재정의한 점을 볼 수 있다. 그러나 mFirstmethod_final 메서드는 오류발생으로 인해 주석으로 처리할 수 밖에 없다. 왜냐하면 해당 메서드 앞에는 final이 포함되어있기 때문이다. final은 한 번 할당하면 재할당이 불가능하다고 설명했다. 메서드도 마찬가지다. 한 번 내부에 실행 코드가 작성되어 있으면 객체를 통해 메인 메서드에 해당 메서드를 호출하는 것만 가능하고 다시 재정의하는 것은 불가능하다.
자식 클래스 내 주석으로 된 오버라이딩하고자 한 메서드를 보면 이미지와 같이 final 메서드는 재정의할 수 없다는 설명을 확인할 수 있다. final이 포함된 거의 모든 멤버들은 호출만 가능할 뿐 재정의는 절대 할 수 없다는 점을 명심하자.
상단 코드블럭에 있는 코드의 실행결과는 상단의 이미지와 같다.
package classes;
final class Firsting {
void mFirstMethod_Basic() {
System.out.println("Firsting 클래스 내 일반 메서드");
}
final void mFirstMethod_Final() {
System.out.println("Firsting 클래스 내 final 메서드");
}
}
class Seconding /* extends Firsting */ { }
public class Final_practice {
public static void main(String[] args) {
}
}
상단의 소스코드는 final이 포함된 클래스는 다른 클래스에서 상속받을 수 없다는 점을 보여준다. final 클래스를 상속할 수 없는 이유는 간단하다. 재정의나 혹시 모를 변수를 원천적으로 차단하기 위함이다. 그렇기 때문에 extends Firsting 부분에 주석을 선언해서 오류를 없앴다.
주석 처리하지 않은 상태에서 빨간 줄이 있는 extends 뒤 final 클래스명에 커서를 대면 상단의 이미지와 같이 오류의 원인에 대한 설명을 확인할 수 있다. (필자는 JetBrain 사의 Intellij IDEA 2022.03이라는 IDE를 사용하고 있다.)
- abstract 제어자
abstract는 사전적 의미로 "추상"이라는 뜻을 가지고 있다. 더 풀어서 해석하면 '구체적이지 않는'이라는 뜻이다. 이를 프로그래밍 언어 관점에서 보면 메서드를 기준으로 보면 중괄호 {} 가 있고 없고의 차이라고 보면 된다. 보통 메서드를 선언하면 내부에 실행 코드도 같이 있지 않은가? 하지만 추상 메서드는 다르게 볼 수 있다. 중괄호가 없는 메서드이며 기능 자체가 정의되지 않으며 {} 대신 단순히 세미콜론(;)만 붙어있는 것이 전부이다.
- 추상 메서드 구조 : abstract 리턴타입 메서드명();
package classes;
abstract class Abstract_Ex {
abstract void mPrint_ab();
//void mPrint_ab(); // java: missing method body, or declare abstract
}
class Abstract_Inher extends Abstract_Ex {
@Override
void mPrint_ab() {
System.out.println("추상 메서드 오버라이딩");
}
}
public class Abstract_practice {
public static void main(String args[]) {
Abstract_Inher ap = new Abstract_Inher();
ap.mPrint_ab();
}
}
해당 소스코드는 추상이라는 제어자를 설명하기 위한 코드이다. Abstract_Ex 클래스 내부를 보면 void 형식의 메서드 하나가 주석처리된 것을 볼 수 있다. 이는 추상 클래스 안에 메서드가 지켜야할 규칙을 어겨서 에러가 발생했기 때문이다.
추상 클래스를 비롯한 멤버들은 기능이 존재하지 않는 단순한 조감도 내지 틀에 불과하기 때문에 추상 클래스 안에 있는 모든 멤버들은 반드시 맨 앞에 abstract라는 키워드가 포함되어야 한다. 이들은 구체적이지 않은 클래스 및 멤버이기 때문에 안에 있는 메서드는 모두 중괄호없이 세미콜론(;)으로 끝나야 하며 어떠한 실행 코드도 있어서는 안된다. 그리고 추상이라는 점을 명시하기 위해 abstract 키워드가 반드시 포함되어야 한다.
추상 클래스가 아닌 일반 클래스가 추상 클래스를 상속받을 때는 내부에 있는 메서드를 하나도 빠짐없이 모두 오버라이딩해야 한다. 만약 단순히 extends 추상 클래스만 명시하면 에러가 발생했다는 빨간 줄이 발생되면서 커서를 올리면 메서드를 구현해야 된다는 알림이 뜨는 것을 확인할 수 있다.
위에서 이때까지 설명했던 abstract 제어자에 대한 설명과 유의사항을 그림으로 요약하면 상단의 이미지와 같다.
비록 별도의 설계도 내지 불필요한 스케치같이 느껴질 수도 있겠지만 추상 클래스를 통해 단순히 일반 클래스를 오버라이딩하는 과정에서 발생할 수 있는 오타로 인한 오류를 방지할 수 있다는 점에서 간결하지 않아도 편하지 않아도 정확성과 효율성을 높인다는 점에서는 매우 장점으로 볼 수 있다고 생각한다. 특히 이는 여러 사람들과 협업하는 프로젝트에서 장점으로 크게 와닿을 수 있을 것이다.
다음 글은 인터페이스에 대한 설명입니다.
'Programming Language > JAVA' 카테고리의 다른 글
[JAVA] 예외 처리 (0) | 2023.05.25 |
---|---|
[JAVA] 인터페이스 (0) | 2023.05.21 |
[JAVA] 상속 - super(), super 키워드, 오버라이딩, 형변환 (1) | 2023.05.16 |
[JAVA] 접근 지정자와 static 정적 키워드 (0) | 2023.05.12 |
[JAVA] package와 import (0) | 2023.05.09 |