본문 바로가기
카테고리 없음

클래스5 (this, 초기화 블록, 패키지)

by 낭만 코딩 2024. 8. 25.

1. this

2. 초기화 블록

3. 패키지

 

 

1. this

this 생성자

같은 클래스의 메서드를 실행할 수 있는것처럼 생성자간에도 서로 실행이 가능합니다. 이때 생성자명 대신 this라는 키워드를 사용합니다. 주의할 점은 다른 생성자를 실행할 때는 반드시 생성자 중괄호 블록의 첫줄에 작성해야 합니다.

 

this 키워드가 사용되는 또 하나는 참조변수로서의 객체 자기자신을 가리킵니다. 객체 외부에서 객체 내부의 멤버에 접근하기 위해 객체변수(참조변수)를 사용하듯이 객체 내부에서도 객체의 멤버에 접근하기 위해 this 키워드를 사용합니다.

 

그냥 편하게 this객체 자신”이라고 생각하면 됩니다.

 

public class Car2 {

	// 필드
	String color;
	String company;
	String type;
	
	Car2() {
		this("white", "기아", "경차");
	}
	
	Car2(String color, String company, String type) {
		this.color = color;
		this.company = company;
		this.type = type;
	}
	
	Car2(String com, String t) {
		this("white", com, t);
	}
	
	Car2(String t) {
		this("white", "기아", t);
	}
	
	public String toString() {
		return color + "-" + company + "-" + type;
	}
}

 

public class Car2Main {

	public static void main(String[] args) {
		Car2 c1 = new Car2();
		Car2 c2 = new Car2("중형차");
		Car2 c3 = new Car2("현대", "대형차");
		Car2 c4 = new Car2("black", "기아", "화물차");
		
		System.out.println("c1 = "+c1);
		System.out.println("c2 = "+c2);
		System.out.println("c3 = "+c3);
		System.out.println("c4 = "+c4);

	}

}

 

실행 결과

c1 = white-기아-경차
c2 = white-기아-중형차
c3 = white-현대-대형차
c4 = black-기아-화물차

 

 

Car2 클래스에 총 4개의 생성자가 있는데 this() 키워드를 사용해 매개변수가 3개인 생성자를 실행하고 있습니다. 그리고 매개변수가 3개인 생성자를 보면 this.color, this.company, this.type 이라는 구문이 보이는데, this는 객체 자신이기 때문에 자기 자신객체의 color 변수, company 변수, type 변수가 됩니다.

이렇게 this.을 붙인 이유는 매개변수 이름과 필드의 이름이 같은데, 구분하기 위해 this를 붙여 자기 자신 객체의 필드에 매개변수를 대입합니다.

객체를 초기화하거나, 필드에 값을 세팅 하는 경우 자주 사용되는 구문이니 기억해두세요.

 

 

2. 초기화 블록

초기화 블록은 static 초기화 블록과 인스턴스 초기화 블록이 있는데, static 초기화 블록은 클래스가 메모리에 로드될 때 한번만 실행고, 인스턴스 초기화 블록은 객체가 생성될 때 마다 실행되는 블록입니다. 여기서 블록은 중괄호 { }를 의미합니다. 이름 그대로 클래스를 초기화 할 때 사용합니다.

앞에서 생성자도 초기화 용도로 사용된다고 했는데, 초기화 블록은 생성자 보다도 먼저 실행됩니다. 예제를 통해 실행되는 순서를 확인해 보세요.

 

public class InitEx {

	// 생성자
	InitEx() {
		System.out.println("생성자 호출");
	}

	//static 초기화블럭
	static {
		System.out.println("클래스 초기화 블럭 실행");
	}
	
	// 인스턴스 초기화 블럭
	{ 
		System.out.println("인스턴스 초기화 블럭 실행");
	}

	public static void main(String[] args) {
		System.out.println("main 메서드시작");
		System.out.println("main init1 객체 생성");
		InitEx init1 = new InitEx();
		System.out.println("main init2 객체 생성");
		InitEx init2 = new InitEx();
	}
}

 

실행 결과

클래스 초기화 블럭 실행
main 메서드시작
main init1 객체 생성
인스턴스 초기화 블럭 실행
생성자 호출
main init2 객체 생성
인스턴스 초기화 블럭 실행
생성자 호출

 

앞에서 main()메서드가 가장 먼저 실행되는 시작점이라고 했었죠. 자바 프로그램이 실행되면 실행되는 코드가 main() 메서드에 있는 코드인데, 이 예제를 보면 “main 메서드시작이라는 문자열 출력보다 클래스 초기화 블럭 실행문자열이 더 먼저 출력이 되었습니다.

main() 메서드보다 static 중괄호 블록이 먼저 실행된 것입니다. static 블록은 처음 한번만 실행되고 그 후엔 실행되지 않습니다. 처음 한번만 메모리에 로드되기 때문입니다. static 블록이 실행되고 나서야 비로소 main() 메서드가 실행되기 시작합니다.

 

“main 메서드시작“main init1 객체 생성이 출력되고 init1이라는 객체를 생성하는데 이때 인스턴스 블록이 실행되며 인스턴스 초기화 블록 실행이 출력 되었습니다. 생성자 보다 먼저 실행된 것입니다. 다음에 생성자 호출이 출력되고, 다시 main() 메서드에서 “main init2 객체 생성이 출력되고, init2 객체를 생성하는 new InitEx()에서 생성자 호출 전에 인스턴스 초기화 블럭 실행이 다시 한번 출력 되었습니다.

인스턴스 블록은 객체 생성 시 마다 생성자 보다 먼저 실행되는 블록이기 때문입니다.

 

글로 읽으면 조금 어렵게 느껴지죠? 꼭 실행 결과를 비교해서 코드를 이해하셔야 합니다.

 

정리하면, 초기화 블록은 static이 붙은 블록과 그렇지 않은 블록이 있는데, static정적인, 고정된이라는 뜻으로 클래스의 고정된 멤버입니다. 주의할 점은 객체 생성 없이도 실행되기 때문에, 블록 내에 인스턴스 변수나, 인스턴스 메서드를 사용할 수 없습니다. 또한 this 키워드도 사용할 수 없습니다. static 블록이나 메서드는 객체 생성 시점이 아니라 클래스를 메모리에 로드될 때 고정되기 때문에 객체 자신을 가리키는 this를 사용할 수 없습니다.

 

public class InitEx2 {

	// static 변수
	static int sVar;
	// static 메서드
	static void sMethod() {
		
	}
	
	// 인스턴스 변수
	int var;
	// 인스턴스 메서드
	void method() {
		
	}

	//static 초기화블럭
	static {
		sVar = 0; // static 변수
		sMethod(); // static 메서드
		
		// 에러
		//var = 0; // 인스턴스 변수 
		//method(); // 인스턴스 메서드
	}
	
	// static 메서드
	static void sMethod2() {
		
		// 에러
		//this.sVar = 0; // static 변수
		//this.sMethod(); // static 메서드
	}
}

 

 

static 초기화 블록은 주로 클래스 변수(static 변수)의 초기화 목적으로 많이 사용하고, 인스턴스 초기화 블록은 인스턴스 변수의 초기화를 주로 담당합니다. 하지만 생성자도 인스턴스 변수의 초기화로 많이 사용되기 때문에 인스턴스 블록은 자주 사용하지 않는 편입니다.

 

 

3. 패키지

패키지는 폴더라고 생각하면 쉽게 이해할 수 있습니다. 우리가 포장한다고 할 때 패키징한다고 말하죠? 자바에서 클래스들을 폴더 별로 묶어서 관리하기 위한 단위라고 보면 됩니다. 원래 클래스의 이름은 패키지명까지 포함해서 사용되는 경우가 많습니다. 그래서 클래스의 이름을 식별하기 위한 식별자로 포함되기도 합니다.

, 클래스명이 같아도 패키지 명이 다르면 (다른 폴더에 있으면) 다른 클래스입니다. 우리가 한 폴더에 같은 파일명은 보관할 수 없지만, 다른 폴더에는 보관할 수 있는 것과 같은 원리입니다.

 

패키지를 상위, 하위로 구분하기 위한 기호는 도트(.)을 사용해서 다음과 같이 표현한다.

 

상위패키지. 하위패키지.클래스명

com.test.Member.class
com.abc.Member.class

 

Member.class 파일명은 같지만 위 이름은 com이라는 폴더 안에 test라는 폴더 안에 있는 Member.class이고, 아래는 com이라는 폴더 안에 abc라는 폴더 그 안에 있는 Member.class 입니.

패키지 선언은 반드시 파일 제일 윗 줄에 선언해야 합니다. 하나의 파일에 여러개의 클래스가 존재하는 경우도 같은 패키지의 클래스입니다. 패키지 선언 후 자바 파일을 클래스로 컴파일하게 되면 자동으로 패키지 구조에 맞는 폴더가 자동으로 생성됩니다.

package test1.test2.test3;
 
public class 클래스명 {
    ...
}

 

예를 들어 위와 같이 패키지를 선언하면 이 클래스는 test1이라는 폴더를 생성하고 그 안에 test2폴더를 또 그 안에 test3 폴더를 생성하고 그 안에 컴파일한 클래스파일을 생성합니다.

 

패키지 이름을 작성하는 규칙이 몇 가지 있습니다.

 

* 숫자로 시작할 수 없고, _,$외 특수문자 사용 불가
* 관례적으로 소문자로 작성
* 회사에서는 회사 도메인으로 많이 사용

 

변수 명명규칙과 비슷하기 때문에 역시 그냥 영문 소문자로 지으면 큰 문제 없이 사용할 수 있고, 만약 잘 못 작성했다면 이클립스에서 바로 알려주니 걱정할 필요 없습니다. 주의할점은 java로 시작하는 패키지명은 java에서 제공하는 기본 API에서 이미 사용 중이기 때문에 쓸 수 없습니다.

 

같은 패키지에 있는 클래스들은 아무 코드 없이 객체를 생성하거나 사용할 수 있지만, 다른 패키지에 있는 클래스를 사용하려면 패키지의 이름까지 전부 기술해야 사용할 수 있습니다. test라는 패키지를 생성해서 클래스파일을 생성해보겠습니다.

 

 

 

package test;

public class TestPackage {

    public void method() {
        System.out.println("test 패키지의 TestPackage 클래스");
    }

}

 

TestPackage 라는 클래스는 main() 메서드가 없고, method()라는 메서드 하나만 존재하는 클래스입니다. 이 클래스는 실행하기 위한 클래스가 아니라 다른 곳에서 사용되기 위한 클래스입니다. 패키지는 가장 상단에 test 라고 선언되었으며 실제 폴더구조를 보면 해당 폴더가 그대로 생성되어 있습니다.

자바파일은 src/test 폴더에, 클래스파일은 bin/test 폴더에 있는 것을 확인할 수 있습니다. 이제 이 클래스를 다른 패키지에 있는 클래스에서 사용해 보겠습니다.

 

public class PackageEx {

	public static void main(String[] args) {
		
		test.TestPackage test = new test.TestPackage();
		test.method();
		
	}
	
}

 

실행 결과

test 패키지의 TestPackage 클래스

 

 

PackageEx 클래스는 패키지가 없는 클래스입니다. 위에서 만든 TestPackage 클래스와는 다른 패키지(폴더)에 있는 것이죠. 같은 패키지에 있다면 패키지명을 다 써주지 않아도 되지만, 다른 패키지에 있기 때문에 클래스명을 사용할 때 예제처럼 패키지명까지 전부 풀네임으로 작성해야 합니다.

하지만 패키지 구조가 더 깊어지거나 패키지이름이 길어지면 이런식으로 코드를 작성하면 너무 지저분해지고, 코드 작성도 어렵기 때문에 사용하기 싶은 클래스를 import 문을 이용해서 정의할 수 있습니다. import라는 단어는 수입이라는 뜻을 가지고 있습니다.

im(안에) + port(항구) 항구 안으로 들어오는 것을 수입이라고 단어를 지은것이죠. 반대 말은 ex + port 수출입니다.

IT쪽에서 import는 다른 모듈이나 프로그램을 사용하기 위해 불러올 때 사용하고, 내보낼 export를 사용합니다. 자바에서도 다른 클래스를 사용하기 위해 불러올 때 import 키워드를 사용합니다.

 

import test.TestPackage;

public class PackageEx2 {

	public static void main(String[] args) {
		
		TestPackage test = new TestPackage();
		test.method();
		
	}
	
}

 

실행 결과

test 패키지의 TestPackage 클래스

 

import test.TestPackage; 라는 코드가 추가 되면서, main() 메서드 안에서 이전 예제처럼 패키지명을 전부 쓰지 않고, 클래스명만 적어주면 사용할 수 있습니다.

위 예제는 test 패키지 안에 TestPackage라는 클래스를 import 한 것인데, 만약 test 패키지 안에 다른 클래스도 불러와 사용하려면 import문을 하나 더 정의해야 합니다.

 

import test.TestPackage;
import test.TestPackage2;

 

이럴 때 클래스명 대신 *를 사용하면 해당 패키지의 모든 클래스를 import 하겠다는 의미가 됩니다.

 

import test.*;

 

이렇게 선언하면 TestPackage, TestPackage2 클래스 모두 사용할 수 있게 됩니다. 주의할 점은 *이 모든 클래스를 의미하지만 하위 패키지까지 포함하지 않는다는 것입니다. 만약 test라는 패키지안에 test2라는 패키지의 클래스까지 모두 불러오려면 아래와 같이 작성해야 합니다.

 

import test.*
import test.test2.*

 

프로그램 작성 시 패키지명을 생략 가능한 경우는 아래 세가지입니다.

 

1. 작성 중인 클래스와 사용하고자 하는 클래스가 같은 패키지에 존재하는 경우
2. 상단 import 구문에 정의되어 있는 경우
3. java.lang 패키지에 있는 클래스를 사용하는 경우

 

우리가 지금까지 자주 사용해왔던 String 클래스나 System 클래스는 같은 패키지에 있지도 않고, import 도 하지 않았지만, 패키지명 없이 사용 가능했었던 이유는 자바 설치 시 같이 설치된 java.lang 이라는 패키지에 있는 클래스이기 때문입니다.

 

팁으로 이클립스에서 코딩하다보면 자바 기본 클래스 외에도 무수히 많은 클래스들을 import 하게 되는데, 모든 패키지를 다 외울 수 없으니 자동으로 import 해주는 단축키는 기억해두세요. 3가지 조건에 해당되지 않는 경우 이클립스는 에러를 표시해주는데, 이 때, ctrl + shift + o 를 누르면 자동으로 import를 해주게 됩니다. 만약 동일한 클래스명이 다른 패키지에도 존재하는 경우 직접 원하는 패키지를 선택할 수 있는 팝업이 뜨며 여러분이 직접 원하는 클래스를 선택할 수 있게 됩니다. 아주 자주 사용하는 단축키이므로 잊지 말도록 하세요.