Wednesday, November 16, 2022
Quiz yourself: Classes, modules, and sealed types
Friday, August 26, 2022
Quiz yourself: Controlling the number of instances of a class
Which is the best approach: singletons, sealed classes, abstract classes, final classes, or enums?
Imagine that your design requires exactly four instances of a particular class.
Which approach best provides for this need? Choose one.
A. Singletons
B. Sealed classes
C. Abstract classes
D. Final classes
E. Enums
Answer. Option A is incorrect because singleton is not a Java keyword, nor is it a concept defined in the Java Language Specification. Singleton is actually the name of a design pattern and as a design pattern, it can be implemented in several different ways.
From the perspective of this question, the most important characteristic of a singleton is that it limits the number of instances of its type to one per JVM. The quiz question simply requires that the number of instances be fixed; it does not require that number to be one, and as such, an approach is necessary that allows the instance count to be greater than one. Consequently, option A is incorrect.
Option B is also incorrect. Sealed classes were added in Java 17, and the feature’s goal is to fix a set of types that exist as specializations of a particular type. For example, you could specify that a class RoadTransport is permitted to have only subtypes Car, Truck, Bus, Motorcycle, and Bicycle. Note that the sealed classes feature does not limit the number of instances of these classes that can exist.
In addition, option C is incorrect. Abstract classes are a mechanism to capture the common functionality that’s shared by several types in a single class, and they require developers to add specific additional functionality to subclasses. As a side note, an abstract class can be sealed, but as before, this does not have an impact on the number of instances you can create.
Option D is also incorrect. The final modifier, when applied to a class, means you cannot subclass that class. However, the modifier does not imply any control on the number of instances.
Option E is correct, because an enum type provides a clear, language-supported solution to control the number of instances of a class. There are some limitations on enum types; notably, the parent class of an enum is always java.lang.Enum, though an enum can implement interfaces of your choosing.
A second limitation is that an enum is always a final class and cannot be subclassed. This is important, since instances of a subclass are also instances of their parents, and if subclassing were possible, those subclasses would break the contract of a fixed number of instances.
It’s worth mentioning that a programmer can tightly control the construction of any class, and with it the number of instances of such a class, by marking all the constructors of that class as private and providing access to instances through a factory method. In fact, this idea is essential to the implementation of both Java’s enum type and the Singleton design pattern. However, because this approach is not an option for this question, it’s not a correct answer here.
Conclusion. The correct answer is option E.
Source: oracle.com
Thursday, April 28, 2022
Bruce Eckel on Java interfaces and sealed classes
With the introduction of default and static methods in interfaces, Java made it possible to write method code in an interface that you might not want to be public. In the code below, Old, fd(), and fs() are default and static methods, respectively. These methods are called only by f() and g(), so you can make them private.
// interfaces/PrivateInterfaceMethods.java
// {NewFeature} Since JDK 9
interface Old {
default void fd() {
System.out.println("Old::fd()");
}
static void fs() {
System.out.println("Old::fs()");
}
default void f() {
fd();
}
static void g() {
fs();
}
}
class ImplOld implements Old {}
interface JDK9 {
private void fd() { // Automatically default
System.out.println("JDK9::fd()");
}
private static void fs() {
System.out.println("JDK9::fs()");
}
default void f() {
fd();
}
static void g() {
fs();
}
}
class ImplJDK9 implements JDK9 {}
public class PrivateInterfaceMethods {
public static void main(String[] args) {
new ImplOld().f();
Old.g();
new ImplJDK9().f();
JDK9.g();
}
}
/* Output:
Old::fd()
Old::fs()
JDK9::fd()
JDK9::fs()
*/
(Note: The {NewFeature} comment tag excludes this example from the Gradle build that uses JDK 8.)
JDK9 turns fd() and fs() into private methods using the feature finalized in JDK 9. Note that fd() no longer needs the default keyword, as making it private automatically makes it default.
Sealed classes and interfaces
An enumeration creates a class that has only a fixed number of instances. JDK 17 finalizes the introduction of sealed classes and interfaces, so the base class or interface can constrain what classes can be derived from it. This allows you to model a fixed set of kinds of values.
// interfaces/Sealed.java
// {NewFeature} Since JDK 17
sealed class Base permits D1, D2 {}
final class D1 extends Base {}
final class D2 extends Base {}
// Illegal:
// final class D3 extends Base {}
The compiler produces an error if you try to inherit a subclass such as D3 that is not listed in the permits clause. In the code above, there can be no subclasses other than D1 and D2. Thus, you can ensure that any code you write will only ever need to consider D1 and D2.
You can also seal interfaces and abstract classes.
// interfaces/SealedInterface.java
// {NewFeature} Since JDK 17
sealed interface Ifc permits Imp1, Imp2 {}
final class Imp1 implements Ifc {}
final class Imp2 implements Ifc {}
sealed abstract class AC permits X {}
final class X extends AC {}
If all subclasses are defined in the same file, you don’t need the permits clause. In the following, the compiler will prevent any attempt to inherit a Shape outside of SameFile.java:
// interfaces/SameFile.java
// {NewFeature} Since JDK 17
sealed class Shape {}
final class Circle extends Shape {}
final class Triangle extends Shape {}
The permits clause allows you to define the subclasses in separate files, as follows:
// interfaces/SealedPets.java
// {NewFeature} Since JDK 17
sealed class Pet permits Dog, Cat {}
// interfaces/SealedDog.java
// {NewFeature} Since JDK 17
final class Dog extends Pet {}
// interfaces/SealedCat.java
// {NewFeature} Since JDK 17
final class Cat extends Pet {}
Subclasses of a sealed class must be modified by one of the following:
◉ final: No further subclasses are allowed.
◉ sealed: A sealed set of subclasses is allowed.
◉ non-sealed: This is a new keyword that allows inheritance by unknown subclasses.
The sealed subclasses maintain strict control of the hierarchy.
// interfaces/SealedSubclasses.java
// {NewFeature} Since JDK 17
sealed class Bottom permits Level1 {}
sealed class Level1 extends Bottom permits Level2 {}
sealed class Level2 extends Level1 permits Level3 {}
final class Level3 extends Level2 {}
Note that a sealed class must have at least one subclass.
A sealed base class cannot prevent the use of a non-sealed subclass, so you can always open things back up.
// interfaces/NonSealed.java
// {NewFeature} Since JDK 17
sealed class Super permits Sub1, Sub2 {}
final class Sub1 extends Super {}
non-sealed class Sub2 extends Super {}
class Any1 extends Sub2 {}
class Any2 extends Sub2 {}
Sub2 allows any number of subclasses, so it seems like it releases control of the types you can create. However, you strictly limit the immediate subclasses of the sealed class Super. That is, Super still allows only the direct subclasses Sub1 and Sub2.
A JDK 16 record (described in a previous article in this series) can also be used as a sealed implementation of an interface. Because a record is implicitly final, it does not need to be preceded by the final keyword.
// interfaces/SealedRecords.java
// {NewFeature} Since JDK 17
sealed interface Employee
permits CLevel, Programmer {}
record CLevel(String type)
implements Employee {}
record Programmer(String experience)
implements Employee {}
The compiler prevents you from downcasting to illegal types from within a sealed hierarchy.
// interfaces/CheckedDowncast.java
// {NewFeature} Since JDK 1
sealed interface II permits JJ {}
final class JJ implements II {}
class Something {}
public class CheckedDowncast {
public void f() {
II i = new JJ();
JJ j = (JJ)i;
// Something s = (Something)i;
// error: incompatible types: II cannot
// be converted to Something
}
}
You can discover the permitted subclasses at runtime using the getPermittedSubclasses() call, as follows:
// interfaces/PermittedSubclasses.java
// {NewFeature} Since JDK 17
sealed class Color permits Red, Green, Blue {}
final class Red extends Color {}
final class Green extends Color {}
final class Blue extends Color {}
public class PermittedSubclasses {
public static void main(String[] args) {
for(var p: Color.class.getPermittedSubclasses())
System.out.println(p.getSimpleName());
}
}
/* Output:
Red
Green
Blue
*/
Source: oracle.com
Monday, September 20, 2021
Differences between Interface and Class in Java
This article highlights the differences between a class and an interface in Java.
Class:
A class is a user-defined blueprint or prototype from which objects are created. It represents the set of properties or methods that are common to all objects of one type. In general, class declarations can include these components, in order:
1. Modifiers: A class can be public or has default access.
2. Class name: The name should begin with a initial letter (capitalized by convention).
3. Superclass(if any): The name of the class’s parent (superclass), if any, preceded by the keyword extends. A class can only extend (subclass) one parent.
4. Interfaces(if any): A comma-separated list of interfaces implemented by the class, if any, preceded by the keyword implements. A class can implement more than one interface.
5. Body: The class body surrounded by braces, { }.
Constructors are used for initializing new objects. Fields are variables that provides the state of the class and its objects, and methods are used to implement the behavior of the class and its objects.
Example:
// Java program to demonstrate Class
// Class Declaration
public class Dog {
// Instance Variables
String name;
String breed;
int age;
String color;
// Constructor Declaration of Class
public Dog(String name, String breed,
int age, String color)
{
this.name = name;
this.breed = breed;
this.age = age;
this.color = color;
}
// method 1
public String getName()
{
return name;
}
// method 2
public String getBreed()
{
return breed;
}
// method 3
public int getAge()
{
return age;
}
// method 4
public String getColor()
{
return color;
}
@Override
public String toString()
{
return ("Hi my name is "
+ this.getName()
+ ".\nMy breed, age and color are "
+ this.getBreed() + ", "
+ this.getAge() + ", "
+ this.getColor());
}
public static void main(String[] args)
{
Dog tuffy = new Dog("tuffy", "papillon",
5, "white");
System.out.println(tuffy.toString());
}
}
Interface:
Differences between a Class and an Interface:
Class | Interface |
The keyword used to create a class is “class” | The keyword used to create an interface is “interface” |
A class can be instantiated i.e, objects of a class can be created. | An Interface cannot be instantiated i.e, objects cannot be created. |
Classes does not support multiple inheritance. | Interface supports multiple inheritance. |
It can be inherit another class. | It cannot inherit a class. |
It can be inherited by another class using the keyword ‘extends’. | It can be inherited by a class by using the keyword ‘implements’ and it can be inherited by an interface using the keyword ‘extends’. |
It can contain constructors. | It cannot contain constructors. |
It cannot contain abstract methods. | It contains abstract methods only. |
Variables and methods in a class can be declared using any access specifier(public, private, default, protected) | All variables and methods in a interface are declared as public. |
Variables in a class can be static, final or neither. | All variables are static and final. |
Friday, March 19, 2021
Java Classes and Objects
Java Classes/Objects
Java is an object-oriented programming language.
Everything in Java is associated with classes and objects, along with its attributes and methods. For example: in real life, a car is an object. The car has attributes, such as weight and color, and methods, such as drive and brake.
A Class is like an object constructor, or a "blueprint" for creating objects.
Create a Class
To create a class, use the keyword class:
Main.java
Create a class named "Main" with a variable x:
public class Main {
int x = 5;
}
Create an Object
In Java, an object is created from a class. We have already created the class named MyClass, so now we can use this to create objects.
To create an object of MyClass, specify the class name, followed by the object name, and use the keyword new:
Example
Create an object called "myObj" and print the value of x:
public class Main {
int x = 5;
public static void main(String[] args) {
Main myObj = new Main();
System.out.println(myObj.x);
}
}
Multiple Objects
You can create multiple objects of one class:
Example
Create two objects of Main:
public class Main {
int x = 5;
public static void main(String[] args) {
Main myObj1 = new Main(); // Object 1
Main myObj2 = new Main(); // Object 2
System.out.println(myObj1.x);
System.out.println(myObj2.x);
}
}
Using Multiple Classes
You can also create an object of a class and access it in another class. This is often used for better organization of classes (one class has all the attributes and methods, while the other class holds the main() method (code to be executed)).Remember that the name of the java file should match the class name. In this example, we have created two files in the same directory/folder:
◉ Main.java
◉ Second.java
Main.java
public class Main {
int x = 5;
}
Second.java
class Second {
public static void main(String[] args) {
Main myObj = new Main();
System.out.println(myObj.x);
}
}
When both files have been compiled:
C:\Users\Your Name>javac Main.java
C:\Users\Your Name>javac Second.java
Run the Second.java file:
C:\Users\Your Name>java Second
And the output will be:
5
Friday, July 31, 2020
How to implement our own Dynamic Array class in Java?
ArrayList is same as dynamic arrays with the ability to resize itself automatically when an element is inserted or deleted, with their storage being handled automatically by the container.
◉ ArrayList elements are placed in contiguous storage so that they can be accessed and traversed using iterators.
◉ In ArrayList, data is inserted at the end.
◉ Inserting at the end takes differential time, as sometimes there may be a need of extending the array.
◉ Removing the last element takes only constant time because no resizing happens.
◉ Inserting and erasing at the beginning or in the middle is linear in time.
Functions to be implemented in the Dynamic array class:
Certain functions associated with the ArrayList that we will implement are:
1. void push(int data): This function takes one element and inserts it at the last. Amortized time complexity is O(1).
2. void push(int data, int index): It inserts data at the specified index. Time complexity is O(1).
3. int get(int index): It is used to get the element at the specified index. Time complexity is O(1).
4. void pop(): It deletes the last element. Time complexity is O(1).
5. int size(): It returns the size of the ArrayList i.e, number of elements in the ArrayList. Time complexity is O(1).
6. int getcapacity(): It returns the capacity of the ArrayList. Time complexity is O(1).
7. void print(): It is used to print array elements. Time complexity is O(N), where N is the size of the ArrayList.
Implementation of the Dynamic array class:
Below is the implementation of our own ArrayList class.
// Java program to implement
// our own Dynamic Array class
import java.util.*;
// Self implementation of
// the ArrayList Class in Java
class ArrayListClass {
// arr is the array which stores
// our ArrayList elements
private int arr[];
// capacity is the total storage
// capacity of the ArrayList
private int capacity;
// current is the number of elements
// currently present in the ArrayList
private int current;
// Default constructor to initialise
// an initial capacity of 1 element and
// allocating storage using dynamic allocation
public ArrayListClass()
{
arr = new int[1];
capacity = 1;
current = 0;
}
// Function to add an element at the last
public void push(int data)
{
// if the number of elements
// is equal to the capacity,
// that means we don't have space
// to accommodate more elements.
// We need to double the capacity
if (current == capacity) {
int temp[] = new int[2 * capacity];
// copying old array elements
// to new array
for (int i = 0; i < capacity; i++)
temp[i] = arr[i];
capacity *= 2;
arr = temp;
}
// Inserting data
arr[current] = data;
current++;
}
// function to add element at any index
void push(int data, int index)
{
// if index is equal to capacity
// then this function is same
// as push defined above
if (index == capacity)
push(data);
else
arr[index] = data;
}
// Function to extract
// element at any index
int get(int index)
{
// if index is within the range
if (index < current)
return arr[index];
// if index is outside the range
return -1;
}
// function to delete last element
void pop()
{
current--;
}
// function to get size
// of the ArrayList
int size()
{
return current;
}
// function to get capacity
// of the ArrayList
int getcapacity()
{
return capacity;
}
// function to print ArrayList elements
void print()
{
for (int i = 0; i < current; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
// Driver program to check ArrayListClass
public static void main(String args[])
{
ArrayListClass v
= new ArrayListClass();
v.push(10);
v.push(20);
v.push(30);
v.push(40);
v.push(50);
System.out.println("ArrayList size: "
+ v.size());
System.out.println(
"ArrayList capacity: "
+ v.getcapacity());
System.out.println(
"ArrayList elements: ");
v.print();
v.push(100, 1);
System.out.println(
"\nAfter updating 1st index");
System.out.println(
"ArrayList elements: ");
v.print();
System.out.println(
"Element at 1st index: "
+ v.get(1));
v.pop();
System.out.println(
"\nAfter deleting the"
+ " last element");
System.out.println(
"ArrayList size: "
+ v.size());
System.out.println(
"ArrayList capacity: "
+ v.getcapacity());
System.out.println(
"ArrayList elements: ");
v.print();
}
}
Saturday, June 20, 2020
Java - Object and Classes
◉ Polymorphism
◉ Inheritance
◉ Encapsulation
◉ Abstraction
◉ Classes
◉ Objects
◉ Instance
◉ Method
◉ Message Passing
In this chapter, we will look into the concepts - Classes and Objects.
◉ Object − Objects have states and behaviors. Example: A dog has states - color, name, breed as well as behaviors – wagging the tail, barking, eating. An object is an instance of a class.
◉ Class − A class can be defined as a template/blueprint that describes the behavior/state that the object of its type support.
Objects in Java
Let us now look deep into what are objects. If we consider the real-world, we can find many objects around us, cars, dogs, humans, etc. All these objects have a state and a behavior.
If we consider a dog, then its state is - name, breed, color, and the behavior is - barking, wagging the tail, running.
If you compare the software object with a real-world object, they have very similar characteristics.
Software objects also have a state and a behavior. A software object's state is stored in fields and behavior is shown via methods.
So in software development, methods operate on the internal state of an object and the object-to-object communication is done via methods.
Classes in Java
A class is a blueprint from which individual objects are created.
Following is a sample of a class.
Example
public class Dog {
String breed;
int age;
String color;
void barking() {
}
void hungry() {
}
void sleeping() {
}
}
A class can contain any of the following variable types.
◉ Local variables − Variables defined inside methods, constructors or blocks are called local variables. The variable will be declared and initialized within the method and the variable will be destroyed when the method has completed.
◉ Instance variables − Instance variables are variables within a class but outside any method. These variables are initialized when the class is instantiated. Instance variables can be accessed from inside any method, constructor or blocks of that particular class.
◉ Class variables − Class variables are variables declared within a class, outside any method, with the static keyword.
A class can have any number of methods to access the value of various kinds of methods. In the above example, barking(), hungry() and sleeping() are methods.
Following are some of the important topics that need to be discussed when looking into classes of the Java Language.
Constructors
When discussing about classes, one of the most important sub topic would be constructors. Every class has a constructor. If we do not explicitly write a constructor for a class, the Java compiler builds a default constructor for that class.
Each time a new object is created, at least one constructor will be invoked. The main rule of constructors is that they should have the same name as the class. A class can have more than one constructor.
Following is an example of a constructor −
Example
public class Puppy {
public Puppy() {
}
public Puppy(String name) {
// This constructor has one parameter, name.
}
}
Java also supports Singleton Classes where you would be able to create only one instance of a class.
Note − We have two different types of constructors. We are going to discuss constructors in detail in the subsequent chapters.
Creating an Object
As mentioned previously, a class provides the blueprints for objects. So basically, an object is created from a class. In Java, the new keyword is used to create new objects.
There are three steps when creating an object from a class −
◉ Declaration − A variable declaration with a variable name with an object type.
◉ Instantiation − The 'new' keyword is used to create the object.
◉ Initialization − The 'new' keyword is followed by a call to a constructor. This call initializes the new object.
Following is an example of creating an object −
Example
public class Puppy {
public Puppy(String name) {
// This constructor has one parameter, name.
System.out.println("Passed Name is :" + name );
}
public static void main(String []args) {
// Following statement would create an object myPuppy
Puppy myPuppy = new Puppy( "tommy" );
}
}
If we compile and run the above program, then it will produce the following result −
Output
Passed Name is :tommy
Accessing Instance Variables and Methods
Instance variables and methods are accessed via created objects. To access an instance variable, following is the fully qualified path −
/* First create an object */
ObjectReference = new Constructor();
/* Now call a variable as follows */
ObjectReference.variableName;
/* Now you can call a class method as follows */
ObjectReference.MethodName();
Example
This example explains how to access instance variables and methods of a class.
public class Puppy {
int puppyAge;
public Puppy(String name) {
// This constructor has one parameter, name.
System.out.println("Name chosen is :" + name );
}
public void setAge( int age ) {
puppyAge = age;
}
public int getAge( ) {
System.out.println("Puppy's age is :" + puppyAge );
return puppyAge;
}
public static void main(String []args) {
/* Object creation */
Puppy myPuppy = new Puppy( "tommy" );
/* Call class method to set puppy's age */
myPuppy.setAge( 2 );
/* Call another class method to get puppy's age */
myPuppy.getAge( );
/* You can access instance variable as follows as well */
System.out.println("Variable Value :" + myPuppy.puppyAge );
}
}
If we compile and run the above program, then it will produce the following result −
Output
Name chosen is :tommy
Puppy's age is :2
Variable Value :2
Source File Declaration Rules
As the last part of this section, let's now look into the source file declaration rules. These rules are essential when declaring classes, import statements and package statements in a source file.
◉ There can be only one public class per source file.
◉ A source file can have multiple non-public classes.
◉ The public class name should be the name of the source file as well which should be appended by .java at the end. For example: the class name is public class Employee{} then the source file should be as Employee.java.
◉ If the class is defined inside a package, then the package statement should be the first statement in the source file.
◉ If import statements are present, then they must be written between the package statement and the class declaration. If there are no package statements, then the import statement should be the first line in the source file.
◉ Import and package statements will imply to all the classes present in the source file. It is not possible to declare different import and/or package statements to different classes in the source file.
Classes have several access levels and there are different types of classes; abstract classes, final classes, etc. We will be explaining about all these in the access modifiers chapter.
Apart from the above mentioned types of classes, Java also has some special classes called Inner classes and Anonymous classes.
Java Package
In simple words, it is a way of categorizing the classes and interfaces. When developing applications in Java, hundreds of classes and interfaces will be written, therefore categorizing these classes is a must as well as makes life much easier.
Import Statements
In Java if a fully qualified name, which includes the package and the class name is given, then the compiler can easily locate the source code or classes. Import statement is a way of giving the proper location for the compiler to find that particular class.
For example, the following line would ask the compiler to load all the classes available in directory java_installation/java/io −
import java.io.*;
A Simple Case Study
For our case study, we will be creating two classes. They are Employee and EmployeeTest.
First open notepad and add the following code. Remember this is the Employee class and the class is a public class. Now, save this source file with the name Employee.java.
The Employee class has four instance variables - name, age, designation and salary. The class has one explicitly defined constructor, which takes a parameter.
Example
import java.io.*;
public class Employee {
String name;
int age;
String designation;
double salary;
// This is the constructor of the class Employee
public Employee(String name) {
this.name = name;
}
// Assign the age of the Employee to the variable age.
public void empAge(int empAge) {
age = empAge;
}
/* Assign the designation to the variable designation.*/
public void empDesignation(String empDesig) {
designation = empDesig;
}
/* Assign the salary to the variable salary.*/
public void empSalary(double empSalary) {
salary = empSalary;
}
/* Print the Employee details */
public void printEmployee() {
System.out.println("Name:"+ name );
System.out.println("Age:" + age );
System.out.println("Designation:" + designation );
System.out.println("Salary:" + salary);
}
}
As mentioned previously in this tutorial, processing starts from the main method. Therefore, in order for us to run this Employee class there should be a main method and objects should be created. We will be creating a separate class for these tasks.
Following is the EmployeeTest class, which creates two instances of the class Employee and invokes the methods for each object to assign values for each variable.
Save the following code in EmployeeTest.java file.
import java.io.*;
public class EmployeeTest {
public static void main(String args[]) {
/* Create two objects using constructor */
Employee empOne = new Employee("James Smith");
Employee empTwo = new Employee("Mary Anne");
// Invoking methods for each object created
empOne.empAge(26);
empOne.empDesignation("Senior Software Engineer");
empOne.empSalary(1000);
empOne.printEmployee();
empTwo.empAge(21);
empTwo.empDesignation("Software Engineer");
empTwo.empSalary(500);
empTwo.printEmployee();
}
}
Now, compile both the classes and then run EmployeeTest to see the result as follows −
Output
C:\> javac Employee.java
C:\> javac EmployeeTest.java
C:\> java EmployeeTest
Name:James Smith
Age:26
Designation:Senior Software Engineer
Salary:1000.0
Name:Mary Anne
Age:21
Designation:Software Engineer
Salary:500.0