[java] Java에서 공개, 보호, 패키지 개인 및 개인의 차이점은 무엇입니까?

자바에서, 즉 기본 (개인 패키지), 액세스 한정자의 각각의 사용시기에 대한 명확한 규칙이있다 public, protected그리고 private하는 동안, class그리고 interface상속을 처리?



답변

공식 튜토리얼 이 유용 할 수 있습니다.

______________________________________________________________
| │ 클래스 │ 패키지 │ 서브 클래스 │ 서브 클래스 │ 월드 |
| │ │ │ (같은 pkg) │ (diff pkg) │ |
| ───────────┼┼───────┼─────────┼──────────┼────────── ──┼──────── |
| 공개 │ + │ + │ + │ + │ + |
| ───────────┼┼───────┼─────────┼──────────┼────────── ──┼──────── |
| 보호 │ + │ + │ + │ + │ |
| ───────────┼┼───────┼─────────┼──────────┼────────── ──┼──────── |
수정 자 없음 │ + │ + │ + │ │ |
| ───────────┼┼───────┼─────────┼──────────┼────────── ──┼──────── |
| 비공개 │ + │ │ │ │ |
| ___________ | _______ | _________ | __________ | __________ | ________ |
 + : 접근 가능 공백 : 접근 불가능


답변

(주의 사항 : 저는 Java 프로그래머가 아니며 Perl 프로그래머입니다. Perl에는 공식적인 보호 기능이 없으므로 문제를 잘 이해하고 있습니다.)

은밀한

당신이 생각하는 것처럼, 그것이 선언 된 클래스 만이 그것을 볼 수 있습니다.

개인 패키지

선언 된 패키지 에서만보고 사용할 수 있습니다 . 이것은 Java의 기본값입니다 (일부는 실수로 간주 됨).

보호

패키지 프라이빗 +는 서브 클래스 또는 패키지 멤버가 볼 수 있습니다.

공공의

누구나 볼 수 있습니다.

출판

내가 통제하는 코드 밖에서 볼 수 있습니다. (Java 구문은 아니지만이 토론에서 중요합니다).

C ++은 “friend”라는 추가 레벨을 정의하며 이에 대해 더 잘 알지 못합니다.

언제 무엇을 사용해야합니까? 전체 아이디어는 정보를 숨기는 캡슐화입니다. 가능한 한 사용자가 수행 한 작업에 대한 세부 정보를 숨기려고합니다. 왜? 따라서 나중에 변경할 수 있으며 다른 사람의 코드를 어 기지 않아도됩니다. 이를 통해 방금 개조 한 코드를 누군가가 사용하고 있다는 걱정없이 버그를 최적화, 리팩토링, 재 설계 및 수정할 수 있습니다.

따라서 경험의 법칙은 필요한만큼만 보이게 만드는 것입니다. 비공개로 시작하고 필요에 따라 더 많은 가시성을 추가하십시오. 사용자가 알기 위해 꼭 필요한 것을 공개하십시오. 공개 경련을 만드는 모든 세부 사항은 시스템을 재 설계 할 수있는 능력입니다.

사용자가 내부를 공개하지 않고 비헤이비어를 커스터마이즈 할 수 있도록 사용자 정의 할 수 있도록하려면 이러한 내장을 객체로 밀어 넣고 해당 인터페이스를 공개하는 것이 좋습니다. 그렇게하면 새로운 객체를 간단히 연결할 수 있습니다. 예를 들어, CD 플레이어를 작성 중이고 “이 CD에 대한 정보 찾기”비트를 사용자 정의 할 수 있기를 원한다면, 이러한 메소드를 공개하지 않고 모든 기능을 자체 오브젝트에 넣고 오브젝트를 getter / setter로 공개하십시오. . 이런 식으로 장을 노출시키는 것에 신경 쓰지 않으면 좋은 구성과 우려의 분리가 촉진됩니다.

개인적으로 저는 “개인”과 “공개”만 고집합니다. 많은 OO 언어가 있습니다. “보호”는 편리 할 수 ​​있지만 실제로는 치트입니다. 인터페이스가 개인용이 아닌 경우 제어 범위를 벗어나면 다른 사람들의 코드를 살펴보고 용도를 ​​찾아야합니다.

여기에서 “게시 됨”이라는 아이디어가 나온다. 인터페이스를 변경 (리팩토링)하려면 인터페이스를 사용하는 모든 코드를 찾아서 변경해야한다. 인터페이스가 개인용이라면 아무 문제가 없습니다. 보호 된 경우 모든 하위 클래스를 찾아야합니다. 공개 된 경우 코드를 사용하는 모든 코드를 찾아야합니다. 예를 들어 내부 용으로 만 사용되는 회사 코드로 작업하는 경우 인터페이스가 공용인지 여부는 중요하지 않은 경우가 있습니다. 회사 리포지토리에서 모든 코드를 가져올 수 있습니다. 그러나 인터페이스가 “게시 된”경우 컨트롤 외부에서 인터페이스를 사용하는 코드가 있으면 문제가 발생합니다. 해당 인터페이스 또는 위험 코드를 지원해야합니다. 보호 된 인터페이스조차도 게시 된 것으로 간주 될 수 있습니다.

많은 언어들이 공공 / 보호 / 민간의 계층 적 성격이 너무 제한적이며 현실과 일치하지 않는 것으로 본다. 이를 위해 특성 클래스 라는 개념이 있지만 그것은 또 다른 쇼입니다.


답변

다음은 더 나은 버전의 테이블이며 여기에는 모듈 열도 포함됩니다.

자바 액세스 수정 자

설명

  • 개인 회원 ( i)입니다 이 선언과 같은 클래스 내 접근.

  • 와 회원 액세스 수정 자 ( j)가 없는 는 동일한 패키지의 클래스 내에서만 액세스 할 수 있습니다.

  • 보호 회원 (k ) 같은 패키지의 모든 클래스에서 접근 하고 다른 패키지의 서브 클래스 내에서.

  • 공공 회원은 ( l) 그것은에 상주하지 않는 (모든 클래스에 액세스 할 수 모듈 이 선언 된 패키지를 내 보내지 않습니다).


어떤 수정자를 선택해야합니까?

액세스 수정자는 실수로 캡슐화가 깨지는 것을 방지하는 데 도움이되는 도구입니다. (*) . 멤버가 클래스, 패키지, 클래스 계층 내부에 있거나 내부에없는 것을 원한다면 자신에게 물어보고 그에 따라 액세스 수준을 선택하십시오.

예 :

  • 필드 long internalCounter 는 변경 가능하고 구현 세부 사항이므로 비공개 일 것입니다.
  • 팩토리 클래스에서만 (동일한 패키지로) 인스턴스화해야하는 클래스는 패키지 외부에서 직접 호출 할 수 없으므로 패키지 제한 생성자가 있어야합니다.
  • void beforeRender()렌더링 직전에 호출되고 서브 클래스에서 후크로 사용되는 내부 메소드를 보호해야합니다.
  • void saveGame(File dst)GUI를 코드에서 호출 방법을 공개한다.

(*) 정확히 캡슐화 란 무엇입니까?


답변

____________________________________________________________________
                | highest precedence <---------> lowest precedence
*———————————————+———————————————+———————————+———————————————+———————
 \ xCanBeSeenBy | this          | any class | this subclass | any
  \__________   | class         | in same   | in another    | class
             \  | nonsubbed     | package   | package       |
Modifier of x \ |               |           |               |
————————————————*———————————————+———————————+———————————————+———————
public          |              |          |              |   
————————————————+———————————————+———————————+———————————————+———————
protected       |              |          |              |   
————————————————+———————————————+———————————+———————————————+———————
package-private |               |           |               |
(no modifier)   |              |          |              |   
————————————————+———————————————+———————————+———————————————+———————
private         |              |          |              |   
____________________________________________________________________


답변

쉬운 규칙. 모든 것을 비공개로 선언하는 것으로 시작하십시오. 그런 다음 요구가 발생하고 디자인이이를 보증 할 때 대중을 향해 나아가십시오.

멤버를 노출시킬 때 표현 선택이나 추상화 선택을 노출하는지 스스로에게 물어보십시오. 첫 번째는 관찰 할 수있는 행동보다는 실제 표현에 너무 많은 의존성을 유발하기 때문에 피하고 싶은 것입니다.

일반적으로 서브 클래 싱으로 메소드 구현을 대체하지 않도록 노력합니다. 논리를 망치기가 너무 쉽습니다. 재정의하려는 경우 추상 보호 방법을 선언하십시오.

또한 재정의 할 때 @Override 주석을 사용하여 리팩토링 할 때 문제가 발생하지 않도록하십시오.


답변

실제로는 간단한 그리드 쇼보다 조금 더 복잡합니다. 그리드는 액세스가 허용되는지 여부를 알려주지 만 액세스를 정확히 구성하는 것은 무엇입니까? 또한 액세스 수준은 중첩 된 클래스 및 상속과 복잡한 방식으로 상호 작용합니다.

“기본”액세스 (키워드 부재로 지정)를 package-private 라고도 합니다 . 예외 : 인터페이스에서 수정자는 공개 액세스를 의미하지 않습니다. public 이외의 수정자는 금지됩니다. 열거 형 상수는 항상 공개입니다.

요약

이 액세스 지정자가있는 멤버에 대한 액세스가 허용됩니까?

  • 멤버 private: 멤버가 호출 코드와 동일한 클래스 내에 정의 된 경우에만 해당됩니다.
  • 멤버가 패키지 비공개 : 호출 코드가 멤버의 즉시 둘러싸는 패키지 내에있는 경우에만 해당됩니다.
  • Member is protected: 동일한 패키지 또는 멤버가 호출 코드를 포함하는 클래스의 수퍼 클래스에 정의 된 경우.
  • 회원 public: 예.

액세스 지정자가 적용되는 대상

지역 변수와 형식 매개 변수는 액세스 지정자를 사용할 수 없습니다. 범위 지정 규칙에 따라 본질적으로 외부에 액세스 할 수 없으므로 사실상 비공개입니다.

최상위 범위의 클래스의 경우에만 public패키지 전용이 허용됩니다. 이 디자인 선택은 아마도 때문에 protectedprivate패키지 레벨에서 중복 될 것이다 (패키지의 상속 재산이 없다).

모든 액세스 지정자는 클래스 멤버 (생성자, 메소드 및 정적 멤버 함수, 중첩 클래스)에서 가능합니다.

관련 : Java 클래스 접근성

주문

액세스 지정자는 엄격하게 주문할 수 있습니다

공개> 보호> 패키지 개인> 개인

public가장 많이 액세스 할 수있는 것을 의미합니다 private. 개인 구성원에 대해 가능한 모든 참조는 패키지 개인 구성원에게도 유효합니다. 패키지 전용 멤버에 대한 모든 참조는 보호 된 멤버 등에서 유효합니다. (동일한 패키지의 보호 된 멤버에게 다른 클래스의 액세스 권한을 부여하는 것은 실수로 간주되었습니다.)

노트

  • 클래스의 메소드 같은 클래스의 다른 객체의 비공개 멤버에 액세스 할 수 있습니다. 보다 정확하게는 클래스 C의 메소드는 C의 모든 서브 클래스의 오브젝트에서 C의 개인 멤버에 액세스 할 수 있습니다. Java는 인스턴스에 의한 액세스 제한을 지원하지 않습니다. (를 사용하여 지원하는 스칼라와 비교하십시오 private[this].)
  • 객체를 생성하려면 생성자에 액세스해야합니다. 따라서 모든 생성자가 비공개 인 경우 클래스는 클래스 내에 존재하는 코드 (일반적으로 정적 팩토리 메소드 또는 정적 변수 이니셜 라이저)만으로 구성 할 수 있습니다. 패키지 개인 또는 보호 된 생성자의 경우와 유사합니다.
    • Java는 서브 클래스의 생성자가 내재적으로 또는 명시 적으로 수퍼 클래스 생성자를 호출해야하므로 개인 생성자 만 있다는 것은 클래스를 외부에서 서브 클래 싱 할 수 없다는 것을 의미합니다. 그러나 하위 클래스를 포함하는 중첩 클래스를 포함 할 수 있습니다.

내부 수업

내부 클래스와 같은 중첩 범위 도 고려해야 합니다. 복잡성의 한 예는 내부 클래스에 멤버가 있으며 자체적으로 액세스 수정자를 사용할 수 있다는 것입니다. 그래서 당신은 공개 멤버와 개인 내부 수업을 가질 수 있습니다; 회원에게 액세스 할 수 있습니까? (아래 참조) 일반적인 규칙은 범위를보고 재귀 적으로 생각하여 각 수준에 액세스 할 수 있는지 여부를 확인하는 것입니다.

그러나 이것은 매우 복잡하며 자세한 내용 은 Java 언어 사양을 참조하십시오 . (예, 과거에는 컴파일러 버그가있었습니다.)

이들이 어떻게 상호 작용하는지 맛 보려면이 예제를 고려하십시오. 개인 내부 클래스를 “누설”할 수 있습니다. 이것은 일반적으로 경고입니다.

class Test {
    public static void main(final String ... args) {
        System.out.println(Example.leakPrivateClass()); // OK
        Example.leakPrivateClass().secretMethod(); // error
    }
}

class Example {
    private static class NestedClass {
        public void secretMethod() {
            System.out.println("Hello");
        }
    }
    public static NestedClass leakPrivateClass() {
        return new NestedClass();
    }
}

컴파일러 출력 :

Test.java:4: secretMethod() in Example.NestedClass is defined in an inaccessible class or interface
        Example.leakPrivateClass().secretMethod(); // error
                                  ^
1 error

몇 가지 관련 질문 :


답변

경험적으로 볼 때 :

  • private: 클래스 범위.
  • default(또는 package-private) : 패키지 범위.
  • protected: package scope + child(패키지와 같지만 다른 패키지에서 서브 클래 싱 할 수 있습니다). 보호 된 수정자는 항상 “부모-자식”관계를 유지합니다.
  • public: 어디서나.

결과적으로 액세스 권한을 세 가지 권한으로 나누면 :

  • (D) 고침 (동일한 클래스 내의 메소드 또는 “this”구문을 통해 호출)
  • (R) 추론 (클래스에 대한 참조를 사용하거나 “도트”구문을 통해 메소드를 호출)
  • (I) 상속 (하위 분류를 통한).

이 간단한 테이블이 있습니다.

+—-———————————————+————————————+———————————+
|                 |    Same    | Different |
|                 |   Package  | Packages  |
+—————————————————+————————————+———————————+
| private         |   D        |           |
+—————————————————+————————————+———————————+
| package-private |            |           |
| (no modifier)   |   D R I    |           |
+—————————————————+————————————+———————————+
| protected       |   D R I    |       I   |
+—————————————————+————————————+———————————+
| public          |   D R I    |    R  I   |
+—————————————————+————————————+———————————+