Important Topics and Questions
1. As static block is used to execute any block exactly once is
this why we write "public static void main " so that it is
executed only once when we write main function??
The reason why the public static void main(String[] args) method
is written the way it is in Java has more to do with how Java
programs are structured for execution, rather than the same
purpose as a static block. Here's an explanation of the difference
between the static block and the main method, and why they are
used:
1. Static Block
Purpose: The static block is used for initializing static variables
or performing other one-time setup tasks when the class is
loaded into memory. It is executed automatically by the JVM
only once, the first time the class is loaded, before any methods
or constructors are called.
Execution Timing: The static block is executed only once per
class load, regardless of how many times the class is referenced
or the program is run.
Example:
java
Copy code
public class Example {
static {
System.out.println("Static block executed.");
}
public static void main(String[] args) {
System.out.println("Main method executed.");
}
}
Output:
Copy code
Static block executed.
Main method executed.
In this example, the static block is executed once when the class is
loaded before the main method is executed.
2. Main Method (public static void main)
Purpose:The main method serves as the entry point for any
Java application that is run by the JVM. This method is called
when the program starts (i.e., when you run the application).
Why it's static:
o The main method must be static so that it can be invoked
by the JVM without having to create an instance of the
class first. Since the JVM does not instantiate objects of
the class when it starts a Java program, making the main
method static allows it to be called directly via the class
name, like ClassName.main().
Executed Once: The main method is executed only once when
you run a Java application. However, if you invoke the program
multiple times (by restarting the JVM or calling the program
multiple times from the command line), the main method will
be executed again each time.
Example:
java
Copy code
public class Example {
public static void main(String[] args) {
System.out.println("Main method executed.");
}
}
Output:
css
Copy code
Main method executed.
The main method will execute when you start the Java program,
but it only runs once per execution of the program.
2. Static Block and Static initializer.
1. Static Block
A static block is a block of code inside a class that is executed
once, when the class is loaded into memory. It is often used to
initialize static variables or perform some one-time setup
operations that need to happen before any instances of the class
are created or static methods are accessed.
Syntax:
java
Copy code
class Example {
static {
// Static block code goes here
System.out.println("Static block is executed.");
}
}
Key Characteristics:
A static block is executed only once when the class is loaded
into memory, and before any other methods (including the
constructor) or fields are accessed.
It is used for initializing static variables or performing any
actions that should happen only once, such as setting up
connections, reading configuration files, etc.
If the class is loaded more than once (e.g., in the case of
multiple class loaders), the static block is executed again each
time the class is loaded.
Example:
java
Copy code
public class StaticBlockExample {
static {
System.out.println("Static block executed.");
}
public static void main(String[] args) {
System.out.println("Main method executed.");
}
}
Output:
scss
Copy code
Static block executed.
Main method executed.
In this example, the static block is executed first, when the class is
loaded into memory, and then the main method is executed.
2. Static Initializer
The static initializer refers to the initialization of static variables
directly in the class definition or within a static block. Essentially, a
static block can serve as a static initializer to initialize static
variables.
Static Variables Initialization:
Static variables can be initialized directly at the time of declaration
or through a static block if more complex initialization is needed.
Example of Static Variable Initialization:
java
Copy code
public class StaticInitializerExample {
static int count;
// Static block as static initializer
static {
count = 10; // Initializing static variable using static block
System.out.println("Static variable count initialized.");
}
public static void main(String[] args) {
System.out.println("count = " + count); // Prints: count = 10
}
}
In this example, the static block serves as a static initializer, where
we initialize the count variable.
Direct Static Variable Initialization:
You can also initialize static variables directly, without needing a
static block:
java
Copy code
public class StaticInitializerExample {
static int count = 10; // Direct initialization of static variable
public static void main(String[] args) {
System.out.println("count = " + count); // Prints: count = 10
}
}
----------------------------------------------------------------------------------------
Example of static method:
class Mobile{
int price;
String brand;
static String type;
Mobile(int price,String brand,String type){
this.price=price;
this.brand=brand;
this.type=type;
}
public void show1(){
System.out.println(brand+" : "+type+" : "+price);
}
//as we know only static variables can be displayed through
static method but if we want to display static variable through
static method then we can do that using object reference.
public static void show2(Mobile obj){
System.out.println(obj.brand+" : "+type+" : "+obj.price);
}
}
class Main {
public static void main(String[] args) {
System.out.println("Try programiz.pro");
Mobile m1=new Mobile(1500,"apple","");
Mobile m2=new Mobile(15000,"vivo","Smartphone");
m1.show1();
m2.show1();
System.out.println();
System.out.println("displaying info using static method and
object reference : ");
Mobile.show2(m1);
Mobile.show2(m2);
}
}
3. How to call one constructor from the other constructor
In Java, you can call one constructor from another constructor
within the same class using the this() keyword. This is called
constructor chaining. It allows you to reuse one constructor's
code inside another constructor, which can be useful to avoid code
duplication and ensure consistency in object initialization.
Syntax for Calling One Constructor from Another:
java
Copy code
this(arguments);
this(arguments): Calls the constructor with the matching
parameter list. It must be the first statement in the constructor.
How It Works:
When you use this() in one constructor, it calls another
constructor in the same class.
The called constructor is responsible for initializing the object,
and the calling constructor can then perform additional tasks or
setup.
Example of Constructor Chaining:
java
class Main {
private int x; private int y;
public Main(int x,int y){
this.x=x;
this.y=y;
System.out.println("Constructor with two parameters
"+this.x+" "+this.y);
}
public Main(int x){
this(x,0);
System.out.println("Constructor with one parameter "+x);
}
public static void main(String[] args) {
System.out.println("Try programiz.pro ");
Main m1=new Main(10,5);
Main m2=new Main(6);
}
}
Output:
Constructor with two parameters 10 5
Constructor with two parameters 6 0
Constructor with one parameter 6
Explanation:
In this example, the class has two constructors:
1. Constructor with two parameters: This constructor
initializes both x and y.
2. Constructor with one parameter: This constructor calls
the two-parameter constructor using this(x, 0), setting y to
0 if no value is provided.
Key Points:
Calling another constructor using this() must be the first
statement in the constructor.
Constructor chaining helps reduce code duplication and
improves maintainability, especially when you have multiple
constructors with similar logic.
If you don't explicitly call another constructor, the default
constructor (if it exists) is used automatically.
Constructor Chaining Example with Default Constructor:
java
Copy code
public class ConstructorChainingExample {
private int x;
private int y;
// Default constructor
public ConstructorChainingExample() {
this(0, 0); // Calls the two-parameter constructor with default
values
System.out.println("Default constructor called.");
}
// Constructor with two parameters
public ConstructorChainingExample(int x, int y) {
this.x = x;
this.y = y;
System.out.println("Constructor with two parameters
called.");
}
public static void main(String[] args) {
ConstructorChainingExample obj = new
ConstructorChainingExample(); // Calls default constructor
}
}
Output:
sql
Copy code
Constructor with two parameters called.
Default constructor called.
Conclusion:
Use this() to call one constructor from another within the same
class. This is useful when you want to avoid code repetition and
simplify object initialization logic.
Make sure that this() is always the first statement in the
constructor where it's used.
4. Collections in java:
https://www.javatpoint.com/collections-in-java
1. What is iterable and also iterator ?can i use iterator for simple
Array like int[] arr=new int();?
In Java, the concepts of iterable and iterator are used to
traverse collections like lists, sets, and other data structures.
Let’s break them down:
Iterable
An Iterable is any object that can be iterated over. It has a
method called iterator() that returns an iterator to traverse the
collection.
Example: Collections such as ArrayList, HashSet, etc.,
implement the Iterable interface.
Usage: You can use an Iterable to get an Iterator, which allows
you to loop through the elements of the collection.
Iterator
An Iterator is an object that allows you to traverse a collection
one element at a time. It provides methods like:
hasNext(): Returns true if there are more elements to iterate
over.
next(): Returns the next element in the iteration.
remove(): Removes the current element from the collection
(optional method).
Example:
java
Copy
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
Can You Use Iterator with a Simple Array like int[] arr = new
int[5];?
No, you cannot directly use an Iterator with a primitive array
like int[]. Arrays do not implement the Iterable interface.
However, you can convert an array into a collection, like a List,
which is iterable.
If you still want to iterate over an array, you can do so using a
for loop or a for-each loop, but you would need to use a
wrapper class like Integer[] or a collection type if you want to
explicitly use an Iterator.
For example:
java
Copy
int[] arr = new int[5];
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
arr[3] = 4;
arr[4] = 5;
// Using Iterator by converting to List
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
2. To iterate over any collection i can use for loop or for each
method then why should i use iterator?
Great question! You are absolutely right that for most
collections in Java, you can use a for loop or for-each loop to
iterate over the elements. So why would you use an Iterator?
There are several reasons for this choice:
1. Modifying the Collection During Iteration (Removing
Elements)
One key advantage of using an Iterator is that it allows you to
safely remove elements from a collection while iterating over it.
The for-each loop and a for loop don't support modification of
the collection (i.e., removing elements) during iteration. If you
try to remove elements while iterating with these loops, you'll
get a ConcurrentModificationException.
Example with Iterator:
java
Copy
List<Integer> list = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
Integer current = iterator.next();
if (current % 2 == 0) {
iterator.remove(); // Safe removal during iteration
}
}
System.out.println(list); // Output will be [1, 3, 5]
This would throw an exception if you tried to use a for-each
loop or a standard for loop to remove elements.
2. Working with Legacy or Custom Collections
When you work with legacy collections (e.g., Vector, Stack,
Hashtable) or custom collections that don't implement the
Iterable interface, you might still need to use an Iterator
explicitly, even if the collection can be traversed with a loop.
An Iterator provides a consistent interface for iteration across
any collection, whether it’s a simple array, a list, or even a more
complex data structure. If you're dealing with non-Iterable
collections, like arrays, or when you want to encapsulate
custom collection behavior, an Iterator might be more useful.
3. More Control Over Iteration
Using an Iterator gives you more control over the iteration
process. For example, you can:
o Skip elements: You can use custom logic in the loop to
skip or selectively access certain elements based on
specific conditions.
o Advanced patterns: In some cases, you may need to
implement more advanced iteration logic (like
bidirectional iteration with a ListIterator) that goes
beyond what the basic for-each loop can do.
4. Handling Different Types of Collections
Iterator works across any collection type, making it easy to
switch between different collection types without changing the
logic of your iteration.
For example, you can use the same iterator logic with an
ArrayList, HashSet, or LinkedList, whereas the for or for-each
loop might require slight adjustments if you're dealing with
different collection types, especially if you want to perform
special actions (like removing elements).
5. Future Compatibility
In some cases, you may want to write code that’s more
generalizable. For example, if you’re developing a method that
could work on various types of collections, using an Iterator
allows you to write code that works consistently across
different types without being concerned about the specific
iteration mechanism.
6. Iterator for Thread-Safety (in Concurrent Collections)
In some advanced scenarios, when you’re working with
concurrent collections (like CopyOnWriteArrayList or
ConcurrentLinkedQueue), using an Iterator is necessary
because these collections handle iteration in a thread-safe way.
When to Use Which?
For-each loop: Best for simple iteration when you don’t need to
modify the collection during iteration.
For loop: Great for iterating through collections (or arrays)
when you need index-based access or are dealing with arrays.
Iterator: Best when you need more control over the iteration
(e.g., removing elements), or if you're working with non-
Iterable collections or legacy code.
Example Comparison:
1. For-each loop:
java
Copy
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
for (int num : list) {
System.out.println(num);
}
2. Iterator:
java
Copy
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);
Iterator<Integer> iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
In summary, use an Iterator when you need more control over
the iteration process (e.g., removal during iteration, or when
working with non-Iterable collections). Otherwise, a simple for-
each loop should suffice for most use cases.
5. What is the difference between List<> l1=new
ArrayList<>(); and ArrayList<> l2=new ArrayList<>();?
The difference between List<> l1 = new ArrayList<>(); and
ArrayList<> l2 = new ArrayList<>(); lies in the type of the reference
variable used for each:
1. List<> l1 = new ArrayList<>();:
o List<> is an interface in Java, and ArrayList<> is a concrete
implementation of this interface.
o Here, l1 is a reference of type List<>, meaning that it can
point to any object that implements the List interface,
such as ArrayList, LinkedList, or any other list
implementation.
o The use of List<> as the reference type is a good practice
when you want to code to an interface, not an
implementation. This provides flexibility to change the
underlying implementation (e.g., swapping ArrayList with
LinkedList) without affecting the rest of the code.
2. ArrayList<> l2 = new ArrayList<>();:
o ArrayList<> is a concrete class that implements the List
interface.
o In this case, l2 is specifically an ArrayList, meaning it can
only hold references to objects of the ArrayList type and
cannot be reassigned to a LinkedList or any other List
implementation.
o This approach is more rigid because it directly ties the
reference variable to the specific implementation of the
List interface (i.e., ArrayList), reducing flexibility.
Summary:
List<> l1 = new ArrayList<>();: Use of the interface type (List<>)
allows flexibility to change the implementation later (e.g.,
swapping ArrayList with LinkedList).
ArrayList<> l2 = new ArrayList<>();: Directly using the concrete
class (ArrayList<>) ties the reference to a specific
implementation.
6. In arraylist how can we add all elements at a time?
Using addAll():-
import java.util.*;
class Main {
public static void main(String[] args) {
System.out.println("Try programiz.pro");
List<Integer> L1=new ArrayList<>();
L1.addAll(Arrays.asList(1,2,3,4,5));
System.out.println(L1);
}
}
Using Collections.addAll():-
import java.util.*;
class Main {
public static void main(String[] args) {
System.out.println("Try programiz.pro");
List<Integer> L1=new ArrayList<>();
Collections.addAll(L1,1,2,3,4,5);
System.out.println(L1);
}
}
7. ArrayList Operations:
import java.util.*;
class ArrList{
ArrayList<Integer> L1=new ArrayList<>();
public void addint(){
Collections.addAll(L1,2,23,13,64,45);
}
public void insert(int i,int ele){
L1.add(i,ele);
}
public void getspecific(int i){
System.out.println("In ArrayList the Element at index"+i+" is
"+L1.get(i));
}
public void replace(int i,int ele){
L1.set(i,ele);
}
public void merge(){
ArrayList<Integer> L2=new ArrayList<>();
Collections.addAll(L2,60,17,28,959,100);
L1.addAll(L2);
}
public void empty(){
L1.clear();
}
public void check(int ele){
System.out.println(L1.contains(ele));
}
public void sort(){
Collections.sort(L1);
}
public void print(){
System.out.println(L1);
}
}
class Main {
public static void main(String[] args) {
System.out.println("Try programiz.pro");
ArrList a1=new ArrList();
Scanner sc=new Scanner(System.in);
System.out.println("1.Add integer elements 2.Get Element of
specific index 3.Update element of specific index (First print old
elements then update) 4.Add element at specified index 5.Merge
Two lists 6.Empty the List 7.Check whether an element is present
or not 8.Sort the list elements 9.Print ArrayList 10.Exit");
char ch='y';
while(ch=='y'){
System.out.println("Enter ur Choice:");
int op=sc.nextInt();
switch(op){
case 1:
a1.addint();
a1.print();
break;
case 2:
System.out.print("Enter the index number to access the
element:");
int i=sc.nextInt();
a1.getspecific(i);
break;
case 3:
System.out.print("Enter the index number at which u
want to set the new element:");
int j=sc.nextInt();
System.out.print("Enter the element:");
int ele=sc.nextInt();
a1.replace(j,ele);
a1.print();
break;
case 4:
System.out.print("Enter the index number at which u
want to insert the new element:");
int k=sc.nextInt();
System.out.print("Enter the element:");
int ele1=sc.nextInt();
a1.insert(k,ele1);
break;
case 5:
a1.merge();
break;
case 6:
a1.empty();
break;
case 7:
System.out.print("Enter the element u want to check:");
int ele2=sc.nextInt();
a1.check(ele2);
break;
case 8:
a1.sort();
break;
case 9:
a1.print();
break;
case 10:
ch='n';
break;
}
}
}
}
8. LinkedList in collections
import java.util.*;
class Linkedlist{
Scanner sc=new Scanner(System.in);
LinkedList<Integer> LL1=new LinkedList<>();
public void addint(){
Collections.addAll(LL1,2,23,13,64,45);
}
public void insert(int i,int ele){
LL1.add(i,ele);
}
public void AddAll(int i,int n){
LinkedList<Integer> LL2=new LinkedList<>();
System.out.println("Enter an elements to insert in 2nd
Linkedlist:");
for(int j=0;j<n;j++){
System.out.println("Element:");
int ele=sc.nextInt();
LL2.add(ele);
}
LL1.addAll(i,LL2);
System.out.println(LL1);
}
public void getspecific(int i){
System.out.println("In LinkedList the Element at index
"+i+" is "+LL1.get(i));
}
public void replace(int i,int ele){
LL1.set(i,ele);
}
public void merge(){
ArrayList<Integer> L2=new ArrayList<>();
Collections.addAll(L2,60,17,28,959,100);
LL1.addAll(L2);
}
public void empty(){
LL1.clear();
}
public void check(int ele){
System.out.println(LL1.contains(ele));
}
public void sort(){
Collections.sort(LL1);
}
public void addatfirst(){
System.out.println("enter element: ");
int ele3=sc.nextInt();
LL1.addFirst(ele3);
}
public void addatlast(){
System.out.println("enter element: ");
int ele4=sc.nextInt();
LL1.addLast(ele4);
}
public void reverse(){
Iterator<Integer> itr=LL1.descendingIterator();
System.out.println("Reverse of Linkedlist:");
while(itr.hasNext()){
System.out.print(itr.next()+" ");
}
}
public void print(){
System.out.println(LL1);
}
}
class Main {
public static void main(String[] args) {
System.out.println("Try programiz.pro");
Linkedlist a1=new Linkedlist();
Scanner sc=new Scanner(System.in);
System.out.println("1.Add integer elements 2.Get
Element of specific index 3.Update element of specific
index (First print old elements then update) 4.Add element
at specified index 5.Merge Two lists 6.Empty the List
7.Check whether an element is present or not 8.Sort the
list elements 9.Add collection to the list 10.Print LinkedList
11.Add element at first 12.Add element at last 13.Get
Reverse of list 13.Exit");
char ch='y';
while(ch=='y'){
System.out.println("Enter ur Choice:");
int op=sc.nextInt();
switch(op){
case 1:
a1.addint();
a1.print();
break;
case 2:
System.out.print("Enter the index number to
access the element:");
int i=sc.nextInt();
a1.getspecific(i);
break;
case 3:
System.out.print("Enter the index number at
which u want to set the new element:");
int j=sc.nextInt();
System.out.print("Enter the element:");
int ele=sc.nextInt();
a1.replace(j,ele);
a1.print();
break;
case 4:
System.out.print("Enter the index number at
which u want to insert the new element:");
int k=sc.nextInt();
System.out.print("Enter the element:");
int ele1=sc.nextInt();
a1.insert(k,ele1);
break;
case 5:
a1.merge();
break;
case 6:
a1.empty();
break;
case 7:
System.out.print("Enter the element u want to
check:");
int ele2=sc.nextInt();
a1.check(ele2);
break;
case 8:
a1.sort();
break;
case 9:
System.out.println("enter the index at which u
want to insert the 2nd LinkedList:");
int x=sc.nextInt();
System.out.println("enter the number of
elements u want add in 2nd list:");
int n=sc.nextInt();
a1.AddAll(x,n);
break;
case 10:
a1.print();
break;
case 11:
a1.addatfirst();
break;
case 12:
a1.addatlast();
break;
case 13:
a1.reverse();
case 14:
ch='n';
break;
}
}
}
}
9. Does stack extends vector?
Yes, in Java, the Stack class extends the Vector class.
Hierarchy:
Stack: A class that represents a last-in, first-out (LIFO) stack of
objects. It extends the Vector class and provides methods for
pushing, popping, and peeking elements.
Vector: A dynamic array class that implements the List
interface. It grows as elements are added to it, and it provides
indexed access to the elements in the list.
Key Points:
1. Inheritance: Since Stack extends Vector, it inherits all the
methods of Vector (like add(), size(), remove(), etc.) and adds its
own specialized methods for stack operations (such as push(),
pop(), and peek()).
2. Vector: Vector is a part of the java.util package and is essentially
a resizable array that grows as elements are added. It is similar
to an ArrayList, but unlike ArrayList, it is synchronized (making it
thread-safe, but potentially slower).
3. Stack-specific Methods:
o push(E item): Adds an item to the top of the stack.
o pop(): Removes and returns the top item from the stack.
opeek(): Returns the top item of the stack without
removing it.
o isEmpty(): Returns true if the stack is empty.
Example:
java
Copy
import java.util.Stack;
public class StackExample {
public static void main(String[] args) {
// Creating a Stack of integers
Stack<Integer> stack = new Stack<>();
// Pushing elements onto the stack
stack.push(1);
stack.push(2);
stack.push(3);
stack.push(4);
// Printing the top element
System.out.println("Top element: " + stack.peek()); // 4
// Popping elements from the stack
System.out.println("Popped: " + stack.pop()); // 4
System.out.println("Popped: " + stack.pop()); // 3
// Checking if the stack is empty
System.out.println("Is stack empty? " + stack.isEmpty()); //
false
// Printing the stack size
System.out.println("Stack size: " + stack.size()); // 2
}
}
Output:
yaml
Copy
Top element: 4
Popped: 4
Popped: 3
Is stack empty? false
Stack size: 2
Why Stack extends Vector?
The Stack class inherits the Vector class to leverage its resizable
array implementation. The Vector class provides methods to
manage the underlying array dynamically as elements are added
or removed, making it a natural choice for Stack's functionality.
However, since Stack only needs a LIFO (Last In, First Out) access
pattern, it provides additional methods tailored to that structure.
Modern Alternatives:
Although Stack is part of the Java standard library, it is
considered somewhat outdated. The Deque interface
(implemented by ArrayDeque) is often preferred over Stack in
modern Java for stack-like behavior, because Deque is more
efficient and versatile.
Example using ArrayDeque (a better alternative to Stack):
java
Copy
import java.util.ArrayDeque;
import java.util.Deque;
public class ArrayDequeExample {
public static void main(String[] args) {
// Creating a Deque for stack operations
Deque<Integer> stack = new ArrayDeque<>();
// Pushing elements onto the stack
stack.push(1);
stack.push(2);
stack.push(3);
// Printing the top element
System.out.println("Top element: " + stack.peek()); // 3
// Popping elements from the stack
System.out.println("Popped: " + stack.pop()); // 3
System.out.println("Popped: " + stack.pop()); // 2
// Checking if the stack is empty
System.out.println("Is stack empty? " + stack.isEmpty()); //
false
}
}
In this example, ArrayDeque is used as a stack, and it provides
efficient push and pop operations. ArrayDeque is generally
preferred over Stack due to better performance and non-
synchronization by default, which is better suited for most use
cases in modern applications.
10. Difference between empty() and isEmpty() in Stack.
isEmpty() is the preferred method for checking if a Stack is
empty because it is clearer, more modern, and not
deprecated.
empty() is inherited from Vector and is now considered
outdated and deprecated. Although it still works, it's better
to use isEmpty() in new code.
11. Stack in collections:
// Online Java Compiler
// Use this editor to write, compile and run your Java code online
import java.util.*;
class Stackop{
Stack<String> S1=new Stack<>();
Scanner sc=new Scanner(System.in);
public void add(){
System.out.println("enter element to insert:");
String ele=sc.nextLine();
S1.push(ele);
}
public void remove(){
System.out.print("Popped Element is:"+S1.pop());
System.out.println();
}
public void get(){
System.out.print("Top Element is:"+S1.peek());
System.out.println();
}
public void check(){
System.out.print("Is Stack Empty:"+S1.isEmpty());
System.out.println();
}
public void find(){
System.out.print("enter element to get its index:");
String ele2=sc.nextLine();
System.out.println(S1.search(ele2));
}
}
class Main {
public static void main(String[] args) {
Stackop stk=new Stackop();
System.out.println("Enter: 1.For Adding element in stack
2.For Removing top element 3.For Accessing top element 4.To
check if the stack is empty 5.To check whether an elment is
present or not");
Scanner sc=new Scanner(System.in);
char ch='y';
while(ch=='y'){
System.out.println("Enter ur choice:");
int op=sc.nextInt();
switch(op){
case 1:
stk.add();
break;
case 2:
stk.remove();
break;
case 3:
stk.get();
break;
case 4:
stk.check();
break;
case 5:
stk.find();
break;
case 6:
ch='n';
break;
}
}
}
}
12. HashSet in collection:
// Online Java Compiler
// Use this editor to write, compile and run your Java code online
import java.util.*;
class hashset{
HashSet<Integer> s1=new HashSet<Integer>();
public void operations(){
s1.add(10);
s1.add(20);
s1.add(30);
s1.add(40);
System.out.println("After adding elements hashset is: "+s1);
ArrayList<Integer> l1=new ArrayList<>(List.of(20,60,70));
s1.addAll(l1);
System.out.println("After adding list hashset is: "+s1);
ArrayList<Integer> l2=new ArrayList<>(List.of(50,60,10));
s1.removeAll(l2);
System.out.println("After removing some elements hashset is:
"+s1);
ArrayList<Integer> l3=new ArrayList<>(List.of(20, 70, 40));
System.out.println("check whether hashset contains given
list(20, 70, 40) or not : "+s1.containsAll(l3));
System.out.println("Size of Set: "+s1.size());
ArrayList<Integer> l4=new ArrayList<>(List.of(25, 70, 40,30));
s1.retainAll(l4);
System.out.println("Common elements between s1set and l4
list are : "+s1);
System.out.println("Size of Set: "+s1.size());
}
}
class Main {
public static void main(String[] args) {
System.out.println("Try programiz.pro");
hashset h1=new hashset();
h1.operations();
}
}
Q. Why we use Hashset?
We use a HashSet in Java because it is a powerful and efficient data
structure for specific use cases. Its key properties make it ideal when
we need a collection that guarantees uniqueness, provides fast
lookups, and doesn't require elements to be ordered. Below are the
main reasons why we use HashSet:
1. To Ensure Uniqueness of Elements
Key Feature: HashSet automatically removes duplicate
elements.
Use Case: When you need to store unique items, like IDs,
usernames, or email addresses.
Example:
java
CopyEdit
HashSet<String> uniqueNames = new HashSet<>();
uniqueNames.add("Alice");
uniqueNames.add("Bob");
uniqueNames.add("Alice"); // Duplicate, ignored
System.out.println(uniqueNames); // Output: [Alice, Bob]
2. Fast Lookup and Search (O(1))
Key Feature: HashSet uses a hash table internally, making
operations like searching, adding, and removing elements very
fast (average time complexity is O(1)).
Use Case: When you need a fast way to check if an element
exists in a collection, like in a whitelist or blacklist.
Example:
java
CopyEdit
HashSet<Integer> allowedIDs = new HashSet<>();
allowedIDs.add(1001);
allowedIDs.add(1002);
if (allowedIDs.contains(1001)) {
System.out.println("Access granted for ID: 1001");
}
3. No Insertion Order (Unordered Collection)
Key Feature: Unlike ArrayList or LinkedList, a HashSet does not
maintain the order of elements.
Use Case: When you don’t care about the order of elements,
and only uniqueness and fast access matter.
Example:
java
CopyEdit
HashSet<String> items = new HashSet<>();
items.add("Apple");
items.add("Banana");
items.add("Mango");
System.out.println(items); // Output: [Banana, Mango, Apple] (Order
is unpredictable)
4. To Remove Duplicates from a Collection
Key Feature: You can use a HashSet to eliminate duplicates
from a list or array automatically.
Use Case: When working with raw data that may contain
duplicates, such as user-submitted data or external API
responses.
Example:
java
CopyEdit
import java.util.ArrayList;
import java.util.HashSet;
ArrayList<String> emails = new ArrayList<>();
emails.add("user1@example.com");
emails.add("user2@example.com");
emails.add("user1@example.com");
HashSet<String> uniqueEmails = new HashSet<>(emails);
System.out.println(uniqueEmails); // Output: [user1@example.com,
user2@example.com]
5. Null Value Handling
Key Feature: A HashSet allows one null value, unlike other
collections like TreeSet that don’t allow null.
Use Case: When you might deal with nulls but still need a set of
unique values.
Example:
java
CopyEdit
HashSet<String> set = new HashSet<>();
set.add(null);
set.add("Java");
set.add(null); // Ignored, as null already exists
System.out.println(set); // Output: [null, Java]
6. Memory Efficient for Sets
Key Feature: Compared to a List, HashSet doesn’t store
duplicates, so it can save memory when storing a large number
of unique items.
Use Case: When memory usage needs to be optimized in large
datasets.
When to Use HashSet
Uniqueness: When you need a collection that ensures no
duplicates.
Fast Search: When you need quick O(1) lookups (e.g., checking
for membership).
No Order Needed: When the order of elements isn’t important.
Handling Large Datasets: When dealing with large collections
where uniqueness and speed are key.
HashSet vs Other Collections
Feature HashSet ArrayList LinkedHashSet TreeSet
Duplicates No Yes No No
Order Maintained No Yes Yes Sorted
1 Not
Null Values Multiple 1 allowed
allowed allowed
Performance
O(1) O(n) O(1) O(log n)
(Add/Search)
Common Use Cases
1. Whitelist or Blacklist: To store unique IDs or values that need
fast validation.
2. Unique Record Validation: To check if a value (like a
username or email) is already in use.
3. Data Cleanup: To filter out duplicates from a collection or
dataset.
4. Caching: When building small, in-memory caches for quick
access to unique items.
5. Graph Algorithms: To keep track of visited nodes.
Q. In hashset what is use of hash table which is
maintained internally and how does hashset makes
insertion,deletion and searching faster using hashtable
The HashSet in Java is backed internally by a hash table
(implemented using a HashMap), and this is the core reason why it
provides efficient insertion, deletion, and searching operations
with an average time complexity of O(1).
Here’s an in-depth explanation of how the hash table works in the
context of a HashSet:
1. What is a Hash Table?
A hash table is a data structure that stores key-value pairs.
It uses a hashing mechanism to compute a unique index (or
"hash") for each key.
The hash value determines where the data is stored in a
fixed-size array called the bucket array.
The elements are placed in buckets, and if two keys generate
the same hash (collision), the elements are stored in the
same bucket but linked as a chain (or other collision-
resolution mechanisms like open addressing).
2. How HashSet Uses a Hash Table Internally
Internally, HashSet uses a HashMap with its keys as the
elements of the set, and the values in the HashMap are
dummy objects (usually Boolean.TRUE).
When you insert an element into a HashSet, it is stored as a
key in the hash table.
Example:
When you call:
java
CopyEdit
HashSet<String> set = new HashSet<>();
set.add("Apple");
It translates internally to:
java
CopyEdit
HashMap<String, Object> map = new HashMap<>();
map.put("Apple", Boolean.TRUE); // "Apple" is the key, and the
value is a dummy object.
3. How HashSet Makes Operations Faster
The key to HashSet's performance is the hashing mechanism and
the hash table structure. Here’s how it works for insertion,
deletion, and searching:
(a) Insertion
1. Hashing the Element:
o When you add an element to the HashSet, the
element’s hashCode() method is called to compute a
hash value.
o This hash value determines the bucket where the
element will be stored.
2. Checking for Duplicates:
1.
o Before inserting, the HashSet checks if the element
already exists in the bucket.
o This is done using the equals() method to compare the
element with others in the same bucket (to resolve
collisions).
2. Adding the Element:
o If no duplicate is found, the element is stored in the
corresponding bucket.
Example:
java
CopyEdit
set.add("Apple");
hashCode() is called on "Apple" to compute its hash.
The hash determines the bucket index, e.g., index 3.
If the bucket at index 3 is empty, "Apple" is added.
If there are already elements in the bucket (due to hash
collisions), equals() is used to check if "Apple" is unique.
(b) Deletion
1. Hashing the Element:
o The hashCode() of the element is computed to locate
the bucket.
2. Locating the Element:
o Inside the bucket, the element is searched using the
equals() method.
3. Removing the Element:
o If the element is found, it is removed from the bucket.
Example:
java
CopyEdit
set.remove("Apple");
hashCode() is called to find the bucket.
"Apple" is searched in the bucket using equals().
If found, it is removed.
(c) Searching
1. Hashing the Element:
o The hashCode() of the element is computed to locate
the bucket.
2. Searching in the Bucket:
o Within the bucket, the equals() method is used to find
the element.
Example:
java
CopyEdit
if (set.contains("Apple")) {
System.out.println("Found Apple!");
}
hashCode() is called to find the bucket.
The bucket is searched for "Apple" using equals().
4. Collision Handling
Collisions occur when two different elements produce the same
hash value and are placed in the same bucket. HashSet resolves
this using separate chaining (a linked list in each bucket).
Example:
java
CopyEdit
set.add("Cat");
set.add("Act"); // Assume these have the same hash value.
Both "Cat" and "Act" are placed in the same bucket.
When adding "Act", equals() is used to ensure "Act" is
unique.
The bucket stores both "Cat" and "Act" as a linked list.
5. Why is it Fast?
1. Direct Access: The hash table uses the hash value to directly
compute the bucket index, so the search space is minimized.
2. Efficient Collision Handling: Even in cases of collisions, only
elements in the same bucket are compared using equals().
3. O(1) Average Complexity:
o Insertion: Calculate hash + store in a bucket.
o Deletion: Calculate hash + find in a bucket + remove.
o Searching: Calculate hash + check in a bucket.
6. Practical Example: Visualizing the Process
java
CopyEdit
import java.util.HashSet;
public class HashSetDemo {
public static void main(String[] args) {
HashSet<String> set = new HashSet<>();
// Adding elements
set.add("Apple");
set.add("Banana");
set.add("Cherry");
// Checking if elements exist
System.out.println(set.contains("Apple")); // true
System.out.println(set.contains("Grape")); // false
// Removing an element
set.remove("Banana");
System.out.println(set); // [Apple, Cherry]
}
}
Key Takeaways
1. Hashing is the Core: HashSet relies on hashCode() to
determine the bucket and equals() to ensure uniqueness.
2. Fast Operations: HashSet provides O(1) average time
complexity for insertion, deletion, and search due to direct
bucket access.
3. Collision Resolution: Even when collisions occur, the equals()
method ensures correctness by comparing only the elements
in the same bucket.
Let me know if you'd like to dive deeper into hash table internals
or related concepts! 😊
4o
You said:
methods in hashset
ChatGPT said:
ChatGPT
Common Methods in HashSet
The HashSet class in Java provides a variety of methods to perform
operations like adding, removing, searching, iterating, and
checking properties of the set. Here’s a detailed overview of the
key methods:
1. Adding Elements
add(E e)
Adds the specified element to the HashSet if it is not already
present.
Returns true if the element was added, false if it was already
present.
Example:
java
CopyEdit
HashSet<String> set = new HashSet<>();
set.add("Apple");
set.add("Banana");
System.out.println(set); // Output: [Apple, Banana]
addAll(Collection<? extends E> c)
Adds all the elements from the specified collection to the
set.
Example:
java
CopyEdit
HashSet<String> set = new HashSet<>();
ArrayList<String> list = new ArrayList<>(List.of("Apple", "Banana",
"Cherry"));
set.addAll(list);
System.out.println(set); // Output: [Apple, Banana, Cherry]
2. Removing Elements
remove(Object o)
Removes the specified element from the set if it exists.
Returns true if the element was removed, false if it was not
found.
Example:
java
CopyEdit
HashSet<String> set = new HashSet<>(Set.of("Apple", "Banana"));
set.remove("Banana");
System.out.println(set); // Output: [Apple]
removeAll(Collection<?> c)
Removes all elements that exist in the specified collection
from the set.
Example:
java
CopyEdit
HashSet<String> set = new HashSet<>(Set.of("Apple", "Banana",
"Cherry"));
ArrayList<String> list = new ArrayList<>(List.of("Banana",
"Cherry"));
set.removeAll(list);
System.out.println(set); // Output: [Apple]
clear()
Removes all elements from the set.
Example:
java
CopyEdit
HashSet<String> set = new HashSet<>(Set.of("Apple", "Banana"));
set.clear();
System.out.println(set); // Output: []
3. Checking for Elements
contains(Object o)
Returns true if the set contains the specified element, false
otherwise.
Example:
java
CopyEdit
HashSet<String> set = new HashSet<>(Set.of("Apple", "Banana"));
System.out.println(set.contains("Apple")); // Output: true
System.out.println(set.contains("Cherry")); // Output: false
containsAll(Collection<?> c)
Returns true if the set contains all elements in the specified
collection.
Example:
java
CopyEdit
HashSet<String> set = new HashSet<>(Set.of("Apple", "Banana",
"Cherry"));
ArrayList<String> list = new ArrayList<>(List.of("Apple", "Cherry"));
System.out.println(set.containsAll(list)); // Output: true
4. Iterating Through the HashSet
iterator()
Returns an iterator over the elements in the set.
Example:
java
CopyEdit
HashSet<String> set = new HashSet<>(Set.of("Apple", "Banana",
"Cherry"));
Iterator<String> iterator = set.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
// Output:
// Apple
// Banana
// Cherry
Enhanced for loop
Simplifies iteration without explicitly using the iterator.
Example:
java
CopyEdit
for (String item : set) {
System.out.println(item);
}
5. Size and Properties
size()
Returns the number of elements in the set.
Example:
java
CopyEdit
HashSet<String> set = new HashSet<>(Set.of("Apple", "Banana"));
System.out.println(set.size()); // Output: 2
isEmpty()
Returns true if the set contains no elements, false otherwise.
Example:
java
CopyEdit
HashSet<String> set = new HashSet<>();
System.out.println(set.isEmpty()); // Output: true
6. Retaining Elements
retainAll(Collection<?> c)
Retains only the elements in the set that are contained in the
specified collection (intersection).
Example:
java
CopyEdit
HashSet<String> set = new HashSet<>(Set.of("Apple", "Banana",
"Cherry"));
ArrayList<String> list = new ArrayList<>(List.of("Banana", "Cherry",
"Date"));
set.retainAll(list);
System.out.println(set); // Output: [Banana, Cherry]
7. Converting to an Array
toArray()
Converts the elements in the set into an array.
Example:
java
CopyEdit
HashSet<String> set = new HashSet<>(Set.of("Apple", "Banana"));
Object[] array = set.toArray();
System.out.println(Arrays.toString(array)); // Output: [Apple,
Banana]
toArray(T[] a)
Converts the elements to an array of a specific type.
Example:
java
CopyEdit
HashSet<String> set = new HashSet<>(Set.of("Apple", "Banana"));
String[] array = set.toArray(new String[0]);
System.out.println(Arrays.toString(array)); // Output: [Apple,
Banana]
8. Cloning
clone()
Creates a shallow copy of the HashSet.
Example:
java
CopyEdit
HashSet<String> set = new HashSet<>(Set.of("Apple", "Banana"));
HashSet<String> cloneSet = (HashSet<String>) set.clone();
System.out.println(cloneSet); // Output: [Apple, Banana]
Summary of Methods
Method Description
Adds the specified element if it is not
add(E e)
already present.
Adds all elements from the specified
addAll(Collection<?>)
collection.
Removes the specified element from
remove(Object o)
the set.
Removes all elements in the
removeAll(Collection<?>)
specified collection.
clear() Removes all elements from the set.
Checks if the set contains the
contains(Object o)
specified element.
Checks if the set contains all
containsAll(Collection<?>)
elements in the collection.
Returns an iterator for the elements
iterator()
in the set.
size() Returns the number of elements in
Method Description
the set.
isEmpty() Checks if the set is empty.
Retains only elements that are also
retainAll(Collection<?>)
in the specified collection.
toArray() Converts the set into an array.
clone() Creates a shallow copy of the set.
Would you like examples or explanations for any specific method?
😊
4o
You said:
// Online Java Compiler // Use this editor to write, compile and
run your Java code online import java.util.*; class
hashset{ HashSet<Integer> s1=new HashSet<Integer>();
s1.add(10); s1.add(20); s1.add(30); s1.add(40);
System.out.println(s1); ArrayList<Integer> l1=new
ArrayList<>(List.of(20,60,70)); s1.addAll(l1); System.out.println(s1);
ArrayList<Integer> l2=new ArrayList<>(List.of(50,60,10));
s1.removeAll(l2); System.out.println(s1); } class Main { public static
void main(String[] args) { System.out.println("Try programiz.pro");
hashset h1=new hashset(); } }
ChatGPT said:
ChatGPT
Your code has several issues that will result in compilation errors.
Here are the problems:
1. Incorrect Class Name:
o The class name hashset should start with an uppercase
letter (Java naming conventions). It should be Hashset
or HashSetDemo to follow proper conventions.
2. Instance Variable Usage:
o The code HashSet<Integer> s1 = new
HashSet<Integer>(); is declared inside the hashset class
but is not inside a method or constructor. This is not
allowed. Statements like s1.add(10) cannot be
executed directly in the class body.
3. Incorrect Method Calls:
o Statements like s1.add(10); and System.out.println(s1);
must be placed inside a method, constructor, or static
block.
4. Constructor Issue:
o In your current code, the hashset class is treated as a
regular class but does not define any methods or
constructors to perform operations.
Corrected Code
Below is the corrected and working version of your program:
java
CopyEdit
import java.util.*;
class HashSetDemo {
HashSet<Integer> s1;
// Constructor to initialize and perform operations
public HashSetDemo() {
// Initialize the HashSet
s1 = new HashSet<Integer>();
// Add elements to the HashSet
s1.add(10);
s1.add(20);
s1.add(30);
s1.add(40);
System.out.println("After adding elements: " + s1);
// Add all elements from an ArrayList to the HashSet
ArrayList<Integer> l1 = new ArrayList<>(List.of(20, 60, 70));
s1.addAll(l1);
System.out.println("After adding elements from ArrayList: " +
s1);
// Remove all elements present in another ArrayList
ArrayList<Integer> l2 = new ArrayList<>(List.of(50, 60, 10));
s1.removeAll(l2);
System.out.println("After removing elements present in
ArrayList: " + s1);
}
}
public class Main {
public static void main(String[] args) {
// Instantiate the HashSetDemo class
HashSetDemo h1 = new HashSetDemo();
}
}
Output
less
CopyEdit
After adding elements: [40, 10, 20, 30]
After adding elements from ArrayList: [70, 40, 10, 20, 60, 30]
After removing elements present in ArrayList: [70, 40, 20, 30]
Explanation
1. Initialization of the HashSet:
o A HashSet<Integer> is created to store unique integers.
2. Adding Elements:
o Elements 10, 20, 30, and 40 are added to the HashSet.
Duplicate values (if any) are ignored.
3. Adding from an ArrayList:
o The addAll() method is used to add elements from l1
(an ArrayList) to the HashSet. Duplicate elements (like
20) are ignored.
4. Removing Elements:
o The removeAll() method is used to remove elements
from the HashSet that exist in another collection (l2).
Let me know if you'd like further clarifications or additional
examples! 😊
13.
14.
15.
16. Overriding in java:
// Online Java Compiler
// Use this editor to write, compile and run your Java code
online
class A{
public void ip(){
System.out.println("i am in class A");
}
}
class B extends A{
public void ip(){
System.out.println("i am in class B");
}
}
class Main {
public static void main(String[] args) {
System.out.println("Try programiz.pro");
A a1=new A();
a1.ip();
B b1=new B();
b1.ip();
A ab=new B();
ab.ip();
}
}
17. Who takes care of method resolution in overriding
and overloading?
1. Method Overriding:
In the case of method overriding, the responsibility for
determining which method to call is handled at runtime. The
runtime system looks at the type of the object and determines
which version of the method to invoke based on the object's
class.
Who handles it? The runtime environment (such as the Java
Virtual Machine (JVM) or Python interpreter) handles
method resolution in overriding.
Example: If you have a base class Animal with a method
speak() and a derived class Dog that overrides speak(), the
method from the Dog class will be called when the object is
of type Dog, even if it's referenced by a variable of type
Animal.
python
Copy
class Animal:
def speak(self):
print("Animal speaks")
class Dog(Animal):
def speak(self):
print("Dog barks")
a = Dog()
a.speak() # Output: Dog barks
2. Method Overloading:
In the case of method overloading (same method name but
different parameters), the resolution happens at compile-time
(for languages like Java or C++). The compiler looks at the
method signature (the number and types of parameters) to
determine which version of the method to call.
Who handles it? The compiler resolves the method overload
based on the method signature.
Example (Java): If you have multiple methods with the same
name but different parameter types, the Java compiler
selects the correct version based on the arguments passed at
the call site.
java
Copy
class Example {
public void display(int a) {
System.out.println("Integer: " + a);
}
public void display(String s) {
System.out.println("String: " + s);
}
}
public class Main {
public static void main(String[] args) {
Example obj = new Example();
obj.display(5); // Output: Integer: 5
obj.display("Hello"); // Output: String: Hello
}
}
In summary:
Overriding is resolved at runtime by the runtime system
(based on the object's actual type).
Overloading is resolved at compile-time by the compiler
(based on the method signature).
18. If i write A b=new B() where B is class which
extends A so it is right but what can be the purpose of
giving reference of class A?
When you write A b = new B();, where B is a subclass of A, the
purpose of using the reference of class A for an object of class B
is to take advantage of polymorphism in object-oriented
programming (OOP). This practice allows you to:
1. Promote Generalization:
By referencing the object with the superclass (A), you allow
your code to operate at a more general level, making it easier
to handle a variety of subclass objects in a uniform way. This is
especially useful when you have many classes in a hierarchy and
want to treat all of them as instances of the superclass.
Example: If you have multiple subclasses of A, you can use the
reference of type A to interact with all these subclasses in a
consistent way.
java
Copy
class A {
void display() {
System.out.println("Class A");
}
}
class B extends A {
void display() {
System.out.println("Class B");
}
}
class C extends A {
void display() {
System.out.println("Class C");
}
}
public class Test {
public static void main(String[] args) {
A obj1 = new B();
A obj2 = new C();
obj1.display(); // Output: Class B
obj2.display(); // Output: Class C
}
}
In this example, you can see that both B and C are treated as
objects of type A, but the actual method that gets called is
determined by the actual object (B or C), thanks to
polymorphism.
2. Achieve Flexibility and Extensibility:
By using the superclass reference (A), your code becomes more
flexible and easier to extend. You can add new subclasses to the
hierarchy without changing the code that uses the superclass
reference.
For example, let's say you have a method that accepts A as a
parameter:
java
Copy
public void printInfo(A a) {
a.display();
}
You can pass any subclass of A (like B, C, etc.) to this method,
and it will call the correct method based on the object's actual
type.
3. Facilitate Polymorphic Behavior:
This type of reference allows polymorphic behavior where the
method that gets called depends on the runtime object, not the
type of the reference. This is key in many OOP designs,
especially in frameworks and libraries that need to work with a
variety of objects that share a common superclass.
4. Implement Abstraction and Design Patterns:
Often, the use of a superclass reference is part of a design
pattern (e.g., Factory Pattern, Strategy Pattern, etc.). You might
have different concrete implementations of a class (B, C, etc.),
but the client code can interact with the common superclass
(A), simplifying the interface and promoting loose coupling
between components.
Summary:
Using A b = new B(); allows you to:
Benefit from polymorphism, where the actual method called
is determined at runtime.
Write more flexible, extensible, and maintainable code.
Use a common interface for different classes, promoting
abstraction.
19. Super() Keyword in Overriding.
In object-oriented programming, super() is used to call the
constructor of the superclass (parent class) from the subclass
(child class). It is primarily used in the following contexts:
1. Calling the Superclass Constructor:
When a subclass constructor is invoked, it can call a constructor
from the superclass using super(). This is particularly useful
when the superclass has constructors that need to be initialized
before the subclass can perform its own initialization.
If a constructor in the subclass does not explicitly call
super(), the default constructor of the superclass is called
automatically.
If the superclass does not have a no-argument constructor
and the subclass constructor doesn’t explicitly call another
constructor of the superclass using super(), the code will
result in a compilation error.
2. Calling Superclass Methods:
You can also use super to call methods from the superclass
when they are overridden in the subclass. This can be useful
when you want to extend or modify the behavior of the
superclass method while still invoking it.
Examples:
1. Calling the Superclass Constructor with super():
java
Copy
class Animal {
Animal(String name) {
System.out.println("Animal's name is " + name);
}
}
class Dog extends Animal {
Dog(String name) {
// Calling the superclass constructor to initialize the 'name'
field
super(name);
System.out.println("Dog's name is also " + name);
}
}
public class Main {
public static void main(String[] args) {
Dog d = new Dog("Buddy");
}
}
Output:
vbnet
Copy
Animal's name is Buddy
Dog's name is also Buddy
Here, the subclass Dog calls the constructor of the superclass
Animal with super(name) to initialize the name field of the
parent class before doing its own initialization.
2. Calling Superclass Methods with super:
java
Copy
class Animal {
void speak() {
System.out.println("Animal speaks");
}
}
class Dog extends Animal {
@Override
void speak() {
super.speak(); // Calling the superclass method
System.out.println("Dog barks");
}
}
public class Main {
public static void main(String[] args) {
Dog d = new Dog();
d.speak();
}
}
Output:
Copy
Animal speaks
Dog barks
In this example, super.speak() calls the speak() method from the
Animal class (the superclass), and then the subclass (Dog)
extends that behavior by adding its own print statement.
3.invisible super():
class A{
public A(){
System.out.println("in A");
}
}
class B extends A{
public B(){
System.out.println("in B");
}
}
class Main {
public static void main(String[] args) {
System.out.println("Try programiz.pro");
B b1=new B();
}
}
Output:
Try programiz.pro
in A
in B
//Here the object of B class is created still we get output as 'in
A' first then 'in B',so this is bcoz every constructor has super() in
it by default even if its not in code still(invisible super().
Important Points:
super() must be the first statement in the constructor: If
you use super() to call a superclass constructor, it must
appear as the first statement in the constructor.
No-Argument Constructor: If the superclass has a no-
argument constructor, it is called implicitly by default when
the subclass constructor is invoked, but you can override it
with an explicit super() call if needed.
Super Method Usage: super can be used to access both
methods and fields from the superclass. However, it's
common to use super when you need to access a method
that has been overridden in the subclass but still want to
invoke the version of the method in the superclass.
Constructor Chaining: You can chain multiple constructors by
calling super() in each constructor to pass control up the
inheritance chain. If no constructor in the subclass explicitly
calls super(), the default constructor of the superclass is
called (if it exists).
Summary:
super() in Java (and other object-oriented languages) is used to:
1. Call a constructor of the superclass.
2. Invoke methods of the superclass, especially when they are
overridden. It plays a key role in constructor chaining and
allows subclasses to build on or extend the behavior of their
parent classes.
20. different ways to use super keyword
1. Accessing Parent Class Constructors
The super keyword can be used to call a constructor of the
parent class from a child class. It must be the first statement in
the constructor of the child class.
java
CopyEdit
class Parent {
Parent(String message) {
System.out.println("Parent constructor: " + message);
}
}
class Child extends Parent {
Child(String message) {
super(message); // Calls the Parent constructor
System.out.println("Child constructor: " + message);
}
}
public class Main {
public static void main(String[] args) {
Child child = new Child("Hello!");
}
}
2. Accessing Parent Class Methods
The super keyword is used to call a method of the parent class
that has been overridden in the child class.
java
CopyEdit
class Parent {
void display() {
System.out.println("Display method in Parent");
}
}
class Child extends Parent {
@Override
void display() {
System.out.println("Display method in Child");
}
void show() {
super.display(); // Calls the Parent class display method
System.out.println("Show method in Child");
}
}
public class Main {
public static void main(String[] args) {
Child child = new Child();
child.show();
}
}
3. Accessing Parent Class Variables
When a child class has a variable with the same name as a
variable in the parent class, the super keyword can be used to
access the parent class's variable.
java
CopyEdit
class Parent {
String name = "Parent";
}
class Child extends Parent {
String name = "Child";
void printNames() {
System.out.println("Child name: " + name);
System.out.println("Parent name: " + super.name); //
Accesses Parent class variable
}
}
public class Main {
public static void main(String[] args) {
Child child = new Child();
child.printNames();
}
}
4. Calling Parent Class Static Context (Special Case)
While super itself cannot directly access static members of the
parent class (since they belong to the class rather than an
instance), a child class can reference them using the parent
class name:
java
CopyEdit
class Parent {
static String staticVar = "Static variable in Parent";
static void staticMethod() {
System.out.println("Static method in Parent");
}
}
class Child extends Parent {
void accessStaticMembers() {
System.out.println(Parent.staticVar); // Access Parent's
static variable
Parent.staticMethod(); // Access Parent's static method
}
}
public class Main {
public static void main(String[] args) {
Child child = new Child();
child.accessStaticMembers();
}
}
5. Using super in Method Overloading
The super keyword can also be useful when overloading
methods, especially when one method in the child class needs
to invoke the corresponding method in the parent class.
java
CopyEdit
class Parent {
void greet(String name) {
System.out.println("Hello from Parent, " + name);
}
}
class Child extends Parent {
void greet(String name) {
super.greet(name); // Calls the Parent's greet method
System.out.println("Hello from Child, " + name);
}
}
public class Main {
public static void main(String[] args) {
Child child = new Child();
child.greet("Alice");
}
}
Key Notes:
1. Placement: When using super in a constructor, it must be
the first line of the constructor.
2. Chaining: You cannot call multiple parent constructors
explicitly (e.g., super() and this()) in the same constructor.
3. Restrictions: super cannot be used in static methods
because it operates on instances, not the class itself.
21. Key Points of Encapsulation in the Code
class Person {
// Private variables (data hiding)
private String name;
private int age;
// Public getter for 'name'
public String getName() {
return name;
}
// Public setter for 'name'
public void setName(String name) {
// Adding validation before setting the value
if (name != null && !name.isEmpty()) {
this.name = name;
} else {
System.out.println("Invalid name.");
}
}
// Public getter for 'age'
public int getAge() {
return age;
}
// Public setter for 'age'
public void setAge(int age) {
// Adding validation before setting the value
if (age > 0 && age <= 120) {
this.age = age;
} else {
System.out.println("Invalid age. Age must be between 1
and 120.");
}
}
}
public class Main {
public static void main(String[] args) {
// Create a Person object
Person person = new Person();
// Set values using setter methods
person.setName("Alice");
person.setAge(30);
// Get values using getter methods
System.out.println("Name: " + person.getName());
System.out.println("Age: " + person.getAge());
// Attempt to set invalid values
person.setName(""); // Invalid name
person.setAge(-5); // Invalid age
}
}
Data Hiding:
a. The name and age variables are declared private, so they cannot be
accessed directly from outside the Person class.
Controlled Access:
b. The getName, setName, getAge, and setAge methods are public,
providing controlled access to the name and age variables.
Validation Logic:
c. The setter methods include validation logic to ensure only valid
data is set to the variables. This helps maintain the integrity of the
object state.
Reusability:
d. By encapsulating the variables and methods, the Person class can
be reused in different parts of the application without worrying
about unintended changes to its state.
22. How Methods Provide Controlled Access
1. Validation Logic:
o The setName method checks if the name is not null or
empty before setting it. If the condition is not met, an
error message is displayed.
o The setAge method ensures that the age is a positive
value and within a valid range (1 to 120). Invalid inputs
are rejected with a message.
Without these checks, invalid data could corrupt the object's
state.
2. Encapsulation:
o By hiding the variables (private), the internal details of
the class are not exposed to the outside world. Only
the public methods provide a way to interact with the
variables.
o This ensures that all changes to the variables go
through the validation logic implemented in the setter
methods.
What Happens if Variables are Declared public?
If the name and age variables are declared public, they can be
accessed and modified directly without any restrictions or
validation. Here's how it would look and the consequences:
Modified Class with public Variables:
java
CopyEdit
class Person {
// Public variables (no data hiding)
public String name;
public int age;
}
public class Main {
public static void main(String[] args) {
// Create a Person object
Person person = new Person();
// Directly access and modify variables
person.name = "Alice";
person.age = 30;
// No validation for invalid data
person.name = ""; // Invalid, but allowed
person.age = -5; // Invalid, but allowed
// Print values
System.out.println("Name: " + person.name); // Outputs:
""
System.out.println("Age: " + person.age); // Outputs: -5
}
}
Consequences of Public Variables:
1. No Validation:
o Invalid data such as an empty name or negative age can
be directly assigned. This can lead to corrupted data in
the object.
2. Lack of Control:
o Anyone with access to the Person object can modify its
variables without any checks. This can result in
unpredictable behavior, especially in larger or
collaborative projects.
3. Breaking Encapsulation:
o Declaring variables as public exposes the internal
implementation of the class, violating the principle of
encapsulation. Future changes to the internal structure
(e.g., switching name to a List of strings) might break
code that directly accesses the variables.
4. Tight Coupling:
o Public variables tightly couple the implementation
details of the Person class to other parts of the code,
making it harder to maintain or refactor the class.
Why Controlled Access is Better?
Controlled access through getter and setter methods:
Ensures Data Integrity: Validates inputs before modifying the
variables.
Improves Maintainability: Future changes to validation logic
or variable implementation are contained within the class,
without affecting external code.
Hides Implementation Details: The outside world does not
need to know how the class manages its data internally.
Example: Why Controlled Access Matters
If you want to add a new feature (e.g., logging every time the
name is updated), you can modify the setName method:
java
CopyEdit
public void setName(String name) {
if (name != null && !name.isEmpty()) {
this.name = name;
System.out.println("Name updated to: " + name); // Added
logging
} else {
System.out.println("Invalid name.");
}
}
With controlled access, this change will not break any external
code. However, if the name variable were public, such logic
would have to be implemented elsewhere, making the code
harder to maintain and prone to errors.
Conclusion: Declaring variables as private and providing
controlled access via getter and setter methods ensures data
integrity, enforces encapsulation, and makes your code more
robust and maintainable.
23. if we declare any method static can we override it
No, you cannot override a static method in Java because static
methods are associated with the class rather than an instance
of the class. Method overriding is based on dynamic (runtime)
binding, but static methods are resolved during compile-time
(using static binding).
When you declare a static method in a subclass with the same
signature as a static method in the parent class, it is known as
method hiding, not overriding.
Example: Static Methods and Method Hiding
java
CopyEdit
class Parent {
static void display() {
System.out.println("Static method in Parent");
}
}
class Child extends Parent {
static void display() {
System.out.println("Static method in Child");
}
}
public class Main {
public static void main(String[] args) {
Parent obj1 = new Parent();
obj1.display(); // Output: Static method in Parent
Child obj2 = new Child();
obj2.display(); // Output: Static method in Child
Parent obj3 = new Child(); // Reference of Parent, instance
of Child
obj3.display(); // Output: Static method in Parent (static
binding)
}
}
Key Points to Understand:
1. Static Methods are Class-Level:
o They belong to the class and are not tied to an
instance.
o When you call a static method using an object
reference, the compiler resolves it based on the
reference type, not the actual object type.
2. Method Hiding vs Overriding:
o In method overriding, the child class provides a new
implementation for a non-static method of the parent
class, and the method to be invoked is determined by
the runtime type of the object.
o In method hiding, if a subclass declares a static method
with the same signature as a static method in the
parent class, the subclass method hides the parent
class method. The method invoked is determined by
the reference type (compile-time).
Difference Between Overriding and Hiding
Aspect Overriding Method Hiding
Applies to Instance methods Static methods
Dynamic (runtime) Static (compile-
Binding
binding time) binding
Based on Actual object type Reference type
Achieved (runtime
Polymorphism Not achieved
polymorphism)
When to Use Static Methods:
If a method is not dependent on the state (fields) of an
object, it should be declared static.
For utility methods, like Math.sqrt(), Collections.sort(), etc.
If you need polymorphic behavior, use non-static methods
instead of static ones. Let me know if you'd like more details or
examples!
24.
25.
26.
27. OOPs Concept in Java: (For simple definition visit
“https://www.javatpoint.com/java-oops-concepts”)
1. Class and Objects:
Q. do class consume memory?
Yes, classes in programming languages like
Python, Java, C++, etc., do consume memory, but
the way they consume memory depends on how
they're used.
1. Class Definition (Blueprint)
A class itself (the definition or blueprint)
consumes a small amount of memory. This includes
the memory required to store:
o The class metadata (e.g., its name, methods,
attributes).
o Any static methods or class variables declared in
the class.
o Its relationship with parent classes if inheritance
is used.
2. Class Instances (Objects)
When you create an instance (object) of a class,
memory is allocated for:
o The instance's attributes (both defined
explicitly and added dynamically).
o A reference to the class definition.
Each object consumes additional memory
beyond the class definition. The amount
depends on:
o The number and type of instance
attributes.
o Whether the instance has dynamically
added attributes.
3. Static and Class Variables
Static or class variables (declared at the class
level) consume memory at the class level, not
individually for each object. All instances share
these variables, so they don't duplicate
memory.
4. Garbage Collection (in Languages like Python)
Memory for classes and objects is reclaimed
when they go out of scope or no longer have
references pointing to them, provided the
garbage collector (GC) is running.
Q. when does the class consumen memory while
creating the class or while creating the object?
A class consumes memory both when the class is
defined and when objects (instances) of the class are
created, but the type and amount of memory
consumed differ at each stage:
1. When the Class is Defined
Memory is consumed when you define a class
because the interpreter needs to store:
o The class name.
o Methods (function definitions) and their code.
o Static variables or class-level attributes.
o Metadata like the class's __dict__ (to store
attributes and methods).
o Relationships with parent classes (if inheritance
is used).
This memory consumption happens only once,
regardless of how many objects you create later.
This is often small compared to memory
consumed by instances.
Example:
python
CopyEdit
class MyClass:
static_var = 42 # Class-level variable
def method(self):
pass
The memory required to store static_var and the
method definition is allocated when MyClass is
defined.
2. When Objects (Instances) are Created
When you create an instance of a class, memory is
allocated for:
o The instance itself.
o Its instance attributes (both explicitly defined
and dynamically added).
o A reference back to the class definition (so the
instance can access class-level methods and
variables).
Each object is separate and consumes memory
independently for its attributes. If you create
multiple objects, each consumes additional
memory.
Example:
python
CopyEdit
obj1 = MyClass()
obj1.dynamic_attr = "Hello" # Consumes
memory in obj1 only
obj2 = MyClass()
obj1 and obj2 each consume memory for their
instance-level data.
Summary:
What
Stage consumes Scope
memory?
Class name,
methods, One-
Class static/class- time
Definition level per
variables, class.
metadata.
Instance
attributes
Object and Per
Creation references object.
to the
class.
If you only define the class and don't create any objects,
the memory usage remains limited to the class
definition itself. However, creating objects will multiply
memory usage based on the number of objects and the
size of their attributes.
2. Inheritance:
1. Single Inheritance
class Parent{
int salary=95000;
Parent(int salary){
System.out.println("Salary Passed through
child Constructor to parent Constructor: "+salary
);
}
}
class Child extends Parent{
int bonus=45000;
Child(){
super(99000);
}
public void display(){
System.out.println("bonus : "+bonus);
System.out.println("Salary of Parent class:
"+salary);//inheritance variable from parent class
}
}
class Main {
public static void main(String[] args) {
System.out.println("Try programiz.pro");
Child c=new Child();
c.display();
}
}
2. Multi-level Inheritance:
class Animal{
void eat(){System.out.println("eating...");}
}
class Dog extends Animal{
void bark(){System.out.println("barking...");}
}
class BabyDog extends Dog{
void weep(){System.out.println("weeping...");}
}
class TestInheritance2{
public static void main(String args[]){
BabyDog d=new BabyDog();
d.weep();
d.bark();
d.eat();
}}
3. Hierarchical Inheritance:
class Company{
int bonus=15000;
Company(int salary,String jobType){
System.out.println(jobType);
System.out.println("Salary : "+salary);
}
}
class emp1 extends Company{
emp1(){
super(99000,"full time employee");
}
public void display(){
System.out.println("bonus : "+super.bonus);
System.out.println();
}
}
class emp2 extends Company{
emp2(){
super(30000,"part time employee");
}
public void display(){
System.out.println("bonus : "+super.bonus);
System.out.println();
}
}
class Main {
public static void main(String[] args) {
emp1 c=new emp1();
c.display();
emp2 e=new emp2();
e.display();
}
}
4. Multiple Inheritance using Interface:
interface A {
void msg1();
}
interface B {
void msg2();
}
class Main implements A, B {
public void msg1()
{ System.out.println("Hello"); }
public void msg2()
{ System.out.println("Welcome"); }
public static void main(String args[]) {
Main obj = new Main();
obj.msg1();
obj.msg2();
}
}
Q. Why Multiple inheritance not possible using
class?
1. Ambiguity Problem (Diamond Problem):
o If a class could inherit from multiple
classes, and those parent classes had
methods with the same name, it would
create ambiguity about which method
should be invoked in the child class.
o For example:
java
CopyEdit
class A {
void msg()
{ System.out.println("Hello from A");
}
}
class B {
void msg()
{ System.out.println("Hello from B");
}
}
class C extends A, B {
public static void main(String
args[]) {
C obj = new C();
obj.msg(); // Ambiguity: Should
it call A's msg() or B's msg()?
}
}
The compiler cannot decide whether
to call A.msg() or B.msg().
2. Java's Design Decision:
o To simplify the language and avoid the
ambiguity caused by the diamond
problem, Java does not allow a class to
extend more than one class.
o Instead, Java allows multiple inheritance
using interfaces, which eliminates the
ambiguity since interfaces only define
method signatures, not their
implementation.
Q. "is-a" Relationship in inheritance?
The "is-a" relationship is a
core concept in inheritance in object-oriented
programming. It describes a relationship between
a child class (subclass) and a parent class
(superclass) where the child class inherits from
the parent class and can be considered as a
specialized version of it.
What Does "Is-A" Mean?
The "is-a" relationship means that the
subclass can be treated as an instance of the
parent class because it inherits all the
properties and behaviors of the parent.
The child class "is a" type of the parent
class.
For example:
A Dog is-a Animal.
A Car is-a Vehicle.
Aggregation in Java
If a class have an entity reference, it is known as
Aggregation. Aggregation represents HAS-A
relationship.
Consider a situation, Employee object contains
many informations such as id, name, emailId etc.
It contains one more object named address,
which contains its own informations such as city,
state, country, zipcode etc. as given below.
class Employee{
int id;
String name;
Address address;//Address is a class
1. ...
}
Example code:
class Operation{
int square(int n){
return n*n;
}
}
class Circle{
Operation op;//aggregation
double pi=3.14;
double area(int radius){
op=new Operation();
int rsquare=op.square(radius);//code reusabil
ity (i.e. delegates the method call).
return pi*rsquare;
}
public static void main(String args[]){
Circle c=new Circle();
double result=c.area(5);
System.out.println(result);
}
}
3. Polymorphism:
1. Compile time polymorphism:
Q. Why is it called Compile-Time Polymorphism?
Method Resolution at Compile Time:
o When you call an overloaded method, the
Java compiler determines which version of
the method to invoke by examining the
method signature at compile time.
o The decision is made before the program
runs, which is why it is called compile-time
polymorphism.
No Runtime Decision:
o Unlike runtime polymorphism (method
overriding), no decisions are made at
runtime. The compiler ensures the correct
method is called based on the method's
parameters.
Example of Method Overloading
java
CopyEdit
class Calculator {
// Method to add two integers
int add(int a, int b) {
return a + b;
}
// Overloaded method to add three
integers
int add(int a, int b, int c) {
return a + b + c;
}
// Overloaded method to add two doubles
double add(double a, double b) {
return a + b;
}
}
public class Main {
public static void main(String[] args) {
Calculator calc = new Calculator();
System.out.println(calc.add(2,
3)); // Calls add(int, int)
System.out.println(calc.add(2, 3,
4)); // Calls add(int, int, int)
System.out.println(calc.add(2.5, 3.5));
// Calls add(double, double)
}
}
Output
CopyEdit
5
9
6.0
How It Works
The compiler determines which version of the
add method to invoke by examining the number
and type of arguments:
o calc.add(2, 3) calls add(int, int).
o calc.add(2, 3, 4) calls add(int, int, int).
o calc.add(2.5, 3.5) calls add(double, double).
This resolution happens at compile time, which is
why it is called compile-time polymorphism.
2. Runtime Polymorphism:
Q. Why overriding is called runtime polymorphism?
1. Dynamic Method Dispatch:
o When a method is overridden in a subclass,
the JVM determines which version of the
method to invoke (parent or child) based on
the object type at runtime, even if the
reference type is the superclass.
o This decision is made dynamically, hence
the term runtime polymorphism.
2. Late Binding:
o Overriding involves late binding, where the
method to be executed is resolved during
runtime, not at compile time.
o This is opposite to early binding, which
happens in method overloading (compile-
time polymorphism).
Example of Runtime Polymorphism
java
CopyEdit
class Animal {
void sound() {
System.out.println("Animal makes a
sound");
}
}
class Dog extends Animal {
@Override
void sound() {
System.out.println("Dog barks");
}
}
class Cat extends Animal {
@Override
void sound() {
System.out.println("Cat meows");
}
}
public class Main {
public static void main(String[] args) {
Animal myAnimal;
myAnimal = new Dog(); // Animal
reference, Dog object
myAnimal.sound(); // Calls Dog's
sound() at runtime
myAnimal = new Cat(); // Animal
reference, Cat object
myAnimal.sound(); // Calls Cat's
sound() at runtime
}
}
Output
CopyEdit
Dog barks
Cat meows
How It Works
1. Inheritance and Overriding:
o The sound() method is defined in the parent
class Animal and overridden in the child
classes Dog and Cat.
2. Reference Type vs. Object Type:
o The reference type of myAnimal is Animal.
o The object type of myAnimal is dynamically
set to Dog and Cat during runtime.
3. JVM Decision:
o At runtime, the JVM looks at the object type
(Dog or Cat) and invokes the corresponding
method.
Compile-Time vs. Runtime Behavior
Compile-
Runtime
Time
Polymor
Polymor
Aspect phism
phism
(Overridi
(Overloa
ng)
ding)
Binding
Binding
happens
Binding happens
at
Time at
compile
runtime.
time.
Based on
Based on
method
Method the
signature
Resoluti runtime
and
on object
paramet
type.
ers.
Requires
Inherita inheritan
nce Not ce and
Require required. method
ment overridin
g.
Flexibili Less More
ty flexible flexible
Compile-
Runtime
Time
Polymor
Polymor
Aspect phism
phism
(Overridi
(Overloa
ng)
ding)
because
because
it's based
it adapts
on
to object
reference
type.
type.
Faster
because
Slightly
the
slower
method
Perform due to
is
ance runtime
resolved
decision-
at
making.
compile
time.
4. Abstraction:
Points to Remember
o An abstract class must be declared with an abstract
keyword.
o It can have abstract and non-abstract methods.
o It cannot be instantiated.
o It can have constructors and static methods also.
o It can have final methods which will force the subclass not
to change the body of the method.
Code:
// Online Java Compiler
// Use this editor to write, compile and run your Java code
online
abstract class bike{
bike(){
System.out.println("Starting...1");
}
abstract void run();
public void say(){
System.out.println("Starting...2");
}
}
class Main extends bike{
void run(){
System.out.println("Running safely");
}
public static void main(String[] args) {
Main m1=new Main();
m1.run();
m1.say();
}
}
Why Does an Interface Provide 100% Abstraction in
Java?
An interface provides 100% abstraction in Java because:
1. It only contains method declarations (before Java 8) – No
implementation, just the method signature.
2. It does not allow instance variables – Only constants
(public static final).
3. A class implementing the interface must provide full
implementation – The actual working of the methods is
hidden in the implementing class.
Example: 100% Abstraction Using Interface
java
CopyEdit
// Interface: Defines only abstract methods (100%
abstraction)
interface Animal {
void makeSound(); // No implementation, just a
method signature
void eat(); // Another abstract method
}
// Concrete class implementing the interface
class Dog implements Animal {
@Override
public void makeSound() {
System.out.println("Dog barks");
}
@Override
public void eat() {
System.out.println("Dog eats bones");
}
}
public class Main {
public static void main(String[] args) {
Animal myDog = new Dog(); // Interface
reference, Dog object
myDog.makeSound(); // Calls Dog's
implementation
myDog.eat(); // Calls Dog's implementation
}
}
Output
CopyEdit
Dog barks
Dog eats bones
How Does This Achieve 100% Abstraction?
✅ Only Essential Features Are Exposed:
The Animal interface provides only method signatures.
It hides the internal details of how these methods are
implemented.
✅ No Implementation in Interface:
Unlike an abstract class, there are no method bodies
inside the interface.
The actual implementation is hidden inside the
implementing class (Dog).
✅ Forces Implementation:
Any class that implements Animal must provide
implementations for all its methods.
This ensures that all concrete classes follow a standard
structure, while keeping the details hidden.
Before Java 8 vs. After Java 8
After Java
Before Java 8
8 (Not
Feature (100%
Always
Abstraction)
100%)
✅ Yes (only
Abstract
method ✅ Yes
Methods
signatures)
✅ Default
❌ No
Concrete & static
implementation
Methods methods
allowed
allowed
✅ Only public
✅ Still the
Variables static final
same
constants
❌ Not
Can it be necessarily
✅ Always 100%
100% (because
abstract
abstract? of default
methods)
Before Java 8, interfaces provided 100% abstraction
because they could not have concrete methods.
After Java 8, interfaces can have default and static
methods (which have implementations), making them not
always 100% abstract.
In interfaces we can not declare variables bcoz interface
does not have heap memory.
Conclusion
An interface provides 100% abstraction because:
✅ It only declares methods (before Java 8).
✅ It hides implementation details.
✅ A class must fully implement all its methods.
✅ It enforces a strict contract between classes
without revealing internal logic.
However, after Java 8, default and static methods
can break 100% abstraction.
Real-World Example of Abstraction
ATM Machine
You interact with the ATM interface – insert your card, enter
the PIN, and withdraw money.
You don’t need to know how the ATM communicates with the
bank servers or processes transactions internally.
Abstraction in ATM Code
java
CopyEdit
// Abstract class defining an ATM
abstract class ATM {
abstract void withdraw(int amount); // Abstract
method
abstract void checkBalance(); // Abstract method
void bankInfo() { // Concrete method
System.out.println("Bank: ABC Bank");
}
}
// Concrete class implementing the ATM functionalities
class MyATM extends ATM {
private int balance = 10000;
@Override
void withdraw(int amount) {
if (amount > balance) {
System.out.println("Insufficient funds!");
} else {
balance -= amount;
System.out.println("Withdrawn: $" + amount);
}
}
@Override
void checkBalance() {
System.out.println("Balance: $" + balance);
}
}
public class Main {
public static void main(String[] args) {
ATM atm = new MyATM();
atm.bankInfo();
atm.withdraw(500);
atm.checkBalance();
}
}
5.
28.
29.
30.
31. Declaration of public static void main(String[] args) is
correct or public static void main(String args[]) is correct?
Both are correct in Java. The difference is just in syntax preference:
1. ✅ public static void main(String[] args) → This is the most
commonly used and recommended way.
2. ✅ public static void main(String args[]) → This is also valid but
follows an older C-style syntax where the brackets [] are placed
after the variable instead of the type.
Both versions compile and run the same way, but the first one
(String[] args) is preferred because it makes it clearer that args is
an array of String.
32. Why we write String[] args in public static void
main(String[] args) what does it do and why is it needed?
Why Do We Write String[] args in public static void main(String[]
args)?
The String[] args in the main method is used to accept command-
line arguments when running a Java program. It allows users to
pass input values to the program from the terminal or command
prompt.
Breakdown of String[] args:
1. String[] → It defines an array of strings, meaning the program
can take multiple command-line arguments.
2. args → This is just a variable name (you can rename it, e.g.,
String[] myArgs).
3. Purpose → It allows passing external data to the program when
it starts.
Why Is It Needed?
1. Entry Point of Java Programs
o The Java Virtual Machine (JVM) looks for the main
method with the exact signature public static void
main(String[] args).
o If this method is not found, your program won't start.
2. Handling User Input from Command Line
o It lets users pass arguments when running a Java program.
Example Usage of String[] args:
Example 1: Printing Command-Line Arguments
java
CopyEdit
public class Main {
public static void main(String[] args) {
System.out.println("Number of arguments: " + args.length);
for (int i = 0; i < args.length; i++) {
System.out.println("Argument " + i + ": " + args[i]);
}
}
}
Running the Program with Arguments
sh
CopyEdit
java Main Hello World 123
Output:
yaml
CopyEdit
Number of arguments: 3
Argument 0: Hello
Argument 1: World
Argument 2: 123
Can We Remove String[] args?
Yes, you can technically write:
java
CopyEdit
public static void main() {
System.out.println("Hello, Java!");
}
However, the JVM won't recognize it as the main method, and
you'll get an error:
Error: Main method not found in class Main, please define the
main method as:
public static void main(String[] args)
This is because Java strictly requires the main method with String[]
args as its parameter.
Summary:
✅ String[] args is needed because:
It's how the JVM identifies the starting point of the program.
It allows passing command-line arguments to the program.
It helps make the program dynamic and flexible.
33. Final Keyword:-
The final keyword in Java is used to apply restrictions on
variables, methods, and classes. It helps ensure immutability,
security, and prevents modifications in certain scenarios.
1. final with Variables (Prevent Reassignment)
A final variable can be assigned only once.
If it is not initialized at declaration, it must be initialized in
the constructor.
Example:
java
CopyEdit
public class Example {
final int x = 10; // Must be assigned only once
final double PI; // Must be initialized in the constructor
Example() {
PI = 3.14159; // Allowed: initializing final variable in
constructor
}
void changeValue() {
// x = 20; // ❌ Compilation error: Cannot assign a value to
final variable 'x'
}
}
Where to Use?
✔ Constants (e.g., final double PI = 3.14;)
✔ When you don’t want a variable to be modified after
initialization
2. final with Methods (Prevent Overriding)
A final method cannot be overridden by subclasses.
Example:
java
CopyEdit
class Parent {
final void display() {
System.out.println("This is a final method.");
}
}
class Child extends Parent {
// void display() { ❌ Compilation error: Cannot override final
method
// System.out.println("Trying to override.");
// }
}
Where to Use?
✔ When you want to prevent a method from being overridden,
ensuring consistent behavior
✔ Used in APIs/frameworks to avoid accidental method
modification
3. final with Classes (Prevent Inheritance)
A final class cannot be extended.
Example:
java
CopyEdit
final class Vehicle {
void run() {
System.out.println("Vehicle is running.");
}
}
// class Car extends Vehicle { ❌ Compilation error: Cannot
inherit from final class 'Vehicle'
// }
Where to Use?
✔ When you want to prevent a class from being inherited (e.g.,
java.lang.String is a final class)
✔ Useful for security-sensitive classes.
Q. class Main {
final String s1="hello"; final int x;
Main(){
x=20; final String s1="hello world";
System.out.println(this.s1);
}
public static void main(String[] args) {
System.out.println("Try programiz.pro");
Main m1=new Main();
System.out.println(m1.x);
System.out.println(m1.s1);
}
}in this code when i write System.out.println(this.s1); in
constructor it gives hello as output but wheen i write
System.out.println(s1); it gives hellow world as output
ChatGPT said:
Understanding the Output in Your Code
Your code demonstrates variable shadowing in Java. Let's break
it down:
java
CopyEdit
class Main {
final String s1 = "hello"; // Instance variable
final int x;
Main() {
x = 20; // Assigning final variable in constructor
final String s1 = "hello world"; // Local variable (shadows
instance variable)
System.out.println(this.s1); // Refers to instance variable ->
Output: hello
System.out.println(s1); // Refers to local variable -> Output:
hello world
}
public static void main(String[] args) {
System.out.println("Try programiz.pro");
Main m1 = new Main();
System.out.println(m1.x); // Output: 20
System.out.println(m1.s1); // Output: hello
}
}
Why Different Outputs?
1. System.out.println(this.s1);
The this keyword refers to the instance variable (s1 = "hello" at
the class level).
So, this.s1 outputs:
hello
2. System.out.println(s1);
Since there is a local variable s1 inside the constructor (final
String s1 = "hello world";), it shadows the instance variable s1.
The local variable takes precedence within the constructor.
So, s1 outputs:
hello world
34. Object Class equals toString hashcode.
Code :
class Laptop{
String model;
int price;
}
public class demo{
public static void main(String a[]){
Laptop obj=new Laptop();
obj.model=”abc”;
obj.price=1000;
System.out.println(obj);
}
}
Output will be:---Some hashcode for example:-
class_name@hexadecimal_value.
For same above code if we write
“System.out.println(obj.toString())” it will print the same output as
above bcoz the toString method is called by default even if we
don’t write.
So to get actual values of the object of class Laptop (model and
price) we can override the toString() method in our Laptop class.
So we can add below code in our Laptop class:
public String toString(){
return model+” : ”+price;
}
Output after adding this will be:
abc : 1000
35.
36.