Unit 2 Notes
Unit 2 Notes
Java is known for its simplicity, robustness, and security features, making it a popular choice for
enterprise-level applications. Java applications are compiled to byte code that can run on any
Java Virtual Machine.
Compiler converts source code to byte code and then the JVM executes the bytecode generated
by the compiler. This byte code can run on any platform be it Windows, Linux, or macOS which
means if we compile a program on Windows, then we can run it on Linux and vice versa. Each
operating system has a different JVM, but the output produced by all the OS is the same after the
execution of the byte code. That is why we call java a platform-independent language.
2. Object-Oriented Programming
Java is an object-oriented language, promoting the use of objects and classes. Organizing the
program in the terms of a collection of objects is a way of object-oriented programming, each of
which represents an instance of the class.
Abstraction
Encapsulation
Inheritance
Polymorphism
3. Simplicity
Java’s syntax is simple and easy to learn, especially for those familiar with C or C++. It
eliminates complex features like pointers and multiple inheritances, making it easier to write,
debug, and maintain code.
4. Robustness
Java language is robust which means reliable. It is developed in such a way that it puts a lot of
effort into checking errors as early as possible, that is why the java compiler is able to detect
even those errors that are not easy to detect by another programming language. The main
features of java that make it robust are garbage collection, exception handling, and memory
allocation.
5. Security
6. Distributed
We can create distributed applications using the java programming language. Remote Method
Invocation and Enterprise Java Beans are used for creating distributed applications in java. The
java programs can be easily distributed on one or more systems that are connected to each other
through an internet connection.
7. Multithreading
Java supports multithreading, enabling the concurrent execution of multiple parts of a program.
This feature is particularly useful for applications that require high performance, such as games
and real-time simulations.
8. Portability
As we know, java code written on one machine can be run on another machine. The platform-
independent feature of java in which its platform-independent bytecode can be taken to any
platform for execution makes java portable. WORA(Write Once Run Anywhere) makes java
application to generates a ‘.class’ file that corresponds to our applications(program) but contains
code in binary format. It provides ease t architecture-neutral ease as bytecode is not dependent on
any machine architecture. It is the primary reason java is used in the enterprising IT industry
globally worldwide.
9. High Performance
Java architecture is defined in such a way that it reduces overhead during the runtime and at
some times java uses Just In Time (JIT) compiler where the compiler compiles code on-demand
basis where it only compiles those methods that are called making applications to execute faster.
Java Virtual Machine Concepts
Java applications are called WORA (Write Once Run Anywhere). This means a programmer can
develop Java code on one system and expect it to run on any other Java-enabled system without
any adjustment. This is all possible because of JVM.
When we compile a .java file, .class files(contains byte-code) with the same class names present
in .java file are generated by the Java compiler. This .class file goes into various steps when we
run it. These steps together describe the whole JVM.
Loading
Linking
Initialization
Loading:
The Class loader reads the “.class” file, generate the corresponding binary data and save it in the
method area.
Linking
Performs verification, preparation, and (optionally) resolution.
Verification - It ensures the correctness of the .class file. This activity is done by the
component ByteCodeVerifier. Once this activity is completed then the class file is ready for
compilation.
Preparation - JVM allocates memory for class static variables and initializing the
memory to default values.
Resolution: It is the process of replacing symbolic references from the type with direct
references.
Initialization
In this phase, all static variables are assigned with their values defined in the code and static
block(if any). In general, there are three class loaders:
Bootstrap class loader: Every JVM implementation must have a bootstrap class loader, capable
of loading trusted classes.
Extension class loader: It is a child of the bootstrap class loader. It loads the classes present in
the extensions directories.
Method area: In the method area, all class level information like class name, immediate parent
class name, methods and variables information etc. are stored, including static variables. There is
only one method area per JVM, and it is a shared resource.
Heap area: Information of all objects is stored in the heap area. There is also one Heap Area per
JVM. It is also a shared resource.
Stack area: For every thread, JVM creates one run-time stack which is stored here. Every block
of this stack is called activation record/stack frame which stores methods calls. All local
variables of that method are stored in their corresponding frame. After a thread terminates, its
run-time stack will be destroyed by JVM. It is not a shared resource.
PC Registers: Store address of current execution instruction of a thread. Obviously, each thread
has separate PC Registers.
Native method stacks: For every thread, a separate native stack is created. It stores native
method information.
3. Execution Engine
Execution engine executes the “.class” (bytecode). It reads the byte-code line by line, uses data
and information present in various memory area and executes instructions. It can be classified
into three parts:
Interpreter: It interprets the bytecode line by line and then executes. The disadvantage here is
that when one method is called multiple times, every time interpretation is required.
It is an interface that interacts with the Native Method Libraries and provides the native
libraries(C, C++) required for the execution. It enables JVM to call C/C++ libraries and to be
called by C/C++ libraries which may be specific to hardware.
These are collections of native libraries required for executing native methods. They include
libraries written in languages like C and C++.
Primitive Data Type: such as boolean, char, int, short, byte, long, float, and double. The
Boolean with uppercase B is a wrapper class for the primitive data type boolean in Java.
Non-Primitive Data Type or Object Data type: such as String, Array, etc.
Primitive data are only single values and have no special capabilities. There are 8 primitive data
types. They are depicted below in tabular format below as follows:
Descriptio Defaul Siz Example
Type n t e Literals Range of values
boolea 8
true or false false true, false true, false
n bits
twos-
8
complement 0 (none) -128 to 127
bits
byte integer
twos-
16
complement 0 (none) -32,768 to 32,767
bits
short integer
twos- -2,147,483,648
32
complement 0 -2,-1,0,1,2 to
bits
int intger 2,147,483,647
-
9,223,372,036,854,775,80
twos-
64 -2L,- 8
complement 0
bits 1L,0L,1L,2L to
integer
9,223,372,036,854,775,80
long 7
1.23e100f , -
IEEE 754 32 1.23e-
0.0 upto 7 decimal digits
floating point bits 100f , .3f ,3.1
float 4F
1.23456e300
IEEE 754 64
0.0 d , -123456e- upto 16 decimal digits
floating point bits
double 300d , 1e1d
Variables:
A variable is a container for storing data values. In Java, variables must be declared with a
specific type before they can be used.
Syntax:
<datatype><variable_name> = <value>;
Example:
Java Operators
Operators in Java are special symbols or keywords used to perform operations on operands. They
can be categorized into various types:
1. Arithmetic Operators:
o + (Addition)
o - (Subtraction)
o * (Multiplication)
o / (Division)
o % (Modulo)
Example:
inta=10, b = 5;
intsum= a + b; // sum = 15
2. Relational Operators:
o == (Equal to)
o != (Not equal to)
o > (Greater than)
o < (Less than)
o >= (Greater than or equal to)
o <= (Less than or equal to)
Example:
inta=10, b = 5;
booleanresult= a >b; // result = true
3. Logical Operators:
o && (Logical AND)
o || (Logical OR)
o ! (Logical NOT)
Example:
booleanx=true, y = false;
booleanresult= x &&y; // result = false
4. Assignment Operators:
o = (Assigns a value)
Example:
inta=5;
a += 3; // a = 8
5. Unary Operators:
o ++ (Increment)
o -- (Decrement)
o + (Unary plus)
o - (Unary minus)
Example:
inta=10;
a++; // a = 11
6. Ternary Operator:
o condition ? expr1 : expr2; (If-Else shorthand)
Example:
inta=10, b = 5;
intresult= (a > b) ? a : b; // result = 10
7. Bitwise Operators:
o & (Bitwise AND) – returns bit-by-bit AND of input values.
o | (Bitwise OR) – returns bit-by-bit OR of input values.
o ^ (Bitwise XOR) – returns bit-by-bit XOR of input values.
o ~ (Bitwise Complement) – inverts all bits
Arrays in Java
Arrays are fundamental structures in Java that allow us to store multiple values of the
same type in a single variable. They are useful for storing and managing collections of data.
There are some basic operations we can start with as mentioned below:
1. Array Declaration
type[] arrayName;
type: The data type of the array elements (e.g., int, String).
2. Create an Array
To create an array, you need to allocate memory for it using the new keyword:
We can access array elements using their index, which starts from 0:
The first line sets the value of the first element to 10. The second line retrieves the value of the
first element.
5. Array Length
Example:
System.out.println(arr[i]);
}
Class and Objects in Java
In Java, classes and objects are the foundational concepts of object-oriented programming
(OOP). A class is a blueprint or template for creating objects, which are instances of the class.
Let's explore these concepts in detail.
Class in Java
A class in Java is a blueprint that defines the structure and behavior (attributes and methods) that
objects created from the class will have. It is essentially a user-defined data type that can hold
variables (fields) and methods (functions) that operate on these variables.
// Constructor(s)
publicClassName() {
// Initialization code
}
// Methods (behavior)
publicreturnTypemethodName() {
// Method body
}
}
Key Points:
The Car class has three fields: model, color, and year.
The Car constructor initializes the object with specific values for these fields.
The displayInfo method displays the car's information.
Object in Java
To create an object, you use the new keyword followed by the constructor of the class.
Let’s create a practical example where we define a Person class with fields and methods, and
create objects of the Person class.
classPerson {
// Fields (Attributes)
String name;
intage;
publicclassMain {
publicstaticvoidmain(String[] args) {
// Creating objects of the Person class
Personperson1=newPerson("Alice", 30);
Personperson2=newPerson("Bob", 25);
Explanation:
The Person class has two fields: name and age, which define the state of a person.
The introduce() method is used to print a greeting message, describing the person.
The Main class contains the main method, where two Person objects (person1 and person2) are
created using the constructor, and their introduce() method is called to display their details.
Class: A blueprint or template for creating objects. It defines the attributes (fields) and behavior
(methods) of the objects.
Object: An instance of a class that holds specific data and can perform actions defined in the
class.
Methods
Method Signature: This includes the method name, the return type, and any parameters.
Method Body: This contains the actual code that defines what the method does.
Syntax:
returnTypemethodName(parameterList) {
// Method body
}
Return Type: Specifies the type of value the method will return (e.g., int, String, void
for no return value).
Method Name: The name of the method, which should be a valid Java identifier.
Parameter List: A comma-separated list of parameters that the method accepts
(optional).
Method Body: The block of code enclosed in curly braces {} that executes when the method is
called.
Static Methods
A static method belongs to the class rather than to instances (objects) of the class. This means
you can call static methods without creating an object of the class. Static methods are declared using the
static keyword.
Static methods are called on the class itself, not on instances of the class.
Static methods can only directly access other static members (fields and methods) of the
class.
Static methods cannot use instance variables or instance methods directly because they do not
operate on an instance of the class.
publicclassMain {
publicstaticvoidmain(String[] args) {
// Calling the static method without creating an instance of Calculator
intresult=Calculator.multiply(4, 5);
System.out.println("The result is: " + result);
}
}
In this example:
Static methods cannot access instance variables or instance methods directly, because
they are not associated with any specific instance of the class.
They can only call other static methods and access static fields in the same class.
Constructors
A constructor is a special type of method used to initialize objects. It has the same name as the
class and does not have a return type (not even void).
Types of Constructors:
1. Default Constructor: A constructor that does not take any arguments. If you don’t
provide any constructor, Java provides a default one.
classCar {
String model;
String color;
intyear;
// Default constructor
publicCar() {
model = "Unknown";
color = "Unknown";
year = 0;
}
}
classCar {
String model;
String color;
intyear;
// Parameterized constructor
publicCar(String model, String color, intyear) {
this.model = model;
this.color = color;
this.year = year;
}
}
classCar {
String model;
String color;
intyear;
publicclassMain {
publicstaticvoidmain(String[] args) {
// Creating objects of the Car class with the parameterized constructor
Carcar1=newCar("Tesla Model 3", "White", 2021);
Carcar2=newCar("BMW X5", "Black", 2020);
Constructor Overloading
Constructor overloading in Java allows you to define multiple constructors with different
parameters in the same class. This enables you to create objects in different ways, depending on
the constructor used.
In Java, a constructor is a special method used to initialize objects. A constructor has the same
name as the class and does not have a return type.
Constructor overloading happens when you define more than one constructor in the same
class with the same name but with different parameter lists (different number, types, or order of
parameters).
Java will choose which constructor to call based on the arguments passed during object
creation.
Different parameter lists: The constructors should differ in the number, types, or order of
parameters.
Cannot differ by return type: Constructor overloading cannot be based on different return
types, because constructors do not have return types.
this Keyword
In Java, the this keyword is a reference variable that refers to the current instance of the class. It
is commonly used within instance methods and constructors to refer to the current object's
instance variables and methods. The this keyword can also be used to differentiate between
instance variables and local variables that have the same name.
In Java, you can pass objects as parameters to methods. When you pass an object to a
method, you are actually passing a reference to that object, not a copy of the object. This means
that changes made to the object's fields (instance variables) inside the method will affect the
original object.
Example:
class Car {
String model;
int year;
this.year = year;
updateCar(myCar);
Argument passing
In Java, argument passing refers to how values are provided to a method when it is called. There
are two main ways arguments can be passed to methods in Java:
1. Pass-by-Value
2. Pass-by-Reference (via Objects)
When you pass a primitive type (like int, char, float, etc.) to a method, you are passing the
value of that variable, not the variable itself. Any changes made to the parameter inside the
method do not affect the original value of the argument in the calling code.
x = 20; // This changes the value of x inside the method, but does not affect the
original 'num'
When you pass an object to a method, you are passing a reference to the object. This means the
method can modify the fields (instance variables) of the object, and the changes will affect the
original object.
However, note that the reference itself is passed by value, meaning you can't change the
reference (i.e., point it to a new object) from within the method. But you can modify the object's
contents.
String name;
int age;
this.name = name;
this.age = age;
changePerson(person1);
}}
Method Overloading
Method overloading in Java refers to defining multiple methods with the same name but
different parameter lists within the same class. This is a form of compile-time polymorphism,
where the method to be invoked is determined at compile-time based on the method signature
(the number and types of parameters).
publicclassMain {
publicstaticvoidmain(String[] args) {
Calculatorcalc=newCalculator();
In this example:
The add method is overloaded with different parameter counts and types, allowing it to handle different
addition operations.
Garbage Collection (GC) in Java is the process by which the Java Virtual Machine (JVM)
automatically reclaims memory by destroying objects that are no longer in use (i.e., objects that
are unreachable or no longer referenced).
Java manages memory automatically via garbage collection, which eliminates the need for
manual memory management.
Unreachable Objects: An object is considered garbage if no active references are pointing to it.
The JVM automatically decides when to perform garbage collection based on memory usage, but
you can trigger it manually by calling System.gc(). However, it is not guaranteed to run at that
time.
The finalize() method is a method of the Object class in Java. It is called by the garbage
collector before an object is destroyed to give the object a chance to release system resources
such as memory, file handles, or network connections.
Purpose: The main purpose of finalize() is to allow an object to clean up any resources before it is
garbage collected. For example, closing file streams or database connections.
Not guaranteed: The finalize() method is not guaranteed to be called immediately or at all. The
JVM is free to call or skip calling the finalize() method based on the garbage collection process.
Deprecated in Java 9: In Java 9 and later, the finalize() method has been deprecated. It is
recommended to use try-with-resources or explicit resource management mechanisms instead.
publicclassMain {
publicstaticvoidmain(String[] args) {
ResourceHandlerhandler=newResourceHandler();
handler = null; // Object is now eligible for garbage collection
In this example:
Inheritance
The extends keyword is used for inheritance in Java. Using the extends keyword indicates you
are derived from an existing class. In other words, “extends” refers to increased functionality.
Syntax :
class DerivedClass extends BaseClass
{
//methods and fields
}
Key Features of Inheritance:
Code Reusability: The subclass can reuse the methods and variables of the superclass.
Method Overriding: The subclass can provide a specific implementation of a method that is
already defined in the superclass.
Example of Inheritance:
classAnimal {
voidspeak() {
System.out.println("Animal speaks");
}
}
classDogextendsAnimal {
// Method overriding
voidspeak() {
System.out.println("Dog barks");
}
}
publicclassMain {
publicstaticvoidmain(String[] args) {
Animalanimal=newAnimal();
animal.speak(); // Output: Animal speaks
Dogdog=newDog();
dog.speak(); // Output: Dog barks
}
}
In this example:
The Dog class inherits the speak method from the Animal class but overrides it with its own
implementation.
Access control in Java defines the visibility and accessibility of classes, methods, and fields. Java
provides several access modifiers to control access to class members:
Multilevel Inheritance
Multilevel inheritance is when a class is derived from another class, and this derived class is
further extended by another class, creating a chain of inheritance. In the below image, class A
serves as a base class for the derived class B, which in turn serves as a base class for the derived
class C. In Java, a class cannot directly access the grandparent’s members.
Example of Multilevel Inheritance:
Class Animal {
void eat() {
System.out.println("Animal is eating");
}
}
In this example:
The Dog class inherits the eat method from Animal and the walk method from Mammal.
Overriding in Java occurs when a subclass implements a method which is already defined in the
superclass or Base Class. The method in the subclass must have the same signature as in the
superclass. It allows the subclass to modify the inherited methods.
@Override annotation: This annotation is used to indicate that a method is intended to override
a method in the superclass.
classDogextendsAnimal {
@Override
voidsound() {
System.out.println("Dog barks");
}
}
publicclassMain {
publicstaticvoidmain(String[] args) {
AnimalmyAnimal=newAnimal();
myAnimal.sound(); // Output: Animal makes a sound
AnimalmyDog=newDog();
myDog.sound(); // Output: Dog barks (method overriding)
}
}
In this example:
The sound() method is overridden in the Dog class. When called on an object of type Animal but
referencing a Dog, the overridden version of the method is invoked.
Abstract Classes
An abstract class is a class that cannot be instantiated directly and may contain abstract methods
(methods without a body) that must be implemented by subclasses.
Abstract Method: A method without a body, declared with the abstract keyword.
Concrete Class: A class that implements all abstract methods from the abstract class.
void sleep() {
System.out.println("Animal is sleeping");
}
}
In this example:
Polymorphism
The word ‘polymorphism’ means ‘having many forms’. In Java, polymorphism refers to the
ability of a message to be displayed in more than one form. This concept is a key feature
of Object-Oriented Programming and it allows objects to behave differently based on their
specific class type.
Polymorphism is the ability of an object to take many forms. It allows you to use a parent class
reference to refer to child class objects and invoke the appropriate method.
Real-life Illustration of Polymorphism in Java: A person can have different characteristics at
the same time. Like a man at the same time is a father, a husband, and an employee. So the same
person possesses different behaviors in different situations. This is called polymorphism.
Method overloading occurs when two or more methods in the same class have the same name
but differ in the number or type of parameters.Functions can be overloaded by changes in the
number of arguments or/and a change in the type of arguments.
class Calculator {
// Overloaded method to add two integers
public int add(int a, int b) {
return a + b;
}
This occurs when a subclass provides its own specific implementation of a method defined in its
superclass. It is a process in which a function call to the overridden method is resolved at
Runtime. This type of polymorphism is achieved by Method Overriding. Method overriding, on
the other hand, occurs when a derived class has a definition for one of the member functions of
the base class. That base function is said to be overridden.
Example of Runtime Polymorphism:
class Animal {
public void makeSound() {
System.out.println("Some sound");
}
}
In the example above, we use an Animal reference to call the makeSound method, but the actual
method executed depends on the object's runtime type (Dog, Cat, or Animal), demonstrating
runtime polymorphism.
final Keyword
The final keyword in Java is used to define constants, prevent method overriding, and prevent
inheritance.
final with variables: Used to define constants (the value cannot be changed after initialization).
final with methods: Prevents a method from being overridden by subclasses.
final with classes: Prevents a class from being inherited.
classMain {
publicstaticvoidmain(String[] args) {
// FinalClass obj = new FinalClass(); // Valid, no issue with instantiating
final class
FinalClassobj=newFinalClass();
obj.show(); // Output: Final class method
}
}
classDogextendsAnimal {
// Error: Cannot override final method sleep()
// void sleep() {
// System.out.println("Dog is sleeping");
// }
}
publicclassMain {
publicstaticvoidmain(String[] args) {
Animaldog=newAnimal();
dog.sleep(); // Output: Animal is sleeping
}
}
In this example: