제어자란?
클래스, 변수 또는 메서드 선언부와 함께 사용되어 부가적인 의미를 부여한다. 크게 접근제어자와 그 외의 제어자로 나뉜다.
접근제어자
접근제어자란 외부에서 접근하지 못하도록 제한하는 역할을 한다. 클래스, 멤버변수, 메서드, 생성자에 사용할 수 있다.
이름 | 기능 |
public | 접근 제한이 없다. |
protected | 같은 패키지 내에서, 다른 패키지의 자손클래스에서 접근 가능 |
default | 같은 패키지 내에서만 접근 가능 |
private | 같은 클래스 내에서만 접근 가능 |
접근 범위는 public -> proteced -> (default) -> private 으로 오른쪽으로 갈 수록 범위가 좁아진다.
접근 제어자를 사용하는 이유?
정보은닉을 위해서, 즉 캡슐화를 하기 위함이다. 외부에게 불필요한 부분이 노출되는 것을 막고, 외부에서 잘못된 사용으로 객체의 손상, 오용을 막아 유지보수나 확장시 오류를 최소화 하기 위해서 입니다.
예를들어 간단히 설명드리겠습니다.
class People{
int gamePoint = 5000;
public void usePoint(int gamePoint) {
this.gamePoint -= gamePoint;
}
public int getGamePoint() {
return gamePoint;
}
}
public class Example {
public static void main(String[] args) {
People user1 = new People();
user1.gamePoint = 100000;
user1.usePoint(50);
System.out.println(user1.getGamePoint());
}
}
People 클래스에는 게임포인트라는 멤버변수가 있습니다. 접근 제어자를 default로 설정하였기 때문에 같은 패키지내에서 gamePoint라는 인스턴스 변수에 접근이 가능합니다. 외부에 노출되어 있는 상태이죠. 그래서 user1 이라는 인스턴스를 생성하고 게임 포인트를 마음대로 외부에서 조작이 가능하게 됩니다. 이러면 운영에 있어서 큰 문제가 발생하겠죠?
해결방법은 방금 배운 접근제어자인 private를 써서 접근을 제한하면 위의 문제가 해결됩니다.
class People{
private int gamePoint = 5000;
public void usePoint(int gamePoint) {
this.gamePoint -= gamePoint;
}
public int getGamePoint() {
return gamePoint;
}
}
public class Example {
public static void main(String[] args) {
People user1 = new People();
// user1.gamePoint = 100000; 에러! 접근 불가
user1.usePoint(50);
System.out.println(user1.getGamePoint());
}
}
접근 제어자를 private로 설정하여 외부에서 접근이 불가하도록 막았습니다. 이제 게임포인트에 직접 접근할 수 없는 상태입니다.
생성자의 접근제어자
생성자에도 접근제어자를 사용할 수 있습니다. 접근제어자를 사용하면 인스턴스의 생성을 제한 할 수 있습니다. 보통은 생성자의 접근 제어자는 해당 클래스와 같지만 다르게도 설정이 가능합니다. 싱글톤 패턴에 활용이 되고, 생성자가 private이면 다른 클래스의 부모가 될 수 없습니다. 왜냐하면 상속받은 자식 클래스가 부모클래스의 생성자를 호출할 수 없기 때문입니다.
그래서 상속할 수 없는 클래스같은 경우에는 final 같은 제어자를 추가하여 상속할 수 없는 클래스라는 것을 알리는게 좋습니다.
그 외 제어자
static, final, abstract, native, trasient 등등이 있지만 static, final, abstract 정도만 정리를 하겠습니다.
static - 클래스의, 공통적인
static 은 '클래스의' or '공통적인' 이라는 의미를 가지고 있으며 멤버변수, 메서드, 초기화 블럭에 사용이 가능합니다.
제어자 | 대상 | 의미 |
static | 멤버변수 | - 모든 인스턴스에 공통적으로 사용되는 클래스변수가 된다. - 클래스 변수는 인스턴스 생성없이 사용이 가능하다. - 클래스가 메모리에 로드될 때 생성이 됨. |
메서드 | - 인스턴스를 생성하지 않고도 호출이 가능한 static메서드가 된다. - static 메서드 내에서는 인스턴스멤버들을 직접 사용이 불가 ->(아직 생성이 안됐을 경우가 있기 때문에) |
final - 마지막의, 변경될 수 없는
final은 '마지막의' 또는 '변경될 수 없는' 의미를 가지고 있으며 클래스, 메서드, 멤버변수, 지역변수에 사용이 가능합니다.
제어자 | 대상 | 의미 |
final | 클래스 | - 변경불가 클래스, 확장될 수 없는 클래스 - 다른 클래스의 부모가 될 수 없다. |
메서드 | - 변경불가 메서드, final로 지정된 메서드는 오버라이딩을 통한 재정의가 불가 | |
멤버변수 | - 변수 앞에 사용이 되면, 값을 변경할 수 없는 상수가 된다. | |
지역변수 |
* final 이 붙은 변수는 상수이기 때문에 일반적으로 선언과 동시에 초기화를 하지만 인스턴스 변수의 경우 생성자에서 초기화 될 수 있게 한다. 그래서 각 인스턴스마다 final 이 붙은 멤버변수가 다른 값을 가질 수 있다.
class People{
private final int gamePoint;
// 에러가 발생한다. final 이 붙은 변수를 변경하려고 했기 때문이다.
// public void usePoint(int gamePoint) {
// this.gamePoint -= gamePoint;
// }
public int getGamePoint() {
return gamePoint;
}
}
public class Example {
public static void main(String[] args) {
People user1 = new People(5000);
People user2 = new People(700);
People user3 = new People(9820);
System.out.println(user1.getGamePoint());
System.out.println(user2.getGamePoint());
System.out.println(user3.getGamePoint());
}
}
abstract - 추상의, 미완성의
abstract 는 '미완성' 의 의미를 가지고 있으며 클래스, 메서드에 사용이 됩니다.
제어자 | 대상 | 의미 |
abstract | 클래스 | - 클래스 내에 추상 메서드가 선언되어 있음을 의미 |
메서드 | - 선언부만 작성하고 구현부는 작성하지 않은 추상메서드임을 알린다. |
추상클래스
미완성 설계도에 비유할 수 있다. 추상클래스로는 인스턴스 생성이 불가하며, 상속을 통하여 자식클래스에서 완성(구체화)이 가능하다.
-> 새로운 클래스를 작성하는데 공통부분을 가지는 틀이 될 수 있다. 즉 효율적으로 새로운 클래스를 작성할 수 있게 된다.
- 추상화 : 클래스 간의 공통점을 찾아내 공통의 부모로 만드는 작업
- 구체화 : 상속을 통해 클래스를 구현, 확장하는 작업
추상메서드
선언부만 작성하고 구현부는 작성하지 않는다. 이유는 상속받는 클래스에 따라 기능이 달라질 수 있기 때문이다.
구현부가 없는 메서드가 뭐가 좋고, 어떤 의미를 가지냐고 생각 할 수 있지만, 메서드의 이름과 매개변수, 리턴값을 정하는 것은 쉽지 않다. 이 선언부만 알고 있으면 내용이 없을 지라도 코드작성이 가능하며, 실제로는 자식클래스에 구현된 완성된 메서드가 호출되도록 할 수 있다.
추상 클래스, 메서드 사용 예)
abstract class Item{
abstract void buyItem(int quantity);
}
class Book extends Item{
private static int stockQuantity = 1000;
@Override
void buyItem(int quantity) {
this.stockQuantity -= quantity;
}
public int getStockQuantity() {
return stockQuantity;
}
}
public class Example {
public static void main(String[] args) {
// Item item = new Item(); //인스턴스 생성 부락
Book book = new Book();
book.buyItem(50);
System.out.println("남은 재고 = " + book.getStockQuantity() + " 개");
}
}
예제에서는 Book 클래스만 구현을 했는데, 재고가 쌓일만한 어떠한 물건이라도 클래스를 만들어 해당 물건을 몇개만큼 구입을 하면 남은 재고를 출력할 수 있도록 만들 수 있습니다.
긴글 읽어주셔서 감사합니다. 예제가 잘못되었거나 질문이 있으시면 언제든 댓글달아주시면 빠르게 답변하도록 하겠습니다.
'자바 (ref. 자바의정석)' 카테고리의 다른 글
함수형 프로그래밍 + 람다(재정리) JAVA (0) | 2022.06.19 |
---|---|
Object 클래스 - JAVA (0) | 2022.04.11 |
기본형 매개변수와 참조형 매개변수 - JAVA (0) | 2022.04.04 |
기본형(Primtive Type) - JAVA (0) | 2022.03.28 |
람다식(Lambda expression) - JAVA (0) | 2022.03.17 |