tipos proyectos metodos ideas funciones clases java polymorphism access-modifiers

java - proyectos - Clase privada como tipo de retorno del método público.



metodos y funciones en java (8)

¿Por qué es esto válido?

Foo.java

public class Foo { public Bar getBar() { return new Bar(); } private class Bar {} }

Si Bar es privado, ¿cómo utilizarán este método los usuarios de esta clase? El polimorfismo se puede usar, por supuesto, pero ¿no debería esto ser inválido y la declaración debería indicar esto como devolver un objeto?


¿Por qué es esto válido?

Debido a que el código de cliente en el lugar de la llamada podría estar esperando un Object (o no esperar nada en absoluto), no hay problema en llamar a este método desde cualquier lugar:

Object o = new Foo().getBar();


Acabo de investigar un poco y no he podido encontrar una respuesta definitiva. Parece más probable que sea solo un descuido por parte de los diseñadores del lenguaje Java y, como en realidad no hace ningún daño, se ha dejado. No es realmente diferente de poner un método public en una clase private . Nada le impide hacer esto, aunque no haya manera de acceder a ese método public .

Ciertamente, NetBeans le da la advertencia "Exportando un tipo no público a través de una API pública" cuando intenta hacer esto. Espero que la mayoría de los otros entornos den una advertencia similar.

El objeto devuelto es completamente inútil para cualquiera que intente usarlo (a menos que use reflexión), casi todo lo que pueden hacer es almacenarlo en un Object (o cualquier otra súper clase a la que tengan acceso) y luego pasar ese Object alrededor.

Es posible que desee hacer esto si el Object pasado se está utilizando como un "identificador" que se pasa, pero nunca se opera. En ese caso, aunque todavía tendría mucho más sentido tener la clase public pero hacer que todos los métodos dentro de ella sean private para evitar que se actúen fuera de su clase (o definir una interfaz public para regresar y hacer que la clase private implemente eso).

Entonces la respuesta parece ser:

Probablemente no debería ser válido, pero como no hace ningún daño, nunca ha sido bloqueado.

Hay una buena respuesta aquí sobre un tema similar:

Exportando tipo no público a través de API pública


Es uno de los tipos de tipos anidados. Este tipo de declaración de clase se conoce como clase interna. Si declara la clase interna como estática, entonces se conocerá como clase anidada de nivel superior. Otras formas de tipos anidados disponibles en Java son clases locales; clase declarada y definida dentro de un bloque, es decir, un método o un constructor o un bloque inicializador. La cuarta forma de tipo anidado es la clase anónima; una clase sin ningún nombre cuyo objeto se usa donde se define la clase.

En lo que respecta a su caso, es decir, clase interna todas las clases dentro de una clase pueden ser declaradas con especificadores de acceso públicos, privados y protegidos. Todas las clases con la clase adjunta, así como la clase adjunta, comparten una relación de confianza. Eso significa que todos los miembros privados de la clase interna, así como los miembros privados de la clase adjunta, se comparten entre sí. Sin embargo, no puede acceder al objeto de la clase interna sin un objeto de clase envolvente.

Cuando intente crear un objeto del compilador de clase interno, se informará un error en tiempo de compilación. Sin embargo, a continuación del ejemplo, acceda a los miembros privados de cada otra clase, es decir, encerrando a los miembros privados de acceso de la clase de la clase interna y a los miembros privados del acceso de la clase de la clase envolvente:

class Bar { private static int x; public void getFoo() { System.out.println(new Foo().y); } private class Foo { private int y; public void getBar() { System.out.println(Bar.x); } } } public class Test{ public static void main(String[] a) { Bar b = new Bar(); //Bar.Foo f = new Bar.Foo(); This is completely illegal syntax. } }

El mejor ejemplo que podría tener para una clase interna es la relación de una clase de Accounts que incluye la clase de Transaction y la clase de Transaction que es la clase interna. Una clase de Accounts puede tener más de un objeto Transaction , pero el objeto Transacción no puede existir sin el objeto Accounts .

Aunque, devolver un objeto de clase interna privada es inútil ya que se vuelve invisible fuera de su clase. Como se explica en el ejemplo anterior de Accounts y clases de Transaction . Transaction no puede existir sin el objeto Accounts .


Es válido porque Bar es visible para la clase Foo . Así se compila.

Por supuesto, otra clase no puede ver Bar y, por lo tanto, no puede usar el valor de retorno.

Pero otra clase aún puede invocar el método sin usar el valor de retorno.

public class FooBar { public void invokeBar() { Foo foo = new Foo(); foo.getBar(); } }


Tengo un caso de uso perfectamente válido para esto, y me alegro de que esto esté permitido.

Quedémonos, tienes una clase que crea piezas de UI. Acepta a algún tipo de objeto de dominio y crea una parte de la interfaz de usuario:

public Node createPersonUI(Person person) { BasePanel panel = new BasePanel(); // ... setup panel with values ... return panel; }

BasePanel es una subclase de Node y es una clase interna con la que la persona que llama no tiene negocios, ya que esta clase determina cómo se verán las cosas.

Ahora, necesité reutilizar parte de esta clase cuando necesitaba admitir un nuevo objeto, PersonalProfile que contiene mucha más información, pero también contiene los datos básicos de Person :

public Node createPersonalProfileUI(PersonalProfile profile) { BasePanel panel = new BasePanel(); // ... setup panel with values ... return panel; }

Sin embargo, ese código fue parcialmente duplicado, así que hice:

public Node createPersonalProfileUI(PersonalProfile profile) { BasePanel panel = (BasePanel)createPerson(profile.getPerson()); // ... only setup missing values ... return panel; }

Sin embargo, el reparto es un poco ridículo: cambiarlo para devolver BasePanel no solo funciona, sino que no expone ninguna funcionalidad de mi clase privada. En su lugar, solo expone los métodos de las clases públicas de las que hereda ... ¡brillante!

Código completo:

public BasePanel createPersonUI(Person person) { BasePanel panel = new BasePanel(); // ... setup panel with values ... return panel; } public BasePanel createPersonalProfileUI(PersonalProfile profile) { BasePanel panel = createPerson(profile.getPerson()); // ... only setup missing values ... return panel; } private class BasePanel extends Node { }


Un método público que devuelve una clase privada puede ser útil si necesita poder llamar al método desde cualquier ámbito (por ejemplo, para mutar un estado interno de Foo) y para uso interno si necesita cualquier tipo de resultado además de simplemente llamar el método.


Clase interna

Las clases internas representan un tipo especial de relación que permite acceder a todos los miembros (miembros de datos y métodos) de la clase externa, incluida la privada. Las clases anidadas pueden llevar a un código más legible y mantenible porque agrupan lógicamente las clases en un solo lugar.


public class Foo { private String myString; public String getMyString() { return myString; } }

Esto es válido también. ¿Por qué las clases internas se comportan de manera diferente?

Hacer que Bar private solo lo hace invisible para el mundo exterior, al igual que hacer que los campos sean private .

Una advertencia importante es que incluso si puede llamar a getBar() en un objeto Foo no puede llamar a los métodos de esa referencia (debido a la visibilidad).

Así que lo principal es que puedes hacer eso, pero no debes hacerlo.

La única situación que puedo imaginar es cuando Foo también es una clase interna y la clase externa de Foo quiere usar Bar .