5. JAVA API_12 ACCESS MODIFIER AND GETTER,SETTER

jaegeunsong97·2022년 11월 20일
0

[Inflearn] 홍팍 자바

목록 보기
12/15

만약 당신의 지갑이 누구에게나 공개되어있다면..? 생각만 해도 끔찍하다.

프로그램에서 또한 마찬가지다. 어떤 건 공개해도 되지만, 어떠한 것은 감추어야만 한다. 이를 위한 개념을 배워보자.
접근 제한자란
public과 private
게터와 세터

Access modifier

access modifier >> 접근 제한자란, 접근 권한을 제한하는 키워드다.
why use? >> 여러분의 지갑이 모두에게 공개돼있다면? 또는 여러분의 개인 정보가 외부에 모두 알려졌다면 어떨까? 안될 것이다. 이를 해결하기 위한 키워드. 바로 접근 제한자다.
type >> 접근 제한자의 종류는 총 4가지로, 외부 접근을 거부하는 private(비공개)에서부터 모든 접근을 허용하는 public(완전 공개)까지 존재한다.

Public and private

public and private >> public 키워드는 완전한 공개를 의미한다. 모두가 사용할 수 있는 공공의 산물이 되는 것이다. 이와 반면 private은 비공개를 의미한다. 오직 해당 클래스 내부에서만 사용할 수 있게 된다.

apply and benefit >> 접근 제한자는 필드와 메소드에 적용될 수 있다. public 선언되면 외부의 접근이 가능하나, private의 경우 외부 접근이 불가능하다.

이를 통해 외부의 악의적 접근을 예방할 수 있다.

Getter and setter

why need? >> private 선언된 필드는 외부 접근이 불가능하다. 심지어 정상적인 사용자도 직접 접근할 수 없다. 이를 해결하기 위해 게터와 세터가 필요하다.

rule >> 게터와 세터를 사용하면, private 필드를 우회하여 가져오거나 변경할 수 있다.

1) if no access modifier

객체의 정보를 외부로부터 보호하지 않는 경우, 데이터가 함부로 변경될 수 있습니다.

이러한 문제를 예방하기 위해, 적절한 접근 제한자가 필요합니다. 접근 제한자의 종류는 크게 4가지이며, 필드와 메소드에 적용할 수 있습니다.

class AAA {
  /* 필드 */
  private String aaa;   // 비공개
  int bbb;              // 디폴트 공개
  protected double ccc; // 상속 공개
  public boolean ddd;   // 완전 공개
  /* 메소드 */
  private void eee() {}     // 비공개
  int fff() {}              // 디폴트 공개
  protected double ggg() {} // 상속 공개
  public boolean hhh() {}   // 비공개
}

CODE

public class Main {
  public static void main (String[] args) {
    // 1. 계좌 생성
    Account myAccount = new Account(1000000);
    System.out.println(myAccount.toString());
    // 2. 계좌 해킹
    Hacker.malcious(myAccount);
    // 3. 결과 출력
    System.out.println(myAccount.toString());
  }
}
class Account {
  // 필드
  int balance;
  // 생성자
  public Account(int balance) {
    this.balance = balance;
  }
  // 메소드
  public String toString() {
    return String.format("Account { balance: %d }", balance);
  }
}
class Hacker {
  // 클래스 메소드 - 계좌의 잔액을 0원으로 변경
  public static void malcious(Account account) {
    /* 1. 파라미터 계좌의 잔액을 0으로 변경하세요. */
    account.balance = 0;
  }
}

2) private

private >> private 키워드는 외부 접근을 차단합니다

example code >> 위 그림을 코드로 나타내면 아래와 같습니다. 외부 클래스에서 해당 내용을 사용할 수 없습니다.

class Account {
  public int number;       // 완전 공개 필드
  private String password; // 비공개 필드
  private int balance;     // 비공개 필드
  // 비공개 메소드 - 외부 호출 불가
  private void somthing() {}
}

CODE

public class Theif {
  // 메인 메소드
  public static void main(String[] args) {
    // 지갑 객체 생성
    Wallet wallet = new Wallet(30000);
    System.out.print(wallet.toString());
    // 지갑에서 돈을 모두 꺼냄
    Theif.steal(wallet);
    // 지갑 확인
    System.out.println(" -> " + wallet.toString());
  }
  // 클래스 메소드
  public static void steal(Wallet target) {
    target.money = 0;
  }
}
class Wallet {
  // 필드(인스턴스 변수)
  private int money; /* 1. 주어진 필드를 외부로부터 감추세요. */
  // 생성자
  public Wallet(int i) {
    money = i;
  }
  // 메소드
  public String toString() {
    return String.format("Wallet { money: %d }", money);
  }
}

3) getter

private field >> private 필드는 외부에서 직접 값을 가져올(read) 수 없습니다. 이를 외부에서 읽기 위해서는 게터 메소드가 필요합니다.

getter >> 게터(getter)는, private 필드를 우회적으로 접근(read)하게 합니다.

class SmartPhone {
  // private 필드 - 외부 접근 불가
  private int number;
  // 게터 메소드 - number를 우회하여 반환
  public int getNumber() {
    return number;
  }
}

getter character >> 게터 메소드는 아래의 특징을 갖습니다.
private 필드를 반환한다.
public 이다.
메소드명은 get + 필드명으로 한다
CODE

public class PersonTest {
  public static void main(String[] args) {
    // 객체 생성
    Person park = new Person("홍팍", "010-1234-5678");
    /* 1. 게터를 호출하여 필드값을 얻으시오. */
    System.out.printf("이 름: %s\n", park.getName());
    System.out.printf("연락처: %s\n", park.getPhonenumber());
  }
}
class Person {
  // 필드
  private String name;
  private String phoneNumber;
  // 생성자
  public Person(String n, String p) {
    name = n;
    phoneNumber = p;
  }
  // 게터
  public String getName() {
    return name;
  }
  /* 2. phoneNumber 필드의 게터를 추가하시오. */  
  public String getPhonenumber() {
    return phoneNumber;
  }
}

4) setter

need setter >> private 필드는 외부에서 직접 값을 변경(write)할 수 없습니다. 이를 해결하기 위해서 세터 메소드가 필요합니다.

example >> 세터(setter)는, private 필드를 우회적으로 변경(write)합니다.

class SmartPhone {
  // private 필드
  private int number;
  // 세터 메소드
  public void setNumber(int n) {
    number = n;
  }
}

setter character >> 세터 메소드는 아래의 특징을 갖습니다.
private 필드를 변경한다.
public 이다.
메소드명은 반환하려는 private 필드명 앞쪽에 set을 붙인다.
CODE

public class LockTest {
  public static void main(String[] args) {
    // 객체 생성
    Lock lock = new Lock("123!@#");
    /* 1. 세터를 호출하여, 비밀번호를 변경하시오. */
    lock.setPassword("654#@!");
    // 객체 정보 출력
    System.out.println(lock.toString());
  }
}
class Lock {
  // 필드
  private String password;
  // 생성자
  public Lock(String p) {
    password = p;
  }
  // 메소드
  public String toString() {
    return String.format("Lock { password: %s }", password);
  }
  /* 2. 비밀번호 변경을 위한, 세터 메소드를 추가하시오. */
  public void setPassword(String pw){
    password = pw;
  }
}

5) method scope review

scope >> 스코프(scope)란, 변수의 활동 영역이었습니다.
method scope vs class scope >> 이러한 스코프는 크게 두 종류로, 메소드 스코프와 클래스 스코프로 나뉘었습니다.
메소드 스코프: 메소드 내부에서 활동 (예 - 파라미터, 지역변수)
클래스 스코프: 클래스 전역에서 활동 (예 - 필드)
notice of scope! >> 스코프 관련하여 주의할 점은, 변수의 이름이 같은 경우입니다.

class Whatever {
  public void cool(int score) {
    String result = "";
    ...
  }
  public void great(int score) {
    String result = "";
    ...
  }
}

위 코드를 보면 cool() 메소드와 great() 메소드 내부에 둘 다 score 및 result 변수를 가지고 있습니다. 이들은 같은 이름이지만 서로 스코프가 다르기에 각각 개별적인 변수입니다. 서울 철수와 부산 철수가 다른 것처럼 말이죠.
CODE

public class MethodScope {
  public static void main(String[] args) {
    // main 메소드의 지역변수 score
    int score = 88;
    System.out.printf("score = %d in main()\n", score);
    // Record 클래스의 메소드 수행
    Record.foo(score);
    // main 메소드의 지역변수 score 출력
    System.out.printf("score = %d in main()\n", score);
  }
}
class Record {
  // 클래스 메소드
  public static void foo(int score) {
    // printMinus10 메소드의 파라미터 score의 값을 10 감소
    score -= 10;
    // printMinus10 메소드의 파라미터 score의 값을 출력
    System.out.printf("score = %d in foo()\n", score);
  }
}

6) scpre and this.

problem from same variable name >> 클래스의 필드와 메소드의 파라미터 이름이 같은 경우, 문제가 생길 수 있습니다.
아래 코드의 생성자는 잘 동작할까요? 잘 안됩니다. 필드의 값은 변경되지 않고, 파라미터 자신의 값을 그대로 대입할 뿐입니다. 왜일까요? 스코프가 중복되었기 때문입니다.

// 호출 영역
Cookie c = new Cookie("버터링", 1500);
// 정의 영역
class Cookie {
  private String name;
  private int price;
  public Cookie(String name, int price) {
    name = name; // 인스턴스 변수 name 초기화(X)
    price = price; // 인스턴스 변수 price 초기화(X)
  }
}

this >> 파라미터와 필드의 이름이 같은 경우, this 키워드 통해 이를 해결할 수 있습니다. this 키워드는 메소드 수행의 주체 객체를 가리키기 때문입니다. 이를 통해 같은 이름의 파라미터 name과 구분할 수 있게 되었습니다.

// 호출 영역
Cookie c = new Cookie("버터링", 1500);
c.setPrice(2000);
// 정의 영역
class Cookie {
  private String name;
  private int price;
  // 생성자
  public Cookie(String name, int price) {
    this.name = name;   // this.name -> 인스턴스 변수
    this.price = price; // this.price -> 인스턴스 변수
  }
  // 세터
  public void setName(String name) {
    this.name = name; // this.name -> 인스턴스 변수
  }
}

CODE

public class CoffeeTest {
  public static void main(String[] args) {
    // 커피 객체 생성
    Coffee americano = new Coffee("아메리카노", 1500);
    System.out.printf("커피값 인상 전 => %s\n", americano.toString());
    // 커피 값 인상: 1500 -> 1800
    americano.setPrice(1800);
    System.out.printf("커피값 인상 후 => %s\n", americano.toString());
  }
}
class Coffee {
  // 필드(인스턴스 변수)
  private String name;
  private int price;
  // 생성자
  public Coffee(String name, int price) {
    /* 1. this 키워드를 사용하여 필드를 초기화하세요.*/
    this.name = name;
    this.price = price;
  }
  // 세터
  public void setPrice(int price) {
    /* 2. this 키워드를 사용하여 필드를 변경하세요.*/
    this.price = price;
  }
  // 메소드
  public String toString() {
    return String.format("Coffee { name: %s, price: %d }", name, price);
  }
}

7) review: getter and setter, this.


CODE 1

public class KnightTest {
  public static void main(String[] args) {
    // 객체 생성
    Knight k = new Knight("돈키호테", 30);
    // 정보 출력
    System.out.println("[객체 생성]");
    System.out.printf("    %s\n",k.toStr());
    // 체력 증가: 기존 체력 + 30
    k.setHp(k.getHp() + 30);
    // 결과 출력
    System.out.println("[체력 증가 +30]");
    System.out.printf("    %s\n",k.toStr());
  }
}
class Knight {
  // 필드
  private String name;
  private int hp;
  // 생성자
  Knight(String name, int hp){
    this.name = name;
    this.hp = hp;
  }
  // 게터
  public int getHp(){
    return hp;
  }
  public String getName(){
    return name;
  }
  // 세터
  public void setHp(int hp){
    this.hp = hp;
}
  public String toStr(){
    return String.format("Knight { name: %s, hp: %d }", this.name, this.hp);
  }
}

CODE 2

public class KnightTest {
  public static void main(String[] args) {
    // 객체 생성
    Knight k = new Knight("돈키호테", 30);
    // 정보 출력
    System.out.println("[객체 생성]");
    System.out.printf("    Knight { name: %s, hp: %d }\n",k.getName(), k.getHp());
    // 체력 증가: 기존 체력 + 30
    k.setHp(30);
    // 결과 출력
    System.out.println("[체력 증가 +30]");
    System.out.printf("    Knight { name: %s, hp: %d }",k.getName(), k.getHp());
  }
}
class Knight {
  // 필드
  private String name;
  private int hp;
  // 생성자
  Knight(String name, int hp){
    this.name = name;
    this.hp = hp;
  }
  // 게터
  public int getHp(){
    return hp;
  }
  public String getName(){
    return name;
  }
  // 세터
  public void setHp(int hp){
    this.hp += hp;
}
}
profile
블로그 이전 : https://medium.com/@jaegeunsong97

0개의 댓글