- 이러한 접근 제어자를 사용하여 적절한 접근 범위를 설정함으로써 클래스와 멤버의 캡슐화를 유지하고 응집도를 높이며 코드의 재사용성과 유지보수성을 향상할 수 있습니다.
[ 더 알아보기 ]
💡 클래스의 멤버 - 클래스 내에서 정의된 변수와 메서드를 의미합니다.
- '클래스의 멤버'는 클래스의 객체 또는 인스턴스를 생성할 때 사용됩니다. - '클래스의 멤버 변수'는 클래스의 속성이나 상태를 나타내는 데 사용됩니다. - '클래스의 멤버 메서드'는 클래스의 동작이나 기능을 정의합니다.
1. 접근 제어자의 종류
💡 접근 제어자의 종류
- 접근 제어자는 public, protected, default, private가 있습니다. - 아래의 이미지는 각각 접근 제어자의 범위를 알려줍니다.
접근 제어자
설명
public
해당 제어자는 ‘어떤 클래스에서든 접근이 가능‘합니다.
protected
해당 제어자는 ‘같은 패키지 내‘에서 또는 해당 클래스를 ‘상속 받은 클래스‘에서 접근 가능합니다.
default
해당 제어자는 제어자는 명시하지 않는 경우를 의미하며, ‘같은 패키지 내에서만 접근 가능‘합니다.
private
해당 제어자는 ‘같은 클래스 내에서만 접근 가능‘합니다
public
💡 public
- 클래스, 메서드 또는 필드가 다른 클래스나 패키지에서 접근할 수 있도록 선언하는 데 사용되는 제어자입니다.
- 클래스, 메서드 또는 필드가 public으로 선언되면 프로그램의 모든 다른 클래스와 패키지에서 접근할 수 있다는 의미입니다.
protected
💡 protected
- 클래스의 멤버(필드, 메서드)가 '같은 패키지' 내의 다른 클래스 또는 서브클래스에서 접근할 수 있도록 선언하는 데 사용됩니다.
default
💡 default
- 클래스, 메서드 또는 필드가 ‘같은 패키지 내’의 다른 클래스에서만 접근할 수 있도록 선언하는 데 사용됩니다.
- default 접근 제어자는 별도의 키워드 없이 접근 제어자를 지정하지 않았을 때 기본적으로 적용되는 접근 제어자입니다.
private
💡 private - ‘클래스 내부’에서만 접근할 수 있는 멤버를 선언하는데 사용됩니다.
- private으로 선언된 멤버는 클래스 외부에서 직접 접근할 수 없으며, 해당 클래스의 메서드를 통해서만 접근할 수 있습니다.
2. 접근 제어자의 사용 가능 범위
💡 접근 제어자의 사용 가능 범위
- 클래스, 생성자, 멤버 변수, 멤버 클래스, 지역 변수 내에서 접근 제어자가 사용이 가능한 범위에 대해 확인해 봅니다.
위치
사용가능 접근제한자
클래스
public, default
생성자
public, protected, default, private
멤버 변수
public, protected, default, private
멤버 클래스
public, protected, default, private
지역 변수
사용 불가능
2) 접근 제어자의 사용 목적
1. 캡슐화
💡 캡슐화
- 접근 제어자를 사용하여 ‘클래스의 멤버’에 대한 접근을 제한함으로써 캡슐화를 구현할 수 있습니다. - 이를 통해 클래스의 내부 구현 세부사항을 숨기고 외부에서 직접 접근하지 못하도록 함으로써 안정성과 유지 보수성을 높일 수 있습니다.
💡 캡슐화 사용예시
- Car라는 클래스에서 멤버 변수로 brand를 선언하였습니다. - 해당 brand 변수는 클래스 내에만 유효한 ‘private’ 접근 제어자로 지정을 하였습니다. - 그렇기에 외부에서 해당 변수를 접근할 수 있는 방법은 없지만 getter/setter를 통해 직접적인 변수 접근 및 변경이 아닌 메서드를 통한 접근이 가능하도록 구성을 하여 캡슐화를 구성하였습니다.
public class Car {
private String brand; // private 접근 제어자를 사용하여 brand 변수에 접근을 제한
public String getBrand() { // public 메소드를 통해 brand 변수에 접근
return brand;
}
public void setBrand(String brand) { // public 메소드를 통해 brand 변수를 수정
this.brand = brand;
}
}
2. 데이터 보호
💡 데이터 보호
- 접근 제어자를 사용하여 ‘멤버 변수에 대한 접근을 제한’함으로써 데이터의 무결성과 안정성을 보호할 수 있습니다. - 외부에서 무작위로 데이터를 수정하는 것을 방지하고, 유효한 메서드를 통해만 데이터에 접근할 수 있도록 합니다.
💡 데이터 보호 사용예시
- BankAccount라는 클래스에서 멤버 변수로 balance를 선언하였습니다. - 해당 balance 변수는 클래스 내에만 유효한 ‘private’ 접근 제어자로 지정을 하였습니다. - 그렇기에 외부에서 해당 변수에 대해 직접적인 접근이 불가능하지만 deposit(), withdraw() 메서드를 통해서 변수를 조작하여 반환하여 데이터 값을 반환하도록 구성하였습니다.
public class BankAccount {
private double balance; // private 접근 제어자를 사용하여 balance 변수에 접근을 제한
public double getBalance() { // public 메소드를 통해 balance 변수에 접근
return balance;
}
public void deposit(double amount) { // public 메소드를 통해 balance 변수를 수정
balance += amount;
}
public void withdraw(double amount) { // public 메소드를 통해 balance 변수를 수정
if (amount <= balance) {
balance -= amount;
} else {
System.out.println("Insufficient funds");
}
}
}
3. 코드 재사용
💡 코드 재사용
- 접근 제어자를 사용하여 상속 관계에서 부모 클래스의 메서드와 변수를 하위 클래스에서 재사용할 수 있습니다. - 이를 통해 코드의 중복을 피하고, 효율적인 개발을 할 수 있습니다.
💡 사용 예시
- Animal이라는 클래스와 Dog라는 클래스가 있으며 Dog 클래스는 Animal로부터 상속을 받은 관계입니다. - Animal 클래스에서는 protected 접근 제어자를 두고 멤버 변수를 선언하였기에, Dog 클래스에서는 Animal 클래스의 멤버 변수에 대한 접근이 가능합니다. - 또한 상속관계이기에 Dog 클래스의 인스턴스를 생성 후 eat() 메서드 접근 역시 가능합니다.
public class Animal {
protected String name; // protected 접근 제어자를 사용하여 name 변수에 접근
public Animal(String name) {
this.name = name;
}
public void eat() {
System.out.println(name + " is eating");
}
}
public class Dog extends Animal {
public Dog(String name) {
super(name);
}
public void bark() {
System.out.println(name + " is barking");
}
}
public class Main {
public static void main(String[] args) {
Dog dog = new Dog("Buddy");
dog.eat(); // 상위 클래스인 Animal의 eat 메소드 재사용
dog.bark(); // 하위 클래스인 Dog의 bark 메소드 사용
}
}
3) 접근 제어자(Access Modifier) 사용 예시
1. 사용 예시 구조
💡 사용 예시 구조
- 호출을 받을 클래스 선언부로 AClass라는 이름의 클래스를 구성하였습니다. - 그리고 호출을 하는 BClass라는 이름의 클래스를 구성하였습니다.
1.1. 클래스 선언부 : AClass
💡 클래스 선언부 : AClass - 해당 클래스의 구조는 모두 접근이 가능한 public class로 접근 제어자를 두었습니다. - 클래스 내에 멤버 변수로 접근 제어자 public, protected, default, private으로 선언을 하였습니다.
package com.adjh.multiflexapi;
public class AClass {
/**
* 클래스의 멤버 변수에 대해 접근 제어자를 확인하봅니다.
*/
// public
public String publicUserNickname = "adjh54";
// protected
protected String protectedUserNickname = "adjh54";
// default
String defaultUserNickname = "adjh54";
// private
private String privateUserNickname = "adjh54";
}
1.2. 클래스 호출부 : BClass
💡 클래스 호출부 : BClass - 해당 클래스의 구조는 모두 접근이 가능한 public class로 접근 제어자를 두었습니다. - 실제 AClass로 인스턴스를 생성하고 멤버 변수를 호출하는 클래스입니다
package com.adjh.multiflexapi.test2;
public class BClass {
public void callAClass() {
}
}
💡 아래와 같이 사용예시를 확인해 볼 예정입니다.
사용 예시
접근 가능
두 개의 클래스가 같은 패키지에 있는 경우
public, default, protected
두 개의 클래스가 다른 패키지에 있는 경우
public
두 개의 클래스가 같은 패키지에 있고 클래스 간 상속 관계인 경우
public, protected
두 개의 클래스가 다른 패키지에 있고 클래스 간 상속 관계인 경우
public, protected
사용예시 -1 : 두 개의 클래스가 같은 패키지에 있는 경우
💡 사용예시 -1 : 두 개의 클래스가 같은 패키지에 있는 경우
- 아래와 같이 AClass와 BClass는 동일한 test라는 패키지 내에 소속되어 있습니다.
💡 멤버 변수 호출
- 아래와 같이 BClass에서 AClass의 인스턴스를 생성하고 멤버 변수에 접근합니다.
- 아래의 표와 같이 같은 클래스에만 있어야 하는 private를 제외하고는 모두 접근이 잘됨을 확인하였습니다.
사용예시 -2 : 두 개의 클래스가 다른 패키지에 있는 경우
💡 사용 예시 -2 : 두 개의 클래스가 다른 패키지에 있는 경우
- 아래와 같이 AClass는 test 패키지에 속해 있고, BClass는 test2 패키지에 속해 있는 경우입니다.
💡 멤버 변수 호출 - 아래와 같이 BClass에서 AClass의 인스턴스를 생성하고 멤버 변수에 접근합니다.
- 아래의 표와 같이 같은 클래스, 같은 패키지에 있는 경우 접근이 허용되는 경우는 public만 가능함을 확인하였습니다.
사용예시 -3 : 두 개의 클래스가 같은 패키지에 있고 클래스 간 상속 관계인 경우
💡 사용예시 -3 : 두 개의 클래스가 같은 패키지에 있고 클래스 간 상속 관계인 경우
- 아래와 같은 AClass와 BClass는 동일한 test라는 패키지 내에 소속되어 있고, BClass는 AClass로부터 상속을 받는 관계입니다.
💡 멤버 변수 호출
- 아래와 같은 AClass와 BClass는 동일한 test라는 패키지 내에 소속되어 있습니다.
- 아래의 표와 같이 같은 클래스, 같은 패키지에 있는 경우이며 상속 관계가 있는 경우는 public, protected만 접근이 가능함을 확인하였습니다.
사용예시 -4 : 두 개의 클래스가 다른 패키지에 있고 클래스 간 상속 관계인 경우
💡 사용예시 -4 : 다른 패키지, 상속 관계에 있는 경우
- 아래와 같은 AClass는 test라는 패키지, BClass는 test2라는 패키지 내에 소속되어 있고, BClass는 AClass로부터 상속을 받는 관계입니다.
💡 멤버 변수 호출
- 아래와 같은 AClass는 test라는 패키지, BClass는 test2라는 패키지 내에 소속되어 있습니다.
- 아래의 표와 같이 다른 패키지에 있는 경우이며, 상속 관계가 있는 경우는 public, protected만 접근이 가능함을 확인하였습니다. (* protected는 같은 패키지 or 상속관계에서 허용됩니다.)