Fragen zum Java-Interview

1. Einleitung

Dieser Artikel enthält Antworten auf einige der wichtigsten Fragen zu Vorstellungsgesprächen zu Java. Die Antworten auf einige von ihnen sind möglicherweise nicht offensichtlich, daher hilft dieser Artikel bei der Aufklärung.

2. Fragen zur Core-Java-Sprache für Anfänger

Q1. Werden Daten in Java als Referenz oder als Wert übergeben?

Obwohl die Antwort auf diese Frage ziemlich einfach ist, kann diese Frage für Anfänger verwirrend sein. Lassen Sie uns zunächst klären, worum es bei der Frage geht:

  1. Übergabe nach Wert - Dies bedeutet, dass wir eine Kopie eines Objekts als Parameter an eine Methode übergeben.
  2. Übergabe als Referenz - Dies bedeutet, dass wir eine Referenz auf ein Objekt als Parameter an eine Methode übergeben.

Um die Frage zu beantworten, müssen wir zwei Fälle analysieren. Sie stellen zwei Arten von Daten dar, die wir an eine Methode übergeben können: ein Grundelement und ein Objekt.

Wenn wir Primitive an eine Methode übergeben, wird deren Wert in eine neue Variable kopiert. Bei Objekten wird der Wert der Referenz in eine neue Variable kopiert. Wir können also sagen, dass Java eine streng pass-by-value- Sprache ist.

Mehr dazu erfahren Sie in einem unserer Artikel: Pass-By-Value als Parameterübergabemechanismus in Java.

Q2. Was ist der Unterschied zwischen Import und statischen Importen?

Wir können reguläre Importe verwenden, um eine bestimmte Klasse oder alle in einem anderen Paket definierten Klassen zu importieren:

import java.util.ArrayList; //specific class import java.util.*; //all classes in util package

Wir können sie auch verwenden, um öffentlich verschachtelte Klassen einer einschließenden Klasse zu importieren:

import com.baeldung.A.*

Wir sollten uns jedoch bewusst sein, dass der obige Import die Klasse A selbst nicht importiert .

Es gibt auch statische Importe, mit denen wir statische Mitglieder oder verschachtelte Klassen importieren können:

import static java.util.Collections.EMPTY_LIST;

Der Effekt ist, dass wir die statische Variable EMPTY_LIST verwenden können, ohne den vollständig qualifizierten Klassennamen voranzustellen, dh als ob er in der aktuellen Klasse deklariert worden wäre.

Q3. Welche Zugriffsmodifikatoren sind in Java verfügbar und wozu dienen sie?

In Java gibt es vier Zugriffsmodifikatoren :

  1. Privat
  2. Standard (Paket)
  3. geschützt
  4. Öffentlichkeit

Der private Modifikator stellt sicher, dass Klassenmitglieder außerhalb der Klasse nicht erreichbar sind. Es kann auf Methoden, Eigenschaften, Konstruktoren und verschachtelte Klassen angewendet werden, jedoch nicht auf Klassen der obersten Ebene.

Im Gegensatz zum privaten Modifikator können wir den Standardmodifikator auf alle Arten von Klassenmitgliedern und auf die Klasse selbst anwenden . Wir können die Standardsichtbarkeit anwenden, indem wir überhaupt keinen Zugriffsmodifikator hinzufügen. Wenn wir die Standardsichtbarkeit verwenden, ist unsere Klasse oder ihre Mitglieder nur innerhalb des Pakets unserer Klasse zugänglich. Wir sollten beachten, dass der Standardzugriffsmodifikator nichts mit dem Standardschlüsselwort gemeinsam hat .

Ähnlich wie beim Standardmodifikator können alle Klassen in einem Paket auf geschützte Mitglieder zugreifen . Darüber hinaus ermöglicht der Modifikator protected, dass Unterklassen auf die geschützten Mitglieder einer Oberklasse zugreifen können, auch wenn sie sich nicht im selben Paket befinden. Wir können diesen Zugriffsmodifikator nicht auf Klassen anwenden, sondern nur auf Klassenmitglieder.

Der öffentliche Modifikator kann zusammen mit dem Schlüsselwort class und allen Klassenmitgliedern verwendet werden. Es macht Klassen und Klassenmitglieder in allen Paketen und für alle Klassen zugänglich.

Weitere Informationen finden Sie im Artikel Java Access Modifiers.

Q4. Welche anderen Modifikatoren sind in Java verfügbar und wozu dienen sie?

In Java stehen fünf weitere Modifikatoren zur Verfügung:

  • statisch
  • Finale
  • abstrakt
  • synchronisiert
  • flüchtig

Diese steuern nicht die Sichtbarkeit.

Zunächst können wir das statische Schlüsselwort auf Felder und Methoden anwenden . Statische Felder oder Methoden sind Klassenmitglieder, während nicht statische Objektelemente sind . Klassenmitglieder müssen keine Instanz aufrufen. Sie werden mit dem Klassennamen anstelle des Objektreferenznamens aufgerufen. In diesem Artikel wird das statische Schlüsselwort ausführlicher beschrieben .

Dann haben wir das endgültige Schlüsselwort. Wir können es mit Feldern, Methoden und Klassen verwenden. Wenn final für ein Feld verwendet wird, bedeutet dies, dass die Feldreferenz nicht geändert werden kann. Es kann also nicht einem anderen Objekt zugewiesen werden. Wenn final auf eine Klasse oder eine Methode angewendet wird, wird sichergestellt, dass diese Klasse oder Methode nicht erweitert oder überschrieben werden kann. Das endgültige Schlüsselwort wird in diesem Artikel ausführlicher erläutert.

Das nächste Schlüsselwort ist abstrakt . Dieser kann Klassen und Methoden beschreiben. Wenn Klassen abstrakt sind , können sie nicht instanziiert werden. Stattdessen sollen sie in Unterklassen unterteilt werden. Wenn Methoden abstrakt sind, bleiben sie ohne Implementierung und können in Unterklassen überschrieben werden.

Das synchronisierte Schlüsselwort ist möglicherweise das am weitesten fortgeschrittene. Wir können es sowohl mit der Instanz als auch mit statischen Methoden und Codeblöcken verwenden. Wenn wir dieses Schlüsselwort verwenden, verwendet Java eine Monitorsperre, um die Synchronisierung für ein bestimmtes Codefragment bereitzustellen. Weitere Informationen zu synchronisierten finden Sie in diesem Artikel.

Das letzte Schlüsselwort, das wir diskutieren werden, ist volatil . Wir können es nur zusammen mit Instanzfeldern verwenden. Es wird deklariert, dass der Feldwert aus dem Hauptspeicher gelesen und in diesen geschrieben werden muss - unter Umgehung des CPU-Cache. Alle Lese- und Schreibvorgänge für eine flüchtige Variable sind atomar. Das flüchtige Schlüsselwort wird in diesem Artikel ausführlich erläutert.

Q5. Was ist der Unterschied zwischen JDK, JRE und JVM?

JDK steht für Java Development Kit , eine Reihe von Tools, die Entwickler zum Schreiben von Anwendungen in Java benötigen. Es gibt drei Arten von JDK-Umgebungen:

  • Standard Edition - Entwicklungskit zum Erstellen von tragbaren Desktop- oder Serveranwendungen
  • Enterprise Edition - eine Erweiterung der Standard Edition mit Unterstützung für verteilte Computer- oder Webdienste
  • Micro Edition – development platform for embedded and mobile applications

There are plenty of tools included in the JDK which help programmers with writing, debugging or maintaining applications. The most popular ones are a compiler (javac), an interpreter (java), an archiver (jar) and a documentation generator (javadoc).

JRE is a Java Runtime Environment. It's a part of the JDK, but it contains the minimum functionality to run Java applications. It consists of a Java Virtual Machine, core classes, and supporting files. For example, it doesn't have any compiler.

JVM is the acronym for Java Virtual Machine, which is a virtual machine able to run programs compiled to bytecode. It's described by the JVM specification, as it's important to ensure interoperability between different implementations. The most important function of a JVM is to enable users to deploy the same Java application into different operating systems and environments without worrying about what lies underneath.

For more information, let's check the Difference Between JVM, JRE, and JDK article.

Q6. What Is the Difference Between Stack and Heap?

There are two parts of memory where all variables and objects are stored by the JVM. The first is the stack and the second is the heap.

The stack is a place where the JVM reserves blocks for local variables and additional data. The stack is a LIFO (last in first out) structure. It means that whenever a method is called, a new block is reserved for local variables and object references. Each new method invocation reserves the next block. When methods finish their execution, blocks are released in the reversed manner they were started.

Every new thread has its own stack.

We should be aware that the stack has much less memory space than the heap. And when a stack is full, the JVM will throw a StackOverflowError. It's likely to occur when there is a bad recursive call and the recursion goes too deep.

Every new object is created on the Java heap which is used for a dynamic allocation. There is a garbage collector which is responsible for erasing unused objects which are divided into young (nursery) and old spaces. Memory access to the heap is slower than access to the stack. The JVM throws an OutOfMemoryError when the heap is full.

We can find more details in the Stack Memory and Heap Space in Java article.

Q7. What Is the Difference Between the Comparable and Comparator Interfaces?

Sometimes when we write a new class, we would like to be able to compare objects of that class. It's especially helpful when we want to use sorted collections. There are two ways we can do this: with the Comparable interface or with the Comparator interface.

First, let's look at the Comparable interface:

public interface Comparable { int compareTo(T var1); }

We should implement that interface by the class whose objects we want to sort.

It has the compareTo() method and returns an integer. It can return three values: -1, 0, and 1 which means that this object is less than, equal to or greater than the compared object.

It's worth mentioning that the overridden compareT0() method should be consistent with the equals() method.

On the other hand, we can use the Comparator interface. It can be passed to the sort() methods of the Collection interface or when instantiating sorted collections. That's why it's mostly used to create a one-time sorting strategy.

What's more, it's also useful when we use a third-party class which doesn't implement the Comparable interface.

Like the compareTo() method, the overridden compare() methods should be consistent with the equals() method, but they may optionally allow comparison with nulls.

Let's visit the Comparator and Comparable in Java article for more information.

Q8. What Is the void Type and When Do We Use It?

Every time we write a method in Java, it must have a return type. If we want the method to return no value, we can use the void keyword.

We should also know that there is a Void class. It's a placeholder class that may be used, for example, when working with generics. The Void class can neither be instantiated nor extended.

Q9. What Are the Methods of the Object Class and What Do They Do?

It's important to know what methods the Object class contains and how they work. It's also very helpful when we want to override those methods:

  • clone() – returns a copy of this object
  • equals() – returns true when this object is equal to the object passed as a parameter
  • finalize() – the garbage collector calls this method while it's cleaning the memory
  • getClass() – returns the runtime class of this object
  • hashCode() – returns a hash code of this object. We should be aware that it should be consistent with the equals() method
  • notify() – sends a notification to a single thread waiting for the object's monitor
  • notifyAll() – sends a notification to all threads waiting for the object's monitor
  • toString() – returns a string representation of this object
  • wait() – there are three overloaded versions of this method. It forces the current thread to wait the specified amount of time until another thread calls notify() or notifyAll() on this object.

Q10. What Is an Enum and How We Can Use It?

Enum is a type of class that allows developers to specify a set of predefined constant values. To create such a class we have to use the enum keyword. Let's imagine an enum of days of the week:

public enum Day { SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY }

To iterate over all constants we can use the static values() method. What's more, enums enable us to define members such as properties and methods like regular classes.

Although it's a special type of class, we can't subclass it. An enum can, however, implement an interface.

Another interesting advantage of Enums is that they are thread-safe and so they are popularly used as singletons.

We can find more about Enums in one of our guides.

Q11. What Is a JAR?

JAR is a shortcut for Java archive. It's an archive file packaged using the ZIP file format. We can use it to include the class files and auxiliary resources that are necessary for applications. It has many features:

  • Security – we can digitally sign JAR files
  • Compression – while using a JAR, we can compress files for efficient storage
  • Portability – we can use the same JAR file across multiple platforms
  • Versioning – JAR files can hold metadata about the files they contain
  • Sealing – we can seal a package within a JAR file. This means that all classes from one package must be included in the same JAR file
  • Extensions – we can use the JAR file format to package modules or extensions for existing software

Q12. What Is aNullPointerException?

The NullPointerException is probably the most common exception in the Java world. It's an unchecked exception and thus extends RuntimeException. We shouldn't try to handle it.

This exception is thrown when we try to access a variable or call a method of a null reference, like when:

  • invoking a method of a null reference
  • setting or getting a field of a null reference
  • checking the length of a null array reference
  • setting or getting an item of a null array reference
  • throwing null

Q13. What Are Two Types of Casting in Java? Which Exception May Be Thrown While Casting? How Can We Avoid It?

We can distinguish two types of casting in Java. We can do upcasting which is casting an object to a supertype or downcasting which is casting an object to a subtype.

Upcasting is very simple, as we always can do that. For example, we can upcast a String instance to the Object type:

Object str = "string";

Alternatively, we can downcast a variable. It's not as safe as upcasting as it involves a type check. If we incorrectly cast an object, the JVM will throw a ClassCastExcpetion at runtime. Fortunately, we can use the instanceof keyword to prevent invalid casting:

Object o = "string"; String str = (String) o; // it's ok Object o2 = new Object(); String str2 = (String) o2; // ClassCastException will be thrown if (o2 instanceof String) { // returns false String str3 = (String) o2; }

We can learn more about type casting in this article.

3. Core-Java Language Questions for Advanced Programmers

Q1. Why Is String an Immutable Class?

We should know that String objects are treated differently than other objects by the JVM. One difference is that String objects are immutable. It means that we can't change them once we have created them. There are several reasons why they behave that way:

  1. They are stored in the string pool which is a special part of the heap memory. It's responsible for saving a lot of space.
  2. The immutability of the String class guarantees that its hash code won't change. Due to that fact, Strings can be effectively used as keys in hashing collections. We can be sure that we won't overwrite any data because of a change in hash codes.
  3. They can be used safely across several threads. No thread can change the value of a String object, so we get thread safety for free.
  4. Strings are immutable to avoid serious security issues. Sensitive data such as passwords could be changed by an unreliable source or another thread.

We can learn more about the immutability of Strings in this article.

Q2. What Is the Difference Between Dynamic Binding and Static Binding?

Binding in Java is a process of associating a method call with the proper method body. We can distinguish two types of binding in Java: static and dynamic.

The main difference between static binding and dynamic binding is that static binding occurs at compile time and dynamic binding at runtime.

Static binding uses class information for binding. It's responsible for resolving class members that are private or static and final methods and variables. Also, static binding binds overloaded methods.

Dynamic binding, on the other hand, uses object information to resolve bindings. That's why it's responsible for resolving virtual and overridden methods.

Q3. What Is JIT?

JIT stands for “just in time”. It's a component of the JRE that runs in the runtime and increases the performance of the application. Specifically, it's a compiler which runs just after the program's start.

This is different from the regular Java compiler which compiles the code long before the application is started. JIT can speed up the application in different ways.

For example, the JIT compiler is responsible for compiling bytecode into native instructions on the fly to improve performance. Also, it can optimize the code to the targeted CPU and operating system.

Additionally, it has access to many runtime statistics which may be used for recompilation for optimal performance. With this, it can also do some global code optimizations or rearrange code for better cache utilization.

Q4. What Is Reflection in Java?

Reflection is a very powerful mechanism in Java. Reflection is a mechanism of Java language which enables programmers to examine or modify the internal state of the program (properties, methods, classes etc.) at runtime. The java.lang.reflect package provides all required components for using reflection.

When using this feature, we can access all possible fields, methods, constructors that are included within a class definition. We can access them irrespective of their access modifier. It means that for example, we are able to access private members. To do that, we don't have to know their names. All we have to do is to use some static methods of Class.

It's worth to know that there is a possibility to restrict access via reflection. To do that we can use the Java security manager and the Java security policy file. They allow us to grant permissions to classes.

When working with modules since Java 9, we should know that by default, we aren't able to use reflection on classes imported from another module. To allow other classes to use reflection to access the private members of a package we have to grant the “Reflection” Permission.

This article goes into more depth about Java Reflection.

Q5. What Is a Classloader?

The classloader is one of the most important components in Java. It's a part of the JRE.

Simply put, the classloader is responsible for loading classes into the JVM. We can distinguish three types of classloaders:

  • Bootstrap classloader – it loads the core Java classes. They are located in the /jre/lib directory
  • Extension classloader – it loads classes located in /jre/lib/ext or in the path defined by the java.ext.dirs property
  • System classloader – it loads classes on the classpath of our application

A classloader loads classes “on demand”. It means that classes are loaded after they are called by the program. What's more, a classloader can load a class with a given name only once. However, if the same class is loaded by two different class loaders, then those classes fail in an equality check.

There is more information about classloaders in the Class Loaders in Java article.

Q6. What Is the Difference Between Static and Dynamic Class Loading?

Static class loading takes place when we have source classes available at compile time. We can make use of it by creating object instances with the new keyword.

Dynamic class loading refers to a situation when we can't provide a class definition at the compile time. Yet, we can do that at runtime. To create an instance of a class, we have to use the Class.forName() method:

Class.forName("oracle.jdbc.driver.OracleDriver") 

Q7. What Is the Purpose of the Serializable Interface?

We can use the Serializable interface to enable serializability of a class, using Java's Serialization API. Serialization is a mechanism for saving the state of an object as a sequence of bytes while deserialization is a mechanism for restoring the state of an object from a sequence of bytes. The serialized output holds the object's state and some metadata about the object's type and types of its fields.

We should know that subtypes of serializable classes are also serializable. However, if we want to make a class serializable, but its supertype is non-serializable we have to do two things:

  • implement the Serializable interface
  • assure that a no argument constructor is present in the superclass

We can read more about Serialization in one of our articles.

Q8. Is There a Destructor in Java?

In Java, the garbage collector automatically deletes the unused objects to free up the memory. Developers have no need to mark the objects for deletion, which is error-prone. So it's sensible Java has no destructors available.

In case the objects hold open sockets, open files, or database connections, the garbage collector is not able to reclaim those resources. We can release the resources in close method and use try-finally syntax to call the method afterward before Java 7, such as the I/O classes FileInputStreamand FileOutputStream. As of Java 7, we can implement interface AutoCloseable and use try-with-resources statement to write shorter and cleaner code. But it's possible the API users forget to call the close method, so the finalize method and Cleaner class come into existence to act as the safety net. But please be cautioned they are not equivalent to the destructor.

It's not assured both the finalize method and Cleaner class will run promptly. They even get no chance to run before the JVM exits. Although we could call System.runFinalization to suggest that JVM run the finalize methods of any objects pending for finalization, it's still non-deterministic.

Moreover, the finalize method can cause performance issues, deadlocks etc. We can find more information by looking at one of our articles: A Guide to the finalize Method in Java.

Ab Java 9 wird die Cleaner- Klasse hinzugefügt, um die Finalize- Methode aufgrund der Nachteile zu ersetzen . Dadurch haben wir eine bessere Kontrolle über den Faden, der die Reinigungsaktionen ausführt.

Die Java-Spezifikation weist jedoch darauf hin, dass das Verhalten von Bereinigern während System.exit implementierungsspezifisch ist und Java keine Garantie dafür bietet, ob Bereinigungsaktionen aufgerufen werden oder nicht.