System.out.println()으로 Java의 많은 것을 설명해보자!
오늘 글은 '챌린지'에 가깝다 ㅋㅋ!!
지금까지 공부한 Java개념을 최~대한 접목시켜서
API를 열심히 뒤져가며 System.out.println()를 분석해보려고 한다.
매우 구구절절 꼬리에 꼬리를 묻는 글이라
분량 조절은 실패일듯 하지만..재밌는 글이 될 것 같다ㅎ.ㅎ
- Naming convention, CamelCase
- Dot Operator ( . )
- Has a / Is a
- Extends
- Access Modifier
- Overloading / Overriding
- println() 호출, toString()
- I/O
- Synchronized, write시 동기화 문제
- Exception
- 최상위 클래스 Object
1. Naming convention (CamelCase)
Java에서는 Naming convention중 CamelCase를 따른다.
CamelCase를 표기한 바와 같이 단어가 시작되는 부분을 대문자로 표기하는 컨벤션이다.
CamelCase는 UpperCamelCase, LowerCamelCase로 나눌 수 있다.
식별자의 시작을 대문자로 하느냐, 소문자로 하느냐의 차이이다.
주로 클래스명은 UpperCamel, 필드명은 LowerCamel을 쓴다. 메서드는 LowerCamel에 () 괄호 노테이션을 붙인다.
System.out.println();
System은 클래스구나,
out은 필드구나,
println()은 그 중 메서드구나.
그리고 이들은 Dot Operator( . )를 통해서 System에서 out으로, out에서 println()으로 접근하고 있구나.
Dot Operator의 쉬운 이해:
'나'에게 접근하려면? 우주.지구.아시아.대한민국.서울.나
2. Has - a 관계
System이 ( . )을 통해 out에 접근했다.
==> System이 out이란 필드를 가지고 있구나.
==> System (has - a) PrintStream out
3. Is - a 관계
out의 DataType은 PrintStream이구나.
그런데 정작 PrintStream에는 out이란 필드가 보이지 않는다?!
out은 없지만 FilterOutputStream을 extends하고있다.
==> 그럼 out은 PrintStream보다 상위클래스인
FilterOutputStream(혹은 그보다 더 상위 클래스)에 있나보다.
도큐먼트에서 PrintStream의 Field요약을 보니
==> out은 역시나 FilterOutputStream으로부터 온 것이었구나.
==> System.out에서 PrintStream타입인 out은 상속(extends, 확장)을 통해
상위 클래스(FilterOutputSteam)의 OutputStream타입인 out에 접근하는 것이구나.
4. Access Modifier (protected)
out의 접근 제한자(Access Modifier)는 protected구나.
==> FilterOutputStream을 상속하거나
같은 패키지에 있는 클래스들만 out에 접근할 수 있겠다.
5. Static 키워드
인스턴스를 통해 필드에 접근하지 않고, System이란 클래스명으로 out 필드에 접근
==> out은 Static한 필드구나.
인스턴스 간에 상태 값이 다르지 않아서,
그냥 Static영역에 올려놓고 공유해서 쓰는구나.
==> 그래서 인스턴스를 생성하지 않고,
클래스명으로 접근했구나!!
6. Overloading 오버로딩
out이라는 PrintStream타입의 필드는 ( . )을 통해서
println() 메서드에 접근했네?
==> PrintStream클래스에 println()이라는 메서드가 있나보다.
그런데 println()이라는 같은 이름의 메서드가
파라미터만 다르게하여 다양하게 쓰이고 있네?
==> 파라미터를 달리 함으로써 하나의 이름으로
메서드를 다양하게 활용할 수 있는 '오버로딩'을 하고 있구나
8. println()에서 toString()
println()에 인자로 레퍼런스만 넣어줘도,
다시 말해, toString()을 굳이 붙여주지 않아도 호출해서 출력이 되네?
==> println()이 내부적으로 toString()을 호출하기 때문.
자세한 내용은 전에 작성한 글을 참고해주세요!
9. Overriding 오버라이딩
println()의 인자로 레퍼런스를 넣을때,
레퍼런스 타입마다 출력 양식이 다르다.
가령, Vector<Integer>는 [1, 2, 3, 4] 이런식으로 대괄호에 묶여 출력되고
String은 문자열로 쭉 나온다.
==> toString()의 메서드 시그니처를 유지하면서
구현부는 서로 다르게 하였구나
==> toString()을 오버라이딩 했구나.
10. 최상위 클래스인 Object
오버라이딩은 상속 관계에서 슈퍼클래스의 메서드를 수정/확장하는 개념이다.
대부분의 클래스들이 toString()을 오버라이딩하고 있다는데,
정작 String, Long등 클래스를 직접 확인해보면
extends 키워드를 사용해서 뭔가를 상속한 흔적이 보이지 않는다.
extends도 하지 않았는데 도대체 어떤 toString()을 오버라이딩 한다는 거야?
==> 모든 클래스는 Object라는 최상위 클래스를 상속하며,
이는 클래스 선언부 뒤에서 생략된 것이다(extends Object)
==> Object의 toString()을 오버라이딩해서 사용하고있다.
자세한 내용은 전에 작성한 글을 참고해주세요!
10. Synchronized
한편, print()는 write()를 호출하길래
write()를 살펴보니 synchrosized라는 키워드가 붙어있다.
만약 우리가 파일에 write를 하고 있는데,
다른 사람이 내 파일(리소스)에 동시에 접근해서 write를 해버리면
동기화 문제가 발생해서 신뢰성이 떨어진다.
==> write할 때 Synchronized 키워드를 붙여서 다른 Thread의 동시 접근을 막았구나.
==> Synchronized block을 사용해서 동기화 범위를 조절할 수 있구나
(특정 범위 외에는 굳이 lock하지 않아도 될 때 효율적이겠다)
11. try ,catch 예외처리
write()는 try - catch를 통해 예외도 처리하고 있구나.
==> 혹시라도 Interrupted라는 예외가 발생하면
currentThread()를 interrupt()하는구나.
+ 오늘의 여담
System.out.println()
처음 Java파일을 생성하기만 해도 마주칠 수 있는 익숙한 코드이다.
이를 단순히 '출력'정도로만 덮어두고
돌아간다 신난다~ 하면
속에 숨은 수 많은 원리와 개념을 알기는 힘들 것이다.
관심을 가지지 않는 개발자가 되고 싶지는 않으니까
결론: 공부할 수 있을 때 계속 공부하자 ^____^ ! !