[Java]패키지와 접근 제한자

Devlog·2024년 3월 12일

Java

목록 보기
16/41

✔️ 패키지(package)

: 물리적인 형태는 파일 시스템의 폴더
: 단순히 파일 시스템의 폴더 기능만 하는 것이 아니라 클래스의 일부분으로,
  클래스를 유일하게 만들어주는 식별자 역할도 함
: 클래스 이름이 동일하더라도 패키지가 다르면 다른 클래스로 인식함


✔️ 패키지 선언

package 상위패키지.하위패키지;

: 해당 클래스가 어떤 패키지에 속할 것인지를 선언하는 것
: 패키지는 클래스의 일부임
  → 클래스만 따로 복사해서 다른 곳으로이동하면 클래스를 사용할 수 없기 때문
     만약 클래스를 이동해야 한다면 패키지 전체를 이동시켜야함
: 패키지 선언이 없는 클래스를 default 패키지(패키지가 없다는 뜻) 포함 시킴


✔️ import문

import 상위패키지.하위패키지.클래스이름;
import 상위패키지.하위패키지.*;

: 사용하고자 하는 클래스 또는 인터페이스가 다른 패키지에 소속되어 있다면,
  import문으로 해당 패키지의 클래스 또는 인터페이스를 가져와 사용할 것임을   컴파일러에게 알려줘야함
: 사용하고자 하는 클래스들이 동일한 패키지 소속이라면
  개별 import문을 작성하는 것보다
  *를 이용해서 해당 패키지에 소속된 클래스들을 사용할 것임
  알려주는 것도 좋은 방법


✔️ 접근 제한자(Access Modifier)

- 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

  • 적용대상: 필드, 생성자, 메소드
  • 접근할 수 없는 클래스: 모든 외부 클래스

✔️ Getter와 Setter 메소드

- Setter

: 일반적으로 객체 지향 프로그래밍에서는
  객체의 필드를 객체 외부에서 직접적으로 접근하는 것을 막음
  → 외부에서 마음대로 변경할 경우
  객체의 무결성(결점이 없는 성질)이 깨질 수 있기 때문
ex) 자동차의 속도는 음수가 될 수 없는데,
외부에서 음수로 변경하면 객체의 무결성이 깨짐

: 무결성이 깨지는 문제를 해결하기 위해
  메소드를 통해서 필드를 변경하는 방법을 선호함
: 필드는 외부에서 접근할 수 없도록 막고 메소드는 공개해서
  외부에서 메소드를 통해 필드에 접근하도록 유도함
  → 메소드는 매개값을 검증해서 유효한 값만 객체의 필드로 저장할 수 있기 때문

- Getter

: 외부에서 객체의 데이터를 읽을 때도 메소드를 사용하는 것이 좋음
→ 필드값을 직접 사용하면 부적절한 경우도 있기 때문
: 이런 경우에는 메소드로 필드값을 가공한 후 외부로 전달 하면 됨

- 클래스를 선언할 때 가능하다면
  필드를 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를 자동 생성시킴

👩‍💻 GetterSetter 메소드 선언

//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

0개의 댓글