Medio
Son comunes
1. ¿Cuáles son las ventajas y desventajas de la programación orientada a objetos en comparación con la programación procedimental/funcional?
Había esta pregunta en el análisis de preguntas para Junior y, en consecuencia, ya la respondí. Busque esta pregunta y su respuesta en esta parte del artículo, preguntas 16 y 17.2. ¿En qué se diferencia la agregación de la composición?
En POO, existen varios tipos de interacción entre objetos, unidos bajo el concepto general de "Relación Tiene-A". Esta relación indica que un objeto es un componente de otro objeto. Al mismo tiempo, existen dos subtipos de esta relación: Composición : un objeto crea otro objeto y la vida útil de otro objeto depende de la vida útil del creador. Agregación : un objeto recibe un enlace (puntero) a otro objeto durante el proceso de construcción (en este caso, la vida útil del otro objeto no depende de la vida útil del creador). Para una mejor comprensión, veamos un ejemplo específico. Tenemos una determinada clase de automóvil - Car , que a su vez tiene campos internos del tipo - Engine y una lista de pasajeros - List<Passenger> , también tiene un método para iniciar el movimiento - startMoving() :public class Car {
private Engine engine;
private List<Passenger> passengers;
public Car(final List<Passenger> passengers) {
this.engine = new Engine();
this.passengers = passengers;
}
public void addPassenger(Passenger passenger) {
passengers.add(passenger);
}
public void removePassengerByIndex(Long index) {
passengers.remove(index);
}
public void startMoving() {
engine.start();
System.out.println("Машина начала своё движение");
for (Passenger passenger : passengers) {
System.out.println("В машине есть пассажир - " + passenger.getName());
}
}
}
En este caso, la Composición es la conexión entre Car y Engine , ya que el rendimiento del auto depende directamente de la presencia del objeto motor, porque si motor = null , entonces recibiremos una NullPointerException . A su vez, un motor no puede existir sin una máquina (¿por qué necesitamos un motor sin una máquina?) y no puede pertenecer a varias máquinas al mismo tiempo. Esto significa que si eliminamos el objeto Car , no habrá más referencias al objeto Engine y pronto será eliminado por Garbage Collector . Como puede ver, esta relación es muy estricta (fuerte). La agregación es la conexión entre Car y Passenger , ya que el rendimiento de Car no depende de ningún modo de los objetos del tipo Passenger y su número. Pueden abandonar el automóvil - removePassengerByIndex(Long index) o ingresar nuevos - addPassenger(Passenger pasajero) , a pesar de esto, el automóvil seguirá funcionando correctamente. A su vez, los objetos Passenger pueden existir sin un objeto Car . Como comprenderá, esta es una conexión mucho más débil de la que vemos en la composición. Pero eso no es todo, un objeto que está conectado por agregación con otro también puede tener una conexión determinada con otros objetos en el mismo momento. Por ejemplo, usted, como estudiante de Java, está inscrito en cursos de inglés, programación orientada a objetos y logaritmos al mismo tiempo, pero al mismo tiempo no es una parte críticamente necesaria de ellos, sin los cuales el funcionamiento normal es imposible (como un profesor).
3. ¿Qué patrones GoF has utilizado en la práctica? Dar ejemplos.
Ya respondí esta pregunta antes, así que solo dejaré un enlace al análisis , vea la primera pregunta. También encontré un maravilloso artículo con una hoja de referencia sobre patrones de diseño, que recomiendo tener a mano.4. ¿Qué es un objeto proxy? Dar ejemplos
Un proxy es un patrón de diseño estructural que le permite sustituir objetos sustitutos especiales, o en otras palabras, objetos proxy, en lugar de objetos reales. Estos objetos proxy interceptan llamadas al objeto original, lo que permite insertar cierta lógica antes o después de que la llamada se pase al original. Ejemplos de uso de un objeto proxy:-
Como proxy remoto: se utiliza cuando necesitamos un objeto remoto (un objeto en un espacio de direcciones diferente) que debe representarse localmente. En este caso, el proxy se encargará de la creación de la conexión, codificación, decodificación, etc., mientras que el cliente lo utilizará como si fuera el objeto original ubicado en el espacio local.
-
Como proxy virtual: se utiliza cuando se necesita un objeto que consume muchos recursos. En este caso, el objeto proxy sirve como algo así como una imagen de un objeto real que en realidad aún no existe. Cuando se envía una solicitud real (llamada a un método) a este objeto, solo entonces se carga el objeto original y se ejecuta el método. Este enfoque también se denomina inicialización retrasada; esto puede ser muy conveniente, porque en algunas situaciones el objeto original puede no ser útil y entonces no habrá ningún costo para crearlo.
-
Como proxy de seguridad: se utiliza cuando es necesario controlar el acceso a algún objeto en función de los derechos del cliente. Es decir, si un cliente al que le faltan derechos de acceso intenta acceder al objeto original, el proxy lo interceptará y no lo permitirá.
public interface Processor {
void process();
}
Cuya implementación utiliza demasiados recursos, pero al mismo tiempo es posible que no se utilice cada vez que se inicia la aplicación:
public class HiperDifficultProcessor implements Processor {
@Override
public void process() {
// некоторый сверхсложная обработка данных
}
}
Clase de proxy:
public class HiperDifficultProcessorProxy implements Processor {
private HiperDifficultProcessor processor;
@Override
public void process() {
if (processor == null) {
processor = new HiperDifficultProcessor();
}
processor.process();
}
}
Ejecutémoslo en main :
Processor processor = new HiperDifficultProcessorProxy();
// тут тяжеловсеного оригинального un objetoа, ещё не сущетсвует
// но при этом есть un objeto, который его представляет и у которого можно вызывать его методы
processor.process(); // лишь теперь, un objeto оригинал был создан
Observo que muchos marcos usan proxy, y para Spring este es un patrón clave (Spring está cosido con él por dentro y por fuera). Lea más sobre este patrón aquí .
5. ¿Qué innovaciones se han anunciado en Java 8?
Las innovaciones que trae Java 8 son las siguientes:-
Se han agregado interfaces funcionales, lea sobre qué tipo de bestia es esta aquí .
-
Las expresiones Lambda, que están estrechamente relacionadas con las interfaces funcionales, leen más sobre su uso aquí .
-
Se agregó Stream API para un procesamiento conveniente de las recopilaciones de datos; lea más aquí .
-
Se agregaron enlaces a métodos .
-
El método forEach() se ha agregado a la interfaz Iterable .
-
Se agregó una nueva API de fecha y hora en el paquete java.time , análisis detallado aquí .
-
API concurrente mejorada .
-
Al agregar una clase contenedora opcional , que se usa para manejar correctamente los valores nulos, puede encontrar un excelente artículo sobre este tema aquí .
-
Agregar la capacidad de que las interfaces utilicen métodos estáticos y predeterminados (lo que, en esencia, acerca a Java a la herencia múltiple), más detalles aquí .
-
Se agregaron nuevos métodos a la clase Collection(removeIf(), spliterator()) .
-
Mejoras menores en Java Core.
6. ¿Qué son la alta cohesión y el bajo acoplamiento? Dar ejemplos.
Alta Cohesión o Alta Cohesión es el concepto cuando una determinada clase contiene elementos que están estrechamente relacionados entre sí y combinados para su propósito. Por ejemplo, todos los métodos de la clase Usuario deberían representar el comportamiento del usuario. Una clase tiene baja cohesión si contiene elementos no relacionados. Por ejemplo, la clase Usuario que contiene un método de validación de dirección de correo electrónico:public class User {
private String name;
private String email;
public String getName() {
return this.name;
}
public void setName(final String name) {
this.name = name;
}
public String getEmail() {
return this.email;
}
public void setEmail(final String email) {
this.email = email;
}
public boolean isValidEmail() {
// некоторая логика валидации емейла
}
}
La clase de usuario puede ser responsable de almacenar la dirección de correo electrónico del usuario, pero no de validarla ni enviar el correo electrónico. Por lo tanto, para lograr una alta coherencia, trasladamos el método de validación a una clase de utilidad separada:
public class EmailUtil {
public static boolean isValidEmail(String email) {
// некоторая логика валидации емейла
}
}
Y lo usamos según sea necesario (por ejemplo, antes de guardar al usuario). Low Coupling o Low Coupling es un concepto que describe la baja interdependencia entre módulos de software. Esencialmente, la interdependencia es cómo cambiar uno requiere cambiar el otro. Dos clases tienen un acoplamiento fuerte (o un acoplamiento estrecho) si están estrechamente relacionadas. Por ejemplo, dos clases concretas que almacenan referencias entre sí y llaman a los métodos de cada uno. Las clases poco acopladas son más fáciles de desarrollar y mantener. Como son independientes entre sí, pueden desarrollarse y probarse en paralelo. Además, se pueden cambiar y actualizar sin afectarse entre sí. Veamos un ejemplo de clases fuertemente acopladas. Tenemos alguna clase de estudiantes:
public class Student {
private Long id;
private String name;
private List<Lesson> lesson;
}
Que contiene una lista de lecciones:
public class Lesson {
private Long id;
private String name;
private List<Student> students;
}
Cada lección contiene un enlace para asistir a los estudiantes. Agarre increíblemente fuerte, ¿no crees? ¿Cómo puedes reducirlo? Primero, asegurémonos de que los estudiantes no tengan una lista de materias, sino una lista de sus identificadores:
public class Student {
private Long id;
private String name;
private List<Long> lessonIds;
}
En segundo lugar, la clase de la lección no necesita conocer a todos los estudiantes, así que eliminemos su lista por completo:
public class Lesson {
private Long id;
private String name;
}
Entonces se volvió mucho más fácil y la conexión se volvió mucho más débil, ¿no crees?
POO
7. ¿Cómo se puede implementar la herencia múltiple en Java?
La herencia múltiple es una característica del concepto orientado a objetos donde una clase puede heredar propiedades de más de una clase principal. El problema surge cuando hay métodos con la misma firma tanto en la superclase como en la subclase. Al llamar a un método, el compilador no puede determinar qué método de clase se debe llamar, ni siquiera cuando se llama al método de clase que tiene prioridad. Por lo tanto, ¡Java no admite herencia múltiple! Pero existe una especie de laguna jurídica, de la que hablaremos a continuación. Como mencioné anteriormente, con el lanzamiento de Java 8, se agregó a las interfaces la capacidad de tener métodos predeterminados . Si la clase que implementa la interfaz no anula este método, entonces se utilizará esta implementación predeterminada (no es necesario anular el método predeterminado, como implementar uno abstracto). En este caso, es posible implementar diferentes interfaces en una clase y utilizar sus métodos predeterminados. Veamos un ejemplo. Tenemos una interfaz de volante, con un método fly() predeterminado :public interface Flyer {
default void fly() {
System.out.println("Я лечу!!!");
}
}
La interfaz de Walker, con el método walk() predeterminado :
public interface Walker {
default void walk() {
System.out.println("Я хожу!!!");
}
}
La interfaz del nadador, con el método swim() :
public interface Swimmer {
default void swim() {
System.out.println("Я плыву!!!");
}
}
Bueno, ahora implementemos todo esto en una clase de pato:
public class Duck implements Flyer, Swimmer, Walker {
}
Y ejecutemos todos los métodos de nuestro pato:
Duck donald = new Duck();
donald.walk();
donald.fly();
donald.swim();
En la consola recibiremos:
- Cambie el nombre de los métodos en las interfaces para que difieran entre sí.
- Anule métodos tan controvertidos en la clase de implementación.
- Hereda de una clase que implementa estos métodos controvertidos (entonces tu clase usará exactamente su implementación).
8. ¿Cuál es la diferencia entre los métodos final, finalmente y finalizar()?
final es una palabra clave que se utiliza para imponer una restricción a una clase, método o variable, una restricción significa:- Para una variable: después de la inicialización inicial, la variable no se puede redefinir.
- Para un método, el método no se puede anular en una subclase (clase sucesora).
- Para una clase, la clase no se puede heredar.
GO TO FULL VERSION