Java Polymorphism, Abstract Classes, Interfaces, and Threads

Polymorphism in Java

Polymorphism is the ability of an object to take on many forms. Any Java object that can pass more than one IS-A test is considered to be polymorphic.

  • Supertype: A class or interface is a supertype relative to another type if its corresponding class or interface has been extended or implemented directly or indirectly by the class or interface of the other type.
  • Subtype: A class or interface is a subtype relative to another type if its corresponding class or interface is directly or indirectly extending or implementing the class of the other type.

Polymorphism Types

Compile-Time (Static Polymorphism)

This type of polymorphism is resolved during compile time. Method overloading is an example of compile-time polymorphism. Method overloading allows us to have multiple methods with the same name if the parameters inside are different.

Runtime (Dynamic Polymorphism)

Also known as Dynamic Method Dispatch, dynamic polymorphism is a process in which a call to an overridden method is resolved at runtime. Declaring a method in a subclass that is already present in the parent class is known as method overriding. Overriding is done so that the child can give implementations to the method provided by the parent class.

Parametric Polymorphism

Say we have some list of items; those items are not of the same type but different ones (there are integers, doubles, strings, and characters). Now consider creating a method head() that returns only the first item in the list. The method doesn’t care if it’s a string, or integers, or any type. Its return type is the one the list is parameterized with, and its implementation is the same for all types: “return the first item”. Parametric polymorphism applies to one of OOP’s techniques: “generics”.

Ad Hoc Polymorphism

Unlike parametric polymorphism, ad hoc polymorphism is bound to a type. Depending on the type, different implementations of the method are invoked. Again, method overloading is one example of Ad Hoc Polymorphism. For example, you can have two versions of a method that appends two items. One takes two integers and adds them, and one takes two strings and concatenates them.

Abstract Classes vs. Interfaces

An abstract class is a class that is declared abstract—it may or may not include abstract methods. Abstract classes cannot be instantiated, but they can be subclassed.

Use 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. This enables you to define methods that can access and modify the state of the object to which they belong.

Use Interfaces If:

  • You expect that unrelated classes would implement your interface. For example, the interfaces Comparable and Cloneable are implemented by many unrelated classes.
  • You want to specify the behavior of a particular data type but are not concerned about who implements its behavior.
  • You want to take advantage of multiple inheritance of type.

Differences

  • Type of methods: An interface can only have abstract methods, while an abstract class can have abstract and non-abstract methods.
  • Final Variables: Variables declared in a Java interface are by default final. An abstract class may contain non-final variables.
  • Type of variables: An abstract class can have final, non-final, static, and non-static variables. An interface has only static and final variables.
  • Implementation: An abstract class can provide the implementation of an interface. An interface cannot provide the implementation of an abstract class.
  • Inheritance vs. abstraction: A Java interface can be implemented using the keyword “implements”, and an abstract class can be extended using the keyword “extends”.
  • Multiple implementation: An interface can extend another Java interface only; an abstract class can extend another Java class and implement multiple Java interfaces.
  • Accessibility of Data Members: Members of a Java interface are public by default. A Java abstract class can have class members like private, protected, etc.

States of Threads

  • New Thread: When a new thread is created, it’s in the new state. The thread has not yet started to run when in this state, the code is yet to be run, and hasn’t started to execute.
  • Runnable: A thread that is ready to run is moved to the runnable state. The thread might be running or ready to run at any instant in this state.
  • Blocked/Waiting State: This is when a thread is temporarily inactive. A thread in this state cannot continue its execution unless moved to the runnable state. Any thread in this state does not consume any CPU cycle. If a currently running thread is moved to a blocked/waiting state, another thread in the runnable state is scheduled by the thread scheduler to run.
  • Timed Waiting: A thread is in the timed waiting state when it calls a method with a timeout parameter. For example, when a thread calls sleep or a conditional wait, it is moved to the timed waiting state.
  • Terminated State: A thread terminates because of either of the following reasons: it exits normally (when the code of the thread has entirely been executed by the program) or because there was some unusual erroneous event, like an unhandled exception.

Concurrency vs. Parallelism

  • Concurrency occurs when tasks that are running look simultaneous, but actually, they may not be. They take advantage of CPU time-slicing, where each task runs part of its task and then goes to the waiting state. When the first task is at the waiting task, the CPU is assigned to the second task to complete its part of the task. So in concurrency, tasks run in overlapping time periods. All in all, concurrency makes programs run like they’re in parallel, but essentially they don’t.
  • Parallelism literally runs parts of tasks or multiple tasks, all at the same time using the multi-core infrastructure of a CPU by assigning one core to each task or sub-task. Parallelism requires hardware with multiple processing units. In a single-core CPU, you may get concurrency but not parallelism.