: 물리적인 형태는 파일 시스템의 폴더임
: 단순히 파일 시스템의 폴더 기능만 하는 것이 아니라 클래스의 일부분으로,
클래스를 유일하게 만들어주는 식별자 역할도 함
: 클래스 이름이 동일하더라도 패키지가 다르면 다른 클래스로 인식함
package 상위패키지.하위패키지;
: 해당 클래스가 어떤 패키지에 속할 것인지를 선언하는 것
: 패키지는 클래스의 일부임
→ 클래스만 따로 복사해서 다른 곳으로이동하면 클래스를 사용할 수 없기 때문
만약 클래스를 이동해야 한다면 패키지 전체를 이동시켜야함
: 패키지 선언이 없는 클래스를 default 패키지(패키지가 없다는 뜻) 포함 시킴
import 상위패키지.하위패키지.클래스이름;
import 상위패키지.하위패키지.*;
: 사용하고자 하는 클래스 또는 인터페이스가 다른 패키지에 소속되어 있다면,
import문으로 해당 패키지의 클래스 또는 인터페이스를 가져와 사용할 것임을 컴파일러에게 알려줘야함
: 사용하고자 하는 클래스들이 동일한 패키지 소속이라면
개별 import문을 작성하는 것보다
*를 이용해서 해당 패키지에 소속된 클래스들을 사용할 것임을
알려주는 것도 좋은 방법
- public, protected, private
■ default 접근 제한
class 클래스 { ··· }
: 같은 패키지에서는 아무런 제한 없이 사용가능
다른 패키지에서는 사용 불가능
■ public 접근 제한
public class 클래스 { ··· }
: 같은 패키지뿐만 아나라 다른 패키지에서도 아무런 제한 없이 사용 가능
- public 접근 제한자: 외부 클래스가 자유롭게 사용할 수 있음
- protected 접근 제한자: 같은 패키지 또는 자식 클래스에서 사용할 수 있도록 함
- private 접근 제한자: 개인적인것이라 외부에서 사용될 수 없도록 함
→ public, protected, private 접근 제한자가 적용되지 않으면
default 접근 제한을 가짐
- default 접근 제한: 같은 패키지에 소속된 클래스에서만 사용할 수 있도록 함
: 객체를 생성하기 위해서는 new 연산자로 생성자를 호출
public class ClassName {
//public 접근 제한
public ClassName( ··· ) { ··· }
//protected 접근 제한
protected ClassName( ··· ) { ··· }
//default 접근 제한
ClassName( ··· ) { ··· }
//private 접근 제한
private ClassNmae( ··· ) { ··· }
}
- public 접근 제한
: 모든 패키지에서 아무런 제한 없이 생성자를 호출할 수 있도록 함
- protected 접근 제한
: default 접근 제한과 마찬가지로
같은 패키지에 속하는 클래스에서 생성자를 호출할 수 있도록 함.
차이점으로 다른 패키지에 속한 클래스가
해당 클래스의 자식 클래스라면 호출 가능
- default 접근 제한
: 같은 패키지에서는 아무런 제한 없이 생성자를 호출할 수 있으나,
다른 패키지에서는 생성자를 호출할 수 없도록함
- private 접근 제한
: 동일한 패키지이건 다른 패키지이건 상관없이
생성자를 호출하지 못하도록 제한됨
오로지 클래스 내부에서만 생성자를 호출할 수 있고 객체를 만들 수 있음
1. class A
package sec06.exam04.package1;
public class A {
//필드
A a1 = new A(true);
A a2 = new A(1);
A a3 = new A("문자열");
//생성자
public A(boolean b) {} // public 접근 제한
A(int b) {} //default 접근 제한
private A(String s) {} //private 접근 제한
}
2. class B
package sec06.exam04.package1; //패키지 동일
public class B {
//필드
A a1 = new A(true); //(o)
A a2 = new A(1); //(o)
A a3 = new A("문자열"); // private 생성자 접근 불가(컴파일 에러)
}
3. class C
package sec06.exam04.package2; //패키지 다름
import sec06.exam04.package1.A;
public class C {
//필드
A a1 = new A(true); //(o)
A a2 = new A(1); // default 생성자 접근 불가(컴파일 에러)
A a3 = new A("문자열"); // private 생성자 접근 불가(컴파일 에러)
}
- 필드 선언
[public | protected | private][static] 타입 필드;
- 메소드 선언
[public | protected | private][static] 리턴 타입 메소드(···) { ··· }
- public 접근 제한
: 모든 패키지에서 아무런 제한 없이 필드와 메소드를 사용할 수 있도록 해줌
- protected 접근 제한
: 같은 패키지에 속하는 클래스에서 필드와 메소드를 사용할 수 있도록 함
default 접근 제한과 차이점으로는 다른 패키지에 속한 클래스가
해당 클래스의 자식 클래스라면 필드와 메소드를 사용할 수 있음
- default 접근 제한
: 필드와 메소드를 선언할 때 접근 제한자를 생략하면 default 접근 제한을 가짐
같은 패키지에서는 아무런 제한 없이 필드와 메소드를 사용할 수 있으나
다른 패키지에서는 필드와 메소드를 사용할 수 있음
- private 접근 제한
: 동일한 패키지이건 다른 패키지이건 상관없이
필드와 메소드를 사용하지 못하도록 제한함
오로지 클래스 내부에서만 사용 가능
1. class A
package sec06.exam05.package1;
public class A {
//필드
public int field1; //public 접근 제한
int field2; //default 접근 제한
private int field3; // private 접근 제한
//생성자
public A() {
// 클래스 내부일 경우 접근 제한자의 영향을 받지 않음
field1 = 1;
field2 = 1;
field3 = 1;
method1();
method2();
method3();
}
//메소드
public void method1() { } //public 접근 제한
void method2() { } //default 접근 제한
private void method3() { } //private 접근 제한
}
2. class B
package sec06.exam05.package1; //패키지 동일
public class B {
public B() {
A a = new A();
a.field1 = 1;
a.field2 = 1;
a.field3 = 1; //private 메소드 접근 불가
a.method1();
a.method2();
a.method3(); //private 메소드 접근 불가
}
}
3. class C
package sec06.exam05.package2; //패키지 다름
import sec06.exam05.package1.A;
public class C {
public C() {
A a = new A();
a.field1 = 1;
a.field2 = 1; //default 필드 접근 불가
a.field3 = 1; //private 메소드 접근 불가
a.method1();
a.method2(); //default 메소드 접근 불가
a.method3(); //private 메소드 접근 불가
}
}
[결론]
■ public
■ protected
■ default
■ private
: 일반적으로 객체 지향 프로그래밍에서는
객체의 필드를 객체 외부에서 직접적으로 접근하는 것을 막음
→ 외부에서 마음대로 변경할 경우
객체의 무결성(결점이 없는 성질)이 깨질 수 있기 때문
ex) 자동차의 속도는 음수가 될 수 없는데,
외부에서 음수로 변경하면 객체의 무결성이 깨짐
: 무결성이 깨지는 문제를 해결하기 위해
메소드를 통해서 필드를 변경하는 방법을 선호함
: 필드는 외부에서 접근할 수 없도록 막고 메소드는 공개해서
외부에서 메소드를 통해 필드에 접근하도록 유도함
→ 메소드는 매개값을 검증해서 유효한 값만 객체의 필드로 저장할 수 있기 때문
: 외부에서 객체의 데이터를 읽을 때도 메소드를 사용하는 것이 좋음
→ 필드값을 직접 사용하면 부적절한 경우도 있기 때문
: 이런 경우에는 메소드로 필드값을 가공한 후 외부로 전달 하면 됨
- 클래스를 선언할 때 가능하다면
필드를 private로 선언해서 외부로부터 보호하고,
필드에 대한 Setter와 Getter 메소드를 작성해서
필드값을 안전하게 변경/사용하는 것이 좋음
private 타입 fieldName; //필드 접근 제한자: private
/*
Getter
접근제한자: public
리턴 타입: 필드타입
메소드 이름: get+필드이름
리턴값: 필드값
→ 필드 타입이 boolean일 경우 Getter는
get으로 시작하지 않고 is로 시작하는 것이 관례임
*/
public 리턴 타입 getFieldName() {
return fieldName;
}
/*
Setter
접근 제한자: public
리턴 타입: void
메소드 이름: set+필드이름
매개변수타입: 필드타입
*/
public void setFieldName(타입 fieldName) {
this.fieldName = fieldName;
}
- Getter/Setter 메소드 자동 생성
: [Source] - [Generate Getters and Setters]메뉴를 선택하면
선언된 필드에 대한 Getter와 Setter를 자동 생성시킴
👩💻 Getter와 Setter 메소드 선언
//Car.java
public class Car {
//필드
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;
this.speed = 0;
}
}
//CarExample.java
public class CarExample {
public static void main(String[] args) {
Car myCar = new Car();
//잘못된 속도 변경
myCar.setSpeed(-50);
// speed필드의 Setter(setSpeed())에서
// 매개값을 검사한 후 0으로 변경하기 때문에
// Getter(getSpeed())의 리턴값은 0으로 나옴
System.out.println("혁재 속도: " + myCar.getSpeed());
//올바른 속도 변경
myCar.setSpeed(60);
//멈춤
if(!myCar.isStop()) {
// stop필드의 Getter(isStop()) 리턴값이 false일 경우,
// 자동차를 멈추기 위해 Setter(setStop(true))를 호출해서
// stop 필드를 true로,
// speed 필드를 0으로 변경
myCar.setStop(true);
}
System.out.println("현재 속도: " + myCar.getSpeed());
}
}
💻 결과
혁재 속도: 0
현재 속도: 0