카카오테크캠퍼스 2기

객체를 접근하는 권한 이해하기

지미닝 2024. 4. 27. 19:12

1. What I learned today

1. 객체를 접근하는 권한 이해하기

객체가 만들어졌다는 것은, 누군가에게 사용이 되어야 한다는 점에서 의미가 있다.

그런데 어떠한 객체를 만들었을 때, 어떤 것은 외부에서 접근이 가능하게 허가할 수도 있고 허가하지 않을 수도 있다. 그렇게 함으로서 객체를 조금 더 안전하게 사용할 수 있다.

 

🚀 학습 목표

객체 지향 프로그래밍에서는 객체 상호간에 접근을 제어할 수 있어야 한다.

ex. 두 클래스가 가지고 있는 상태와 동작을 상호간에 접근을 허용할 수 있어야 되고, 접근을 막아야 되는 경우가 있기 때문이다.

이번 시간에 알아볼 내용

  • 접근 제어 (Access Modifier)란?
  • 패키지(package)란 무엇인가
  • 클래스를 접근하는 방법 2가지

🤔 접근 제어(Access Modifier)란?

 

먼저 객체 상호간에 접근 제어라는 것이 왜 필요할까?

각자의 클래스 간에 “행위 정보”와 같이 무언가 무언가의 동작을 시키도록 하는 동작을 제어할 수 있다.

그런데 다른 객체가 마음대로 나의 상태를 접근해서 멋대로 바꾸면 안되는 것을 변경시킬 수 있다.

 

따라서 결론적으로, 객체를 보호할 수 있어야 하기 때문에 접근 제어자가 존재한다.

 

앞서 예시에서 다른 객체가 내 객체의 어떤 특성에 대해서 접근하지 못하게 하는 것정보 은닉이라고 한다. 반대로, 다른 객체의 행위정보를 상호작용 해야 되기 때문에 접근을 허용하는 경우도 있다.

 

이렇게 두 가지 케이스 처럼 접근 권한을 관리해야해야 하기 때문에 접근제어를 사용한다.

 

📎 Person 클래스에 이름, 나이, 전화번호를 저장하고 출력하는 예제

/*
* Person 객체를 생성하는 코드
* 메모리에 Person 객체를 생성한다!
*/
Person p = new Person(); 

// 아무 제약 없이 값을 집어넣을 경우 age를 1000으로 넣을 경우 아무 validation없이 처리된다.
p.name = "홍길동";
p.age = 1000;
p.phone = "010-1111-1111";

 

위 예제에서 알아볼 수 있듯이 위 예제처럼 1000이라는 값을 나이로 할당할 경우에는 아무 제약 없이 값이 할당되게 된다.

따라서 위와 같이 값을 변경하려는 접근을 막으려고 접근 제어가 필요한 것이다.

✔️ 따라서 접근 제어란?

  • 객체 상호간(클래스 상호간에)에 접근을 제어하는 방법이다.
  • 4가지의 접근 제한자(Access Modifier)를 사용한다.
  • 클래스를 설계할 때 고려해야 한다.
  • 클래스와 클래스 내부에서 만들어지는 멤버에 접근 제한자를 사용할 수 있다.
접근 제한자 설명
public 모든 패키지에서 접근 가능(모든 클래스는 public)(모든 멤버메서드는 public)
private 모든 패키지에서 접근 불가(자기 자신만 접근 가능)(모든 멤버변수는 private)
protected 상속 관계에서 하위 클래스에서 상위 클래스 접근 가능
default 동일한 패키지에서만 접근 가능
(단어로 존재하지않음)  

📎 MemberDTO 예제

public class MemberDTO { // 어디서든 접근할 수 없는 클래스는 가치가 없기 때문에 public
    public String name;
    private Integer age;
    public String phoneNumber;
}

위 예제에서 public으로 선언 한 프로퍼티들은 외부에서 마음대로 값을 할당하거나 접근 할 수 있다.

그러나 private로 선언한 age의 경우에는 외부에서 접근할 수도 없고 값을 할당할 수도 없다.

 

그렇다면 나이를 어떻게 할당할 수 있을까?

접근 자체도 되지 않기 때문에 출력도 할 수 없는 상황이 된다!

 

따라서 class내부에 public method를 생성하여 외부에서 사용할 수 있는 이 메서드를 통해서 값을 수정/접근 할 수 있게 된다. 해당 메소드는 private한 프로퍼티에 대한 접근이 가능하기 때문이다.

 

그러나, 이 메소드 조차도 private로 선언할 경우에는 외부에서 접근이 되지 않기 때문에 사용할 수 없게 된다.

 

따라서, 일반적으로 메소드는 public으로 생성한다.


2. 패키지(Package)란

🤔 만약 클래스의 접근 제어자를 생략하면 무엇이 될까?

 

바로 default가 생략되어있다!

default 접근제어자는 앞에서 언급했듯이, 동일판 패키지에서만 접근 가능하다!

⭐️ 패키지란

  • 서로 기능이 비슷한 클래스끼리 모아서 관리를 쉽게하기 위해서 사용한다. (폴더 개념)
  • 패키지 외부에서 클래스의 접근을 할 수 없도록하기 위해서 사용(보안측면)
  • 자바에서 제공해주는 API도 패키지의 형태로 배포된다.

자바에서 제공해주는 대표적인 패키지

패키지 이름 설명
java.lang 자바에서 자주 사용하는 클래스(String, System 등)
java.io 입출력 관련 클래스
java.net 네트워킹 관련 클래스
java.util 도움을 주는 클래스(Scanner)
java.sql 데이터베이스 관련 클래스, SQL
java.math 수학 관련 클래스

3. 클래스를 접근하는 이름 이해하기

클래스를 접근하기 위해서는 만들어진 위치와 접근 제어를 알아야 한다.

클래스 이름

  • 패키지를 포함하지 않는 클래스 이름: class name
  • 패키지를 포함한 클래스 이름: class full-name

우리에게는 단순히 클래스 이름보다는 class full-name이 더 중요하다.

Intellij는 알아서 임포트를 하게 해준다.


4. 클래스를 접근하는 방법 이해하기

  1. 클래스 전체이름(class full name)으로 접근하는 방법
java.lang.System.out.println("뭐시기뭐시기");

fc.java.model.BookDTO b = new fc.java.model.BookDTO();
  1. import를 사용하여 접근하는 방법
import java.lang.*;

[정리] Chapter 학습 정리 & Quiz

자바에서 객체를 접근할 때 사용하는 접근제한자(Access Modifier) 4개

🧑‍💻 public, private, protected, default

 

자바에서 서로 기능이 비슷한 클래스들끼리 모아서 관리를 쉽게 하기 위해서 사용하는 것

🧑‍💻 패키지(package)

 

자바에서 제공해주는 패키지 중 default package

🧑‍💻 java.lang

 

클래스에 접근하는 방법 2가지

🧑‍💻 클래스 전체 이름으로 접근, import를 사용하여 접근

 

자바에서 제공해주는 API 중에서 String클래스와 Scanner 클래스의 full name

🧑‍💻 java.lang.String.java.utilScanner

 

패키지를 현재 클래스에 포함시킬 때 사용하는 명령어

🧑‍💻 import

[부록] 실습 잠시 짚고 넘어가기

public class MemberDTO { // 어디서든 접근할 수 없는 클래스는 가치가 없기 때문에 public
    public String name;
    private Integer age;
    public String phoneNumber;
}

Q. 만약 저번 시간의 예제에서 public을 삭제해버리면 어떻게 될까?

🧑‍💻 다른 패키지에서 import를 시도할 때, 서로 다른 패키지 내에서는 접근할 수 없다는 경고가 뜨면서 접근할 수 없게 된다.

 

왜냐하면 접근 제어가 생략된다면 곧 default 가 기본 접근 제어자이기 때문에 접근제어자를 사용하지 않을 경우에는 같은 패키지 내부에서만 접근할 수 있게 된다.

 

여기서, 일반적으로 public이라고 사용하는 이유를 알 수 있다. 일반적으로 클래스는 다른 패키지에서도 해당 객체를 생성하기 위해서 선언되기 때문에 클래스는 웬만하면 public으로 선언된다.

마찬가지로 프로퍼티들도 접근 제어자를 생략한다면 default가 들어가게 된다.

2. Challenging (학습하며 어려웠던 점)

1. default 접근제한자

  • 디폴트는 쓰는 일이 있을까??? 라이브러리를 만들 때 주로 사용하는것인가?? 라이브러리를 딱히 뜯어본 적이 없어서 잘 모르겠당😅

내가 찾아본 해답:

인터페이스 내에서 디폴트 메소드를 사용한다!

  • default키워드를 사용하면 인터페이스 내에서 메소드에 대한 기본 구현을 제공할 수 있다. 이를 통해 메소드를 인터페이스에 추가하면서 기존 인터페이스를 구현한 클래스들이 해당 메소드를 구현하지 않아도 되는 이점이 있다. 이는 라이브러리 개발자들이 기존 라이브러리의 호환성을 유지하면서 새로운 기능을 추가할 수 있도록 해준다.

스위치 문의 디폴트 케이스에서 사용한다!

  • 스위치 문에서 default케이스를 사용하여 주어진 케이스 중 어떤 것도 일치하지 않을 때 실행될 코드 블록을 정의할 수 있다.
  • 이는 필수적인 요소는 아닌데, 모든 가능한 케이스르 처리하고 싶을 때 유용하다.

결론

라이브러리를 만들거나 API를 설계할 때 인터페이스의 default 메소드 기능은 매우 유용하다.

이 기능을 통해 라이브러리 사용자가 라이브러리 업데이트 후에도 기존 코드를 변경하지 않고도 새 기능을 쉽게 통합할 수 있게 된다.

2. 와일드 카드 사용

  • 예제로 import java.lang.*로 클래스 의존성을 주입한다고 알려주신 부분에서, 와일드카드로 import할 경우에는 쓸모없는 다른 것들도 모두 함께 import하게 되어서 성능상 좋지 않은 것으로 알고 있다. 심지어 프로덕션 코드에서는 klint로 와이드카드를 사용했을 경우, commit 자체를 허용하지 않고 있는데 웬만하면 와일드 카드를 지양하는 것이 좋지 않을까??? 뭐 딱히 상관없는건지 궁금하다.
    • 근데 강의에서는 굳이 귀찮으니깐 와일드 카드를 사용하라고 하셨는데 무엇이 맞는지 잘 모르겠다. 일단 학습하는 과정이기 때문에 번거로움을 덜고자 *를 사용하라고 하셨는지 궁금하다!!

내가 찾아본 해답:

import 문에서 와일드 카드(*) 사용에 대한 질문은 자바 커뮤니티 내에서도 의견이 다양하다.

성능과 영향 관점에서

  • 컴파일 시간의 관점에서는 컴파일러가 필요한 클래스를 찾기 위해서 더 많은 패키지를 탐색해야할 수도 있지만 매우 미미한 영향을 미치며, 현대 자바 컴파일러는 이정도 쯤은 괜찮다.
  • 런타임 성능 관점에서는 와일드카드는 런타임 성능에는 전혀 영향을 주지 않는다. 자바의 런타임 성능은 사용하는 클래스들이 메모리에 로드되는 방식에 의해 결정되기 때문에 import문과는 전혀 무관하다.

코드 유지보수와 가독성

오히려 와일드 카드의 사용은 코드 유지보수와 가독성 측면에서 더 중요한 영향을 미친다.

  • 가독성면에서 클래스를 하나하나 나열하는 것은 어떤 클래스가 사용되고 있는지 명확하게 보여주기 때문에 코드를 읽는 사람이 어떤 패키지를 어떤 클래스가 사용하는지 쉽게 파악할 수 있다.
  • 유지보수면에서 명시적 import는 이름 충돌을 해결하고, 불필요한 종속성을 제거하는데 도움이 된다. 가령, 두 패키지에서 같은 이름의 클래스를 사용할 경우, 와일드카드를 사용하면 어떤 클래스인지 명확하지 않을 수 있다.

교육적 맥락에서의 와일드 카드

교육 과정에서 와일드카드를 사용하려고 하는 것은, 초보자가 다루어야 할 복잡성을 줄이기 위한 것이다. 학습 초반에는 클래스 로딩이나 패키지 구조보다는 언어의 기본적인 문법이나 프로그래밍 로직을 익히는 데집중하는 것이 좋다.

그러나, 실제 프로덕션 환경이나 복잡한 프로젝트에서는 와일드카드 사용을 지양하는 것이 좋은 것으로 간주된다.

 

결론

실제 개발 환경에서는 명시적인 import를 사용하는 것이 좋다. 이는 가독성과 유지보수성을 높이는데 도움이 되고 팀 내에서 코드 스타일을 일관되게 유지하는데 기여하기 때문이다.

그러나, 학습 과정에서는 번거로움을 줄이기 위해서 와일드카드를 사용하는 것도 합리적인 선택일 수도 있다.