회고록 블로그
[공부 필기] Java 기본 공부하기 (9) 본문
공부 중인 강의 : 윤성우 선생님, 윤성우의 열혈 Java 프로그래밍 강의.
링크 : https://cafe.naver.com/cstudyjava
공부 중 개인적으로 기억해둬야할 것 같은 내용들만 필기해놓음
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 지시자가 필요함
→ void
* 프로그램의 시작과 끝을 담당하기 때문에 main 메소드에게 반환값(return)은 필요 없기도 하지만
만약 반환값이 있어도 그 '반환값은 누가 처리할건가' 등 생각치 못한 문제가 생김
- 보통 main 메소드만 담은 클래스를 하나 만들지만, 다른 클래스에 main 메소드를 담아버려도 상관은 없음
→ 다만 실행할 클래스 파일은 main 메소드가 담겨있는 파일이어야함
추가 참고 자료 : https://www.journaldev.com/12552/public-static-void-main-string-args-java-main-method
> 별첨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 참고)
- static import
→ JDK 1.5부터 추가된 문법
→ 보통 다른 클래스에 있는 static 변수를 사용하려면 아래와 같이 [클래스명].[static변수명]으로 써야하지만 (그림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
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 참고)
→ 생성자의 매개변수를 다르게 해서 여러개 정의할 수 있음
- this 키워드를 이용하면 코드의 중복을 제거할 수 있음 (그림4 참고)
→ this는 간단하게 말하면 '현재의 인스턴스'를 의미함 (별첨3 참고)
> 별첨3. this를 이용해서 현재 인스턴스의 멤버 변수 호출해오기
- (아직 배우지 않은) this는 간단하게 말하면 현재의 인스턴스를 의미함
- 아래와 같이 사용하면 매개변수 이름과 인스턴스 멤버 이름을 중복해서 사용할 수 있음 (그림5 참고)
→ 매개변수명도 registerNum, 인스턴스 멤버명도 registerNum
→ 여기에서 this.registerNum은 Practice31 인스턴스의 멤버변수인 registerNum을 의미함
'2. 프로그래밍 언어 공부 > Java' 카테고리의 다른 글
[공부 필기] Java 기본 공부하기 (11) (0) | 2021.10.27 |
---|---|
[공부 필기] Java 기본 공부하기 (10) (0) | 2021.10.26 |
[공부 필기] Java 기본 공부하기 (8) (0) | 2021.09.25 |
[공부 필기] Java 기본 공부하기 (패키지) (0) | 2021.09.22 |
[공부 필기] Java 기본 공부하기 (7) (0) | 2021.09.17 |