Ch6 - 패키지, 접근제한자
패키지
클래스를 체계적으로 관리하기 위한 파일 시스템의 폴더와 같다. 패키지를 선언하면 클래스를 컴파일하는 과정에서 자동적으로 폴더를 생성한다.
또한 패키지는 클래스를 유일하게 만들어주는 식별자 역할을 한다. 클래스 이름이 동일하더라도 패키지가 다르면 다른 클래스로 인식한다.
클래스의 전체이름 이름 : [상위패키지.]하위패키지.클래스명
com.mycompany.Car -> 실제 파일 시스템 : com\mycompany 폴더에 Car.class 저장되어 있음
클래스를 이동할 경우에는 패키지 전체를 이동시켜야 한다.
패키지의 이름규칙
1. 숫자로 시작할 수 없고, 특수문자는 _, $만 쓸 수 있다.
2. java로 시작하는 패키지는 자바 표준 API에서만 사용하므로 사용해선 안된다.
3. 모두 소문자로 작성하는 것이 관례이다.
4. 여러 회사가 함께 프로젝트에 참여할 때, 패키지 이름의 중복을 막기 위해 도메인 이름 역순으로 패키지 이름을 짓는다.
ex)com.samsung.pjname
패키지선언이 포함된 클래스 컴파일
cmd로 직접 컴파일하기
1.메모장으로 패키지 선언을 포함하여 소스파일 작성
package sec12.exam01_package_compile;
public class Application {
public static void main(String[] args){
System.out.println("Run Application");
}
}
2. 명령프롬프트 실행

1) cd + 디렉토리경로 복붙 //cd: change directory(소스파일이 저장되어 있는 경로로 이동)
cd C:\Temp
2) 컴파일 //javac : 클래스파일(.java)을 바이트 코드 파일로 컴파일하는 명령어 -d : 현재 directory에 패키지 폴더 저장
javac -d . Application.java
> sec12폴더가 C:\Temp에 자동 생성된다.
3) 실행하기
패키지가 시작하는 폴더(여기선 sec12)에서 java명령어를 사용한다 (바이트 코드 파일이 있는 폴더가 아닌 패키지가 속한 폴더)
java sec12.exam01_package_compile.Application
cf. 패키지 선언이 없는 클래스는 이클립스가 default 패키지에 포함시킨다. (좋지않음)
import
다른 패키지에 속하는 클래스를 사용하려면
1. 패키지와 클래스를 모두 기술
서로 다른 패키지에 동일한 클래스 이름이 존재하고, 두 패키지가 모두 import되어 있을 때 2로는 컴파일러가 식별할 수 없기 때문에 패키지 이름 전체를 기술해야한다.
package sec12.exam03_import.mycompany;
import sec12.exam03_import.hankook.SnowTire;
import sec12.exam03_import.hyndai.BigWidthTire;
import sec12.exam03_import.kumho.Engine;
public class Car { //import문 자동작성 (Ctrl+Shift_O)
//필드
Engine engine = new Engine(); //나머지는 import문을 사용해서 코드를 할 때는 간단하게 줄일 수 있다.
SnowTire tire1 = new SnowTire();
BigWidthTire tire2 = new BigWidthTire();
sec12.exam03_import.hankook.Tire tire3 = new sec12.exam03_import.hankook.Tire(); //Tire클래스는 import된 두 패키지에 모두 있음
sec12.exam03_import.kumho.Tire tire4 = new sec12.exam03_import.kumho.Tire(); //따라서 전체 이름 기술
}
2. import문을 작성한다 : 같은 패키지에 없으면 import 안에서 찾아준다
import com.myCom.myCom1.*; //myCom1경로에 들어있는 모든 클래스라는 뜻
import com.*; //단, com 바로 안에 있는 클래스만 import, 그 하위 패키지까진 import하지 않는다
import문 자동 생성 shortcut : Ctrl+Shift+O
package com;
import com.myCom.MyComClass; //같은 패키지에 없으면 import안에서 찾아준다
import com.myCom.myCom1.*; //myCo1 경로에 들어 있는 모든 클래스라는 뜻
import com.*; //com 바로 안에 있는 클래스만 import, 그 하위패키지는 X
import com.myCom.myCom2.MyCom2Class;
import com.yourCom.YourComClass;
import com.yourCom.yourCom1.YourCom1Class;
//import com.yourCom.yourCom2.YourCom2Class;
public class BusinessClass {
public static void main(String[] args) {
ComClass comClass = new ComClass();
MyComClass myComClass = new MyComClass(); //패키지의 경로를 알려주기
//모든 패키지 안에 있는 클래스를 객체 생성하기
MyCom1Class myCom1Class = new MyCom1Class();
MyCom1Class11 myCom1Class11 = new MyCom1Class11();
MyCom1Class22 myCom1Class22 = new MyCom1Class22();
MyCom2Class myCom2Class = new MyCom2Class();
YourComClass yourComClass = new YourComClass();
YourCom1Class yourCom1Class = new YourCom1Class();
com.yourCom.yourCom2.YourCom2Class yourCom2Class = new com.yourCom.yourCom2.YourCom2Class();
}
}
저장 경로 찾기 (File - Switch Workspace - Other)

Window - Show View - Navigator
Package explorer에서는 패키지의 하부구조가 드러나지 않지만,
Navigator를 통해 물리적 저장 구조 볼 수 있다

접근제한자


클래스 내부일 경우 접근 제한자의 영향을 받지 않는다.
클래스의 접근 제한
같은 패키지 내에서 선언할 것인지, 아니면 다른 패키지에서도 사용할 수 있도록 할것인지 public과 default 두 가지이다.
public을 생략하면 클래스는 default 접근 제한을 가진다.
클래스를 다른 개발자가 사용할 수 있도록 라이브러리 클래스로 개발되어야 한다면 public 접근 제한을 갖도록 한다.
생성자의 접근 제한
public - 제한이 없다. 다만 클래스가 default라면 생성자가 public이어도 같은 패키지에서만 생성자 호출 가능
protected - 같은 패키지 + 다른 패키지이더라도 자식 클래스에서 생성자 호출 가능
default - 생략될 수 있으며, 같은 패키지에서만 생성자 호출 가능
private - 클래스 외부에서는 절대 생성자 호출이 불가능. 오로지 클래스 내부에서만 생성자를 호출하고 객체를 만들 수 있다.
클래스에 생성자를 선언하지 않으면 컴파일러에 의해 자동적으로 기본 생성자가 추가되는데 이때 생성자의 접근 제한은 클래스의 접근 제한을 따른다.
필드와 메소드의 접근 제한
public - 필드와 메소드가 public 접근 제한을 가질 경우, 클래스도 public접근 제한을 가져야 한다.
protected - 같은 패키지 + 다른 패키지의 자식 클래스
default - 생략했을 때
private - 클래스 내부
Getter와 Setter 메소드
객체의 데이터를 외부에서 마음대로 읽고 변경할 경우 객체의 무결성이 깨질 수 있기 때문에 객체 지향 프로그래밍에서는 메소드를 통해서 데이터를 변경하는 방법을 선호한다. 메소드는 매개값을 검증해서 유효한 값만 데이터로 저장할 수 있기 때문이다. 이 때 Setter메소드를 사용하고, 객체 외부에서 객체의 필드값을 사용하기에 부적절한 경우 메소드로 필드 값을 가공한 후 외부로 전달하기 위해 Getter 메소드를 사용한다.
클래스를 선언할 때 가능하면 필드를 private으로 선언해서 외부로부터 보호하고, 필드에 대한 Setter와 Getter 메소드를 작성해서 필드값을 안전하게 변경/사용하는 것이 좋다.
필드 타입이 boolean 일 경우에는 Getter은 get으로 시작하지 않고 is로 시작하는 것이 관례이다.
private 타입 fieldName;
private boolean stop;
//Getter
public 리턴타입 getFieldName(){
return fieldName;
}
//Setter
public void setFieldName(){
this.fieldName = fieldName;
}
//Getter
public boolean isStop(){
return stop;
}
//Setter
public void setStop(boolean stop){
this.stop = stop;
}
만약 필드값을 읽기전용으로 만들고 싶다면, Getter 메소드만 선언하거나 Setter메소드를 private 접근 제한을 갖도록 선언한다.
이클립스의 메뉴 [Source → Generate Getters and Setter]를 이용해서 Getter와 Setter의 자동생성이 가능하다.
45 Getter와 Setter 메소드 선언
package BookExampleHomeWork;
public class Car6 {
//필드
private int speed;
private boolean stop;
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
if(speed <0) {
this.speed = 0;
return; //잘못된 매개값이면 메소드 종료
} else { //매개값이 맞으면 필드값 변경
this.speed = speed;
}
}
public boolean isStop() {
return stop;
}
public void setStop(boolean stop) {
this.stop = stop; //stop 상태를 바꾸고 speed를 바꾸는 메소드
this.speed = 0;
}
}
46 Getter와 Setter 메소드 사용
package BookExampleHomeWork;
public class CarExample5 {
public static void main(String[] args) {
Car6 myCar = new Car6();
// 잘못된 속도 변경
myCar.setSpeed(-50);
System.out.println("현재 속도: " + myCar.getSpeed());
// 올바른 속도 변경
myCar.setSpeed(60);
// 멈춤
if (!myCar.isStop()) { //isStop의 리턴값이 false일 경우(=조건이 true, 자동차는 달리는중) setStop 호출 > 자동차를 멈춘다.
myCar.setStop(true);
}
System.out.println("현재 속도: " + myCar.getSpeed());
}
}