Entrevista de Java: preguntas de programación orientada a objetos
1. ¿Qué características tiene Java?
Respuesta:-
Conceptos de programación orientada a objetos:
- orientación de objetos;
- herencia;
- encapsulación;
- polimorfismo;
- abstracción.
-
Multiplataforma: un programa Java se puede ejecutar en cualquier plataforma sin modificaciones. Lo único que necesita es una JVM (máquina virtual Java) instalada.
-
Alto rendimiento: JIT (compilador Just In Time) permite un alto rendimiento. JIT convierte el código de bytes en código de máquina y luego la JVM comienza la ejecución.
- Multihilo: un hilo de ejecución conocido como
Thread
. La JVM crea un hilo llamadomain thread
. Un programador puede crear múltiples subprocesos heredando de la clase Thread o implementando una interfazRunnable
.
2. ¿Qué es la herencia?
Herencia significa que una clase puede heredar (“ extender ”) otra clase. De esta manera puedes reutilizar el código de la clase de la que heredas. La clase existente se conoce comosuperclass
, y la que se está creando se conoce como subclass
. También dicen parent
y child
.
public class Animal {
private int age;
}
public class Dog extends Animal {
}
donde Animal
esta parent
, y Dog
- child
.
3. ¿Qué es la encapsulación?
Esta pregunta surge a menudo durante las entrevistas con desarrolladores de Java. La encapsulación oculta la implementación mediante modificadores de acceso, captadores y definidores. Esto se hace con el fin de cerrar el acceso para uso externo en aquellos lugares donde los desarrolladores lo consideren necesario. Un ejemplo accesible de la vida es un automóvil. No tenemos acceso directo al funcionamiento del motor. Para nosotros, el trabajo es poner la llave en el contacto y encender el motor. Y los procesos que se llevarán a cabo bajo el capó no son asunto nuestro. Además, nuestra intromisión en esta actividad puede dar lugar a una situación impredecible, por la que podemos romper el coche y hacernos daño. En programación pasa exactamente lo mismo. Bien descrito en Wikipedia . También hay un artículo sobre encapsulación en JavaRush .4. ¿Qué es el polimorfismo?
El polimorfismo es la capacidad de un programa de utilizar de forma idéntica objetos con la misma interfaz sin información sobre el tipo específico de ese objeto. Como dicen, una interfaz, muchas implementaciones. Con el polimorfismo, puedes combinar y utilizar diferentes tipos de objetos según su comportamiento común. Por ejemplo, tenemos una clase Animal que tiene dos descendientes: Perro y Gato. La clase Animal genérica tiene un comportamiento común para todos: emitir un sonido. En el caso de que necesitemos reunir a todos los descendientes de la clase Animal y ejecutar el método "hacer un sonido", utilizamos las posibilidades del polimorfismo. Así es como se verá:List<Animal> animals = Arrays.asList(new Cat(), new Dog(), new Cat());
animals.forEach(animal -> animal.makeSound());
Entonces el polimorfismo nos ayuda. Además, esto también se aplica a los métodos polimórficos (sobrecargados). Práctica de uso del polimorfismo.
Preguntas de la entrevista: sintaxis de Java
5. ¿Qué es un constructor en Java?
Son válidas las siguientes características:- Cuando se crea un nuevo objeto, el programa utiliza el constructor apropiado para hacerlo.
- Un constructor es como un método. Su peculiaridad es que no hay ningún elemento que regrese (incluido el vacío) y su nombre es el mismo que el nombre de la clase.
- Si no se escribe ningún constructor explícitamente, se creará automáticamente un constructor vacío.
- El constructor se puede anular.
- Si se creó un constructor con parámetros, pero también se necesita sin parámetros, se debe escribir por separado, ya que no se crea automáticamente.
6. ¿Qué dos clases no heredan de Object?
No se deje engañar por las provocaciones, no existen tales clases: ¡todas las clases directamente o a través de ancestros se heredan de la clase Objeto!7. ¿Qué es la variable local?
Otra pregunta popular durante una entrevista para un desarrollador de Java. Una variable local es una variable que se define dentro de un método y existe hasta el momento en que se ejecuta el método. Una vez finalizada la ejecución, la variable local dejará de existir. Aquí hay un programa que usa la variable local helloMessage en el método main():public static void main(String[] args) {
String helloMessage;
helloMessage = "Hello, World!";
System.out.println(helloMessage);
}
8. ¿Qué es la variable de instancia?
La variable de instancia es una variable que se define dentro de una clase y existe hasta el momento en que existe el objeto. Un ejemplo es la clase Bee, que tiene dos variables nectarCapacity y maxNectarCapacity:public class Bee {
/**
* Current nectar capacity
*/
private double nectarCapacity;
/**
* Maximal nectar that can take bee.
*/
private double maxNectarCapacity = 20.0;
...
}
9. ¿Qué son los modificadores de acceso?
Los modificadores de acceso son una herramienta que le permite personalizar el acceso a clases, métodos y variables. Existen los siguientes modificadores, ordenados en orden creciente de acceso:private
- utilizado para métodos, campos y constructores. El nivel de acceso es sólo la clase dentro de la cual se declara.package-private(default)
- se puede utilizar para clases. Acceso solo en un paquete específico en el que se declara una clase, método, variable, constructor.protected
— el mismo acceso quepackage-private
+ para aquellas clases que heredan de una clase con el modificadorprotected
.public
- También se utiliza para clases. Acceso completo a toda la aplicación.
10. ¿Qué son los métodos primordiales?
La anulación de métodos ocurre cuando el niño quiere cambiar el comportamiento de la clase principal. Si desea que se ejecute lo que está en el método principal, puede usar una construcción como super.methodName() en el método secundario, que hará el trabajo del método principal y solo entonces agregará lógica. Requisitos a cumplir:- la firma del método debe ser la misma;
- el valor de retorno debe ser el mismo.
11. ¿Qué es la firma de un método?
La firma de un método es un conjunto del nombre del método y los argumentos que acepta el método. La firma de un método es un identificador único de un método cuando se sobrecargan métodos.12. ¿Qué es la sobrecarga de métodos?
La sobrecarga de métodos es una propiedad del polimorfismo en la que al cambiar la firma del método, puedes crear diferentes métodos para las mismas acciones:- mismo nombre de método;
- diferentes argumentos;
- puede haber un tipo de devolución diferente.
add()
se ArrayList
puede sobrecargar de la siguiente manera y realizará la suma de una manera diferente, dependiendo de los argumentos entrantes:
add(Object o)
- simplemente añade un objeto;add(int index, Object o)
— agrega un objeto a un índice específico;add(Collection<Object> c)
— agrega una lista de objetos;add(int index, Collection<Object> c)
— agrega una lista de objetos, a partir de un índice determinado.
13. ¿Qué es la interfaz?
La herencia múltiple no está implementada en Java, por lo que para superar este problema, se agregaron interfaces tal como las conocemos;) Durante mucho tiempo, las interfaces solo tenían métodos sin implementarlos. Como parte de esta respuesta, hablaremos de ellos. Por ejemplo:
public interface Animal {
void makeSound();
void eat();
void sleep();
}
De esto se desprenden algunos matices:
- todos los métodos de la interfaz son públicos y abstractos;
- todas las variables son públicas estáticas finales;
- las clases no los heredan (extienden), sino que los implementan (implementan). Además, puedes implementar tantas interfaces como quieras.
- Las clases que implementan una interfaz deben proporcionar implementaciones de todos los métodos que tiene la interfaz.
public class Cat implements Animal {
public void makeSound() {
// implementación del método
}
public void eat() {
// implementación
}
public void sleep() {
// implementación
}
}
14. ¿Cuál es el método predeterminado en la interfaz?
Ahora hablemos de los métodos predeterminados. ¿Para qué, para quién? Estos métodos se agregaron para que todo fuera “tanto tuyo como nuestro”. ¿De qué estoy hablando? Sí, por un lado, era necesario agregar una nueva funcionalidad: lambdas, Stream API, por otro lado, era necesario dejar aquello por lo que Java es famoso: la compatibilidad con versiones anteriores. Para hacer esto, fue necesario introducir soluciones listas para usar en las interfaces. Así es como nos llegaron los métodos predeterminados. Es decir, el método predeterminado es un método implementado en la interfaz que tiene la palabra clavedefault
. Por ejemplo, el conocido método stream()
en Collection
. Compruébalo, esta interfaz no es tan sencilla como parece ;). O también un método igualmente conocido forEach()
de Iterable
. Tampoco existía hasta que se agregaron los métodos predeterminados. Por cierto, también puedes leer sobre esto en JavaRush .
15. ¿Cómo entonces heredar dos métodos predeterminados idénticos?
Según la respuesta anterior sobre cuál es el método predeterminado, puedes hacer otra pregunta. Si puede implementar métodos en interfaces, entonces, en teoría, puede implementar dos interfaces con el mismo método, y ¿cómo hacerlo? Hay dos interfaces diferentes con el mismo método:interface A {
default void foo() {
System.out.println("Foo A");
}
}
interface B {
default void foo() {
System.out.println("Foo B");
}
}
Y hay una clase que implementa estas dos interfaces. Para evitar incertidumbre y compilar el código, necesitamos anular el método foo()
en la clase C
y podemos simplemente llamar a un método foo()
de cualquiera de las interfaces que contiene, A
o B
. Pero, ¿ cómo elegir un método de interfaz específico А
? В
Hay una estructura como esta para esto A.super.foo()
:
public class C implements A, B {
@Override
public void foo() {
A.super.foo();
}
}
o:
public class C implements A, B {
@Override
public void foo() {
B.super.foo();
}
}
Por lo tanto, un método foo()
de clase C
utilizará el método predeterminado foo()
de la interfaz A
o un método foo()
de la interfaz B
.
16. ¿Qué son los métodos y clases abstractos?
Java tiene una palabra reservadaabstract
que se utiliza para indicar clases y métodos abstractos. Primero, algunas definiciones. Un método abstracto es un método que se crea sin una implementación con una palabra clave abstract
en una clase abstracta. Es decir, este es un método como en la interfaz, solo que con la adición de una palabra clave, por ejemplo:
public abstract void foo();
Una clase abstracta es una clase que también tiene abstract
la palabra:
public abstract class A {
}
Una clase abstracta tiene varias características:
- no se puede crear un objeto sobre su base;
- puede tener métodos abstractos;
- puede que no tenga métodos abstractos.
17. ¿Cuál es la diferencia entre String, String Builder y String Buffer?
Los valoresString
se almacenan en un grupo de cadenas constante. Una vez que se crea una fila, aparecerá en este grupo. Y no será posible eliminarlo. Por ejemplo:
String name = "book";
...la variable se referirá al grupo de cadenas Grupo de cadenas constantes Si establece el nombre de la variable en un valor diferente, obtendrá lo siguiente:
name = "pen";
Grupo de cadenas constantes Entonces estos dos valores permanecerán allí. Búfer de cadena:
- Los valores
String
se almacenan en la pila. Si se cambia el valor, el nuevo valor será reemplazado por el anterior; String Buffer
sincronizado y por lo tanto seguro para subprocesos;- Debido a la seguridad del hilo, la velocidad de funcionamiento deja mucho que desear.
StringBuffer name = "book";
Tan pronto como el valor del nombre cambia, el valor en la pila cambia: StringBuilder Exactamente igual que StringBuffer
, solo que no es seguro para subprocesos. Por tanto, su velocidad es claramente mayor que en StringBuffer
.
18. ¿Cuál es la diferencia entre una clase abstracta y una interfaz?
Clase abstracta:- las clases abstractas tienen un constructor predeterminado; se llama cada vez que se crea un hijo de esta clase abstracta;
- Contiene métodos tanto abstractos como no abstractos. En general, puede que no contenga métodos abstractos, pero aún así sea una clase abstracta;
- una clase que hereda de una abstracta debe implementar sólo métodos abstractos;
- una clase abstracta puede contener una variable de instancia (consulte la pregunta n.° 5).
- no tiene constructor y no se puede inicializar;
- sólo se deben agregar métodos abstractos (sin contar los métodos predeterminados);
- las clases que implementan una interfaz deben implementar todos los métodos (sin contar los métodos predeterminados);
- Las interfaces solo pueden contener constantes.
19. ¿Por qué acceder a un elemento de una matriz requiere O(1)?
Esta pregunta es literalmente de la última entrevista. Como supe más tarde, esta pregunta se hace para ver cómo piensa una persona. Está claro que este conocimiento tiene poco significado práctico: basta con conocer este hecho. Primero, debemos aclarar que O(1) es una designación para la complejidad temporal de un algoritmo cuando la operación se realiza en tiempo constante. Es decir, esta designación es la ejecución más rápida. Para responder a esta pregunta, ¿necesitamos comprender lo que sabemos sobre las matrices? Para crear un arrayint
, debemos escribir lo siguiente:
int[] intArray = new int[100];
De esta grabación se pueden sacar varias conclusiones:
- Al crear una matriz, se conoce su tipo, si se conoce el tipo, entonces está claro qué tamaño tendrá cada celda de la matriz.
- Se sabe qué tamaño tendrá la matriz.
¿Cómo se obtiene O(1) al acceder a objetos en una ArrayList?
Esta pregunta sigue inmediatamente a la anterior. Es cierto que cuando trabajamos con un array y hay primitivas ahí, sabemos de antemano cuál es el tamaño de ese tipo cuando se crea. Pero, ¿qué pasa si hay un esquema como el de la imagen: y queremos crear una colección con elementos de tipo A y agregar diferentes implementaciones: B, C, D:List<A> list = new ArrayList();
list.add(new B());
list.add(new C());
list.add(new D());
list.add(new B());
En esta situación, ¿cómo se puede saber qué tamaño tendrá cada celda, porque cada objeto será diferente y puede tener diferentes campos adicionales (o ser completamente diferentes)? ¿Qué hacer? Aquí la pregunta se plantea de tal manera que confunde y confunde. Sabemos que, de hecho, la colección no almacena objetos, solo enlaces a estos objetos. Y todos los enlaces tienen el mismo tamaño, y se sabe. Entonces contar el espacio aquí funciona de la misma manera que en la pregunta anterior.
21. Autoboxing y unboxing
Antecedentes históricos: el autoboxing y el autounboxing son una de las principales innovaciones de JDK 5. El autoboxing es el proceso de conversión automática de un tipo primitivo a la clase contenedora apropiada. Auto-unboxing : hace exactamente lo opuesto al auto-boxing: convierte una clase contenedora en una primitiva. Pero si hay un valor contenedornull
, se generará una excepción durante el descomprimido NullPointerException
.
Coincidencia primitiva - contenedor
Primitivo | clase contenedora |
---|---|
booleano | Booleano |
En t | Entero |
byte | Byte |
carbonizarse | Personaje |
flotar | Flotar |
largo | Largo |
corto | Corto |
doble | Doble |
Se produce el embalaje automático:
-
al asignar una primitiva una referencia a la clase contenedora:
ANTES de Java 5:
//empaquetado manual o como era ANTES de Java 5. public void boxingBeforeJava5() { Boolean booleanBox = new Boolean(true); Integer intBox = new Integer(3); // y así sucesivamente con otros tipos } после Java 5: //empaquetado automático o cómo se convirtió en Java 5. public void boxingJava5() { Boolean booleanBox = true; Integer intBox = 3; // y así sucesivamente con otros tipos }
-
al pasar una primitiva como argumento a un método que espera un contenedor:
public void exampleOfAutoboxing() { long age = 3; setAge(age); } public void setAge(Long age) { this.age = age; }
Se produce el desembalaje automático:
-
cuando asignamos una variable primitiva a la clase contenedora:
//antes de Java 5: int intValue = new Integer(4).intValue(); double doubleValue = new Double(2.3).doubleValue(); char c = new Character((char) 3).charValue(); boolean b = Boolean.TRUE.booleanValue(); //y después de JDK 5: int intValue = new Integer(4); double doubleValue = new Double(2.3); char c = new Character((char) 3); boolean b = Boolean.TRUE;
-
En los casos con operaciones aritméticas. Se aplican solo a tipos primitivos; para esto es necesario realizar unboxing al primitivo.
// Antes de Java 5 Integer integerBox1 = new Integer(1); Integer integerBox2 = new Integer(2); // para comparar era necesario hacer esto: integerBox1.intValue() > integerBox2.intValue() //в Java 5 integerBox1 > integerBox2
-
cuando se pasa a un contenedor en un método que acepta la primitiva correspondiente:
public void exampleOfAutoboxing() { Long age = new Long(3); setAge(age); } public void setAge(long age) { this.age = age; }
22. ¿Cuál es la palabra clave final y dónde utilizarla?
La palabra clavefinal
se puede utilizar para variables, métodos y clases.
- Una variable final no se puede reasignar a otro objeto.
- la clase final es estéril)) no puede tener herederos.
- El método final no se puede anular en un antepasado.
variables finales
;Java nos ofrece dos formas de crear una variable y asignarle algún valor:- Puede declarar una variable e inicializarla más tarde.
- Puede declarar una variable y asignarla inmediatamente.
public class FinalExample {
//variable estática final, que se inicializa inmediatamente:
final static String FINAL_EXAMPLE_NAME = "I'm likely final one";
//final es una variable que no se inicializa, pero solo funcionará si
//inicializar esto en el constructor:
final long creationTime;
public FinalExample() {
this.creationTime = System.currentTimeMillis();
}
public static void main(String[] args) {
FinalExample finalExample = new FinalExample();
System.out.println(finalExample.creationTime);
// campo final FinalExample.FINAL_EXAMPLE_NAME no se puede asignar
// FinalExample.FINAL_EXAMPLE_NAME = "Not you're not!";
// no se puede asignar el campo final Config.creationTime
// finalExample.creationTime = 1L;
}
}
¿Se puede considerar la variable final como una constante?
Como no podremos asignar un nuevo valor a una variable final, parece que se trata de variables constantes. Pero esto es sólo a primera vista. Si el tipo de datos al que se refiere la variable esimmutable
, entonces sí, es una constante. Pero si el tipo de datos mutable
es mutable, utilizando métodos y variables será posible cambiar el valor del objeto al que final
se refiere la variable, y en este caso no se le puede llamar constante. Entonces, el ejemplo muestra que algunas de las variables finales son realmente constantes, pero otras no lo son y se pueden cambiar.
public class FinalExample {
//variables finales inmutables:
final static String FINAL_EXAMPLE_NAME = "I'm likely final one";
final static Integer FINAL_EXAMPLE_COUNT = 10;
// variables de filtro mutables
final List<String> addresses = new ArrayList();
final StringBuilder finalStringBuilder = new StringBuilder("constant?");
}
Variables finales locales
Cuandofinal
se crea una variable dentro de un método, se llama local final
variable:
public class FinalExample {
public static void main(String[] args) {
// Así es como puedes
final int minAgeForDriveCar = 18;
// o puedes hacerlo de esta manera, en el bucle foreach:
for (final String arg : args) {
System.out.println(arg);
}
}
}
Podemos usar la palabra clave final
en bucle extendido for
porque después de completar una iteración del bucle, for
se crea una nueva variable cada vez. Pero esto no se aplica a un bucle for normal, por lo que el siguiente código generará un error en tiempo de compilación.
// final local modificado j no se puede asignar
for (final int i = 0; i < args.length; i ++) {
System.out.println(args[i]);
}
clase final
No se puede extender una clase declarada comofinal
. En pocas palabras, ninguna clase puede heredar de ésta. Un gran ejemplo final
de una clase en el JDK es String
. El primer paso para crear una clase inmutable es marcarla como final
para que no pueda ampliarse:
public final class FinalExample {
}
// Error de compilación aquí
class WantsToInheritFinalClass extends FinalExample {
}
Métodos finales
Cuando un método está marcado como final, se llama método final (lógico, ¿verdad?). El método Final no se puede anular en una clase descendiente. Por cierto, los métodos de la clase Object (esperar() y notificar()) son finales, por lo que no tenemos la posibilidad de anularlos.public class FinalExample {
public final String generateAddress() {
return "Some address";
}
}
class ChildOfFinalExample extends FinalExample {
// error de compilación aquí
@Override
public String generateAddress() {
return "My OWN Address";
}
}
Cómo y dónde usar final en Java
- use la palabra clave final para definir algunas constantes a nivel de clase;
- cree variables finales para objetos cuando no desee que se modifiquen. Por ejemplo, propiedades específicas de objetos que podemos usar con fines de registro;
- si no desea que la clase se extienda, márquela como final;
- si necesita crear una clase inmutable <, debe hacerla definitiva;
- Si desea que la implementación de un método no cambie en sus descendientes, designe el método como
final
. Esto es muy importante para garantizar que la implementación no cambie.
23. ¿Qué es mutable e inmutable?
Mudable
Mutables son objetos cuyos estados y variables se pueden cambiar después de la creación. Por ejemplo, clases como StringBuilder, StringBuffer. Ejemplo:public class MutableExample {
private String address;
public MutableExample(String address) {
this.address = address;
}
public String getAddress() {
return address;
}
// este setter puede cambiar el campo de nombre
public void setAddress(String address) {
this.address = address;
}
public static void main(String[] args) {
MutableExample obj = new MutableExample("first address");
System.out.println(obj.getAddress());
// actualice el campo de nombre, por lo que este es un objeto mutable
obj.setAddress("Updated address");
System.out.println(obj.getAddress());
}
}
Inmutable
Inmutables son objetos cuyos estados y variables no se pueden cambiar después de crear el objeto. ¿Por qué no una gran clave para un HashMap, verdad?) Por ejemplo, String, Integer, Double, etc. Ejemplo:// hacer que esta clase sea final para que nadie pueda cambiarla
public final class ImmutableExample {
private String address;
ImmutableExample (String address) {
this.address = address;
}
public String getAddress() {
return address;
}
//quitar el setter
public static void main(String[] args) {
ImmutableExample obj = new ImmutableExample("old address");
System.out.println(obj.getAddress());
// Por lo tanto, no cambie este campo de ninguna manera, por lo que este es un objeto inmutable
// obj.setName("new address");
// System.out.println(obj.getName());
}
}
24. ¿Cómo escribir una clase inmutable?
Después de descubrir qué son los objetos mutables e inmutables, la siguiente pregunta es natural: ¿cómo escribirlos? Para escribir una clase inmutable inmutable, debe seguir unos sencillos pasos:- hacer la clase definitiva.
- haga que todos los campos sean privados y cree solo captadores para ellos. Los configuradores, por supuesto, no son necesarios.
- Haga que todos los campos mutables sean finales para que el valor solo se pueda establecer una vez.
- inicializar todos los campos a través del constructor, realizando una copia profunda (es decir, copiando el objeto en sí, sus variables, variables de variables, etc.)
- clonar objetos variables mutables en captadores para devolver solo copias de valores y no referencias a objetos reales.
/**
* Un ejemplo de creación de un objeto inmutable.
*/
public final class FinalClassExample {
private final int age;
private final String name;
private final HashMap<String, String> addresses;
public int getAge() {
return age;
}
public String getName() {
return name;
}
/**
* Clona el objeto antes de devolverlo.
*/
public HashMap<String, String> getAddresses() {
return (HashMap<String, String>) addresses.clone();
}
/**
* En el constructor, copia en profundidad los objetos mutables.
*/
public FinalClassExample(int age, String name, HashMap<String, String> addresses) {
System.out.println("Realizando una copia profunda en el constructor");
this.age = age;
this.name = name;
HashMap<String, String> temporaryMap = new HashMap<>();
String key;
Iterator<String> iterator = addresses.keySet().iterator();
while (iterator.hasNext()) {
key = iterator.next();
temporaryMap.put(key, addresses.get(key));
}
this.addresses = temporaryMap;
}
}
GO TO FULL VERSION