회고록 블로그

[공부 필기] Java 기본 공부하기 (2) 본문

2. 프로그래밍 언어 공부/Java

[공부 필기] Java 기본 공부하기 (2)

김간장 2021. 8. 26. 05:08

1.1. Java 소스 코드 구조 - 주요

   → 클래스 정의하기

public class Sample {
	......
}

#1. 클래스를 만들고 그 안에 코드를 작성해야함

#2. 클래스를 선언할 땐 반드시 class 키워드를 사용해야함

#3. public은 "접근 지정자"라고 하며, 다른 클래스에서 자유롭게 Sample 클래스(class)를 참조할 수 있다는 의미임


   → main() 메소드 작성하기

public class Sample {
	public static void main(String[] args) {
    	......
    }
}

#1. main() 메소드부터 실행이 됨

       즉, Java 소스 코드가 처음 실행될 때 main() 메소드를 먼저 찾고 실행함

#2. 1개의 클래스(class)에는 1개의 main 메소드가 있어야 함

#3. main() 메소드는 public static void로 선언되어야 함(?)

#4. public static void는 알고 있는데, args가 뭐였더라

   → args = 변수명을 해석하자면 arguments(인자들)이며, 데이터타입에 의해 String(문자열)이 다수 들어가는 배열([]) 형태임

   → 변수 args는 변수명이 꼭 args일 필요는 없음, 중요한 것은 그 변수의 역할임(문자열들을 담고 있는 배열)


   → 메소드 작성하기

public class Sample {
	...
    public static int add(int n, int m) {
    	......
    }
    ...
}

#1. 클래스 안에 있는 함수를 "메소드"라고 함

#2. 메소드는 클래스 안에서만 선언 가능함

#3. 소괄호 안에 있는 int n과 int m은 "인자"임

#4. 위의 예시에서 static 뒤에 있는 int는 리턴된 값의 타입을 의미하고 add는 메소드명을 의미함


1.2. Java 소스 코드 구조 - 그외

   → 메소드 내에서 선언된 변수는 '지역 변수'라고 함

   → 메소드를 호출할 때에는 add(1, 2)와 같이 메소드명을 이용해서 호출함

         특히, 인자 개수와 인자 타입을 정확하게 작성해야함

   → 주석은 /* */ 혹은 // 으로 작성함

   → 문장이 끝날 때에는 세미콜론(;)을 붙이고, 블록이 끝날 때에는 중괄호({})를 이용함

 

2. Java의 이름 붙이는 관습

   → 클래스 이름의 첫번째 문자는 "대문자"로 시작

   → 변수와 메소드 이름의 첫번째 문자는 "소문자"로 표기하며, 각 단어의 첫번째 문자만 "대문자"로 표기

         e.g. boolean isChar (값이 'char'형인지 확인하는 변수)

   → 상수 이름은 전체를 "대문자"로 표기하기를 권유

 

3. 데이터 타입

   →  기본 타입 : boolean, char, int, long, float, double 등이 있음

   → 레퍼런스 타입 : 배열에 대한 레퍼런스, 클래스에 대한 레퍼런스, 인터페이스에 대한 레퍼런스가 있음

         레퍼런스는 C의 '포인터'와 비슷한 개념임

   → Java에서 데이터 타입은 항상 크기가 일정함 (int는 항상 4바이트, JVM 덕분)

   → String 클래스 : Java는 기본적으로 문자열을 표현할 수 없음, 하지만 JDK에서 제공하는 String 클래스를 이용하면 가능

        https://docs.oracle.com/en/java/javase/16/docs/api/java.base/java/lang/String.html

 


4. 변수의 값

   → int, short, float, long 등 데이터 타입의 값을 표현할 때는 아래와 같이 표현함

         * 8진수로 표현 할 때 : 가장 앞에 0 추가

         * 16진수로 표현 할 때 : 가장 앞에 0x 추가

         * 10진수로 표현 할 때 : 특별한 추가사항 없음 (가장 앞에 0을 추가하면 8진수가 되어버림)

         * 2진수로 표현 할 때 : 가장 앞에 0b 추가

         * 실수형 : 디폴트로 double 타입으로 처리하므로 float 타입으로 할 땐 숫자 뒤에 f or F 붙임

                           (명시적으로 double 타입으로 처리할 땐 d or D를 붙임)

                           (float 타입의 값에 'f 혹은 F' 붙이지 않으면 에러 발생함)

         * 문자형 : 작은 따옴표 안에 문자를 넣거나, \u 를 이용해서 유니코드로 표현도 가능

short num1; // 변수 선언
num1 = 1; // 변수 값 대입

short num2 = 2; // 각각 변수 선언과 동시에 초기화
short num3 = 3;

char char1 = 'a', char2 = 'b'; // 동일한 데이터 타입의 변수 선언 및 초기화

int var1 = 017; // 017(8진수임)은 10진수로 변환하면 15가 됨
int var2 = 0xF; // F(16진수임)는 10진수로 변환하면 15가 됨
int var3 = 15; // 10진수로 표현한 방법임
int var4 = 0b1111; // 1111(2진수임)은 10진수로 변환하면 15가 됨

float var5 = .1234F; // 0.1234를 float 형으로 선언 및 초기화
double var6 = 1234E-2; // 12.34를 double형으로 선언 및 초기화

   → int, float, char 등의 키워드는 JDK 16 기준으로 java.lang 패키지의 클래스로 있음

        (java.lang 패키지는 Java의 기본이 되는 클래스를 제공한다고 함)

# 참고

https://docs.oracle.com/en/java/javase/16/docs/api/java.base/java/lang/package-summary.html

 

※ escape sequence는 변수에 대입할 수도 있음

public class Practice {
	public static void main(String[] arg) {
		char enter = '\n';
		
		System.out.print("시작 전");
		System.out.print(enter);
		System.out.print("시작 후");
	}
}

/* 출력결과:
시작 전
시작 후
*/

 

5. 상수

   → 상수는 변수와 달리 도중에 값이 변할 수 없음

예시1

   → final 키워드를 이용해서 상수를 선언하고 초기화함

        * final 키워드는 어디에 선언되어 있을까.. java.lang.reflect 패키지의 Modifier 클래스의.. final 필드 같은데..

   → 사실, 상수는 static 타입으로 선언하는 것이 좋음

 


현재 책의 앞장을 공부하고 있는데,

간단하게 설명하듯이 빠르게 넘어가는거보니 뒷장에서 더 자세하게 배우나보다.

 

 

참고 문헌

황기태.김표수 저자(2016). 명품 Java Programming(제2판). 경기:생능출판.

 

 


책에 나와있는 내용에 집중해서 공부해야하는데,

쓸데 없는 호기심이 많아서 그런지..

책의 진도는 못나가고 궁금증을 해결하기 위한 구글링이나 하고 앉아있다니.

 

일단 혼자 공부하면서 생각했던 내용들과 그에 대한 서칭 결과를 함께 적어놓자.

※ 틀린 내용이 있을 수 있음


Q1. 상수는 'static' 타입으로 선언하는 것이 좋다고 한다. 근데 static final로 입력하면 에러가 발생한다.

위의 예시1 코드에서 상수 TEN을 static 타입으로 선언하려고 했지만

아래와 같이 에러가 발생한다.

final 키워드만 사용하라는 에러인데.. static도 쓰라고 해놓고 왜 final 키워드만 된다고 하는건지

이해가 안되어서 스택오버플로우를 뒤적뒤적하다가 정답을 찾아냈다.

 

https://stackoverflow.com/questions/21280038/java-error-illegal-modifier-for-parameter-only-final-permitted

 

Java Error - Illegal Modifier for Parameter - Only final Permitted

What's wrong with the below Code public static void main(String[] args){ public static final String Name = "Robin Wilson"; } String Reference Name shows Compilation Error - Java Error -

stackoverflow.com

 

메소드 안에 있는 변수에는 static과 final 키워드를 동시에 사용할 수 없다고 한다.

final 키워드만 사용이 가능하다고 함.

 

다만, 아래와 같이 메소드 밖에서는 사용이 가능하다고 한다.

 

아직 Java의 기초도 떼지 못한 상태이기 때문에 이렇게 해야만 하는 그 이유에 대해서는 나중에 천천히 알아보기로 했다.

 


Q2. final에 대해 알아보다가 알게된 Modifier에 대하여.

 

final 키워드가 도대체 어디에 정의되어 있는 키워드인지 궁금해졌다.

 

"내가 코드에 final이라는 키워드를 사용하면

누군가가 'final은 어떤 기능을 하는 키워드이다' 라고 정의를 해놓은 것을 불러와서 쓰게 되는걸텐데...

그게 분명 코드 형태로 어딘가에 있어야 하는데 도대체 어디에 있을까"

 

라는 생각으로 시작된 호기심은 나를 6시간째 구글링에서 벗어나지 못하게 만들었다.

 

일단 공식 문서에서 final을 검색해봤다.

그리고 아래와 같이 아마 final 키워드가 정의되어 있는 것으로 추측되는 클래스를 찾았다.

(API 문서에는 정말 다 있다. 너무 방대해서 찾기 힘들뿐...)

JDK 16버전 API 문서로 final 키워드를 찾던 중

 

일단 java.base라는 모듈에 있는 이 java.lang.reflect 패키지에 대해서 알아보았다.

공식 문서에는 "어떤 클래스나 객체의 reflective information을 얻기 위한 클래스나 인터페이스를 제공"한다고 되어 있다.

 

공식 문서의 설명은 이해하기 어려워서

구글링을 통해 'reflection'이라는 것에 대해서 찾아봐야한다.

 

1) 출처 : https://www.geeksforgeeks.org/reflection-in-java/

"Reflection이라는 API는 런타임의  메소드, 클래스, 인터페이스의 행위(동작)를 검사하거나, 수정할 때 사용한다"고 한다.

 

하지만 여전히 무슨 소리인지 모르겠다.

그래서 또 다른 글을 찾아봤다.

 

2) 출처 : https://codechacha.com/ko/reflection/

"자바의 리플렉션(Reflection)은 클래스, 인터페이스, 메소드들을 찾을 수 있고, 객체를 생성하거나 변수를 변경할 수 있고, 메소드를 호출할 수도 있습니다" 라고 나와있다.

 

두 번째 출처에서 예시로 여러가지를 보여주고 있는데

reflection은 클래스 이름만 알고, 클래스 정보를 알아내고 싶을 때 사용할 수 있고

메소드 이름만 가지고 일치하는 메소드가 있는지 찾을 때 사용할 수도 있다고 한다.

 

그래서 위의 내용을 가지고 자체적으로 해석해보면... 

java.lang.reflect 패키지는 '개발자가 특정 정보만 가지고 있을 때, 그 정보를 이용해서 다른 정보를 알아내거나 값을 변경하고 싶을 때 사용'하는 API이라는 것 같다.

(정확한지 모르겠음)


어쨌든, java.lang.reflect 패키지가 무엇인지 까지는 얼추 알아냈다. 

final 필드는 그 패키지 안의 Modifier 클래스에 있다고 한다.

 

java.lang.reflect 패키지에는 Field, Method, Modifier, Array, Constructor 등의 클래스가 있는데

그 중 Modifier 클래스에는 final 이 있고, 그 유명한(?) public, private 필드도 있다.

 

물론 필드 말고 메소드도 있다.

예를 들면 isFinal(final 키워드를 포함하고 있는지 확인하는 메소드인 듯), classModifiers 등.

 

Modifier 클래스에 대해서 이해해보려고 했는데

일단 공식적인 문서에서 하는 말은 이해가 되지 않는다.

뭔소리야

 

그래서 구글에서 찾아봤다.

 

3) 출처 : http://tcpschool.com/java/java_modifier_accessModifier

"클래스와 클래스 멤버의 선언 시 사용하여 부가적인 의미를 부여하는 키워드"라고 한다.

 

 

final 키워드가 Modifier 클래스에 포함되어 있는 이유도

상수를 선언할 때 사용하며 + '초기화 이후에 값을 변경하지 못함'이라는 의미를 담고 있는 키워드이기 때문이지 않을까.

 


이제 final 키워드가 어느 위치에 있는지 알아냈다.

java.lang.reflect.Modifier.class를 디컴파일해서 보면 될 것 같다.

 

코드를 확인해보니

final 제어자(modifier)를 나타내는 코드값이 16진수로 10이라는 것을 알아냈다.

 

이게 전부였다.


 

하지만 final 키워드의 (동작)기능을 나타내는 코드는 보이지가 않는다..

 

 

 

해답은 아닌데, 고민하며 찾아다니다가 알게 된 것도 있다.

 

1) 왜 코드값을 넣어놨나 했는데...

 

(java.lang.reflect 패키지의) Modifier.class에서는 public의 코드값을 0x0001로 지정해놓았다.

제어자(modifier)에 부여된 16진수 값을 보면서 '굳이 왜 숫자를 대입해놨지?' 라는 생각을 했었는데...

이 public의 코드값이 java.io의 ObjectInputStream.class에서도 사용됐다. 아마 더 많은 클래스에서 사용됐을 것이다.

 

숫자를 이용하니까 if문도 훨씬 깔끔해진 것 같다. 역시 쓸모없는 코드는 없다. (?)

 

 

2) final 키워드가 제 기능을 할 수 있는 것은

여러 클래스에서 final 이라는 값(변수, 코드값)을 가져다 쓰고 + 여러 클래스에서 final의 기능을 일부씩 구현해 놓았고 + 그 코드들이 유기적으로 뭉쳐져서 만들어진 것 같다. (추측임)

 

Modifier 클래스 파일을 처음 봤을 때,

그 안에 final 필드의 동작 코드(초기화된 이후 값을 변경하지 못하도록 함, 변경하려고 하면 에러 메시지를 발생시킴 등)가 모두 담겨 있는 줄 알았는데 그게 아니였다.

 

그래서 여기저기 흩어져 있을 동작 코드를 찾아보려고 했는데,

그럴려면 라이브러리에 있는 많은 변수와 메소드의 관계를 정리하는게 선행되어야 했다.

클래스도 너무 많고, 메소드도 너무 많고, 변수도 너무 많아서 쉽게 찾을 수가 없다..

 


어쨌든 이 삽질 덕분에 다양한 생각을 해볼 수 있었다.

 

1) final, public, private 등과 같은 키워드도 모두 클래스 파일 안 어딘가에 들어있다는 것. 찾으면 반드시(?) 나온다는 것.

    ('접근 제어자에는 public, protected, private가 있다'는 기본 개념 조차도 모두 코드로 표현되어있다)

2) 공식 문서에는 정말 모든 내용이 다 있다는 것. 다만 영어실력과 서칭 능력이 좀 필요하다는 것..

    (왜 API 문서를 열어놓고 코딩하라는건지 알 것 같다)

3) '잘 만들어진 프로그램에서 final 키워드의 코드 하나 찾는데도 이렇게 오랜 시간이 걸리는데, 유지보수가 난장판인 복잡한 프로그램에서는 얼마나 고통스러울까' 라는 소름끼치는 생각을 하게 됐다는 것. 코드를 처음 짤 때 주석을 잘 써야겠다는 것.

 

 

자바에 대해 공부를 하고 어느정도 이해하게 되면, 공식 문서를 찬찬히 읽어보고 싶다.

 

Comments