1 .when use interface and abstract ?
When the sub-types behaviour is totally different then you use an interface,
when the sub-types behaviour is partially common and different with respect to
the supertype an abstract class is used.
When to use an abstract class
- An abstract class is a good choice if we are using the inheritance concept
since it provides a common base class implementation to derived classes.
- An abstract class is also good if we want to declare non-public members. In
an interface, all methods must be public.
- If we want to add new methods in the future, then an abstract class is a
better choice.
Because if we add new methods to an interface, then all of the classes
that already implemented that interface will have to be changed to implement the
new methods.
- If we want to create multiple versions of our component, create an abstract
class. Abstract classes provide a simple and easy way to version our components. By
updating the base class, all inheriting classes are automatically updated with the
change. Interfaces, on the other hand, cannot be changed once created. If a new
version of an interface is required, we must create a whole new interface.
- Abstract classes have the advantage of allowing better forward
compatibility. Once clients use an interface, we cannot change it; if they use an
abstract class, we can still add behavior without breaking the existing code.
- If we want to provide common, implemented functionality among all
implementations of our component, use an abstract class. Abstract classes allow us
to partially implement our class, whereas interfaces contain no implementation for
any members.
abstract class Car {
public void accelerate() {
System.out.println("Do something to accelerate");
}
public void applyBrakes() {
System.out.println("Do something to apply brakes");
}
public abstract void changeGears();
}
Now, any Car that wants to be instantiated must implement the changeGears ()
method.
class Alto extends Car {
public void changeGears() {
System.out.println("Implement changeGears() method for Alto
Car");
}
}
class Santro extends Car {
public void changeGears() {
System.out.println("Implement changeGears() method for Santro
Car");
}
}
When to use an interface
- If the functionality we are creating will be useful across a wide range of
disparate objects, use an interface.
Abstract classes should be used primarily for objects that are closely
related, whereas interfaces are best suited for providing a common functionality to
unrelated classes.
- Interfaces are a good choice when we think that the API will not change for
a while.
- Interfaces are also good when we want to have something similar to multiple
inheritances since we can implement multiple interfaces.
- If we are designing small, concise bits of functionality, use interfaces.
If we are designing large functional units, use an abstract class.
If you are designing small, concise bits of functionality, use interfaces. If
you are designing large functional units, use an abstract class.
Example
public interface Actor {
void perform();
}
public interface Producer {
void invest();
}
Nowadays most of the actors are rich enough to produce their own movie. If we
are using interfaces rather than abstract classes, we can implement both Actor and
Producer. Also, we can define a new ActorProducer interface that extends both.
public interface ActorProducer extends Actor, Producer{
// some statements
}
interface does not provide method implementation" is no longer valid with Java 8
launch. Now java provides implementation in interface for default methods.
In simple terms, I would like to use
interface: To implement a contract by multiple unrelated objects. It provides "HAS
A" capability.
abstract class: To implement the same or different behaviour among multiple related
objects. It establishes "IS A" relation.
Oracle website provides key differences between interface and abstract class.
Consider using abstract classes if :
You want to share code among several closely related classes.
You expect that classes that extend your abstract class have many common methods or
fields, or require access modifiers other than public (such as protected and
private).
You want to declare non-static or non-final fields.
Consider using interfaces if :
You expect that unrelated classes would implement your interface. For example,many
unrelated objects can implement Serializable interface.
You want to specify the behaviour of a particular data type, but not concerned
about who implements its behaviour.
You want to take advantage of multiple inheritance of type.
https://stackoverflow.com/questions/479142/when-to-use-an-interface-instead-of-an-
abstract-class-and-vice-versa
1.1. Why can't constructors be final, static, or abstract?
When you set a method as final it means: "I don't want any class override it."
But according to the Java Language Specification:
JLS 8.8 - "Constructor declarations are not members. They are never inherited
and therefore are not subject to hiding or overriding."
When you set a method as abstract it means: "This method doesn't have a body and
it should be implemented in a child class." But the constructor is called
implicitly when the new keyword is used so it can't lack a body.
When you set a method as static it means: "This method belongs to the class, not
a particular object." But the constructor is implicitly called to initialize an
object, so there is no purpose in having a static constructor.
2. immutable class ?
we have created a final class named Employee. It have one final datamember, a
parameterized constructor and getter method.
3. How to create an immutable class with mutable object references in Java?
- Make your class final, so that no other classes can extend it.
- Make all instance variables private & final, so that they’re initialized only
once inside the constructor and never modified afterward.
- Provide only getter methods don’t provide setter methods.
- If the class holds a mutable object: You make sure to always return a clone or
defensive copy of the field and never return the
real object instance from getter method.
https://kkjavatutorials.com/how-can-we-maintain-immutability-of-a-class-with-
a-mutable-reference
// Here id,name and email are already Immutable
private final Integer id;
private final String name;
private final String email;
/*As Date,Set<String> and Address are Mutable referfeces
so returns clone or defensive copy from their getter method*/
private final Date dob;
private final Set<String> skills;
private final Address address;
public Date getDob() {
//Returns clone or defensive copy of Date
return new Date(dob.getTime());
}
public Set<String> getSkills() {
//Returns clone or defensive copy of Set
return new LinkedHashSet<>(skills);
}
public Address getAddress() {
//Returns clone or defensive copy of Set
Address empAddress = new Address();
empAddress.setStreet(address.getStreet());
empAddress.setZipCode(address.getZipCode());
empAddress.setAddressLine1(address.getAddressLine1());
empAddress.setAddressLine2(address.getAddressLine2());
return empAddress;
}
3. String intern() - *** https://www.journaldev.com/7929/java-string-intern
- The method intern() creates an exact copy of a String object in the heap
memory and stores it in the String constant pool.
- Java String intern() is a native method. When the intern() method is invoked
on a String object, if the String Pool already has a String with the same value,
then the reference of String from the Pool is returned. Otherwise, this string
object is added to the pool and the reference is returned.
4. Singleton class in Java
*Singleton- A Singleton class in Java allows only one instance to be created and
provides global access to all other classes through this single object or instance.
*Purpose - The primary purpose of Single class is to restrict the limit of the
number of object creation to only one.
The memory space wastage does not occur with the use of singleton
class because it restricts the instance creation. As the object creation will take
place only once instead of creating it each time a new request is made.
*How to design a singleton class -
Static member: It gets memory only once because of static, itcontains the
instance of the Singleton class.
Private constructor: It will prevent to instantiate the Singleton class from
outside the class.
Static factory method: This provides the global point of access to the Singleton
object and returns the instance to the caller.
https://techvidvan.com/tutorials/java-singleton-class/
*There are several ways to implement or design a Singleton class. The following
are some popular methods by which we can design a Singleton class:
Eager Initialization Method -
This is the easiest method of creating a Singleton class where the instance
is created at the time of class loading.
but it has a drawback that object of a class is always created whether you
need it or not, this may lead to resource wastage.
1.Declare the constructor of the class as private.
2.Now, create a private class member for this Singleton class.
3.In the next step, you need to define a factory method that will return the
object of the Singleton class.
public class EagerSingleton {
private static final EagerSingleton INSTANCE = new EagerSingleton();
private EagerSingleton() {}
public static EagerSingleton getInstance() {
return INSTANCE;
}
}
Lazy Initialization Method -
the object is created only if it is required. This method helps in avoiding
unnecessary creation of the class instance.
1.First of all, declare the constructor as private.
2.Then you need to create a private static instance for this class but no
need to instantiate it yet.
3.Finally, create a factory method that will first check whether the instance
member is null or not.
If not then it will create an instance of the singleton class for you and
return it.
public class EagerSingleton {
private static final EagerSingleton INSTANCE ;
private EagerSingleton() {}
public static EagerSingleton getInstance() {
if(instance == INSTANCE {
INSTANCE = new EagerSingleton();
}
return INSTANCE;
}
}
The above implementation works fine in case of the single-threaded
environment but when it comes to multithreaded systems,
it can cause issues if multiple threads are inside the if condition at the
same time. It will destroy the singleton pattern and both threads will get the
different instances of the singleton class.
In next section, we will see different ways to create a thread-safe
singleton class.
Thread Safe Singleton Method -
The easier way to create a thread-safe singleton class is to make the global
access method synchronized, so that only one thread can execute this method at a
time
public class LazySingleton {
private static LazySingleton INSTANCE = null;
private LazySingleton() {}
public static LazySingleton getInstance() {
if (INSTANCE == null) {
synchronized(LazySingleton.class)
{
INSTANCE = new LazySingleton();
}
}
return INSTANCE;
}
}
Disadvantages - The getInstance() method is synchronized, which slows down
the performance of the application as it restricts the multiple threads to be
accessed simultaneously.
Lazy Initialization with Double Lock Method -
In this approach, we overcome the overhead problem of synchronized methods.
Here, we do not synchronize the getInstance() method. Instead of making it
synchronized, we enclose the code of creating objects within a synchronized block.
By doing this, only a minimum number of threads have to wait and that too
only for the first time. This approach usually boosts the performance of the
application
public class LazyDoubleLockSingleton {
private static LazyDoubleLockSingleton INSTANCE = null;
private LazyDoubleLockSingleton() {}
public static LazyDoubleLockSingleton getInstance() {
if (INSTANCE == null) {
synchronized (LazyDoubleLockSingleton.class) {
if (INSTANCE == null) {
INSTANCE = new LazyDoubleLockSingleton();
}
}
}
return INSTANCE;
}}
Advantages
Lazy initialization is possible.
It is also a thread-safe method.
Performance improves because of the synchronized block.
Lazy Load Method -
In the Lazy Load method, the JVM will load static data members only when
required.
Thus, when the JVM loads the singleton class into the JVM, no object is created.
//Lazy Load Method
public class LazyLoadSingleton {
private LazyLoadSingleton() {}
private static class SingletonClassHolder {
static final Var INSTANCE = new LazyLoadSingleton();
}
public static LazyLoadSingleton getInstance() {
return SingletonClassHolder.INSTANCE;
} }
Static Block Initialization Method -
This method of creating a singleton class in Java is similar to eager
initialization method.
The only difference is that the instance for this class is created within the
static block having exception handling functionality.
//Static Block Initialization
public class StaticBlockSingleton {
private static StaticBlockSingleton INSTANCE;
private StaticBlockSingleton(){}
//exception handling within static block
static{
try{
INSTANCE = new StaticBlockSingleton();
} catch (Exception e) {
throw new RuntimeException("Exception occured while creating a
Singleton Class");
}
}
public static StaticBlockSingleton getInstance(){
return INSTANCE;
}
}
Bill Pugh Implementation Method -
Enum Singleton -
Java ensures that any enum value is instantiated only once in a Java program.
Since Java Enum values are globally accessible, so is the singleton.
The drawback is that the enum type is somewhat inflexible; for example, it
does not allow lazy initialization.
public enum EnumSingleton {
INSTANCE;
public static void doSomething(){
//do something
}
}
5. different ways to create objects in Java.
By new keyword
- NewKeyword obj = new NewKeyword();
By newInstance() method of Class class
- ClassName cls = Class.forName("ClassName").newInstance();
By newInstance() method of constructor class
- NewInstanceMethod obj =
NewInstanceMethod.class.getDeclaredConstructor().newInstance();
By clone() method
- CloneMethod obj1 = new CloneMethod();
CloneMethod obj2 = (CloneMethod) obj1.clone();
By deserialization
Code to serialize an object:
- FileOutputStream fileOut = new FileOutputStream("/tmp/employee.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut);
out.writeObject(e);
Code to deserialize an object:
FileInputStream fileIn = new FileInputStream("/tmp/employee.ser");
ObjectInputStream in = new ObjectInputStream(fileIn);
e = (Employee) in.readObject();
By factory method
-