Java Basics
Java Basics
Every Java program consists of classes and methods. Here's the structure:
System.out.println("Hello, World!");
Explanation:
public class Main: This declares a class named Main. In Java, everything is written
inside a class.
public static void main(String[] args): This is the main method, the entry
point of any Java program.
System.out.println("Hello, World!");: This prints "Hello, World!" to the
console.
The main method in Java is the entry point of any application. When you run a Java
program, the Java Virtual Machine (JVM) looks for the main method with this exact
signature:
String[] args is an array of String values, which can be used to pass command-
line arguments to the program. When the program is executed from the command
line, the arguments that follow the program's name are passed to the main method as
elements of the args array.
args[1] = "World";
Yes, you can use any valid variable name in place of args, like this:
}
The String[] args parameter allows the program to accept command-line arguments.
You can replace args with any valid name (e.g., input, myArgs), but the type (String[])
must remain the same
If you have multiple Java programs (classes), each with its own main method, here's how you
differentiate between them:
Each class can have its own main method. When you compile the code, the .class
files for each class are generated. // Using javac Main
To run a specific program, you specify the class name that contains the main method
you want to execute.
For example, say you have two classes, Main and AnotherProgram:
1. What Happens When You Run java Main Without Compiling (javac
Main.java)?
When you run the command java Main, the Java Virtual Machine (JVM) expects a file
called Main.class to exist, which is the compiled bytecode of your Java program. This file is
generated when you compile the Java file using javac Main.java.
If you haven't compiled the program yet, there will be no .class file for the JVM to execute.
As a result, the JVM will throw an error.
The JVM will throw an error like this:
Java source code (in .java files) is written in human-readable form, but the JVM doesn't
understand this directly. It can only run bytecode (which is stored in .class files). The
javac command compiles your Java code into bytecode.
javac Main.java: This command compiles the Java code and generates a
Main.class file that contains the bytecode.
java Main: This command runs the bytecode from the Main.class file.
One public class per file: Java enforces this rule because the filename must match the
public class name.
You can have multiple classes in the same file, but only one can be public.
If you need more than one public class, put each class in its own file
7. Access Modifiers
Public members (classes, methods, variables) can be accessed from anywhere in the
program, including different packages.
Classes can be declared public only at the top level (i.e., not inside another class).
Private members (variables, methods, constructors) can only be accessed within the same
class. They are not visible to other classes, even in the same package.
Top-level classes cannot be private, but inner classes can be.
3. Protected Access Modifier
package mypackage;
protected String protectedVar = "I am protected"; // Accessible to subclasses and classes in the
same package
package anotherpackage;
import mypackage.Parent;
}
4. Default Access (Package-Private)
If you don’t specify an access modifier (like public, private, or protected), the default
access level is package-private.
Package-private members are accessible only within the same package, but not from
outside the package, even in subclasses.
Top-level classes can have default access and are accessible only within the same package.
package mypackage;
void showDefault() {
package mypackage;
PackageClass obj = new PackageClass(); // Can access because it's in the same package
1. Encapsulation
Encapsulation is the concept of bundling data (variables) and methods (functions) that
operate on that data into a single unit, called a class. It also involves restricting access to
certain parts of the object’s data and methods using access modifiers (like private, public,
and protected).
Key Ideas:
Keep sensitive data hidden from the outside world using private access.
Provide controlled access to data through getters and setters.
class Student {
// Constructor
this.name = name;
return name;
}
// Setter (controlled modification)
this.name = name;
2. Inheritance
Inheritance allows a class to inherit fields and methods from another class, promoting code
reuse. The class that inherits is called the subclass (or child class), and the class being
inherited from is the superclass (or parent class).
Key Ideas:
The subclass can use the parent class's members (variables and methods).
Inheritance is done using the extends keyword.
// Parent class
class Animal {
}
// Child class
@Override
3. Polymorphism
Compile-time (Method Overloading): Methods with the same name but different
parameters.
Run-time (Method Overriding): A subclass provides a specific implementation of a method
that is already defined in its superclass.
class Calculator {
return a + b;
}
return a + b + c;
//OverRiding
class Animal {
@Override
}
}
Even though the reference type is Animal, the actual object is Cat, and the Cat's
version of makeSound is executed at runtime.
In Animal myAnimal = new Dog();, the reference type is Animal, but the object type is
Dog.
4. Abstraction
Abstraction is the concept of hiding the implementation details and exposing only the
essential features of an object. It can be achieved using abstract classes and interfaces.
Key Ideas:
An abstract class can have both abstract (unimplemented) and non-abstract methods.
An interface is a completely abstract class; it can only have abstract methods (before Java 8).
Java 8 and later allows default and static methods in interfaces.
At the abstract level, you are focusing on what should happen (the behavior), without
worrying about how it is actually done.
The child class (or implementing class) is responsible for providing the specific details of how
to perform that behavior.
// This defines "what" the object can do, but no details on "how"
Now, each specific animal (child class) defines how it makes that sound:
@Override
System.out.println("Dog barks");
@Override
System.out.println("Cat meows");
Achieving Abstraction
The abstraction comes from the fact that, as a user of the Animal class, you don’t need to
know how the Dog or Cat makes a sound. You just need to know that any Animal can make a
sound, and how it does that is left to the child classes to define.
When you write code that interacts with an Animal object, you're dealing with the abstract
behavior — "an animal can make a sound" — without needing to care about the specific
details:
public class Main {
What is Abstraction?
Abstraction is the process of hiding the implementation details and showing only the
essential features of an object. In other words, you focus on what an object does rather than
how it does it.
1. Abstract classes
2. Interfaces
1. Abstract Classes
An abstract class is a class that cannot be instantiated on its own. It may have abstract
methods, which are methods that are declared without an implementation (i.e., the method
just has a name and parameters, but no body). Subclasses are required to provide the
implementation for those abstract methods.
Key Points:
An abstract class can have both abstract methods (without body) and regular methods
(with body).
You cannot create an instance of an abstract class.
Subclasses must override and implement the abstract methods.
@Override
@Override
// Animal myAnimal = new Animal(); // Error: Cannot instantiate the abstract class
Animal dog = new Dog(); // Create a Dog object
2. Interfaces
An interface in Java is another way to achieve abstraction. It defines a contract that any class
implementing the interface must follow. Unlike abstract classes, interfaces can only have
abstract methods (until Java 8, where default methods were introduced).
Key Points:
All methods in an interface are implicitly abstract and public (until Java 8).
A class can implement multiple interfaces, but it can only extend one abstract class.
Interfaces provide full abstraction (no concrete methods, unless using default methods from
Java 8 onwards).
interface Animal {
@Override
}
@Override
@Override
@Override
System.out.println("Vehicle is starting.");
interface Electric {
@Override
@Override
Here we are using Tesla myTesla = new Tesla(); not like Animal cat = new Cat(). Still we are able to
fetch all 3 class.
System.out.println("Vehicle is starting.");
}
interface Electric {
void chargeBattery();
@Override
System.out.println("Tesla is driving.");
@Override
Java does not support multiple inheritance directly through classes. This means a class
cannot extend more than one class. However, Java allows a class to implement multiple
interfaces, which is Java's way of achieving multiple inheritance.
interface Animal {
@Override
System.out.println("Dog eats");
@Override
System.out.println("Dog sleeps");
Java does not support multiple inheritance directly through classes. This means a class
cannot extend more than one class. However, Java allows a class to implement multiple
interfaces, which is Java's way of achieving multiple inheritance.
interface Flyable {
void fly();
interface Swimmable {
void swim();
@Override
System.out.println("Duck flies.");
@Override
System.out.println("Duck swims.");
Here, the Duck class implements two interfaces: Flyable and Swimmable. This means a Duck can
both fly and swim. Even though Java doesn't allow multiple inheritance using classes (i.e., a class
can't extend more than one class), it achieves multiple inheritance through interfaces.
what is difference between extends and implements ?
The terms extends and implements in Java are both used for inheritance, but they serve
different purposes and are used in different contexts. Let’s break down the differences
between them:
1. extends:
Key Points:
class Animal {
void eat() {
System.out.println("Animal is eating");
void bark() {
System.out.println("Dog is barking");
For interfaces, the extends keyword can be used to extend another interface
interface Swimmable {
void swim();
The FastSwimmable interface extends Swimmable, which means any class that implements
FastSwimmable must implement both swim() and swimFast().
2. implements:
Key Points:
interface Flyable {
void fly();
interface Swimmable {
void swim();
@Override
System.out.println("Duck is flying");
@Override
public void swim() {
System.out.println("Duck is swimming");
Here, the Duck class implements both the Flyable and Swimmable interfaces. It must provide
implementations for both fly() and swim() methods.
Starting from Java 8, interfaces can also contain default methods and static methods. This
was introduced to allow interfaces to evolve without breaking existing classes that implement
the interface.
Default Methods:
A default method is a method in an interface that has a body (implementation). It allows the
interface to provide a default behavior that implementing classes can either use or override.
Example:
interface Vehicle {
void drive();
System.out.println("Vehicle is honking");
@Override
System.out.println("Car is driving");
System.out.println("Car is honking");
Here, the Vehicle interface has a default method honk(), which provides a default
implementation. The Car class can use this method or choose to override it.
static Methods:
Interfaces can also have static methods. These methods can be called on the interface itself,
not on the objects of the classes that implement the interface.
Example:
1. Interfaces define the behavior that a class must implement but do not provide the
implementation (except with default methods from Java 8).
2. Multiple inheritance is achieved by allowing a class to implement multiple interfaces.
3. Default methods allow interfaces to provide method implementations, while static methods
allow utility-like methods that can be called on the interface itself.
An exception is an event that occurs during the execution of a program that disrupts its
normal flow. In simpler terms, it's an error or an unwanted event that can occur while your
program is running, like dividing by zero or trying to access an invalid array index.
Java provides a way to handle these exceptions gracefully using exception handling
mechanisms so that the program doesn’t crash abruptly.
2. Types of Exceptions:
Checked Exceptions: These exceptions are checked at compile time by the compiler.
The programmer must handle these exceptions, otherwise, the program won’t
compile. Examples include:
o IOException
o SQLException
o FileNotFoundException
3. Try-Catch Block
To handle exceptions, Java provides the try-catch block. When an exception occurs inside
the try block, the flow of control moves to the corresponding catch block where the
exception is handled.
try {
} catch (ExceptionType e) {
The finally block is used to execute code that must run whether an exception occurs or not. It’s
typically used for clean-up actions like closing files, releasing resources, etc.
try {
} catch (ArrayIndexOutOfBoundsException e) {
} finally {
validateAge(15);
System.out.println("Valid age.");
throws keyword: It is used in the method signature to indicate that a method can throw an
exception, and it must be handled by the caller.
import java.io.*;
6. Custom Exceptions
Java allows you to create your own exceptions. To do this, you create a class that extends
Exception (for checked exceptions) or RuntimeException (for unchecked exceptions).
super(message);
try {
validateAge(15);
} catch (InvalidAgeException e) {
System.out.println(e.getMessage());
System.out.println("Valid age.");
super.method(): Calls a method from the parent class, even if it’s overridden in the child
class.
super.field: Accesses a field from the parent class when there’s a name conflict
between the parent and child classes.
ArrayList (from List interface) is like a dynamic array where you can access
elements in constant time, but inserting or deleting elements in the middle may take
time.
LinkedList (from List interface) is a doubly linked list, which makes it easy to
insert or remove elements at any position, but accessing elements by index is slower
compared to an array.
HashSet (from Set interface) uses a hash table to store elements. It allows constant-
time performance for basic operations (add, remove, check), but doesn’t guarantee
any order of elements.
TreeSet (from Set interface) uses a red-black tree to store elements. It ensures that
the elements are stored in sorted order, but operations take slightly longer
(logarithmic time).
HashMap (from Map interface) uses a hash table to store key-value pairs, providing
constant-time access to keys and values.
TreeMap (from Map interface) uses a red-black tree to store key-value pairs,
ensuring that the keys are always sorted.
Multithreading in Java
Multithreading is a Java feature that allows concurrent execution of two or more parts of a
program, referred to as threads. Each thread runs in parallel, allowing more efficient use of
CPU resources. This is useful when you want to perform multiple tasks at the same time.
1. What is a Thread?
2. Creating Threads in Java
3. Thread Lifecycle
4. Thread Methods
5. Thread Synchronization
6. Deadlock in Threads
1. What is a Thread?
Main Thread: Every Java program has at least one thread, known as the main thread, which
is created by the JVM (Java Virtual Machine).
Multithreading: It is the process of running multiple threads concurrently to perform various
tasks in parallel.
You can create a new class that extends Thread and overrides the run() method to define the
task for the thread.
Example:
System.out.println("Thread is running.");
}
}
Another way is to implement the Runnable interface and pass it to a Thread object.
Example:
System.out.println("Thread is running.");
thread.start();
Both methods are widely used, but implementing Runnable is generally preferred
because it allows the class to extend other classes if needed (since Java does not
support multiple inheritance).
3. Thread Lifecycle
4. Thread Methods
Java provides several methods to control the behavior of threads:
System.out.println(i);
try {
} catch (InterruptedException e) {
System.out.println(e);
thread1.start();
try {
thread1.join(); // Wait for thread1 to finish before starting thread2
} catch (InterruptedException e) {
System.out.println(e);
thread2.start();
5. Thread Synchronization
Thread synchronization is essential when multiple threads try to access shared resources.
Without synchronization, it can lead to race conditions, where the outcome depends on the
thread scheduling and can be inconsistent.
Java provides the synchronized keyword to lock a method or a block of code, ensuring that
only one thread can access it at a time.
class Counter {
count++;
return count;
counter.increment();
});
counter.increment();
});
thread1.start();
thread2.start();
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Final count: " + counter.getCount()); // Should print 2000
Types of Synchronization:
synchronized (this) {
count++;
6. Deadlock in Threads
A deadlock occurs when two or more threads are blocked forever, each waiting for the other
to release a resource. This can happen if threads hold locks on different resources and try to
acquire locks held by the other thread.
Summary:
Java provides various classes and methods to work with files and perform input/output (I/O)
operations. These are primarily located in the java.io and java.nio.file packages.
We'll cover:
1. File Class
2. Reading and Writing Files
3. Streams in Java
4. Working with Buffered Streams
5. Try-with-resources for better resource management
1. File Class
The File class is used to represent file and directory pathnames. You can use it to create,
delete, and check the existence of files and directories, among other things.
import java.io.File;
if (file.exists()) {
System.out.println("File exists.");
} else {
In Java, we can read and write files using different classes like FileReader,
BufferedReader, FileWriter, and BufferedWriter.
We use FileReader for reading character files and wrap it with BufferedReader for
efficient reading of lines.
Example:
import java.io.*;
String line;
System.out.println(line);
} catch (IOException e) {
e.printStackTrace();
}
readLine() reads a line of text and returns null when the end of the file is reached.
FileWriter is used to write characters to a file, and BufferedWriter is used for more
efficient writing.
import java.io.*;
public class Main {
writer.write("Hello, World!");
writer.newLine();
} catch (IOException e) {
e.printStackTrace();
3. Streams in Java
Streams are used to perform input and output operations in Java. A stream is a sequence of
data that flows from a source to a destination.
import java.io.*;
int i;
} catch (IOException e) {
e.printStackTrace();
In this case, FileInputStream reads byte by byte from a file. Each byte is cast to a character
before being printed.
import java.io.*;
fos.write(str.getBytes());
} catch (IOException e) {
e.printStackTrace();
Here, FileOutputStream writes bytes to a file. We convert the string into bytes
using the getBytes() method.
4. Buffered Streams
Buffered streams, such as BufferedInputStream and BufferedOutputStream, are used to
make reading and writing operations more efficient by buffering data. This reduces the
number of I/O operations by reading/writing larger chunks of data at once.
import java.io.*;
int data;
System.out.print((char) data);
} catch (IOException e) {
e.printStackTrace();
BufferedReader is often used with FileReader to improve performance for larger text files.
FileReader is responsible for connecting to the file and reading characters, while
BufferedReader adds buffering, which speeds up the process by reducing the number of
file I/O operations.
1. What is JDBC?
JDBC (Java Database Connectivity) is an API that allows Java applications to interact with
relational databases like MySQL, PostgreSQL, Oracle, etc. It provides methods to execute
SQL queries, retrieve results, and handle database transactions.
2. Setting Up Your Environment
Database Table
sql
Copy code
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50),
email VARCHAR(100)
);
Java Code
java
Copy code
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
// JDBC Connection
try (Connection connection = DriverManager.getConnection(url, user,
password);
Statement statement = connection.createStatement()) {
What is ORM?
Why Hibernate?
1. Setup Hibernate
Install Hibernate in your project using Maven/Gradle or manually add the required
.jar files.
2. Hibernate Configuration
Learn how to configure Hibernate using an XML or hibernate.cfg.xml file and
annotations.
3. Mapping Entities
Map Java classes to database tables using annotations like @Entity and @Table.
4. Basic CRUD with Hibernate
Perform CRUD operations using Hibernate's Session object.
5. Hibernate Query Language (HQL)
Learn how to write object-oriented queries with HQL.
6. Advanced Hibernate Features
Explore caching, transactions, and relationships (@OneToMany, @ManyToOne, etc.).
Generics in Java
1. Basics of Generics
Generics allow you to define classes, interfaces, and methods with type parameters.
// Casting is required
String str = (String) list.get(0);
System.out.println(str);
2. Generic Classes
Example:
java
Copy code
// A generic class with a type parameter T
class Box<T> {
private T item;
public T getItem() {
return item;
}
}
3. Generic Methods
Example:
java
Copy code
public class GenericMethodExample {
// A generic method with type parameter T
public static <T> void printArray(T[] array) {
for (T element : array) {
System.out.println(element);
}
}
System.out.println("String Array:");
printArray(stringArray);
System.out.println("Integer Array:");
printArray(intArray);
}
}
Syntax:
java
Copy code
<T extends Superclass>
Example:
java
Copy code
class Calculator<T extends Number> {
public double add(T num1, T num2) {
return num1.doubleValue() + num2.doubleValue();
}
}
5. Wildcards in Generics
Types of Wildcards:
Unbounded Wildcard:
java
Copy code
public static void printList(List<?> list) {
for (Object item : list) {
System.out.println(item);
}
}
java
Copy code
public static void printNumbers(List<? extends Number> list) {
for (Number num : list) {
System.out.println(num);
}
}
java
Copy code
public static void addNumbers(List<? super Integer> list) {
list.add(10);
}
Annotations in Java
Annotations in Java are special markers or metadata that provide information about the code
but do not affect the program's logic. They are often used to instruct the compiler or provide
runtime hints.
@Override
public String toString() {
return "Example class";
}
@SuppressWarnings("unchecked")
public void unsafeCode() {
List rawList = new ArrayList();
rawList.add("Unchecked warning suppressed.");
}
}
2. Types of Annotations
3. Meta-Annotations
Meta-annotations are annotations that are applied to other annotations to provide additional
information. Common ones include:
Annotation Description
@Retention Specifies how long the annotation is retained: source, class, or runtime.
@Target Specifies where the annotation can be applied (e.g., methods, fields).
java
Copy code
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
java
Copy code
@MyAnnotation(author = "John Doe", date = "2024-11-16", version = 2)
public class MyClass {
java
Copy code
import java.lang.reflect.Method;
5. Key Points
1. Retention Policies:
o SOURCE: Available in the source code but discarded during compilation.
o CLASS: Present in the class file but not available at runtime.
o RUNTIME: Available at runtime and can be accessed via reflection.
2. Targets:
o ElementType.TYPE: Classes, interfaces, enums.
o ElementType.METHOD: Methods.
o ElementType.FIELD: Fields.
3. Default Values:
o Default values are optional and can be overridden when using the annotation.
Would you like to dive deeper into Reflection with annotations or explore real-world
annotations like those in Spring Framework? 😊
4o
You said:
what are reflections ?
ChatGPT said:
ChatGPT
Reflection in Java
What is Reflection?
Reflection is a feature in Java that allows you to inspect, analyze, and manipulate the
structure and behavior of classes, methods, fields, and constructors at runtime. It is part of the
java.lang.reflect package.
1. Inspecting classes and objects at runtime: Retrieve metadata about a class, such as its
methods and fields.
2. Accessing private members: Bypass access modifiers to access private fields or methods.
3. Dynamic method invocation: Call methods dynamically based on runtime information.
4. Frameworks and tools: Many frameworks like Spring and Hibernate rely on reflection for
dynamic proxy creation, dependency injection, and more.
java
Copy code
Class<?> cls = MyClass.class;
java
Copy code
Field field = cls.getDeclaredField("fieldName");
java
Copy code
Method method = cls.getDeclaredMethod("methodName", parameterTypes);
java
Copy code
Constructor<?> constructor =
cls.getDeclaredConstructor(parameterTypes);
Reflection in Action
class MyClass {
private String message = "Hello Reflection!";
}
class MyClass {
public void sayHello(String name) {
System.out.println("Hello, " + name + "!");
}
}
class MyClass {
private String name;
// Invoke method
Method method = cls.getDeclaredMethod("display");
method.invoke(obj);
}
}
Reflection Use Cases
Advantages of Reflection
Disadvantages of Reflection
1. Performance Overhead: Reflection is slower than direct access due to its dynamic nature.
2. Security Risks: Bypassing access modifiers can compromise security.
3. Code Complexity: Makes debugging and maintenance more challenging.
Use reflection sparingly, only when dynamic behavior is essential (e.g., in frameworks or
tools).
Avoid using reflection in performance-critical code or simple use cases where it is
unnecessary.