접근 제어자 이해
자바는 public, private 같은 접근 제어자를 제공, 접근 제어자를 사용하면 해당 클래스 외부에서 트정 필드나 메서드에 접근하는 것을 허용, 제한
public class Speaker {
private int volume;
Speaker(int volume) {
this.volume = volume;
}
void volumeUp() {
if (volume >= 100) {
System.out.println("음량을 증가 할 수 X");
} else {
volume += 10;
System.out.println("음량을 10 증가 합니다");
}
}
void volumeDown() {
volume -= 10;
System.out.println("음량을 10 줄입니다");
}
void showVolumeInfo(){
System.out.println("현재 음량 " + volume);
}
}
public class SpeakerMain {
public static void main(String[] args) {
Speaker speaker = new Speaker(90);
speaker.volumeUp();
speaker.showVolumeInfo();
speaker.volumeUp();
speaker.showVolumeInfo();
speaker.volumeDown();
speaker.showVolumeInfo();
}
}

Speaker 객체를 사용하는 사용자는 Speaker volume 필드와 메서드에 모두 접근 가능
volumeUp에 100까지만 이라는 제한을 두었지만, Speaker를 사용하는 입장에서는 volume 필드에 직접 접근해서 원하는 값을 설정 가능
접근 제어자 이해
public class Speaker {
private int volume;
private으로 변경시 외부 호출을 막는다.

volume 필드는 이제 Speaker 내부에서만 접근 가능.
만약 임의적으로 변경한다면, CompileError
접근 제어자 종류
private -> 모든 외부 호출을 막는다.
default -> 같은 패키지 안에서 호출을 막는다.
protected -> 같은 패키지안에서만 호출은 허용. 패키지가 달라도 상속관계라면 허용
public -> 다 허용
package-private
접근 제어자를 명시하지 않으면 같은 패키지 안에서 호출을 허용, default 접근 제어자가 적용
default라는 용어는 해당 접근 제어자가 기본값으로 사용, 실제로는 package-private이 더 정확한 표현.
왜냐하면 해당 접근 제어자를 사용하는 멤버는 동일한 패키지 내의 다른 클래스에서만 접근 가능
접근 제어자 사용 위치
접근 제어자는 필드와 메서드, 생성자에 사용
접근 제어자 예시
public class Speaker { //클래스 레벨
private int volume; //필드
public Speaker(int volume) {} //생성자
public void volumeUp() {} //메서드
public void volumeDown() {}
public void showVolume() {}
}
private -> 나의 클래스 안으로 속성과 기능을 숨길때 사용. 외부 클래스에서 해당 기능을 호출
default -> 나의 패키지 안으로 속성과 기능을 숨길때 사용, 외부 패키지에서 해당 기능을 호출
protected -> 상속관계로 속성과 기능을 숨길때 사용, 송속 관계가 아닌 곳에서 해당 기능을 호 출 할 수 X
public -> 기능을 숨기지 않고 어디서든 호출 할 수 있게 공개
접근 제어자용 -> 필드, 메서드
public class AccessData {
public int publicField;
int defaultField;
private int privateField;
public void publicMethod(){
System.out.println("publicField = " + publicField);
}
void defaultMethod(){
System.out.println("defaultField = " + defaultField);
}
private void privateMethod(){
System.out.println("privateField = " + privateField);
}
public void innerAccess(){
System.out.println("내부 호출");
publicField = 100;
defaultField = 100;
privateField = 100;
publicMethod();
defaultMethod();
privateMethod();
}
}
public class AccessInnerMain {
public static void main(String[] args) {
AccessData data = new AccessData();
//public
data.publicField = 1;
data.publicMethod();
//default
data.defaultField = 2;
data.defaultMethod();
//private은 호출 X
data.innerAccess();
}
}
public class PublicClass {
public static void main(String[] args) {
PublicClass publicClass = new PublicClass();
PublicClass2 publicClass2 = new PublicClass2();
PublicClass3 publicClass3 = new PublicClass3();
}
}
class PublicClass2 { //default
}
class PublicClass3 { //defualt
}
public class PublicClassInnerMain {
public static void main(String[] args) {
PublicClass publicClass = new PublicClass();
PublicClass2 publicClass2 = new PublicClass2();
PublicClass3 publicClass3 = new PublicClass3();
}
}
public class OuterMain {
public static void main(String[] args) {
AccessData data = new AccessData();
//public
data.publicField = 1;
data.publicMethod();
// data.defaultField = 2;
// System.out.println("defaultField = " + defaultField);
//private은 호출 X
data.innerAccess();
}
}
캡술화
데이터와 해당 데이터를 처리하는 메서드를 하나로 묶어서 외부에서의 접근 제한하는 것을 말함
캡슐화를 통해 데이터의 직접적 변경을 방지, 제한
캡슐화는 쉽게 이야기 해서 송성과 기능을 하나로 묶고, 외부에 꼭 필요한 기능만 노출, 나머지는 내부로 숨기는 것
객체의 데이터는 객체가 제공하는 기능인 메서드를 통해 접근
public class BankAccount {
private int balance;
public BankAccount() {
this.balance = 0;
}
public void deposit(int amount){
if (isAmountValid(amount)){
balance += amount;
} else {
System.out.println("유요하지 않은 금액 입니다");
}
}
public void withdraw(int amount){
if (isAmountValid(amount) && balance - amount >= 0){
balance -= amount;
} else {
System.out.println("유효하지 않은 금액 입니다.");
}
}
public int getBalance(){
return balance;
}
private boolean isAmountValid(int amount) {
return amount > 0;
}
}
public class BankAccountMain {
public static void main(String[] args) {
BankAccount bankAccount = new BankAccount();
bankAccount.deposit(10000);
bankAccount.withdraw(3000);
System.out.println("bankAccount = " + bankAccount.getBalance());
}
}
접근 제어자와 캡슐화를 통해 데어터를 안전하게 보호, BankAccount 사용하는 개발자 입장에서 해당 기능을 사용하는 난이도를 줄인다.
문제풀이
1.
package chap15.maxCounter;
public class MaxCounter {
private int count = 0;
private int max;
public MaxCounter(int max) {
this.max = max;
}
void increment() {
if (count >= max){
System.out.println("최대 값을 초과 할 수 없습니다 " + count);
}
count++;
System.out.println("값을 증가" + count);
}
public int getCount() {
return count;
}
}
public class CounterMain {
public static void main(String[] args) {
MaxCounter maxCounter = new MaxCounter(3);
maxCounter.increment();
maxCounter.increment();
maxCounter.increment();
maxCounter.increment();
int cnt = maxCounter.getCount();
System.out.println(cnt);
}
}
public class Item {
private String name;
private int price;
private int quantity;
public Item(String name, int price, int quantity) {
this.name = name;
this.price = price;
this.quantity = quantity;
}
public String getName(){
return name;
}
public int getTotalPrice(){
return quantity * price;
}
}
public class ShoppingCart {
private Item[] items = new Item[10];
private int itemCnt;
public void addItem(Item item) {
if (itemCnt >= items.length) {
System.out.println("장바구나 가득 참");
return;
}
items[itemCnt] = item;
itemCnt++;
}
public void showInfo(){
System.out.println("장바구니 상품 출력");
for (int i = 0; i < itemCnt; i++) {
Item item = items[i];
System.out.println("상품명 " + item.getName()
+ item.getTotalPrice());
}
System.out.println("전체 가격 합 " + calculateTotalPrice());
}
private int calculateTotalPrice() {
int totalPrice = 0;
for (int i = 0; i < itemCnt; i++) {
Item item = items[i];
totalPrice += item.getTotalPrice();
}
return totalPrice;
}
}
public class ShoppingCartMain {
public static void main(String[] args) {
}
}