JavaRush /Blog Java /Random-ES /Clases, tipos de clases anidadas con ejemplos.
Ярослав
Nivel 40
Днепр

Clases, tipos de clases anidadas con ejemplos.

Publicado en el grupo Random-ES
Hola a todos. En este tema, quiero hablar en detalle sobre las clases de Java y sus tipos para ayudar a los principiantes a comprender este tema y tal vez a los no novatos a aprender algo nuevo. Siempre que sea posible, todo se mostrará utilizando ejemplos de la vida real con ejemplos de código adjuntos. Empecemos. Clases, tipos de clases anidadas con ejemplos - 1Y me gustaría señalar que lo principal es comprender los dos primeros tipos de clases, y que las locales y anónimas son simplemente subtipos de la clase interna.

¿Qué es una clase?

Una clase es una descripción lógica de algo, una plantilla con la que puedes crear instancias reales de eso mismo. En otras palabras, es simplemente una descripción de cómo deberían ser las entidades creadas: qué propiedades y métodos deberían tener. Las propiedades son características de una entidad, los métodos son acciones que puede realizar. Un buen ejemplo de una clase de la vida real, que permite comprender qué es una clase, pueden considerarse dibujos: los dibujos se utilizan para describir estructuras (catapulta, destornillador), pero un dibujo no es un diseño. Así como los ingenieros usan planos para crear diseños, la programación usa clases para crear objetos que han descrito propiedades y métodos.
public class Student {
    private String name, group, specialty;

    public Student(String name, String group, String specialty) {
       this.name = name;
       this.group = group;
       this.specialty = specialty;
   }

   // getters/setters
}
En este ejemplo, creamos una clase Java que describe la entidad "estudiante": cada estudiante tiene un nombre, grupo y especialidad. Ahora, en otros lugares del programa, podemos crear ejemplos reales de esta clase. En otras palabras: si la clase Studentes un retrato de lo que debería ser un estudiante, entonces la instancia creada es el estudiante mismo. Un ejemplo de creación de un nuevo estudiante: new Student("Ivan", "KI-17-2", "Computer Engineering");el operador newbusca la clase Studenty luego llama a un método especial (constructor) de esta clase. El constructor devuelve un objeto de clase ya preparado Student: nuestro querido y hambriento estudiante sin beca :))

Tipos de clases en Java

En Java existen 4 tipos de clases dentro de otra clase:
  1. Las clases internas anidadas son clases no estáticas dentro de una clase externa.

  2. Las clases estáticas anidadas son clases estáticas dentro de una clase externa.

  3. Las clases locales de Java son clases dentro de métodos.

  4. Las clases anónimas de Java son clases que se crean sobre la marcha.

Hablaremos de cada uno de ellos por separado.

Clases no estáticas dentro de una clase externa.

Primero quiero que entiendas qué es esto con un ejemplo real, porque hace que sea mucho más fácil de entender. ¡Así que ahora dividiremos algo realmente grande en componentes más pequeños y desmontaremos un avión! Sin embargo, a modo de ejemplo, bastará con mostrar un poco; no lo desglosaremos por completo. Para visualizar este proceso, usaremos un diagrama de avión. Clases, tipos de clases anidadas con ejemplos - 2 Primero, necesitamos crear una clase Airplanedonde podamos agregar una pequeña descripción: nombre de la aeronave, código de identificación, vuelo.
public class Airplane {
    private String name, id, flight;

    public Airplane(String name, String id, String flight) {
        this.name = name;
        this.id = id;
        this.flight = flight;
    }

    // getters/setters
}
Ahora queremos agregar alas. ¿Crear una clase separada? Quizás esta sea la lógica si tenemos un programa complejo para diseñar aviones, y donde necesitamos crear una gran cantidad de clases derivadas (clases que tienen la misma lógica que la clase padre, es decir, la clase de la que heredan, pero por lo que amplían la clase principal agregando lógica o características más detalladas), pero ¿qué pasa si solo tenemos un juego en el que tenemos un avión? Entonces será más racional para nosotros completar toda la estructura en un solo lugar (en una clase). Aquí es donde entran en juego las clases anidadas no estáticas. Básicamente, esta es una descripción más detallada de algunos detalles de nuestra clase externa. En este ejemplo, necesitamos crear alas para un avión: izquierda y derecha. ¡Vamos a crear!
public class Airplane {
    private String name, id, flight;
    private Wing leftWing = new Wing("Red", "X3"), rightWing = new Wing("Blue", "X3");

    public Airplane(String name, String id, String flight) {
        this.name = name;
        this.id = id;
        this.flight = flight;
    }

    private class Wing {
        private String color, model;

        private Wing(String color, String model) {
            this.color = color;
            this.model = model;
        }

        // getters/setters
    }

    // getters/setters
}
Así que creamos una clase anidada no estática Wing(ala) dentro de una clase Airplane(avión) y agregamos dos variables: ala izquierda y ala derecha. Y cada ala tiene sus propias propiedades (color, modelo) que podemos cambiar. De esta manera podrá dotar de personal a las estructuras tanto como necesite. Y tenga en cuenta: anteriormente en el diagrama había muchas piezas para el avión y, de hecho, podemos dividir todas las piezas en clases internas, pero ese proceso no siempre es aconsejable. Estos momentos deben rastrearse según la tarea. Es posible que no necesites alas para resolver el problema. Entonces no hay necesidad de hacerlos. Es como cortar a una persona en piernas, brazos, torso y cabeza; es posible, pero ¿por qué si esta clase solo se usa para almacenar datos sobre personas? Características de las clases Java anidadas no estáticas:
  1. Sólo existen en objetos, por lo que para crearlos necesitas un objeto. En otras palabras: diseñamos nuestra ala para que sea parte de un avión, por lo que para crear un ala necesitamos un avión; de lo contrario, no lo necesitamos.
  2. No puede haber variables estáticas dentro de una clase Java. Si necesita algunas constantes o cualquier otra cosa estática, debe moverlas a una clase externa. Esto se debe al estrecho acoplamiento de la clase anidada no estática con la clase externa.
  3. La clase tiene acceso completo a todos los campos privados de la clase externa. Esta característica funciona de dos maneras.
  4. Puede obtener una referencia a una instancia de una clase externa. Ejemplo: Avión. Este es un enlace a un avión, este es un enlace a un ala.

Clases estáticas dentro de una clase externa.

Este tipo de clase no se diferencia de una clase externa normal, excepto por una cosa: para crear una instancia de dicha clase, debe enumerar la ruta completa desde la clase externa hasta la deseada, separada por un punto. Por ejemplo: Building.Plaftorm platform = new Building.Platform(); las clases estáticas se utilizan para colocar clases relacionadas una al lado de la otra para que sea más fácil trabajar con la estructura lógica. Por ejemplo: podemos crear una clase externa Building, donde habrá una lista específica de clases que representarán un edificio específico.
public abstract class Building {
    private String name, address, type;

    Building(String name, String address) {
        this.name = name;
        this.address = address;
    }

    public static class Platform extends Building {
        public Platform(String name, String address) {
            super(name, address);
            setType("Platform");
        }

        // some additional logic
    }

    public static class House extends Building {
        public House(String name, String address) {
            super(name, address);
            setType("House");
        }

        // some additional logic
    }

    public static class Shop extends Building {
        public Shop(String name, String address) {
            super(name, address);
            setType("Shop");
        }

        // some additional logic
    }

    // getters/setters
}
Este ejemplo demuestra cómo las clases estáticas le permiten empaquetar una estructura lógica en una forma más conveniente. Si no existieran, necesitaríamos crear 4 clases completamente diferentes. Las ventajas de este enfoque:
  1. El número de clases ha disminuido.
  2. Todas las clases están dentro de su clase principal. Podemos rastrear toda la jerarquía sin abrir cada clase por separado.
  3. Podemos referirnos a la clase Construcción y el IDE ya mostrará la lista completa de todas las subclases de esta clase. Esto hará que sea más fácil encontrar las clases que necesita y le mostrará el panorama completo de manera más integral.
Un ejemplo de creación de una instancia de una clase estática anidada:Building.Shop myShop = new Building.Shop(“Food & Fun!”, “Kalyaeva 8/53”); también me gustaría señalar que esta estrategia se utiliza en clases AWT 2D para describir formas, como Line2D, Arc2D, Ellipse2D y otras.

clases locales

Estas clases se declaran dentro de otros métodos. De hecho, tienen todas las propiedades de una clase anidada no estática, solo que sus instancias solo pueden crearse en un método, y el método no puede ser estático (para crearlas necesitas una instancia de una clase externa, una referencia a una La instancia del objeto que llama se pasa implícitamente a métodos no estáticos y en un método estático no hay ningún método para este enlace). Pero tienen sus propias características:
  1. Las clases locales solo pueden funcionar con variables del método final. La cuestión es que las instancias de clases locales se pueden almacenar en el montón una vez que se completa el método y la variable se puede borrar. Si la variable se declara final, entonces el compilador puede guardar una copia de la variable para que el objeto la utilice más adelante. Y una cosa más: desde las versiones 8+ de Java, puedes usar variables no finales en clases locales, pero solo con la condición de que no cambien.
  2. Las clases locales no se pueden declarar con modificadores de acceso.
  3. Las clases locales tienen acceso a las variables del método.
Las clases locales se pueden encontrar muy raramente, ya que dificultan la lectura del código y no tienen ninguna ventaja, excepto una: el acceso a las variables del método. No sé qué ejemplo de clase local se puede tomar que muestre su uso efectivo, así que solo mostraré mi ejemplo. Digamos que tenemos una clase Person(se supondrá que es una persona) con propiedades street(calle), house(casa). Nos gustaría devolver algún objeto para acceder solo a la ubicación de la persona. Para ello, creamos la interfaz AddressContainer, que implica un almacenamiento de datos sobre la ubicación de una persona.
public class Person {
    private String name, street, house;

    public Person(String name, String street, String house) {
        this.name = name;
        this.street = street;
        this.house = house;
    }

    private interface AddressContainer {
        String getStreet();
        String getHouse();
    }

    public AddressContainer getAddressContainer() {
        class PersonAddressContainer implements AddressContainer {
            final String street = Person.this.street, house = Person.this.house;

            @Override
            public String getStreet() {
                return this.street;
            }

            @Override
            public String getHouse() {
                return this.house;
            }
        }

        return new PersonAddressContainer();
    }

    public static void main(String[] args) {
        Person person = new Person("Nikita", "Sholohova", "17");

        AddressContainer address = person.getAddressContainer();

        System.out.println("Address: street - " + address.getStreet() + ", house - " + address.getHouse());
    }

    // getters/setters
}
Como puede ver, dentro del método creamos una clase que implementa el almacenamiento de la ubicación de una persona, creamos variables constantes allí (para que después de salir del método, las variables se almacenaran en un objeto) e implementamos un método para obtener la dirección y casa. Ahora podemos usar este objeto en otros lugares del programa para obtener la ubicación de una persona. Entiendo que este ejemplo no es ideal y sería más correcto hacerlo simplemente dejando getters en la clase Person, sin embargo, se mostró la creación de esta clase y su posible uso, y luego ya depende de ti.

clases anónimas

En esencia, las clases anónimas son simplemente clases anidadas no estáticas normales. Su peculiaridad es su facilidad de uso. Puede escribir su clase directamente al crear una instancia de otra clase.
public class Animal {
    public void meow() {
        System.out.println("Meow!");
    }

    public static void main(String[] args) {
        Animal anonTiger = new Animal() {
            @Override
            public void meow() {
                System.out.println("Raaar!");
            }
        };

        Animal notAnonTiger = new Animal().new Tiger();

        anonTiger.meow(); // будет выведено Raaar!
        notAnonTiger.meow(); // будет выведено Raaar!
    }

    private class Tiger extends Animal {
        @Override
        public void meow() {
            System.out.println("Raaar!");
        }
    }
}
Esencialmente, simplemente estamos combinando dos cosas en un solo lugar: crear una instancia de una clase ( Animal) y crear una instancia de su clase interna heredera ( Tiger). De lo contrario, necesitamos crear la clase por separado y usar construcciones más largas para lograr el mismo resultado. El uso de clases anónimas está justificado en muchos casos, en particular cuando:
  • el cuerpo de clases es muy corto;
  • sólo se necesita una instancia de la clase;
  • la clase se utiliza en el lugar donde fue creada o inmediatamente después;
  • El nombre de la clase no es importante y no hace que el código sea más fácil de entender.
Las clases anónimas se utilizan a menudo en las GUI para crear controladores de eventos. Por ejemplo, para crear un botón y reaccionar a su clic:
JButton b2 = new JButton("Click");
b2.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        System.out.println("Кнопка нажата!");
    }
});
Sin embargo, después de Java 8 comenzaron a usar expresiones lambda, pero aún se escribió mucho código antes de la versión 8 y es posible que encuentres (y encontrarás durante tu entrenamiento en JavaRush) este tipo de inscripciones.\ Análogo con lambdas:
JButton b2 = new JButton("Click");
b2.addActionListener(e -> System.out.println("Кнопка нажата!"));
Fin del artículo Gracias a todos por su atención y espero que hayan aprendido algo nuevo o hayan entendido algo que no entendían antes. También me gustaría aclarar que este artículo pertenece a la categoría de “atención al detalle” . Este es mi primer trabajo, así que espero que haya sido útil para alguien. En un futuro próximo, cuando surjan nuevas ideas, intentaré escribir algo más, solo tengo una idea... Buena suerte a todos y éxito en la programación :)
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION