정적 멤버에서 개인 멤버에 액세스 할 수있는 이유는 무엇입니까?


25

다음은 의사 코드이며 Java 및 PHP에서 시도했지만 모두 작동했습니다.

class Test { 

    private int a = 5;

    public static function do_test(){
        var t = new Test();
        t.a = 1;
        print t.a // 1
    }

}

Test::do_test();

왜 OOP 패러다임에서이 작업을 수행 할 수 있습니까?


6
왜 그렇지 않습니까? Java 개인 멤버는 인스턴스 전용이 아니라 소스 파일 전용 입니다. 가장 먼저 염두에 두어야 할 것은 equals다른 인스턴스의 프라이빗 필드를 확인해야한다는 것입니다 . (이것은 짧고,이 접근법의 OOP-ness에 대해서는 아무것도 언급하지 않음)
Ordous

2
정적 메소드에는가 없으므로 this자체 클래스의 유일한 객체는 자신이 생성하거나 객체로 매개 변수로 전달되는 객체입니다. 따라서 이것을 캡슐화 또는 보안 허위 위반으로 간주하면 매우 큰 것이 아니며 플러그 할 가치가 없습니다.
Kilian Foth

4
이것이 왜 다운 보트인지 확실하지 않습니다. 문제는 사소한 것일 수도 있지만 OP는 요청하기 전에 두 언어로 동작을 테스트하는 데 어려움을 겪었습니다. 그것은 우리가 새로 온 사람들보다 일반적으로 보는 것보다 더 많은 노력입니다.
yannis

1
@YannisRizos Agreed, 사실 나는 그 질문이 사소한 것이라고 생각하지 않습니다. "최소 권한의 원칙"을 따르는 것과 관련이 있습니다. 즉, 인스턴스의 내부에 액세스 할 필요가없는 도우미 함수는 별도의 클래스 로 정의해야하며 반대로이 규칙을 준수하면 정적 메서드가 동일한 클래스 내에 존재할 때 내부 상태에 액세스한다는 것을 알 수 있습니다.
Doval

1
사실, 내가 내 동료들에게 물었을 때 그들 모두는 이것이 불가능하다고 말했다. 그것이 내가 사소한 것이라고 생각하지 않은 이유입니다
Ben

답변:


17

Java에서 개인 변수는 전체 클래스에 표시됩니다. 정적 메소드와 같은 클래스의 다른 인스턴스에서 액세스 할 수 있습니다.

예를 들어, 팩토리 메소드에 유용 합니다 . 팩토리 메소드는 일반적으로 너무 복잡한 객체를 초기화하여 응용 프로그램 코드에 남기고 싶지 않습니다. 초기화를 수행하기 위해 팩토리 메소드는 종종 노출하고 싶지 않은 클래스 내부에 액세스해야합니다. 개인 변수에 직접 액세스 할 수 있으면 인생이 훨씬 쉬워집니다.

그러나 정적 메소드 또는 해당 클래스의 다른 인스턴스에서도 클래스의 구현 세부 사항을 숨기려면 개인 클래스 데이터 패턴을 따를 수 있습니다. 클래스의 모든 개인 변수를 개인 내부 클래스에 넣고 getter 또는 setter를 해당 내부 클래스의 getter 및 setter에 위임하십시오.

또 다른 옵션은 클래스의 모든 공용 메소드를 선언 한 클래스의 인터페이스를 정의한 다음 가능한 경우 해당 인터페이스에서 클래스 만 참조하는 것입니다. 인터페이스 유형에 대한 참조는 인터페이스에 선언되지 않은 모든 항목에 직접 액세스하는 데 사용할 수 없습니다 (물론 리플렉션 제외). 인터페이스가없는 객체 지향 프로그래밍 언어 (예 : C ++)를 사용하는 경우 실제 클래스에 상속 된 추상 기본 클래스로 시뮬레이션 할 수 있습니다.

interface ITest {
     public int getA();
}

class Test implements ITest { 

    private int a = 5;

    public int getA() { return a; } // implementation of method declared in interface

    public static void main(){
        ITest t = new Test();
        t.a = 1; // syntax error: Interface ITest has no "a"
        System.out.println(t.getA()); // calls Test.getA, visible because ITest declares it
    }

}

개인 클래스 데이터 패턴이 유용한 상황을 생각할 수 있습니까? 개인적으로 설정 (스윙 등)이나 코딩 연습에서 정적 내부 클래스와 같은 GUI에서만 내부 클래스를 사용합니다.
정보 : A

1
클래스의 내부를 다른 인스턴스 에서 숨기면 클래스가 인터페이스를 다시 가져 오지 않고 인터페이스보다 장점을 갖습니다. 더 간단하고 유연한 솔루션은 인터페이스를 사용하는 것입니다.
Doval

3

일부 언어 및 런타임 프레임 워크 (예 : Java, .NET)는 특정 클래스에 대한 코드를 컴파일하는 사람은 해당 클래스의 인스턴스의 개인 멤버를 올바른 방식으로 해칠 수있는 방식으로 사용하지 않을 것을 신뢰할 수 있다고 가정합니다. 조작. 다른 언어와 프레임 워크는 점에서 더 제한, 실행 코드에 의한 경우를 제외 인스턴스의 private 멤버에 대한 액세스를 허용하지 않는 인스턴스에 . 두 디자인 모두 장단점이 있습니다.

클래스 내의 모든 코드가 인스턴스의 비공개 멤버에 액세스 할 수있게하는 가장 큰 장점은 해당 액세스 수준이 적절한 경우가 있으며, private그러한 방식으로 작업을 수행하면 해당 용도로 사용할 수있는 다른 액세스 한정자가 없어도됩니다. 그렇지 않으면 코드가 다른 것보다 더 광범위하게 멤버를 노출하도록합니다.

Microsoft COM (Common Object Model)에서와 같이 이러한 액세스를 허용하지 않으면 외부 코드에서 클래스를 인터페이스로 처리 할 수 ​​있다는 이점이 있습니다. 클래스가 있으면 ImmutableMatrix전용 또는 보호 포함 double[][]배면 필드 클래스 내의 코드는 다른 인스턴스 백킹 어레이를 검사하는 경우, 그리고, 비 - 배열 백업 클래스를 정의하는 것이 가능하지 않을 것 (예를 들어 ZeroMatrix, IdentityMatrix) 외부 코드로 사용할 수있는 Immutable2dMatrix배킹 필드 등을 갖는 클래스없이. 내부 Immutable2dMatrix에서을 제외한 다른 인스턴스의 전용 멤버를 사용 하지 않는 경우 this클래스 이름을로 변경 하고 앞에서 언급 한 비 배열 클래스뿐만 아니라 하위 유형으로 가질 수 ImmutableArrayBackedMatrix있는 새로운 추상 ImmutableMatrix클래스를 정의 할 수 있습니다 ImmutableArrayBackedMatrix.

언어가 해당 기능을 활용하지 않고 실제로 외부 인스턴스를 검사하지 않는 한, 언어가 ImmutableMatrix이외의 인스턴스에 대해 배킹 배열을 검사 할 수 있도록 "허용"하도록하여 리팩토링을 방지 할 수는 없습니다 this. 언어가 그러한 사용을 제한하는 주요 효과는 리팩토링에 적합하지 않은 코드를 작성하려고 할 때 컴파일러가 즉시 스 쿼크하게 만든다는 것입니다.


2

Java는 엄격하게 객체 지향 언어가 아니라 클래스 기반 언어입니다 . 클래스는 인스턴스가 아닌 작업 및 동작 액세스를 결정합니다.

따라서 객체 지향적이 아닌 작업을 수행 할 수 있다는 사실에 지나치게 놀라지 마십시오.

이 메소드는 인스턴스와 동일한 클래스 범위에 있으므로 개인 멤버에 대한 전체 액세스 권한이 있습니다. 비슷한 규칙이 외부 클래스의 인스턴스에서 데이터에 액세스하는 내부 클래스의 인스턴스를 관리합니다. 내부 클래스의 인스턴스는 외부 클래스의 개인 멤버에 액세스 할 수 있습니다.

이것은 C ++에서 상속되며 복사 및 이동 생성자를 만드는 데 유용합니다. 또한 효율적인 방식으로 공개적으로 액세스 할 수없는 멤버에 따라 값이 의존하는 두 객체를 비교하거나 결합하는 데 유용합니다 (예 : Java의 배열에 대한 getter는 클라이언트 코드가이를 수정할 수 없도록 배열을 복사해야 함). 객체의 내부 상태이지만 객체의 동등성을 비교하기 위해 배열을 복사 해야하는 것은 효율적이지 않습니다)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.