Java로 캐스팅하면 서브 클래스 방법과 필드가 숨어 있습니까?

StackOverflow https://stackoverflow.com/questions/712528

  •  23-08-2019
  •  | 
  •  

문제

내가 쓰고있는 프로그램에서 나는 수업이 있습니다 RestrictedUser 그리고 수업 User 그것은 파생되었습니다 RestrictedUser. 캐스트하여 사용자 특정 방법을 숨기려고합니다. RestrictedUser 그러나 캐스팅을 할 때 사용자 메소드는 여전히 사용할 수 있습니다. 또한 디버거를 실행하면 변수의 유형이 다음과 같이 나타납니다. User.

RestrictedUser restricted = regularUser;

Java로 캐스팅하면 서브 클래스 방법과 필드가 숨어 있습니까? 아니면 내가 뭔가 잘못하고 있습니까? 해결 방법이 있습니까?

감사

도움이 되었습니까?

해결책

이 코드를 실행하려는 경우 :

User user = new User(...);
RestrictedUser restricted = user;
restricted.methodDefinedInTheUserClass(); // <--

컴파일 오류가 발생합니다. 그것은 어떤 식 으로든 안전하지 않을 것입니다. RestrictedUser 또 다른 방법으로는이 방법을 수행 할 수 있습니다.

if (restricted instanceof User) {
    User realUser = (User)restricted;
    realUser.methodDefinedInTheUserClass(); // !!
}

그리고 "제한된"사용자는 더 이상 제한되지 않습니다.

객체는 디버거에 User 객체는 그대로 있기 때문입니다 User 객체, 객체 참조가 RestrictedUser 변하기 쉬운. 기본적으로, 아동 클래스의 인스턴스를 부모 클래스 유형의 변수에 넣으면 실제로 서브 클래스의 방법과 필드를 "숨기기"하지만 안전하지는 않습니다.

다른 팁

나는 당신이 사용하는 용어로서 당신이 무엇을 요구하는지 정확히 잘 모르겠습니다. 슈퍼 클래스와 서브 클래스가있는 경우 비공개로 만들어 서브 클래스에서 슈퍼 클래스의 메소드를 숨길 수 있습니다. 보이지 않도록 슈퍼 클래스에 공개 방법이 필요한 경우 운이 좋지 않습니다. 서브 클래스를 슈퍼 클래스에 시전하면 서브 클래스의 공개 메소드가 더 이상 보이지 않습니다.

상속 대신 구성을 사용하는 데 도움이 될 수있는 한 가지 제안은 민감한 방법을 별도의 클래스로 추출한 다음 필요에 따라 해당 클래스의 적절한 인스턴스를 객체에 삽입하는 것입니다. 필요한 경우 클래스에서 주입 된 클래스까지 방법을 위임 할 수 있습니다.

정적 유형과 동적 유형을 혼동하고 있습니다.

정적 유형은 참조 유형입니다. 당신이 파생에서 기본으로 업 캐스트를 할 때, 당신은 컴파일러에게 당신과 그것이 아는 한, 지적한 것이 기지라고 말합니다. 즉, 당신은 지적한 물체가 널 또는베이스 또는베이스에서 파생 된 것임을 약속하고 있습니다. 즉, Base의 공개 인터페이스가 있습니다.

그런 다음 파생에서 선언 된 메소드를 호출 할 수는 없지만 (기본이 아닌), 파생 된 기본 메소드를 호출하면 파생의 재정의 버전이 얻을 수 있습니다.

서브 클래스를 보호 해야하는 경우 대의원 패턴을 사용할 수 있습니다.

public class Protect extends Superclass {  // better implement an interface here
  private final Subclass subclass;

  public Protect(Subclass subclass) {
    this.subclass = subclass;
  }

  public void openMethod1(args) {
    this.subclass.openMethod1(args);
  }

  public int openMethod2(args) {
    return this.subclass.openMethod2(args);
  }
  ...
}

당신은 또한 사용에 대해 생각할 수도 있습니다 java.lang.reflect.proxy
[]]

베드로의 대답 그리고 존의 대답 정확합니다 : 정적 유형을 캐스팅하면 실제 유형의 객체 (클라이언트 코드가 캐스트 할 수있는 클라이언트 코드, 반사 메소드 등)가 여전히 사용할 수있는 경우 아무것도하지 않습니다. 당신은 어떻게 든 실제 유형을 가야합니다 (베드로의 답변이 언급 한 것처럼).

실제로 이것을하는 패턴이 있습니다. unconfigurable* 방법의 방법 Executors 클래스, JDK 소스 코드에 액세스 할 수있는 경우.

자바

Java에서는 물체에서 무언가를 "숨길"수 없습니다. 컴파일러는 가지고있는 특정 인스턴스에 대해 자세히 알고있는 것을 잊을 수 있습니다. (서브 클래스와 마찬가지로) 디버거는 컴파일러보다 훨씬 더 많은 것을 알고 있으므로 현재 인스턴스가 실제 유형이 무엇인지 알려줍니다.

OOP

OOP에서 권장하지 않지만 종종 실제적인 이유로 필요한 유형의 객체를 알아야하는 논리를 작성하는 것처럼 들립니다.

형용사 제한

내가 질문에 대한 의견에서 말했듯이, 당신은 여기서 기본 클래스가 무엇인지 명확하게해야합니다. 이름이보다 전문화 된 유형을 제안하기 때문에 직관적으로 제한된 사용자는 사용자의 서브 클래스 여야합니다. (추가적인 활성 형용사를 갖는 이름.) 귀하의 경우에 이것은 제한적인 형용사이기 때문에 사용자를 제한적인 서브 클래스의 서브 클래스로 완전히 잘게 할 수 있기 때문에 특별합니다. 여기서 혼란스러운 부분 인 제한적인 형용사를 피하기 위해 Basicuser/UserwithID 및 NonrestrictedUser와 같은 두 가지로 이름을 바꾸는 것이 좋습니다.

또한 익명 수업에서 방법을 숨길 수 있다고 생각하지 마십시오. 예를 들어, 이것은 당신이 기대하는 개인 정보를 제공하지 않습니다.

Runnable run = new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello, world!");
    }

    public void secretSquirrel() {
        System.out.println("Surprise!");
    }
}

실제 유형의 이름을 지정하지 못할 수도 있습니다. run (직접 캐스트하기 위해), 그러나 여전히 수업을받을 수 있습니다. getClass(), 그리고 당신은 전화 할 수 있습니다 secretSquirrel 반사 사용. (설사 secretSquirrel 당신이 없다면 사적입니다 SecurityManager, 또는 접근성을 허용하기 위해 설정된 경우, 반사는 개인 방법을 호출 할 수 있습니다.)

나는 당신이 아마도 불쌍한 이름을 선택했을 것 같아요 : 나는 생각합니다. RestrictedUser 서브 클래스 일 것입니다 User, 다른 방법은 아니므로 사용하겠습니다. UnrestrictedUser 서브 클래스로.

당신이 Upcast an UnrestrictedUser a RestrictedUser, 귀하의 참조는 선언 된 방법에만 액세스 할 수 있습니다. RestrictedUser. 그러나, 당신이 그것을 다시 다운 캐스팅하면 UnrestrictedUser, 모든 방법에 액세스 할 수 있습니다. Java 객체는 실제로 어떤 유형인지 알고 있기 때문에 실제로 UnrestrictedUser 어떤 유형의 참조를 사용하든 항상 다시 캐스트 할 수 있습니다 (심지어 Object). 불가피하고 언어의 일부가 있습니다. 그러나 어떤 종류의 대리 뒤에 숨길 수 있지만, 당신의 경우 목적을 물리 칠 수 있습니다.

또한 Java에서는 모든 비 정적 메소드가 기본적으로 가상입니다. 이것은 IF를 의미합니다 UnrestrictedUser 선언 된 일부 메소드를 무시합니다 RestrictedUser, 그런 다음 UnrestrictedUser 버전은 RestrictedUser 참조. 상위 클래스 버전을 호출 해야하는 경우 RestrictedUser.variableName.someMethod(). 그러나 아마도 이것을 자주 사용해서는 안됩니다 (캡슐화를 중단하는 이유 중 가장 적은 이유).

나는 또한이 질문이 또 다른 질문을 구걸한다고 생각합니다. 이 방법을 어떻게 호출 할 계획입니까? 서브 클래스가 새로운 메소드 서명을 소개하는 클래스 상속장이있는 것 같습니다.

문제의 메소드라고 부르는 시나리오를 포함하도록 질문을 업데이트 할 수 있습니까? 아마도 우리는 더 많은 것을 도울 수있을 것입니다.

John Calsbeek은 기술적 인 답변을 제공했습니다. 디자인 문제에 대해 생각하고 싶습니다. 당신이하려고하는 것은 코드의 일부 세그먼트 또는 일부 개발자가 사용자 클래스에 대해 아는 것을 막는 것입니다. 당신은 그들이 모든 사용자를 제한된 거주자 인 것처럼 취급하기를 원합니다.

당신이 그렇게 할 방법은 권한에 관한 것입니다. 문제의 개발자가 사용자 클래스에 액세스 할 수없는 것을 방지해야합니다. 패키지에 넣고 패키지에 대한 액세스를 제한하여 그렇게 할 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top