Pregunta

En el programa que estoy escribiendo Tengo un RestrictedUser clase y User clase que se deriva de RestrictedUser. Estoy tratando de ocultar el usuario métodos específicos por colada a RestrictedUser pero cuando lo haga la fundición de los métodos de usuario están todavía disponibles. También cuando corro el depurador del tipo de la variable aparece como User.

RestrictedUser restricted = regularUser;

hace hasta la fundición en Java ocultar los métodos de la subclase y campos o estoy haciendo algo mal? ¿Hay alguna solución?

Gracias

¿Fue útil?

Solución

Si se va a tratar de ejecutar este código:

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

que se obtiene un error de compilación. Eso no será segura de ninguna manera, forma o forma, ya que incluso si tuviera que pasar alrededor de la RestrictedUser a, por ejemplo, otro método, este método podría hacer esto:

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

y el usuario "restringida" no es tan restringido más.

El objeto está apareciendo en el depurador como un objeto User porque es como objeto User, incluso si la referencia de objeto se almacena en una variable RestrictedUser. Básicamente, poniendo una instancia de una clase hija de una variable con el tipo de una clase padre será hecho "ocultar" los métodos y campos de la subclase, pero no de forma segura.

Otros consejos

No estoy seguro exactamente lo que están pidiendo que la terminología que utiliza está del todo claro, pero aquí va. Si usted tiene una superclase y una subclase puede ocultar los métodos de la superclase de la subclase haciéndolos privado. Si necesita métodos públicos en la superclase para ser invisible usted está fuera de suerte. Si lanzas la subclase a la superclase a continuación los métodos públicos en la subclase ya no son visibles.

Una sugerencia que podría ayudarle a sería el uso de la composición en lugar de la herencia, extraer los métodos sensibles en una clase separada y luego insertar una instancia apropiada de esa clase en el objeto según sea necesario. Puede delegar métodos de la clase a la clase inyectada si es necesario.

Estás confundiendo tipo estático y dinámico tipo.

tipo estático es el tipo de la referencia. Cuando arriba a cielo desde Derivado de Base, que está diciendo al compilador que en la medida que se conoce y, lo que señala a una base. Es decir, que está prometiendo que el objeto apuntado es o nula, o una base, o algo derivadas de la base. Lo que quiere decir, que tiene una interfaz pública de base.

No A continuación, será capaz de llamar a métodos declarados en derivados (y no en la base), pero cuando se llama a cualquier método Base anulado por Derivado versión sustituida, obtendrá de derivados.

Si usted necesita para proteger la subclase, se puede utilizar el patrón Delegado:

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);
  }
  ...
}

También se puede pensar en usar .lang.reflect.Proxy
[]]

respuesta de Pedro y respuesta de Juan son correctas: acaba de lanzar el tipo estático no hará nada si el tipo real del objeto (que el código del cliente puede lanzar a, métodos de reflexión sobre la llamada, etc.) aún está disponible. Usted tiene que enmascarar el verdadero tipo de alguna manera (como la respuesta de Pedro menciona).

En realidad, hay un patrón para hacer esto: echar un vistazo a los métodos unconfigurable* en la clase Executors, si tiene acceso al código fuente del JDK.

Java

En Java, nunca se puede "ocultar" algo de un objeto. El compilador puede olvidar lo que sabe en detalle sobre el caso particular que tiene. (Como lo es subclase) El depurador sabe mucho más que el compilador, por lo que le dirá qué tipo real de la instancia actual es, que es probablemente lo que estás experimentando.

programación orientada a objetos

Parece que usted está escribiendo lógica que necesita saber qué tipo de objeto que utiliza que no se recomienda en la programación orientada a objetos, pero a menudo se requiere por razones prácticas.

Los adjetivos Restricción

Como dije en un comentario a la pregunta, debe ser claro en lo que es la clase base aquí. Intuitivamente RestrictedUser debe ser una subclase de usuario ya que el nombre sugiere un tipo más especializado. (Nombre teniendo un adjetivo activo adicional en él.) En su caso esto es especial, ya que este es un adjetivo que limita lo que permitirá poner usuario como una subclase de RestrictedUser totalmente bien. Yo recomendaría cambiar el nombre de los dos a algo como:. BasicUser / UserWithId y NonRestrictedUser para evitar el adjetivo limitante que es la parte confusa aquí

Además, no tener la tentación de pensar que se puede ocultar métodos en una clase anónima tampoco. Por ejemplo, esto no va a proporcionar la privacidad que espera:

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

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

Es posible que no sea capaz de nombrar el tipo real de run (a fin de emitir directamente a ella), pero todavía puede obtener su clase con getClass(), y se le puede llamar secretSquirrel utilizando la reflexión. (Incluso si secretSquirrel es privado, si no tiene SecurityManager, o si se ha configurado para permitir la accesibilidad, la reflexión puede invocar métodos privados también.)

Creo que probablemente hecho una elección de nombres pobres:. Me gustaría pensar RestrictedUser habría una subclase de User, no al revés, por lo que voy a utilizar UnrestrictedUser como la subclase

Si upCast un UnrestrictedUser a un RestrictedUser, su referencia sólo podrá acceder a métodos declarados en RestrictedUser. Sin embargo, si abatido de nuevo a un UnrestrictedUser, tendrá acceso a todos los métodos. Desde objetos Java saben qué tipo son en realidad, nada de lo que en realidad es un UnrestrictedUser siempre se puede convertir de nuevo a ella, no importa qué tipo de referencia que está utilizando (incluso un Object). No es inevitable y parte de la lengua. Sin embargo, se puede ocultar detrás de algún tipo de proxy, pero en su caso que, probablemente, en contra del propósito.

Además, en Java, todos los métodos no estáticos son virtuales por defecto. Esto significa que si UnrestrictedUser anula algún método declarado en RestrictedUser, entonces se usará la versión UnrestrictedUser, incluso si se accede a él a través de una referencia RestrictedUser. Si es necesario invocar la versión de la clase padre, puede hacer una llamada no virtual llamando RestrictedUser.variableName.someMethod(). Sin embargo, es probable que no use este muy a menudo (la menor de las razones es que se rompe la encapsulación).

También que esta pregunta plantea otra cuestión. ¿Cómo se va a llamar a este método? Parece como tener una jerarquía de clases donde la subclasificación introduce nuevas firmas de método requerirá instanceof cheques en las personas que llaman.

¿Se puede actualizar su pregunta para incluir un escenario en el que llamarían estos métodos en cuestión? Tal vez vamos a ser capaces de ayudar más.

La respuesta técnica se ha dado por John Calsbeek. Quiero pensar en el problema de diseño. Lo que estamos tratando de hacer es evitar que algún segmento del código, o algunos desarrolladores, de saber nada acerca de la clase de usuario. Usted quiere que ellos tratan a todos los usuarios como si fueran RestrictedUsers.

La forma que lo haría de hacerlo es con permisos. Es necesario para evitar que los desarrolladores se trata tengan acceso a la clase de usuario. Es probable que pueda hacer eso, colocándolo en un paquete y restringir el acceso al paquete.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top