Ethickfox kb page with all notes
OOP - a programming methodology based on representing a program as a set of objects, each of which is an instance of a certain class, and the classes form an inheritance hierarchy. What are the limitations of OOP?
Hiding the state and implementation of the class and providing a public API for interacting with the class and its instances.
a mechanism that allows you to build some classes on the basis of others (children based on parent classes), in which the child class inherits the behavior and state of the parent.
Originally, in Java we didn't have multi-inheritance so we didn’t face the diamond problem. With the emergence of default methods, the diamond problem may arise. Candidates may be asked what will happen if we have two unrelated interfaces that have a default method with the same signature and different implementation, and we want to implement these two interfaces in a class. the problem will arise at the compilation level, and will return a compilation error. One solution is to override this method in the class. Another option is to use composition: if you have one class that implements one interface, you can try to represent it as an inner class inside of another class.
Java does not support the multiple inheritance for classes, which means that a class can only inherit from a single superclass.
But you can implement multiple interfaces with a single class, and some of the methods of those interfaces may be defined as default and have an implementation. This allows you to have a safer way of mixing different functionality in a single class.
the ability to identically use objects with the same interface without information about the specific type of this object
highlighting common characteristics and functionality of objects or systems, ignoring unnecessary details. Пример: Банковское приложение/автомобиль
the inner class can exist separately from the outer class.
static inner class does not have access to members of the outer classвнутренний класс полностью инкапсулирован внешним классом. Внешний мир не может получить ссылку на внутренний класс отдельно от внешнего. Он живет и умирает вместе с внешним - Inner Class
Inheritance lags behind composition in the following scenarios:
перепоручение задачи от внешнего объекта внутреннему
Класс, от которого неявно наследуются все объекты в Java
hashCode - метод для вычисления хэш функции. Дефолтная реализация зависит от jvm, может основываться на адресе объекта в памяти. При переопределении следует учитывать следующие правила:
@Override
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof Money))
return false;
Money other = (Money)o;
boolean currencyCodeEquals = (this.currencyCode == null && other.currencyCode == null)
|| (this.currencyCode != null && this.currencyCode.equals(other.currencyCode));
return this.amount == other.amount && currencyCodeEquals;
}
Статические поля или переменные инициализируются после загрузки класса в память. Статичный блок НЕ может пробросить перехваченные исключения, но может выбросить не перехваченные. В таком случае возникнет «Exception Initializer Error». На практике, любое исключение возникшее во время выполнения и инициализации статических полей, будет завёрнуто Java в эту ошибку. Это также самая частая причина ошибки «No Class Def Found Error», т.к. класс не находился в памяти во время обращения к нему.
Интерфейс без методов, с помощью которого можно помечать другие классы, тем самым предоставляя доп информацию о классе. Например Serializible, Clonable
Интерфейс с одним не реализованным методом. За исключением default и методов Object’a. Используется для лямбд.
Immutable objects are those objects whose state can not be changed once created. Class whose objects possess this characteristic can be termed as immutable class.
Immutable classes are thread safe because you can not change state of immutable objects, so even if two thread access immutable object in parallel, it won’t create any issue.
Collections.unmodifiable* - wraps collection into unmodifiable, returns UnsupportedOperationException for editing operations and returns object itself in case of getting operations. So objects should be immutable too.
Поймать исключение можно с помощью try-catch-finally. В случе если было выброшено исключение, поток, в котором оно выброшено завершает работу.
Указывает, что метод может выбросить исключение. При наследовании можно добавлять uncheked, не указывать, либо сужать
Новый вид try catch, который сам может закрывать ресурсы(если они наследуются от AutoCloseable), с которыми работал, вне зависимости от того, было ли исключение
Блок выполняется всегда(кроме System.exit()).
Composition, and Aggregation help to build (Has - A - Relationship) between classes and objects. But both are not the same in the end.
if the container object destroys then the contained objects will also get destroyed automatically. So here we can say that there is a strong association between the objects. So this Strong Association is called Composition.
if the class is destroyed then the inner object will become free to bind with other objects. Because container objects only hold the references of contained objects. So here is the weak association between the objects. And this weak association is called Aggregation.
Describe the Difference Between equals() and ==
The == operator allows you to compare two objects for “sameness” (i.e. that both variables refer to the same object in memory). It is important to remember that the new keyword always creates a new object which will not pass the == equality with any other object, even if they seem to have the same value:
The equals() method is defined in the java.lang.Object class and is, therefore, available for any reference type. By default, it simply checks that the object is the same via the == operator. But it is usually overridden in subclasses to provide the specific semantics of comparison for a class.
How Do You Compare Two Enum Values: With equals() or With ==?
Actually, you can use both. The enum values are objects, so they can be compared with equals(), but they are also implemented as static constants under the hood, so you might as well compare them with ==. This is mostly a matter of code style, but if you want to save character space (and possibly skip an unneeded method call), you should compare enums with ==.
equals and hashCode contract
hashCode - метод для вычисления хэш функции. Дефолтная реализация зависит от jvm, может основываться на адресе объекта в памяти. При переопределении следует учитывать следующие правила:
equals - сравнивает объекты по содержанию
Can you call a constructor of a class inside the another constructor?
Yes, the concept can be termed as constructor chaining and can be achieved using this().
Constructor chaining is a way of simplifying object construction by providing multiple constructors that call each other in sequence.
The most specific constructor may take all possible arguments and may be used for the most detailed object configuration. A less specific constructor may call the more specific constructor by providing some of its arguments with default values. At the top of the chain, a no-argument constructor could instantiate an object with default values.
Why is Java not a pure object oriented language?
Java supports primitive data types - byte, boolean, char, short, int, float, long, and double and hence it is not a pure object oriented language.
Java works as “pass by value” or “pass by reference” phenomenon?
Java always works as a “pass by value”. There is nothing called a “pass by reference” in Java. However, when the object is passed in any method, the address of the value is passed due to the nature of object handling in Java. When an object is passed, a copy of the reference is created by Java and that is passed to the method. The objects point to the same memory location. 2 cases might happen inside the method:
Explain the concept of object-oriented programming (OOP)
Object-oriented programming is a model that centers on data fields with distinct behaviors and attributes — referred to as objects — instead of logic or functions. Developers focus on the objects that need to be manipulated instead of the processes required to manipulate them.
Describe the Place of the Object Class in the Type Hierarchy. Which Types Inherit from Object, and Which Don’t? Do Arrays Inherit from Object? Can a Lambda Expression Be Assigned to an Object Variable?
The java.lang.Object is at the top of the class hierarchy in Java. All classes inherit from it, either explicitly, implicitly (when the extends keyword is omitted from the class definition) or transitively via the chain of inheritance.
However, there are eight primitive types that do not inherit from Object, namely boolean, byte, short, char, int, float, long and double.
According to the Java Language Specification, arrays are objects too. They can be assigned to an Object reference, and all Object methods may be called on them.
Lambda expressions can’t be assigned directly to an Object variable because Object is not a functional interface. But you can assign a lambda to a functional interface variable and then assign it to an Object variable(or simply assign it to an Object variable by casting it to a functional interface at the same time).
Explain the Difference Between Primitive and Reference Types.
Reference types inherit from the top java.lang.Object class and are themselves inheritable (except final classes). Primitive types do not inherit and cannot be subclassed.
Primitively typed argument values are always passed via the stack, which means they are passed by value, not by reference. This has the following implication: changes made to a primitive argument value inside the method do not propagate to the actual argument value.
What Is a Default Method?
Prior to Java 8, interfaces could only have abstract methods, i.e. methods without a body. Starting with Java 8, interface methods can have a default implementation. If an implementing class does not override this method, then the default implementation is used. Such methods are suitably marked with a default keyword.
One of the prominent use cases of a default method is adding a method to an existing interface. If you don’t mark such interface method as default, then all existing implementations of this interface will break. Adding a method with a default implementation ensures binary compatibility of legacy code with the new version of this interface.
A good example of this is the Iterator interface which allows a class to be a target of the for-each loop. This interface first appeared in Java 5, but in Java 8 it received two additional methods, forEach, and spliterator. They are defined as default methods with implementations and thus do not break backward compatibility:
What Are Static Class Members?
Static fields and methods of a class are not bound to a specific instance of a class. Instead, they are bound to the class object itself. The call of a static method or addressing a static field is resolved at compile time because, contrary to instance methods and fields, we don’t need to walk the reference and determine an actual object we’re referring to.
What is the ‘IS-A ‘ relationship in OOPs java?
‘IS-A’ relationship is another name for inheritance. When we inherit the base class from the derived class, then it forms a relationship between the classes. So that relationship is termed an ‘IS-A’ Relationship.
Example - Consider a Television (Typical CRT TV). Now another Smart TV that is inherited from television class. So we can say that the Smart iv is also a TV. Because CRT TV things can also be done in the Smart TV.
When can you use super keyword?
What are shallow copy and deep copy in java?
To copy the object's data, we have several methods like deep copy and shallow copy.
Object for this Rectangle class - Rectangle obj1 = new Rectangle();
Now by doing this what will happen is the new reference is created with the name obj2 and that will point to the same memory location.
Apart from the security aspect, what are the reasons behind making strings immutable in Java?
A String is made immutable due to the following reasons:
May a Class Be Declared Abstract If It Does Not Have Any Abstract Members? What Could Be the Purpose of Such Class?
Yes, a class can be declared abstract even if it does not contain any abstract members. As an abstract class, it cannot be instantiated, but it can serve as a root object of some hierarchy, providing methods that can be useful to its implementations.
What Is an Anonymous Class? Describe Its Use Case.
Anonymous class is a one-shot class that is defined in the same place where its instance is needed. This class is defined and instantiated in the same place, thus it does not need a name.
Before Java 8, you would often use an anonymous class to define the implementation of a single method interface, like Runnable. In Java 8, lambdas are used instead of single abstract method interfaces. But anonymous classes still have use cases, for example, when you need an instance of an interface with multiple methods or an instance of a class with some added features.
Can default methods override an Object method?
Default methods of the interface can’t override some methods of the Object class
If we create a default method with the same signature as, for example, equals in the Object class, then we'll change the class's behavior, which is inherited from another class. This violates the basic principle that distinguishes interfaces and classes.
What Is the Difference Between an Abstract Class and an Interface? What Are the Use Cases of One and the Other?
An abstract class is a class with the abstract modifier in its definition. It can’t be instantiated, but it can be subclassed. The interface is a type described with interface keyword. It also cannot be instantiated, but it can be implemented.
The main difference between an abstract class and an interface is that a class can implement multiple interfaces, but extend only one abstract class.
An abstract class is usually used as a base type in some class hierarchy, and it signifies the main intention of all classes that inherit from it.
An abstract class could also implement some basic methods needed in all subclasses. For instance, most map collections in JDK inherit from the AbstractMap class which implements many methods used by subclasses (such as the equals method).
An interface specifies some contract that the class agrees to. An implemented interface may signify not only the main intention of the class but also some additional contracts.
Why is the character array preferred over string for storing confidential information?
In Java, a string is basically immutable i.e. it cannot be modified. After its declaration, it continues to stay in the string pool as long as it is not removed in the form of garbage. In other words, a string resides in the heap section of the memory for an unregulated and unspecified time interval after string value processing is executed.
As a result, vital information can be stolen for pursuing harmful activities by hackers if a memory dump is illegally accessed by them. Such risks can be eliminated by using mutable objects or structures like character arrays for storing any variable. After the work of the character array variable is done, the variable can be configured to blank at the same instant. Consequently, it helps in saving heap memory and also gives no chance to the hackers to extract vital data.
What Are the Restrictions on the Members (Fields and Methods) of an Interface Type?
An interface can declare fields, but they are implicitly declared as public, static and final, even if you don’t specify those modifiers. Consequently, you can’t explicitly define an interface field as private. In essence, an interface may only have constant fields, not instance fields.
All methods of an interface are also implicitly public. They also can be either (implicitly) abstract, or default.
Since java 9 there can be private methods, they can be both static and non static
What is Interface?
An interface is a completely "abstract class" that is used to group related methods with empty bodies:
What Is the Difference Between an Inner Class and a Static Nested Class?
Nested class is basically a class defined inside another class.
Nested classes fall into two categories with very different properties. An inner class is a class that can’t be instantiated without instantiating the enclosing class first, i.e. any instance of an inner class is implicitly bound to some instance of the enclosing class.
What Are the Wrapper Classes? What Is Autoboxing?
For each of the eight primitive types in Java, there is a wrapper class that can be used to wrap a primitive value and use it like an object. Those classes are, correspondingly, Boolean, Byte, Short, Character, Integer, Float, Long, and Double. These wrappers can be useful, for instance, when you need to put a primitive value into a generic collection, which only accepts reference objects.
To save the trouble of manually converting primitives back and forth, an automatic conversion known as autoboxing/auto unboxing is provided by the Java compiler.
List<Integer> list = new ArrayList<>();
list.add(5);
int value = list.get(0);
Suppose You Have a Variable That References an Instance of a Class Type. How Do You Check That an Object Is an Instance of This Class?
You cannot use instanceof keyword in this case because it only works if you provide the actual class name as a literal.
Thankfully, the Class class has a method isInstance that allows checking if an object is an instance of this class:
Class<?> integerClass = new Integer(5).getClass();
assertTrue(integerClass.isInstance(new Integer(4)));
What is the value object? Why should you use them?
[!info] Entity vs Value Object: полный список отличий
Тема отличий таких понятий как Entity (Сущность) и Value Object (Объект-Значение) из Domain-Driven Design не нова.
https://habr.com/ru/articles/275599/
Describe the Meaning of the Final Keyword When Applied to a Class, Method, Field or a Local Variable.
What Is Overriding and Overloading of Methods? How Are They Different?
Can You Override a Static Method?
No, you can’t. By definition, you can only override a method if its implementation is determined at runtime by the type of the actual instance (a process known as the dynamic method lookup). The static method implementation is determined at compile time using the type of the reference, so overriding would not make much sense anyway. Although you can add to subclass a static method with the exact same signature as in superclass, this is not technically overriding.
What Is an Immutable Class, and How Can You Create One?
An instance of an immutable class cannot be changed after it’s created. By changing we mean mutating the state by modifying the values of the fields of the instance. Immutable classes have many advantages: they are thread-safe, and it is much easier to reason about them when you have no mutable state to consider.
To make a class immutable, you should ensure the following:
What Is an Initializer Block? What Is a Static Initializer Block?
An initializer block is a curly-braced block of code in the class scope which is executed during the instance creation. You can use it to initialize fields with something more complex than in-place initialization one-liners.
Actually, the compiler just copies this block inside every constructor, so it is a nice way to extract common code from all constructors.
A static initializer block is a curly-braced block of code with the static modifier in front of it. It is executed once during the class loading and can be used for initializing static fields or for some side effects.
What Is a Marker Interface? What Are the Notable Examples of Marker Interfaces in Java?
A marker interface is an interface without any methods. It is usually implemented by a class or extended by another interface to signify a certain property. The most widely known marker interfaces in standard Java library are the following:
What Is a Var-Arg? What Are the Restrictions on a Var-Arg? How Can You Use It Inside the Method Body?
Var-arg is a variable-length argument for a method. A method may have only one var-arg, and it has to come last in the list of arguments. It is specified as a type name followed by an ellipsis and an argument name. Inside the method body, a var-arg is used as an array of specified type.
Can You Access an Overridden Method of a Superclass? Can You Access an Overridden Method of a Super-Superclass in a Similar Way?
To access an overridden method of a superclass, you can use the super keyword. But you don’t have a similar way of accessing the overridden method of a super-superclass.
How to not allow serialization of attributes of a class in Java?
• In order to achieve this, the attribute can be declared along with the usage of transient keyword as shown below:
What do you understand by Object Cloning and how do you achieve it in Java?
• It is the process of creating an exact copy of any object. In order to support this, a java class has to implement the Cloneable interface of java.lang package and override the clone() method provided by the Object class the syntax of which is:
• In case the Cloneable interface is not implemented and just the method is overridden, it results in CloneNotSupportedException in Java.
Is it possible to import the same class or package twice in Java and what happens to it during runtime?
It is possible to import a class or package more than once, however, it is redundant because the JVM internally loads the package or class only once.
In case a package has sub packages, will it suffice to import only the main package? e.g. Does importing of com.myMainPackage. also import com.myMainPackage.mySubPackage.*?*
This is a big NO. We need to understand that the importing of the sub-packages of a package needs to be done explicitly. Importing the parent package only results in the import of the classes within it and not the contents of its child/sub-packages.
Why is it said that the length() method of String class doesn't return accurate results?
Now if a string contained supplementary characters, the length function would count that as 2 units and the result of the length() function would not be as per what is expected.
In other words, if there is 1 supplementary character of 2 units, the length of that SINGLE character is considered to be TWO - Notice the inaccuracy here? As per the java documentation, it is expected, but as per the real logic, it is inaccurate.
What is a Memory Leak?
The Java Garbage Collector (GC) typically removes unused objects when they are no longer required, but when they are still referenced, the unused objects cannot be removed. So this causes the memory leak problem. Example - Consider a linked list like the structure below -

In the above image, there are unused objects that are not referenced. But then also Garbage collection will not free it. Because it is referencing some existing referenced object. So this can be the situation of memory leak.
Some common causes of Memory leaks are -
What Is the Difference Between an Unlabeled and a Labeled break Statement?
An unlabeled break statement terminates the innermost switch, for, while or do-while statement, whereas a labeled break ends the execution of an outer statement.
outer: for (int[] rows : table) {
for (int row : rows) {
loopCycles++;
if (row == 37) {
found = true;
break outer;
}
}
}
Why would it be more secure to store sensitive data (such as a password, social security number, etc.) in a character array rather than in a String?
In Java, Strings are immutable and are stored in the String pool. What this means is that, once a String is created, it stays in the pool in memory until being garbage collected. Therefore, even after you’re done processing the string value (e.g., the password), it remains available in memory for an indeterminate period of time thereafter (again, until being garbage collected) which you have no real control over. Therefore, anyone having access to a memory dump can potentially extract the sensitive data and exploit it.
In contrast, if you use a mutable object like a character array, for example, to store the value, you can set it to blank once you are done with it with confidence that it will no longer be retained in memory.
When designing an abstract class, why should you avoid calling abstract methods inside its constructor?
This is a problem of initialization order. The subclass constructor will not have had a chance to run yet and there is no way to force it to run it before the parent class.
[!info] 11.7 Implementing the 'equals()', 'hashCode()', and 'compareTo()' Methods :: Chapter 11. Collections and Maps :: A programmer's guide to java certification :: Certification :: eTutorials.org
The majority of the non-final methods of the Object class are meant to be overridden.
http://etutorials.org/cert/java+certification/Chapter+11.+Collections+and+Maps/11.7+Implementing+the+equals+hashCode+and+compareTo+Methods/
What is the difference between the ‘throw’ and ‘throws’ keyword in java?
Exceptions hierarchy
What Is an Exception?
An exception is an abnormal event that occurs during the execution of a program and disrupts the normal flow of the program’s instructions.
How Can You Catch Multiple Exceptions?
There are three ways of handling multiple exceptions in a block of code.
The first is to use a catch block that can handle all exception types being thrown:
try {
// ...
} catch (Exception ex) {
// ...
}
The second way is implementing multiple catch blocks:
try {
// ...
} catch (FileNotFoundException ex) {
// ...
} catch (EOFException ex) {
// ...
}
Note that, if the exceptions have an inheritance relationship; the child type must come first and the parent type later. If we fail to do this, it will result in a compilation error.
The third is to use a multi-catch block:
try {
// ...
} catch (FileNotFoundException | EOFException ex) {
// ...
}
Exceptions types
Исключения, которые необходимо проверять, без этого не пройдет компилци
Исключения, которые можно не проверять
How does an exception propagate in the code?
When an exception occurs, first it searches to locate the matching catch block. In case, the matching catch block is located, then that block would be executed. Else, the exception propagates through the method call stack and goes into the caller method where the process of matching the catch block is performed. This propagation happens until the matching catch block is found. If the match is not found, then the program gets terminated in the main method.
Is it mandatory for a catch block to be followed after a try block?
No, it is not necessary for a catch block to be present after a try block. - A try block should be followed either by a catch block or by a finally block. If the exceptions likelihood is more, then they should be declared using the throws clause of the method.
How do exceptions affect the program if it doesn't handle them?
try with resources
Новый вид try catch, который сам может закрывать ресурсы(если они наследуются от AutoCloseable), с которыми работал, вне зависимости от того, было ли исключение
What Is the Difference Between a Checked and an Unchecked Exception?
A checked exception must be handled within a try-catch block or declared in a throws clause; whereas an unchecked exception is not required to be handled nor declared.
Checked and unchecked exceptions are also known as compile-time and runtime exceptions respectively.
All exceptions are checked exceptions, except those indicated by Error, RuntimeException, and their subclasses.
What Is the Difference Between an Exception and Error?
An exception is an event that represents a condition from which is possible to recover, whereas error represents an external situation usually impossible to recover from.
All errors thrown by the JVM are instances of Error or one of its subclasses, the more common ones include but are not limited to:
Although an error can be handled with a try statement, this is not a recommended practice since there is no guarantee that the program will be able to do anything reliably after the error was thrown.
What Is Exception Chaining?
Occurs when an exception is thrown in response to another exception. This allows us to discover the complete history of our raised problem:
try {
task.readConfigFile();
} catch (FileNotFoundException ex) {
throw new TaskException("Could not perform task", ex);
}
Can You Throw Any Exception Inside a Lambda Expression’s Body?
When using a standard functional interface already provided by Java, you can only throw unchecked exceptions because standard functional interfaces do not have a “throws” clause in method signatures
However, if you are using a custom functional interface, throwing checked exceptions is possible:
What Are the Rules We Need to Follow When Overriding a Method That Throws an Exception?
Is There Any Way of Throwing a Checked Exception from a Method That Does Not Have a Throws Clause?
Yes. We can take advantage of the type erasure performed by the compiler and make it think we are throwing an unchecked exception, when, in fact; we’re throwing a checked exception:
public <T extends Throwable> T sneakyThrow(Throwable ex) throws T {
throw (T) ex;
}
public void methodWithoutThrows() {
this.<RuntimeException>sneakyThrow(new Exception("Checked Exception"));
}
In Which Situations try-finally Block Might Be Used Even When Exceptions Might Not Be Thrown?
This block is useful when we want to ensure we don’t accidentally bypass the clean up of resources used in the code by encountering a break, continue or return statement:
Also, we may face situations in which we can’t locally handle the exception being thrown, or we want the current method to throw the exception still while allowing us to free up resources:
How Does try-with-resources Work?
he try-with-resources statement declares and initializes one or more resources before executing the try block and closes them automatically at the end of the statement regardless of whether the block completed normally or abruptly. Any object implementing AutoCloseable or Closeable interfaces can be used as a resource:
How can you catch an exception thrown by another thread in Java?
This can be done using Thread.UncaughtExceptionHandler.
Here’s a simple example:
//create our uncaughtexceptionhandler
Thread.UncaughtExceptionHandlerhandler = new Thread.UncaughtExceptionHandler() {
public void uncaughtException(Thread th, Throwable ex) {
System.out.println("Uncaught exception: " + ex);
}
};
//create another thread
Thread otherThread = new Thread() {
public void run() {
System.out.println("Sleeping ...");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("Interrupted.");
}
System.out.println("Throwing exception ...");
throw new RuntimeException();
}
};
//set our uncaughtexceptionhandleras the oneto be usedwhen the new thread
// throws an uncaughtexception
otherThread.setUncaughtExceptionHandler(handler);
//start the other thread - our uncaughtexceptionhandler will be invokedwhen
// the other thread throws an uncaughtexception
otherThread.start();
What Are Annotations? What Are Their Typical Use Cases?
Annotations have been around since Java 5, they are metadata bound to elements of the source code of a program and have no effect on the operation of the code they operate.
Their typical uses cases are:
Describe Some Useful Annotations from the Standard Library
There are several annotations in the java.lang and java.lang.annotation packages, the more common ones include but not limited to:
How to create Annotation
Annotations are a form of an interface where the keyword interface is preceded by @, and whose body contains annotation type element declarations that look very similar to methods:
public @interface SimpleAnnotation {
String value();
int[] types();
}
After the annotation is defined, yon can start using it in through your code:
@SimpleAnnotation(value = "an element", types = 1)
public class Element {
@SimpleAnnotation(value = "an attribute", types = { 1, 2 })
public Element nextElement;
}
Optionally, default values can be provided as long as they are constant expressions to the compiler:
public @interface SimpleAnnotation {
String value() default "This is an element";
int[] types() default { 1, 2, 3 };
}
What Object Types Can Be Returned from an Annotation Method Declaration?
The return type must be a primitive, String, Class, Enum, or an array of one of the previous types. Otherwise, the compiler will throw an error.
Here’s an example code that successfully follows this principle:
enum Complexity {
LOW, HIGH
}
public @interface ComplexAnnotation {
Class<? extends Object> value();
int[] types();
Complexity complexity();
}
The next example will fail to compile since Object is not a valid return type:
public @interface FailingAnnotation {
Object complexity();
}
Which Program Elements Can Be Annotated?
Annotations can be applied in several places throughout the source code. They can be applied to
declarations of classes, constructors, and fields:
Methods and their parameters:
Local variables, including a loop and resource variables:
Other annotation types:
And even packages, through the package-info.java file
As of Java 8, they can also be applied to the use of types. For this to work, the annotation must specify an @Target annotation with a value of ElementType.USE
Now, the annotation can be applied to class instance creation:
new @SimpleAnnotation Apply();
//Type casts:
aString = (@SimpleAnnotation String) something;
//Implements clause
public class SimpleList<T>
implements @SimpleAnnotation List<@SimpleAnnotation T> {
// ...
}
//And throws clause:
void aMethod() throws @SimpleAnnotation Exception {
// ...
}
Is There a Way to Limit the Elements in Which an Annotation Can Be Applied?
Yes, the @Target annotation can be used for this purpose. If we try to use an annotation in a context where it is not applicable, the compiler will issue an error.
We can pass multiple constants if we want to make it applicable in more contexts
We can even make an annotation so it cannot be used to annotate anything. This may come in handy when the declared types are intended solely for use as a member type in complex annotations:
What Are Meta-Annotations?
Are annotations that apply to other annotations.
All annotations that aren’t marked with @Target, or are marked with it but include ANNOTATION_TYPE constant are also meta-annotations:
What Are Repeating Annotations?
These are annotations that can be applied more than once to the same element declaration.
For compatibility reasons, since this feature was introduced in Java 8, repeating annotations are stored in a container annotation that is automatically generated by the Java compiler. For the compiler to do this, there are two steps to declared them.
First, we need to declare a repeatable annotation:
@Repeatable(Schedules.class)
public @interface Schedule {
String time() default "morning";
}
Then, we define the containing annotation with a mandatory value element, and whose type must be an array of the repeatable annotation type:
public @interface Schedules {
Schedule[] value();
}
Now, we can use @Schedule multiple times:
@Schedule
@Schedule(time = "afternoon")
@Schedule(time = "night")
void scheduledMethod() {
// ...
}
How Can You Retrieve Annotations? How Does This Relate to Its Retention Policy?
You can use the Reflection API or an annotation processor to retrieve annotations.
The @Retention annotation and its RetentionPolicy parameter affect how you can retrieve them. There are three constants in RetentionPolicy enum:
Is It Possible to Extend Annotations?
No. Annotations always extend java.lang.annotation.Annotation, as stated in the Java Language Specification.