부모 자식 클래스간 상속관계에서 자식클래스에 Final이 선언되어있으면 부모의메서드의 오버라이딩을 제한합니다
I/O기반 입출력 스트림을 배우다가 갑자기 컴파일오류가 발생했습니다
15번째 라인에 선언된 코드 myOut.print("메롱"); 에서 빨갛게 밑줄이 뜬게 보이시죠?
print()메서드가 myOuy객체에 접근하지못하고 컴파일오류가 발생하게 된 것입니다.
import java.lang.*;
System.out.print();
우리가 자바를 가장 처음 배울때 문자를 출력하는것으로 처음 걸음마를 때곤 하는데 출력을 해주는 코드가 바로 System.out.print(); 입니다.
System.out.print()코드중에 가장 뒤에 선언된 print() 메서드 안에 따옴표와함께 변수,객체 혹은 문자열을 넣은 후 출력을 수행하게 됩니다.
위의 코드에서는 System.out을 분석해보도록 하죠
여기서 System은 Java.lang패키지에 속하는 클래스입니다
Java의 lang 패키지는 JAVA 프로그래밍에 필요한 가장 기본적인 클래스들이 모여있는 패키지이고요
그래서 import구문으로 호출해야 사용할 수 있는 다른 패키지들과는 달리 lang패키지는 import구문 없이도 자동으로 프로그램에 포함되게 됩니다.
뒤따라오는 out은 콘솔 객체를 의미합니다. 정확히 말하면 콘솔에 출력해주는 기능을 가진 PrintStream 클래스의 객체라고 할수있죠
마지막에 선언된 print(); 메서드는 문자열을 출력하는 메서드이고 PrintStream 클래스의 내장메서드입니다
System.out.print(); 의 전체적 흐름은 자바 기본 패키지에있는 System클래스의 out객체로부터 print()메서드를 호출하고 그 기능을 수행하는것입니다.
package java.lang; import java.io.*; public final class System { public final static PrintStream out = null; }
package java.lang;
import java.io.*;
public final class System {
public final static PrintStream out = null;
}
사실 out객체는 PrintStream클래스의 객체이고 PrintStream클래스는 OutputStream클래스로부터 상속받고있습니다.
System클래스에 정적상수로 객체가 선언되어있어 System클래스로부터 out 객체를 불러올 수 있는것입니다.
제목은 Final로인한 상속의 제한에 대해 써놨는데 갑자기 I/O에 관련된 소스코드는 뭐며 왜 System.out.print를 분석하고 있는걸까요?
앞서 말했듯 15번라인의 코드를 짜보았는데 사실 필자는 자바개념정리가 미흡한 부분이 많습니다.
아직 다룬지 얼마 되지않아 까먹기도하고 익숙하지않아요...(복습을 제대로 안해서 혼나야해요 ㅠㅠ)
그래서 자바코드를할때 어? 이거랑 이거랑 이렇게저렇게하면 같은건데 그럼 이렇게 접근하면 접근이가능한거 아닌가? 하고 제 멋대로 접근해서 코드했다가 컴파일 오류(빨간밑줄쫙)가 발생했던 경험이 많아요
저는 자바를 조금 더 재밌게 접근하고 효율적으로 개념정리를 하고자 컴파일 오류가 나는부분들로 블로그에 작성하며 공부를 해나가고자 합니다.
서론은 여기까지 하고 우선 필자가 작성한 코드를 보고 왜 저렇게 작성하게 되었는지 말해드리겠습니다. 또 I/O에대해, 상속과 오버라이딩에 대해 설명해 드릴게요!
11번라인 코드를 보겠습니다
OutputStream myOut = System.out;
OutputStream클래스의 객체 myOut에 System.out 을 저장했습니다
앞서말했듯 System.out은 콘솔에 접근하기위해 선언된것이고 그것을 OutputStream클래스의 myOut객체에 저장해준것이죠.
OutputStream을 설명하자면 우선 입력과 출력중에 "출력"에 관한 최상위 스트림 클레스라고 짧게 말하겠습니다.
System.out의 out은 앞서말한듯이 PrintStream이라는 클래스의 객체입니다
이 객체가 속한 PrintStream 클래스의 부모클래스는 OutputStream이에요
[OutputStream] [myOut] = System.[out];
↘2.부모클래스의 ↘3.객체에 저장 ↘1.자식클래스의 객체를
정리하자면
1. OutputStream클래스를 상속받은 자식클래스 PrintStream클래스의 객체 out 을
2. 부모 OutputStream클래스의 객체 myOut에 저장했다.
(이게 업캐스팅이 됬다고 말할수도 있는건지 직접 따로 공부해보고. 질문하기)
필자는 문득 I/O 개념정리 코드를 리딩하다가 갑자기 생각이 들었습니다.
오오... 그렇다면 System.out.print(); 출력코드의 print()메서드를 System.out을 저장한 객체로부터 호출이 가능한거 아닌가???!
그래서 myOut.print();라는 코드가 탄생하게 되었고 하지만 컴파일오류라는 불상사가 일어나게되죠...
너무 어이가없어서 아니 이게 왜 안되는거지? 하고 코드마다 마우스를 올려봤습니다
근데 대체 왜안되는거지? 메서드와 객체가 소속된 클래스가 동일한대 왜 접근이 안되는걸까?
혹시 PrintStream클래스의 out객체가 부모타입인 OutputStream으로 업캐스팅되서그런가?
하고 다운캐스팅 코드로 선언 후 출력해봤습니다.
역시나 생각했던데로라 별로 놀랍지는않네요 컴파일 오류 없이 "메롱" 이라는 글자 출력에 성공합니다.
접근이 된거죠 System.out코드를 객체단위로 저장하여 print()메서드의 접근이 성공한거죠.
근데 왜 다운캐스팅 하기 전 상속관계에서는 안된거지?
우선 상속관계와 Overridng을 짧게 설명해드릴게요.
상속관계에서 자식클래스의 객체는 부모클래스에 선언된 메서드를 Overridng (재정의) 하여 새롭게 사용할수 있게됩니다.
(+추가설명 작성예정)
그렇다면 왜 안된거지? 그 이유는 바로 우리가 놓치고 간 부분에 있습니다. (제가 놓친거죠...?)
클래스에 final이 선언된게 보이시죠?
final클래스는 짧게말하면 상속을 금지시키는것으로 알고있습니다.
하지만 이것은 잘못된 해석이에요.
final클래스는 해당 클래스를 상속을통해 확장할수 없도록 정의하는거죠
상속을 금지하는 것이 아니라 부모 클래스를 자식 클래스가 확장 => 덮어쓰기하는 것(override)을 금지하는 것이 더 정확한 표현이 됩니다.
어쨋든 그래서... 부모클래스에 존재하는 해당 메서드자체가 오버로딩이 금지되버려서... 호출이 불가능해 졌던것이죠...
결국 final 클래스에는 메서드 오버라이딩이 금지되어 메서드호출이 안되고 객체를 통해 접근하기위해서는 다운캐스팅을 꼭 해줘야한다 라고 결론을 짓게되네요!
static final은 추후에 개념정리로 작성하도록 하겠습니다!
(빈 설명이나 잘못 설명된 부분은 계속 수정할 계획입니다.)
'JAVA > BASIC' 카테고리의 다른 글
JAVA Generic 제네릭 (2) / 제한된 타입 파라미터, 와일드카드 타입, 제네릭 타입의 상속과 구현 (0) | 2023.03.12 |
---|---|
JAVA Generic 제네릭 (1) / 제네릭 타입, 멀티 타입 파라미터, 제네릭 메소드 (0) | 2023.03.10 |
람다식과 인터페이스 익명구현 객체 (0) | 2022.10.27 |
Static 정적 멤버(변수,메서드 등) (0) | 2021.05.09 |
[스프링 JdbcTemplate 참조용] 익명클래스와 람다식 (0) | 2020.09.02 |