회고록 블로그

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

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

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

김간장 2021. 10. 19. 22:28

공부 중인 강의 : 윤성우 선생님, 윤성우의 열혈 Java 프로그래밍 강의.

링크 : https://cafe.naver.com/cstudyjava

 

윤성우의 프로그래밍 스터디그룹 [C/... : 네이버 카페

윤성우의 스터디 공간입니다. C와 JAVA를 공부하시는 분들은 모두 들어오세요. ^^

cafe.naver.com

 

공부 중 개인적으로 기억해둬야할 것 같은 내용들만 필기해놓음


1. System.out.println ?

- 이제 System.out.println을 어느정도 해석할 수 있음

   → System은 "클래스 이름"

   → out은 "클래스 변수"

        * 클래스 변수(static 변수)는 클래스이름.클래스변수로 접근한다고 했음

   → out 뒤에 온점을 찍고 println을 썼다는 것은 "out"이 클래스 변수이자 참조변수라는 의미 (별첨1 참고)

        * out은 참조변수이며 인스턴스를 가리키고 있음

   → println 메소드를 호출하고 있음

- 사실 Systme.out.println은 java.lang.System.out.println임

   → 컴파일 할 때 import java.lang.*; 를 컴파일러가 추가해줌

   → 그때문에 패키지명까지 모두 쓸 필요가 없음 (import가 없다면 java.lang.System.out.println으로 써야함)

   → 보통 별모양(*)을 사용하지 않도록 권장하는데 이때에는 사용하는 나름의 이유가 있음 (별첨2 참고)

 

 

2. public static void main() ?

- public static void main() 또한 해석할 수 있음

   → main 메소드는 하나여야함

         * 인스턴스 생성 시마다 main 메소드가 추가적으로 생성되면 안되기 때문에 static을 붙여줌

         * 또다른 이유로는 프로그램 시작 시 main 메소드가 가장 먼저 JVM에 올라가 있어야 하기 때문에 

            인스턴스를 생성하지 않아도 바로 호출하도록 하기 위함

   → public을 붙인 것은 일종의 "약속"임

        * main 메소드는 프로그램의 시작과 끝을 담당함

        * 그리고 public 접근수준 지시자는 모든 클래스에서 접근이 가능하게 수준을 지정함

        * main 메소드의 호출은 프로그램 내부 보다는 프로그램 외부(JVM 등)에서 하게되는데 JVM이 main 메소드를 발견하려면 public 지시자가 필요함

실험 : public을 뺀 main 메소드
실행하면 "Main method not found in class ---" 라는 에러가 발생함 (JVM이 메인 메소드를 찾지 못..)

   → void

        * 프로그램의 시작과 끝을 담당하기 때문에 main 메소드에게 반환값(return)은 필요 없기도 하지만

           만약 반환값이 있어도 그 '반환값은 누가 처리할건가' 등 생각치 못한 문제가 생김

- 보통 main 메소드만 담은 클래스를 하나 만들지만, 다른 클래스에 main 메소드를 담아버려도 상관은 없음

   → 다만 실행할 클래스 파일은 main 메소드가 담겨있는 파일이어야함

 

추가 참고 자료 : https://www.journaldev.com/12552/public-static-void-main-string-args-java-main-method

 

public static void main(String[] args) - Java main method - JournalDev

public static void main(String args[]), java main method. Entry point of java program. public static void main string args, java command line arguments

www.journaldev.com

 

 

> 별첨1. 참조변수 되새김

- 아래와 같이 인스턴스 "Account"를 생성

new Account();

- 하지만 이대로는 인스턴스에 접근할 수가 없음

   (인스턴스를 식별할 수 있는 '이름'도 없고, 메모리 어디에 저장되어 있는지도 모름)

- 따라서, 인스턴스에 접근해서 메소드를 호출하려면 해당 인스턴스를 부를 수 있는 '이름/별명'이 필요함

- 그 '이름/별명'이 "참조변수"임

- 아래의 코드는 참조변수 "a"를 정의하고 있음

Account a = new Account();

- 참조변수에는 '주소값'이 저장됨

- 보통 인스턴스의 메소드를 호출할 때는 "a.printAccount();" 와 같이 사용함

- 따라서, "out.println" 역시도 마찬가지 (out은 참조변수)

   → 실제로 System 클래스에서 out 클래스 변수를 찾아보면 아래와 같이 코드를 확인할 수 있음

   → out 이라는 클래스변수(static 변수)는 PrintStream 이라는 인스턴스의 "참조변수"임을 알 수 있음

 

> 별첨2. java.lang.*; 을 사용?

- import에 대해 먼저 복습할 필요가 있음

- import로 클래스 하나를 선언했다면, 동일한 클래스명의 (다른 패키지에 있는) 클래스는 import 할 수 없음

- 클래스이름의 충돌을 우려해서, 일반적으로 한 패키지 내의 모든 클래스를 import 하는 것을 권장하지 않는다고 함

   → 참고로 아래와 같이 스타(*)를 이용하면 com.example.project1 패키지의 모든 클래스가 import 됨

import com.example.project1.*;

- 하지만 자바 컴파일러는 컴파일 시 아래의 코드를 삽입함

 

import java.lang.*;

- 스타(*)를 굳이 쓰는 이유가 나름 있음

- java.lang 패키지는 Java 시스템에 있어서 필요하고 중요한 클래스들이 모여있음

- 만약 스타(*)를 사용하지 않으면 사용자가 java.lang 패키지에 있는 클래스와 동일한 이름의 클래스를 생성해버릴 수 있고

  문제가 생길 수 있음

- 따라서, java.lang.*;으로 코드를 쓴 이유는 'java.lang 패키지에 있는 클래스명과 중복된 클래스는 사용하지 말라'는 의미를 내포하고 있기도 함

 

 

3. static의 다른 쓰임새

- static 초기화 블록

   → 사용하는 경우

         * static 변수는 생성자에서 초기화를 잘 하지 않음(인스턴스 생성 시마다 static 변수가 초기화되기 때문)

         * 초기화 블록은 "현재 시간을 컴퓨터에서 읽어와 static 변수에 저장할 때" 사용함(static 변수에 고정된 값을 대입하는게 아님)

         * 즉, 고정된 값을 대입하는게 아니라 static 변수가 메모리에 할당되는 순간, 어떤 값을 계산해서 static 변수에 대입하고 싶을 때 초기화 블록을 사용함

   → 어떻게?

         * static 변수(클래스 변수)는 JVM이 static 변수가 포함된 클래스의 정보를 읽어올 때 메모리에 독립적으로 할당됨

         * 이후 static 초기화 블록이 있으면 JVM은 바로 static 초기화 블록을 읽어서 안의 코드를 해석 후 static 변수의 값을 초기화시킴

   → 사용 방법

         * static 변수에 '프로그램이 실행되는 순간의 날짜'를 저장하려면 아래와 같이 static 초기화 블록 입력(그림1 참고)

[그림1]

- static import

   → JDK 1.5부터 추가된 문법

   → 보통 다른 클래스에 있는 static 변수를 사용하려면 아래와 같이 [클래스명].[static변수명]으로 써야하지만 (그림2 참고)

[그림2]

   → 새로운 문법으로 표현하면 아래와 같이 사용할 수 있음

         * 하지만 아래와 같이 작성하면 date와 time 변수가 어디에 있는 변수인지 한번에 파악하기 어려워짐

// Practice28 소스파일
import static Practice29.date;
import static Practice29.time;

class Practice28 {
	public static void main(String args[]) {
		System.out.println(date);	// date의 변수가 어디에서 온 것인지 파악하기 어려워짐
		System.out.println(time);
	}
}

참고 자료 : https://atoz-develop.tistory.com/entry/JAVA-static-import%EB%AC%B8

 

[JAVA] static import문

static import문은 JDK1.5부터 추가된 기능이다. import문을 사용하면 클래스의 패키지명을 생략할 수 있는 것과 같이 static import문을 사용하면 static멤버를 호출할 때 클래스명을 생략할 수 있다. 코드

atoz-develop.tistory.com

 

4. 메소드 오버로딩(Overloading)

- JVM이 메소드를 호출할 때, 메소드를 찾는 기준은 "메소드 이름"과 "메소드 매개변수(parameter) 정보"임

- 즉, 이름이 다른 메소드를 정의할 수 있고, "이름은 같은데 매개변수가 다른" 메소드를 정의할수도 있음

- 이름은 같지만 매개변수가 다른 메소드를 정의하는게 '메소드 오버로딩'

- 매개변수의 개수가 다르거나, 매개변수의 자료형이 다르면 메소드 오버로딩임

   → 참고로, 반환형이 다른 경우는 메소드 오버로딩이라고 할 수 없음

- 유의할 점 :

   → 아래와 같이 메소드 매개변수와 인자가 애매하면 안됨

        * 결과는 첫번째 printNum 메소드가 실행됨 (char형은 double형보다 int형으로 먼저 자동형변환 되기 때문)

           따라서, 인자값 'A'는 int형으로 자동형변환됨

        * 만약 첫번째 printNum 메소드가 없고, 두번째 printNum 메소드만 있다면 인자값 'A'는 double형으로 자동형변환됨

        * 아래의 코드는 '실행이 안되는 것은 아니지만, 나중에 코드를 다시볼 때 혼란스러워'질 수 있음

   → 만약 아래와 같은 상황에 있다면, 강제형변환으로 명확하게 자료형을 명시해주는 것이 좋음 (혼란 방지 위함) 

class Practice31 {
	void printNum(int n1, int n2) {...}; // 첫번째 printNum 메소드
	void printNum(int n1, double n2) {...}; // 두번째 printNum 메소드
}
class MainMethod {
	Practice31 p = new Practice31();
	p.printNum(1, 'A'); // 첫번째 printNum 메소드가 실행될까, 두번째 printNum 메소드가 실행될까..?
}

 

5. 생성자 오버로딩(Overloading)

- 코드를 보고 이해하는게 더 빠름 (그림3 참고)

   → 생성자의 매개변수를 다르게 해서 여러개 정의할 수 있음

[그림3]  //  중복되는 부분이 많아서 그리 효율적인 코드는 아닌 듯함...(TMI)

- this 키워드를 이용하면 코드의 중복을 제거할 수 있음 (그림4 참고)

   → this는 간단하게 말하면 '현재의 인스턴스'를 의미함 (별첨3 참고)

[그림4]

 

 

 

> 별첨3. this를 이용해서 현재 인스턴스의 멤버 변수 호출해오기

- (아직 배우지 않은) this는 간단하게 말하면 현재의 인스턴스를 의미함

- 아래와 같이 사용하면 매개변수 이름과 인스턴스 멤버 이름을 중복해서 사용할 수 있음 (그림5 참고)

   → 매개변수명도 registerNum, 인스턴스 멤버명도 registerNum

   → 여기에서 this.registerNum은 Practice31 인스턴스의 멤버변수인 registerNum을 의미함

[그림5]

 

Comments