Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
28 views

Unit-1 Java Notes New

Uploaded by

as2225315
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
28 views

Unit-1 Java Notes New

Uploaded by

as2225315
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 14

Unit-1

Organization of java virtual machine(JVM)


Java Virtual Machine (JVM) is an engine that provides runtime environment to drive the Java Code or
applications. It converts Java bytecode into machines language. JVM is a part of Java Runtime
Environment (JRE). In other programming languages, the compiler produces machine code for a
particular system. However, Java compiler produces code for a Virtual Machine known as Java Virtual
Machine.

How JVM Works?


First, Java code is compiled into bytecode. This bytecode gets interpreted on different machines by the
java interpreter. Between host system and Java source, Bytecode is an intermediary language or code.

JVM in Java is responsible for allocating memory space.

Working of Java Virtual Machine (JVM)

JVM Architecture
JVM architecture in Java contains classloader, memory area, execution engine etc.

Java Virtual Machine Architecture


1) ClassLoader
The class loader is a subsystem used for loading class files. The class loader reads the class file, generate
the corresponding binary data and save it in the method area. It performs three major functions viz.
Loading, Linking, and Initialization.

(i) Loading – loads the classes dynamically into the JVM memory during runtime.
(ii) Linking- After a class is loaded into the memory, it undergoes the linking process. Linking a
class or interface involves combining the different elements and dependencies of the program
together. The linking process involves following 3 steps:
(a) Verification - JVM verifies the bytecode for type mismatches and buffer overflows. For
example, for the code built using Java 11 and run on Java 8, verification fails.
(b) Preparation – Java allocates memory for the static fields of a class or interface and
initializes them with default values.
For example: a variable is declared in your class-
public static final boolean enabled=true;
so, during preparation phase, JVM allocates memory for the variable enabled &sets its
value to the default value for a Boolean, which is false.
(c) Resolution – in this phase, symbolic references are replaced with direct references
present in the runtime constant pool. For example-if you have references to other classes
or constant variables present in other classes, they are replaced with their actual
references.
(iii) Initialization – It includes calling the class’s constructor, executing the static block,
assigning values to all the static variables. For example- variable enabled is now assigned its
actual value i.e. true.

2) Method Area
JVM Method Area stores all the class level data such as the runtime constant pool, fields and method
data, and the code for methods and constructors.
public class Employee{
private String name;
private int age;
public Employee(String name, int age)
{
this.name=name;
this.age=age;
}
}
So the field level data such as name and age, and constructor details are loaded into the method area. This
method area is created on the virtual machine startup and there is only one method area per JVM.
3) Heap
All the Objects, their related instance variables, and arrays are stored in the heap. It is mainly 2-3 GB to
minimize garbage collection pauses. This is the runtime area from which memory for all class instances
and arrays are allocated. This memory is common and shared across multiple threads.
For example-
Employee employee = new Employee;
Here, an instance of Employee is created and loaded into the heap area.
Method area and heap area share the same memory for multiple threads.
4) JVM language Stack Area
Java language Stacks store local variables, and it’s partial results. Each thread has its own JVM stack,
created simultaneously as the thread is created. A new frame is created whenever a method is invoked,
and it is deleted when method invocation process is complete. So the stack area is short lived.
For every method call, one entry is made in the stack memory, which is called stack frame. When the
method call is complete, the stack frame is destroyed. The stack frame contains local variables, operand
stack and frame data.
5) PC Registers
PC register store the address of the Java virtual machine instruction which is currently executing. In Java,
each thread has its separate PC register.
6) Native Method Stacks
Native method stacks hold the instruction of native code depends on the native library. It is written in
another language instead of Java.
7) Execution Engine
It is a type of software used to test hardware, software, or complete systems. The test execution engine
never carries any information about the tested product.
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.
 Just-In-Time Compiler(JIT) : It is used to increase the efficiency of an interpreter. It compiles the
entire bytecode and changes it to native code so whenever the interpreter sees repeated method
calls, JIT provides direct native code for that part so re-interpretation is not required, thus
efficiency is improved.
 Garbage Collector: It destroys un-referenced objects. Garbage collection runs on the heap memory
to free the memory used by objects that don’t have any reference.

8) Native Method interface


The Native Method Interface is a programming framework which provides an interface to communicate
with other applications written in another language C, C++, assembly etc. It allows Java code which is
running in a JVM to call by libraries and native applications. Java uses JNI framework to send output to
the console or interact with OS libraries.

9) Native Method Libraries


Native Libraries is a collection of the Native Libraries(C, C++) which are needed by the Execution
Engine.

Java code Compilation and Execution in Java VM


In your main, you have two methods f1 and f2.

 The main method is stored in file a1.java


 f1 is stored in a file as a2.java
 f2 is stored in a file as a3.java
The compiler will compile the three files and produces 3 corresponding .class file which consists of
BYTE code. Unlike C, no linking is done.

The Java VM or Java Virtual Machine resides on the RAM. During execution, using the class loader the
class files are brought on the RAM. The bytecode is verified for any security breaches.

Next, the execution engine will convert the Bytecode into Native machine code. This is just in time
compiling. It is one of the main reason why Java is comparatively slow.
NOTE: JIT or Just-in-time compiler is the part of the Java Virtual Machine (JVM). It interprets part of
the Byte Code that has similar functionality at the same time.

Why is Java both Interpreted and Compiled Language?


Programming languages are classified as

 Higher Level Language Ex. C++, Java


 Middle-Level Languages Ex. C
 Low-Level Language Ex Assembly
 The lowest level as the Machine Language.

A compiler is a program which converts a program from one level of language to another. Example
conversion of C++ program into machine code.

The java compiler converts high-level java code into bytecode (which is also a type of machine code).

An interpreter is a program which converts a program at one level to another programming language at
the same level. Example conversion of Java program into C++

In Java, the Just In Time Code generator converts the bytecode into the native machine code which are at
the same programming levels.

Hence, Java is both compiled as well as interpreted language.

Why is Java slow?


The two main reasons behind the slowness of Java are

1. Dynamic Linking: Unlike C, linking is done at run-time, every time the program is run in Java.
2. Run-time Interpreter: The conversion of byte code into native machine code is done at run-time
in Java which furthers slows down the speed

Summary:

 Full form of JVM is Java Virtual Machine. JVM in Java is the engine that drives the Java Code. It
converts Java bytecode into machines language.
 JVM architecture in Java contains classloader, memory area, execution engine etc.
 In JVM, Java code is compiled to bytecode. This bytecode gets interpreted on different machines
 JIT stands for Just-in-time compiler. JIT is the part of the Java Virtual Machine (JVM). It is used
to speed up the execution time
 In comparison to other compiler machines, JVM in Java may be slow in execution.

Types of class loaders


There are three main types of class loaders. To start, take a look at this diagram of Java class loaders
interacting in a Java program.

IDG

Figure 1. Java class loaders in a Java program.

Notice that the class search begins with the bootstrap class loader. If the class is not found, the class
search returns to the extension class loader for another search. If the class is still not found, the process
tries again using the application class loader. If none of the searches finds the class, then the program
throws a ClassNotFoundExecption.
Bootstrap class loader

Also known as the primordial class loader, this is the class loader where the search starts. The bootstrap
class loader is responsible for loading core Java classes such as java.lang.Object and java.lang.String. It is
implemented in native code and classes are located in the $JAVA_HOME/lib directory.

There were some important changes to class loaders between Java 8 and Java 9. For example, in Java 8,
the bootstrap class loader was located in the Java Runtime Environment's rt.jar file. In Java 9 and
subsequently, the rt.jar file was removed.

Moreover, Java 9 introduced the Java module system, which changed how classes are loaded. In the
module system, each module defines its own class loader, and the bootstrap class loader is responsible for
loading the module system itself and the initial set of modules. When the JVM starts up, the bootstrap
class loader loads the java.base module, which contains the core Java classes and any other modules that
are required to launch the JVM.

The java.base module also exports packages to other modules, such as java.lang, which contains core
classes like Object and String. These packages are then loaded by the bootstrap class loader.

The bootstrap class loader in action


In the following code example, we'll use the getClassLoader() method on the String class to get its class
loader. Since the String class is one of the core Java classes, we'll get a reference to the bootstrap class
loader.

We'll print out the name of the class loader using the toString() method. When we run the code, we should
see output similar to what's shown in Listing 1.

Listing 1. Bootstrap class loader

public class BootstrapClassLoaderExample {


public static void main(String[] args) {
// Get the class loader for the String class, loaded by the Bootstrap Class Loader
ClassLoader loader = String.class.getClassLoader();

// Print the class loader's name


System.out.println("Class loader for String class: " + loader);
}
}

Output:
null
The output is null because the bootstrap class loader has no parent class loader.

Extension class loader

In Java 9 and later versions, the extension class loader was removed from the JVM. It was used in earlier
versions of Java to load classes from the extension directory, which was typically located in
the JRE/lib/ext directory.
Instead of the extension class loader, Java 9 and later versions use the java.lang.ModuleLayer class to
load modules from the extension directory. The extension directory is now treated as a separate layer in
the module system, and modules in the extension directory are loaded by the extension layer's class
loader.

Note that in Java 9 and later versions, it is recommended to use modules instead of the extension
mechanism to share code between applications.

Application class loader

The Application class loader (also called the system class loader) loads classes from the application's
classpath. The classpath is a list of directories and JAR files that the JVM searches to find a class.

The application class loader is a standard Java class that loads classes from the directories and JAR files
listed in the CLASSPATH environment variable or the -classpath command-line option. It loads the first
class it finds if there are multiple versions.

The application class loader is the last class loader to search for a class. If it can't find it, the JVM throws
a ClassNotFoundException. This class loader can also delegate class loading to its parent class loader, the
extension class loader.

Aside from loading classes from the classpath, the application class loader also loads classes generated at
runtime, like those created by the Java Reflection API or third-party libraries that use bytecode
generation.

The application class loader is important because it lets developers easily use third-party libraries and
modules in their applications.

The code example in Listing 3 demonstrates how to get the application class loader using
the ClassLoader.getSystemClassLoader() method.

Listing 3. How to call the application class loader

public class ApplicationClassLoaderExample {


public static void main(String[] args) {
// Get the Application Class Loader
ClassLoader appClassLoader = ClassLoader.getSystemClassLoader();
// Load a class using the Application Class Loader
try {
Class<?> clazz = appClassLoader.loadClass("java.util.ArrayList");
System.out.println("Loaded class: " + clazz.getName());
} catch (ClassNotFoundException e) {
System.out.println("Class not found: " + e.getMessage());
}
}
}
In this example, we get the application class loader by calling
the ClassLoader.getSystemClassLoader() method. We then use the application class loader to load
the java.util.ArrayList class. If the class is found and loaded successfully, we print its name to the
console. If the class is not found, we print an error message.
Rules for working with class loaders
There are just a few rules for working with Java class loaders. Knowing them will make your work
simpler and more effective.

Delegation
The delegation model in Java allows for loading classes flexibly and dynamically at runtime. This is
useful in environments where the class loading requirements are unknown at compile-time.

For instance, in an application server, different applications may need different versions of the same class.
The class loader delegation model makes it possible to meet these requirements without causing conflicts.

Visibility
Class loaders in Java can have varying levels of visibility, which determines their ability to find and load
classes from other class loaders. There are three levels of visibility:

 Parent-first visibility: The parent class loader is used first to load a class. If it cannot find the class, the
child class loader is consulted. This is the default visibility model.
 Child-first visibility: The child class loader is used first to load a class. If it cannot find the class, the
parent class loader is consulted. This model is useful when a different version of a class is needed.
 Hierarchical visibility: Each class loader has its own classpath, and classes loaded by a child class loader
are not visible to parent class loaders. This model is useful to isolate different parts of an application from
each other.

The level of visibility depends on the class loader hierarchy and the classpath, and it can have significant
implications for application behavior. It's important to consider the visibility model used in an application
to ensure that classes are loaded correctly and that classloading conflicts are avoided.

Uniqueness
Java class loaders keep different versions of the same class in separate namespaces, which allows for
creating multiple instances of a class with different versions. This is useful for web applications that need
to load shared libraries without conflicts.

However, this feature can cause issues if not used carefully. If a class is loaded by two different class
loaders, the JVM will treat them as separate classes, and objects created from them will not be
interchangeable. This can lead to unexpected behavior if these objects are passed between methods
expecting objects created by different class loaders.

To avoid these issues, it is recommended to use a single class loader to load classes whenever possible.
When multiple class loaders are used, take extra care to ensure that objects are not passed between classes
with different namespaces.

Class loader methods


Java's ClassLoader class has the following main methods:

 loadClass(String name): Loads a class with the specified name. It first checks if the class has already been
loaded, and if not, it delegates the loading of the class to the parent class loader.
 findClass(String name): Finds the class with the name you've specified. It is called by
the loadClass() method if the parent class loader cannot find the class.
 getParent(): Returns a class loader's parent class loader.
 getResource(String name): Finds the resource with the name you have specified. It searches the classpath
for the resource and returns a URL object that can be used to access the resource.
 setDefaultAssertionStatus(boolean enabled): Enables or disables assertions for this class loader and all
classes loaded by it.

Conclusion

Here are the key points to remember when working with Java class loaders:

 Java class loaders are responsible for loading classes into the JVM at runtime.
 The three main types of class loaders are the bootstrap class loader, the extension class loader, and the
application class loader (also known as the system class loader).
 The bootstrap class loader is responsible for loading core Java classes that are part of the JRE.
 The extension class loader is responsible for loading classes that are part of the Java extension
mechanism.
 The application class loader is responsible for loading classes that are part of the application's classpath.
 You can also define custom class loaders to load classes from non-standard locations or to modify the
behavior of the class-loading process.

The class File Format


This chapter describes the Java Virtual Machine class file format. Each class file contains the
definition of a single class or interface.

A class file consists of a stream of 8-bit bytes. All 16-bit, 32-bit, and 64-bit quantities are
constructed by reading in two, four, and eight consecutive 8-bit bytes, respectively. Multibyte
data items are always stored in big-endian order, where the high bytes come first. In the Java
SE platform, this format is supported by
interfaces java.io.DataInput and java.io.DataOutput and classes such
as java.io.DataInputStream and java.io.DataOutputStream.

This chapter defines its own set of data types representing class file data: The types u1, u2,
and u4 represent an unsigned one-, two-, or four-byte quantity, respectively. In the Java SE
platform, these types may be read by methods such as readUnsignedByte, readUnsignedShort,
and readInt of the interface java.io.DataInput.

The ClassFile Structure

A class file consists of a single ClassFile structure:

ClassFile
{
magic_number;
minor_version;
major_version;
constant_pool_count;
constant_pool[];
access_flags;
this_class;
super_class;
interfaces_count;
interfaces[];
fields_count;
fields[];
methods_count;
methods[];
attributes_count;
attributes[];
}
Elements of class file are as follows:
1. magic_number: The first 4 bytes of class file are termed as magic_number. This is a predefined
value which the JVM use to identify whether the .class file is generated by valid compiler or not.
The predefined value will be in hexadecimal form i.e. 0xCAFEBABE. Now let’s see what happen
when JVM will not find valid magic number. Suppose we have a .java file named
as Sample.java as follows and follow step by step process on your system.

// class Declaration
class Sample
{
public static void main(String[] args)
{
System.out.println("Magic Number");
}
}

Step 1: Compile using javac Sample.java


Step 2: Now open the Sample.class file. It will looks like following.

Step 3: Now erase at least single symbol from this Sample.class file from starting of file and save
it. Step 4: Now try to run this using java Sample command and see the magic i.e. you will get run time
exception (See the highlighted text in below image):

Note: This can vary depending on how much you remove the .class file data.
2. minor_version & major_version: These both together represents .class file version. JVM will use
these versions to identify which version of the compiler generates the current .class file. We
denotes the version of class file as M.m where M stands for major_version and m stands for
minor_version
Note: Lower version compiler generated .class file can be executed by high version JVM but higher
version compiler generated .class file cannot be executed by lower version JVM. If we will try to
execute we will get run time exception.
This demonstration is for Windows OS as follows:
Step 1: Open a command prompt window and try to check java compiler version and JVM version
using following commands respectively (Highlighted text in image are the commands) Output for 1.8
version will be:

Step 2: Now check with another version which may be higher or lower than already
installed.thisDownload link. And install this to your PC or laptops and note the installation address.
Step 3: Open a second command prompt window and set the path of bin folder of installed jdk installed
during 2nd step. And check for Java compiler version ad JVM version.

Step 4: Now on 1st command prompt compile the any valid .java file. For example: See
above Sample.java file. Compile it as:

Step 5: Now on 2nd command prompt window try to run the above compiled code class file and see
what happen. There is a run time exception which I have highlighted in below image.
Note: Internally jdk 1.5 version means 49.0 and 1.6 means 50.0 and 1.7 means 51.0 etc. class file
version where the digits before the decimal point represent the major_version and digits after decimal
point represents the minor_version.
1. constant_pool_count: It represents the number of the constants present in the constant pool (When
a Java file is compiled, all references to variables and methods are stored in the class’s constant
pool as a symbolic reference).
2. constant_pool[]: It represents the information about constants present in constant pool file.
3. access_flags: It provide the information about the modifiers which are declared to the class file.
4. this_class: It represents fully qualified name of the class file.
5. super_class: It represents fully qualified name of the immediate super class of current class.
Consider above Sample.java file. When we will compile it, then we can say this_class will
be Sample class and super_class will be Object class.
6. interface_count: It returns the number of interfaces implemented by current class file.
7. interface[]: It returns interfaces information implemented by current class file.
8. fields_count: It represents the number of fields (static variable) present in current class file.
9. fields[]: It represent fields (static variable) information present in current class file.
10. method_count: It represents number of methods present in current class file.
11. method[]: It returns information about all methods present in current class file.
12. attributes_count: It returns the number of attributes (instance variables) present in current class
file.
13. attributes[]: It provides information about all attributes present in current class file.

You might also like