<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Pratik T on Medium]]></title>
        <description><![CDATA[Stories by Pratik T on Medium]]></description>
        <link>https://medium.com/@pratik.941?source=rss-7f42c99fe66f------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*8J4WfsbMKHyTA_b51Gndtg.jpeg</url>
            <title>Stories by Pratik T on Medium</title>
            <link>https://medium.com/@pratik.941?source=rss-7f42c99fe66f------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Thu, 05 Nov 2026 16:13:05 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@pratik.941/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Understanding SOLID Principles: A Detailed Explanation with Examples]]></title>
            <link>https://medium.com/@pratik.941/understanding-solid-principles-a-detailed-explanation-with-examples-47c606d3f21e?source=rss-7f42c99fe66f------2</link>
            <guid isPermaLink="false">https://medium.com/p/47c606d3f21e</guid>
            <category><![CDATA[oops-interview-questions]]></category>
            <category><![CDATA[backend-development]]></category>
            <category><![CDATA[java]]></category>
            <dc:creator><![CDATA[Pratik T]]></dc:creator>
            <pubDate>Wed, 30 Apr 2025 04:33:14 GMT</pubDate>
            <atom:updated>2025-04-30T04:33:14.941Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/474/0*iq7RXHeUwwpZmsD4" /></figure><p>SOLID is an acronym for five fundamental principles of ObjectOriented Programming (OOP) and design. These principles help developers create maintainable, scalable, and flexible software. Introduced by Robert C. Martin (Uncle Bob), these principles are now standard guidelines for writing clean and efficient code.</p><h4>1. Single Responsibility Principle (SRP)</h4><p>Definition:A class should have only one reason to change, meaning it should handle only one responsibility.</p><p>Explanation:If a class has multiple jobs, changes in one part can affect unrelated functionality. Separating responsibilities improves maintainability and testability.</p><p>❌ Violation:</p><p>In an online store, if a OrderService class is responsible for placing orders, processing payments, and sending confirmation emails, it’s doing too much.</p><pre>class OrderService {<br>    void placeOrder() { /* order logic */ }<br>    void processPayment() { /* payment logic */ }<br>    void sendConfirmationEmail() { /* email logic */ }<br>}</pre><p>✅ Solution:Split responsibilities</p><pre>class OrderService { void placeOrder() { } }<br>class PaymentService { void processPayment() { } }<br>class EmailService { void sendEmail() { } }</pre><p>🎯 Each service now has <strong>one job</strong>, making them easier to maintain and test.</p><h4><strong>2. 🔓 Open/Closed Principle (OCP)</strong></h4><p>✅ Definition:Software entities should be open for extension but closed for modification.</p><p>📝 Explanation:You should be able to add new behavior without changing existing code. Use inheritance or interfaces.</p><p>❌ Violation:</p><pre>class PaymentProcessor {<br>    double pay(String gateway, double amount) {<br>        if (gateway.equals(&quot;Stripe&quot;)) return amount * 0.98;<br>        else if (gateway.equals(&quot;PayPal&quot;)) return amount * 0.95;<br>        return amount;<br>    }<br>}</pre><p>Adding a new discount type requires modifying this class.</p><p>✅ Solution:</p><pre>interface PaymentGateway {<br>    double processPayment(double amount);<br>}<br><br>class StripeGateway implements PaymentGateway {<br>    public double processPayment(double amount) { return amount * 0.98; }<br>}<br><br>class PayPalGateway implements PaymentGateway {<br>    public double processPayment(double amount) { return amount * 0.95; }<br>}</pre><p>Now, you can add new discount types without modifying existing classes.</p><h4>3. 🧬 Liskov Substitution Principle (LSP)</h4><p>✅ Definition:Subclasses should be substitutable for their parent classes without breaking functionality.</p><p>📝 Explanation:You should be able to use a subclass anywhere a parent class is expected, and it should behave properly.</p><h3>Example: Document Generation System</h3><p>In a reporting tool, you generate multiple formats: PDF, Word, Excel. All documents should follow a common interface.</p><p>❌ Violation:</p><pre>class Document {<br>    void print() { System.out.println(&quot;Printing...&quot;); }<br>}<br><br>class SecurePDF extends Document {<br>    @Override<br>    void print() {<br>        throw new UnsupportedOperationException(&quot;Secure PDFs can&#39;t be printed&quot;);<br>    }<br>}</pre><p>✅ Solution:</p><pre>class Document { /* common functionality */ }<br><br>class PrintableDocument extends Document {<br>    void print() { System.out.println(&quot;Printing...&quot;); }<br>}<br><br>class SecurePDF extends Document {<br>    // No print() method here<br>}</pre><p>🎯 Substituting subclasses won’t break behavior expected by the system.</p><h4>4. 🧩 Interface Segregation Principle (ISP)</h4><p>✅ Definition:Clients should not be forced to depend on methods they do not use.</p><p>📝 Explanation:Use smaller, more specific interfaces instead of one large interface.</p><h3>Example: Banking Software — Different User Roles</h3><p>A BankUser interface shouldn&#39;t force all users (e.g., tellers, customers, auditors) to implement all actions.</p><p>❌ Violation:</p><pre>interface BankUser {<br>    void withdrawCash();<br>    void approveLoan();<br>    void viewAuditLogs();<br>}</pre><p>A teller might not approve loans, and an auditor doesn’t need to withdraw cash.</p><p>✅ Solution:</p><pre>interface CashHandler {<br>    void withdrawCash();<br>}<br><br>interface LoanManager {<br>    void approveLoan();<br>}<br><br>interface Auditor {<br>    void viewAuditLogs();<br>}</pre><p>🎯 Each role implements <strong>only what it needs</strong>.</p><h4>5. 🔌 Dependency Inversion Principle (DIP)</h4><p>✅ Definition:</p><p>Highlevel modules should not depend on lowlevel modules. Both should depend on abstractions.</p><p>📝 Explanation:Use interfaces or abstract classes to reduce tight coupling.</p><h3>Example: Notification System in Enterprise Applications</h3><p>An app needs to send notifications via SMS, email, or push notifications.</p><p>❌ Violation:</p><pre>class NotificationService {<br>    EmailSender sender = new EmailSender();<br>    void notifyUser() { sender.sendEmail(); }<br>}</pre><p>✅ Solution:</p><pre>interface Notifier {<br>    void notifyUser(String message);<br>}<br><br>class EmailSender implements Notifier {<br>    public void notifyUser(String message) { /* send email */ }<br>}<br><br>class SMSender implements Notifier {<br>    public void notifyUser(String message) { /* send SMS */ }<br>}<br><br>class NotificationService {<br>    private Notifier notifier;<br>    public NotificationService(Notifier notifier) {<br>        this.notifier = notifier;<br>    }<br><br>    void send(String message) {<br>        notifier.notifyUser(message);<br>    }<br>}</pre><p>🎯 This design allows switching between notification types easily and is easier to test with mocks.</p><h4>🏁 Conclusion</h4><p>SOLID principles help create better software architecture.</p><p>Here’s a quick recap:</p><p>✅ SRP: One class = one responsibility</p><p>✅ OCP: Extend behavior without changing existing code</p><p>✅ LSP: Subtypes must be replaceable without errors</p><p>✅ ISP: Avoid forcing classes to use methods they don’t need</p><p>✅ DIP: Depend on abstractions, not concrete classes</p><p>➡️ Applying these principles makes code easier to understand, reuse, test, and maintain.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=47c606d3f21e" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Exception Handling in REST API]]></title>
            <link>https://medium.com/@pratik.941/exception-handling-in-rest-api-be74cd8c62b8?source=rss-7f42c99fe66f------2</link>
            <guid isPermaLink="false">https://medium.com/p/be74cd8c62b8</guid>
            <category><![CDATA[java]]></category>
            <category><![CDATA[back-end-development]]></category>
            <category><![CDATA[rest-api]]></category>
            <category><![CDATA[spring-boot]]></category>
            <dc:creator><![CDATA[Pratik T]]></dc:creator>
            <pubDate>Sat, 01 Mar 2025 07:37:07 GMT</pubDate>
            <atom:updated>2025-03-01T07:37:07.790Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/450/0*NDJzDL-KKMNqZk53" /></figure><p>Exception handling is a critical aspect of building robust and userfriendly REST APIs. When something goes wrong in your application — be it a validation error, a database issue, or an unexpected server error — it’s essential to handle these exceptions gracefully and provide meaningful feedback to the client. In this article, we’ll explore how to handle exceptions in REST APIs using Spring Boot, along with best practices and examples.</p><h4>Why is Exception Handling Important?</h4><p>1. <strong>Improved User Experience:</strong> Clients receive clear and meaningful error messages instead of cryptic stack traces.</p><p>2.<strong> Debugging and Maintenance</strong>: Proper exception handling makes it easier to identify and fix issues.</p><p>3. <strong>Consistency</strong>: Standardized error responses ensure consistency across your API.</p><h4>Key Concepts in REST API Exception Handling</h4><p><strong>1. HTTP Status Codes</strong></p><p>HTTP status codes are used to indicate the result of a client’s request. Some common status codes include:</p><p>2xx (Success): 200 OK, 201 Created</p><p>4xx (Client Errors): 400 Bad Request, 404 Not Found</p><p>5xx (Server Errors): 500 Internal Server Error</p><p><strong>2. Error Response Structure</strong></p><p>A well structured error response typically includes:</p><p>Status Code: The HTTP status code.</p><p>Message: A human readable error message.</p><p>Details: Additional information about the error (optional).</p><p>Timestamp: When the error occurred (optional).</p><p>Example:</p><pre>{<br>  &quot;status&quot;: 404,<br>  &quot;message&quot;: &quot;Resource not found&quot;,<br>  &quot;details&quot;: &quot;The requested resource with ID 123 does not exist.&quot;,<br>  &quot;timestamp&quot;: &quot;2023-10-25T12:34:56Z&quot;<br>}</pre><h4>Exception Handling in Spring Boot</h4><p>Spring Boot provides several mechanisms to handle exceptions in REST APIs. Let’s explore them step by step.</p><p><strong>1. Custom Exception Class</strong></p><p>Create a custom exception class to represent specific errors in your application.</p><pre>public class ResourceNotFoundException extends RuntimeException {<br>    public ResourceNotFoundException(String message) {<br>        super(message);<br>    }<br>}</pre><p><strong>2. Global Exception Handler</strong></p><p>Use the @ControllerAdvice and @ExceptionHandler annotations to create a global exception handler. This ensures that all exceptions are handled consistently across your application.</p><pre>@ControllerAdvice<br>public class GlobalExceptionHandler {<br><br>    @ExceptionHandler(ResourceNotFoundException.class)<br>    public ResponseEntity&lt;ErrorResponse&gt; handleResourceNotFoundException(ResourceNotFoundException ex) {<br>        ErrorResponse errorResponse = new ErrorResponse(<br>            404,<br>            ex.getMessage(),<br>            &quot;The requested resource was not found.&quot;,<br>            LocalDateTime.now()<br>        );<br>        return new ResponseEntity&lt;&gt;(errorResponse, HttpStatus.NOT_FOUND);<br>    }<br><br>    @ExceptionHandler(Exception.class)<br>    public ResponseEntity&lt;ErrorResponse&gt; handleGenericException(Exception ex) {<br>        ErrorResponse errorResponse = new ErrorResponse(<br>            500,<br>            &quot;An unexpected error occurred.&quot;,<br>            ex.getMessage(),<br>            LocalDateTime.now()<br>        );<br>        return new ResponseEntity&lt;&gt;(errorResponse, HttpStatus.INTERNAL_SERVER_ERROR);<br>    }<br>}</pre><p><strong>3. Error Response Class</strong></p><p>Create a class to represent the error response structure.</p><pre>public class ErrorResponse {<br>    private int status;<br>    private String message;<br>    private String details;<br>    private LocalDateTime timestamp;<br><br>    // Constructor, Getters, and Setters<br>}</pre><p><strong>4. Throwing Exceptions in Service Layer</strong></p><p>Throw custom exceptions in your service layer when specific conditions are met.</p><pre>@Service<br>public class UserService {<br><br>    @Autowired<br>    private UserRepository userRepository;<br><br>    public User getUserById(Long id) {<br>        return userRepository.findById(id)<br>            .orElseThrow(() -&gt; new ResourceNotFoundException(&quot;User not found with ID: &quot; + id));<br>    }<br>}</pre><p><strong>5. Example: REST Controller</strong></p><p>Use the service layer in your controller and let the global exception handler manage exceptions.</p><pre>@RestController<br>@RequestMapping(&quot;/users&quot;)<br>public class UserController {<br><br>    @Autowired<br>    private UserService userService;<br><br>    @GetMapping(&quot;/{id}&quot;)<br>    public ResponseEntity&lt;User&gt; getUserById(@PathVariable Long id) {<br>        User user = userService.getUserById(id);<br>        return new ResponseEntity&lt;&gt;(user, HttpStatus.OK);<br>    }<br>}</pre><p><strong>Best Practices for Exception Handling</strong></p><p><strong>1. Use Specific Exceptions:</strong> Create custom exceptions for specific error scenarios (e.g., ResourceNotFoundException, ValidationException).</p><p><strong>2. Return Meaningful Error Messages:</strong> Provide clear and actionable error messages to the client.</p><p><strong>3. Log Exceptions:</strong> Log exceptions for debugging and monitoring purposes.</p><p><strong>4. Use HTTP Status Codes Correctly:</strong> Follow REST conventions for status codes (e.g., 404 for missing resources, 400 for bad requests).</p><p><strong>5. Avoid Exposing Sensitive Information:</strong> Do not include stack traces or internal details in production error responses.</p><h4><strong>Example: Complete Workflow</strong></h4><p>Step 1: Client Sends a Request</p><pre>GET /users/123</pre><p>Step 2: Service Layer Throws an Exception</p><pre>public User getUserById(Long id) {<br>    return userRepository.findById(id)<br>        .orElseThrow(() -&gt; new ResourceNotFoundException(&quot;User not found with ID: &quot; + id));<br>}</pre><p>Step 3: Global Exception Handler Catches the Exception</p><pre>@ExceptionHandler(ResourceNotFoundException.class)<br>public ResponseEntity&lt;ErrorResponse&gt; handleResourceNotFoundException(ResourceNotFoundException ex) {<br>    ErrorResponse errorResponse = new ErrorResponse(<br>        404,<br>        ex.getMessage(),<br>        &quot;The requested resource was not found.&quot;,<br>        LocalDateTime.now()<br>    );<br>    return new ResponseEntity&lt;&gt;(errorResponse, HttpStatus.NOT_FOUND);<br>}</pre><p>Step 4: Client Receives the Error Response</p><pre>{<br>  &quot;status&quot;: 404,<br>  &quot;message&quot;: &quot;User not found with ID: 123&quot;,<br>  &quot;details&quot;: &quot;The requested resource was not found.&quot;,<br>  &quot;timestamp&quot;: &quot;2023-10-25T12:34:56Z&quot;<br>}</pre><p><strong>Conclusion</strong></p><p>Exception handling is a crucial part of building reliable and userfriendly REST APIs. By using custom exceptions, global exception handlers, and structured error responses, you can ensure that your API provides meaningful feedback to clients and simplifies debugging for developers.</p><p>In this article, we covered:</p><p>The importance of exception handling.</p><p>How to implement exception handling in Spring Boot.</p><p>Best practices for designing error responses.</p><p>With these techniques, you can build REST APIs that are robust, maintainable, and easy to use. Happy coding!</p><p>If you found this article helpful, feel free to share it with your network. Let me know your thoughts in the comments below!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=be74cd8c62b8" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Spring vs. Spring Boot: Understanding the Key Differences with Examples]]></title>
            <link>https://medium.com/@pratik.941/spring-vs-spring-boot-understanding-the-key-differences-with-examples-aff8f27d243d?source=rss-7f42c99fe66f------2</link>
            <guid isPermaLink="false">https://medium.com/p/aff8f27d243d</guid>
            <category><![CDATA[spring]]></category>
            <category><![CDATA[java-backend]]></category>
            <category><![CDATA[spring-boot]]></category>
            <dc:creator><![CDATA[Pratik T]]></dc:creator>
            <pubDate>Sat, 01 Mar 2025 05:45:56 GMT</pubDate>
            <atom:updated>2025-03-01T08:56:31.088Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*EWhH6NLwb46IcUKZTgDATw.png" /></figure><p>If you’re a Java developer, chances are you’ve heard of Spring Framework and Spring Boot. Both are part of the Spring ecosystem, but they serve different purposes and cater to different needs. While Spring Framework is the foundation for building Java applications, Spring Boot is a game-changer that simplifies the development process. In this article, well dive deep into the differences between Spring and Spring Boot, explore their use cases, and provide practical examples to help you understand when and why to use each.</p><p><strong>What is Spring Framework?</strong></p><p>Spring Framework is a comprehensive, modular framework for building enterprise-level Java applications. It provides infrastructure support for dependency injection, transaction management, web applications, data access, messaging, and more. However, with great power comes great responsibility — Spring Framework requires developers to configure many components manually, which can be time-consuming.</p><p><strong>Key Features of Spring Framework</strong><br> — <strong>Dependency Injection (DI)</strong>: Promotes loose coupling and easier testing.<br> — <strong>Aspect-Oriented Programming (AOP)</strong>: Enables modularization of cross-cutting concerns.<br> — <strong>Data Access</strong>: Simplifies database access with JDBC, ORM, and transaction management.<br> — <strong>Web Framework</strong>: Supports MVC architecture for building web applications.</p><p><strong>Example of Spring Framework</strong><br> Heres an example of a manually configured Spring MVC application:</p><pre>@Configuration<br>@EnableWebMvc<br>@ComponentScan(basePackages = &quot;com.example&quot;)<br>public class AppConfig implements WebMvcConfigurer {<br>    // Define beans and configurations manually<br>}<br><br>// Main class to deploy on an external server<br>public class Main {<br>    public static void main(String[] args) {<br>        // Deploy as WAR to Tomcat<br>    }<br>}</pre><p>In this example, you need to manually configure the DispatcherServlet, view resolvers, and other beans. Additionally, you must deploy the application to an external server like Apache Tomcat.</p><p><strong>What is Spring Boot?</strong></p><p>Spring Boot is an extension of the Spring Framework designed to simplify the development of Spring-based applications. It provides defaults and auto-configuration to reduce boilerplate code and setup time. Spring Boot is particularly useful for creating stand-alone, production-grade applications with minimal effort.</p><p><strong>Key Features of Spring Boot</strong><br> — <strong>Auto-Configuration</strong>: Automatically configures beans based on dependencies.<br> — <strong>Embedded Server</strong>: Comes with Tomcat, Jetty, or Undertow by default.<br> — <strong>Starter Dependencies</strong>: Simplifies dependency management.<br> — <strong>Spring Boot Actuator</strong>: Provides built-in monitoring and management tools.</p><p><strong>Example of Spring Boot</strong><br> Heres an example of a Spring Boot application:</p><pre>@SpringBootApplication<br>public class MyApp {<br>    public static void main(String[] args) {<br>        SpringApplication.run(MyApp.class, args);<br>    }<br>}<br><br>@RestController<br>public class MyController {<br>    @GetMapping(&quot;/hello&quot;)<br>    public String sayHello() {<br>        return &quot;Hello, Spring Boot!&quot;;<br>    }<br>}</pre><p>In this example, Spring Boot automatically configures the embedded server, data source, and other components. You can run the application as a standalone JAR file without needing an external server.</p><p><strong>Key Differences Between Spring and Spring Boot</strong></p><p>Lets break down the differences between Spring Framework and Spring Boot in detail:</p><p><strong>1. Configuration</strong><br> — Spring Framework: Requires explicit configuration for most components (e.g., XML or Java-based configuration).<br> — Spring Boot: Uses auto-configuration to reduce manual setup.</p><p>Example:<br> — In Spring Framework, you manually configure a DataSource:</p><pre>&lt;bean id=&quot;dataSource&quot; class=&quot;org.springframework.jdbc.datasource.DriverManagerDataSource&quot;&gt;<br>    &lt;property name=&quot;driverClassName&quot; value=&quot;com.mysql.cj.jdbc.Driver&quot;/&gt;<br>    &lt;property name=&quot;url&quot; value=&quot;jdbc:mysql://localhost:3306/mydb&quot;/&gt;<br>    &lt;property name=&quot;username&quot; value=&quot;root&quot;/&gt;<br>    &lt;property name=&quot;password&quot; value=&quot;password&quot;/&gt;<br>&lt;/bean&gt;</pre><p>- In Spring Boot, you simply add the configuration in</p><pre>spring.datasource.url=jdbc:mysql://localhost:3306/mydb<br> spring.datasource.username=root<br> spring.datasource.password=password<br> spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver</pre><p><strong>2. Dependency Management</strong><br> — Spring Framework: Developers need to manually manage dependencies and resolve version conflicts.<br> — Spring Boot: Provides starter dependencies to simplify dependency management.</p><p>Example:<br> — In Spring Framework, you add dependencies manually:</p><pre>&lt;dependency&gt;<br>    &lt;groupId&gt;org.springframework&lt;/groupId&gt;<br>    &lt;artifactId&gt;spring-webmvc&lt;/artifactId&gt;<br>    &lt;version&gt;5.3.20&lt;/version&gt;<br>&lt;/dependency&gt;</pre><p>In Spring Boot, you use starter dependencies:</p><pre>&lt;dependency&gt;<br>    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;<br>    &lt;artifactId&gt;spring-boot-starter-web&lt;/artifactId&gt;<br>&lt;/dependency&gt;<br></pre><p><strong>3. Embedded Server</strong><br> — Spring Framework: Does not include an embedded server. You need to deploy the application to an external server like Tomcat.<br> — Spring Boot: Comes with an embedded server (Tomcat, Jetty, or Undertow) by default.</p><p><strong>4. Development Speed</strong><br> — Spring Framework: Requires more time for setup and configuration.<br> — Spring Boot: Speeds up development with defaults and auto-configuration.</p><p><strong>5. Use Cases</strong><br> — Spring Framework: Suitable for large, complex applications where fine-grained control over configuration is required.<br> — Spring Boot: Ideal for microservices, REST APIs, and rapid prototyping.</p><p><strong>When to Use Spring Framework vs. Spring Boot?</strong></p><p>- Use Spring Framework when:<br> — You need full control over configuration.<br> — You’re building large, complex applications with custom requirements.</p><ul><li>Use Spring Boot when:<br> — You want to quickly develop stand-alone, production-ready applications.<br> — Youre building microservices or REST APIs.<br> — You want to reduce boilerplate code and configuration.</li></ul><p>Thus,</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Es64tbjWCKXZwE8i2jqWjQ.png" /></figure><p><strong>Conclusion</strong></p><p>Both Spring Framework and Spring Boot are powerful tools in the Java ecosystem, but they cater to different needs. Spring Framework provides the foundation and flexibility for building complex applications, while Spring Boot simplifies and accelerates the development process. By understanding their differences and use cases, you can choose the right tool for your project and build robust, scalable applications with ease.</p><p>Whether you’re building an enterprise-level application with Spring Framework or a microservice with Spring Boot, the Spring ecosystem has you covered. Happy coding! 🚀</p><p>If you found this article helpful, feel free to share it with your network. Let me know your thoughts in the comments below!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=aff8f27d243d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to Use Thymeleaf with Spring Boot]]></title>
            <link>https://medium.com/@pratik.941/how-to-use-thymeleaf-with-spring-boot-cea17f0d5340?source=rss-7f42c99fe66f------2</link>
            <guid isPermaLink="false">https://medium.com/p/cea17f0d5340</guid>
            <category><![CDATA[springboot-3]]></category>
            <category><![CDATA[thymeleaf]]></category>
            <category><![CDATA[java]]></category>
            <dc:creator><![CDATA[Pratik T]]></dc:creator>
            <pubDate>Sat, 22 Feb 2025 11:05:27 GMT</pubDate>
            <atom:updated>2025-02-22T11:10:55.930Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*bNMqO82cclNIogIx.png" /></figure><p>Thymeleaf is a modern server-side Java template engine that is widely used with Spring Boot for rendering HTML views. It integrates seamlessly with Spring MVC and provides a natural way to create dynamic web pages. In this tutorial, we’ll walk through the steps to set up a Spring Boot project with Thymeleaf, create a simple web application, and explore some of Thymeleaf’s key features.</p><h4><strong>Step 1: Set Up a Spring Boot Project</strong></h4><p>To get started, create a Spring Boot project using Spring Initializr:</p><p>1. Go to <a href="https://start.spring.io/">https://start.spring.io/</a>.</p><p>2. Add the following dependencies:</p><p>- Spring Web (for building web applications).</p><p>- Thymeleaf (for templating).</p><p>3. Generate the project and download the ZIP file.</p><p>4. Extract the ZIP file and open it in your favorite IDE (e.g., IntelliJ IDEA, Eclipse).</p><h4>Step 2: Project Structure</h4><p>Your project structure should look like this:</p><pre>src<br>├── main<br>│   ├── java<br>│   │   └── com<br>│   │       └── example<br>│   │           └── demo<br>│   │               ├── DemoApplication.java<br>│   │               ├── controller<br>│   │               │   └── HomeController.java<br>│   │               └── model<br>│   │                   └── User.java<br>│   └── resources<br>│       ├── static<br>│       ├── templates<br>│       │   └── home.html<br>│       └── application.properties<br>└── test<br>    └── java</pre><h4>Step 3: Add Thymeleaf Dependency</h4><p>If you didn’t use Spring Initializr, add the Thymeleaf dependency to your `pom.xml`:</p><pre>&lt;dependency&gt;<br>    &lt;groupId&gt;org.springframework.boot&lt;/groupId&gt;<br>    &lt;artifactId&gt;spring-boot-starter-thymeleaf&lt;/artifactId&gt;<br>&lt;/dependency&gt;</pre><h4>Step 4: Create a Model Class</h4><p>Create a simple `User` class to represent data:</p><pre>package com.example.demo.model;<br><br>public class User {<br>    private String name;<br>    private String email;<br><br>    // Constructors, Getters, and Setters<br>    public User() {}<br><br>    public User(String name, String email) {<br>        this.name = name;<br>        this.email = email;<br>    }<br><br>    public String getName() {<br>        return name;<br>    }<br><br>    public void setName(String name) {<br>        this.name = name;<br>    }<br><br>    public String getEmail() {<br>        return email;<br>    }<br><br>    public void setEmail(String email) {<br>        this.email = email;<br>    }<br>}</pre><h4>Step 5: Create a Controller</h4><p>Create a `HomeController` class to handle requests and pass data to the view:</p><pre>package com.example.demo.controller;<br><br>import com.example.demo.model.User;<br>import org.springframework.stereotype.Controller;<br>import org.springframework.ui.Model;<br>import org.springframework.web.bind.annotation.GetMapping;<br><br>@Controller<br>public class HomeController {<br><br>    @GetMapping(&quot;/&quot;)<br>    public String home(Model model) {<br>        // Add data to the model<br>        model.addAttribute(&quot;message&quot;, &quot;Hello, Thymeleaf!&quot;);<br><br>        // Create a User object<br>        User user = new User(&quot;John Doe&quot;, &quot;john.doe@example.com&quot;);<br>        model.addAttribute(&quot;user&quot;, user);<br><br>        // Return the Thymeleaf template name (home.html)<br>        return &quot;home&quot;;<br>    }<br>}</pre><h4>Step 6: Create a Thymeleaf Template</h4><p>Create a `home.html` file in the `src/main/resources/templates` directory:</p><pre>&lt;!DOCTYPE html&gt;<br>&lt;html xmlns:th=&quot;http://www.thymeleaf.org&quot;&gt;<br>&lt;head&gt;<br>    &lt;meta charset=&quot;UTF-8&quot;&gt;<br>    &lt;title&gt;Home Page&lt;/title&gt;<br>&lt;/head&gt;<br>&lt;body&gt;<br>    &lt;h1 th:text=&quot;${message}&quot;&gt;Default Message&lt;/h1&gt;<br><br>    &lt;h2&gt;User Information&lt;/h2&gt;<br>    &lt;p&gt;Name: &lt;span th:text=&quot;${user.name}&quot;&gt;Default Name&lt;/span&gt;&lt;/p&gt;<br>    &lt;p&gt;Email: &lt;span th:text=&quot;${user.email}&quot;&gt;Default Email&lt;/span&gt;&lt;/p&gt;<br><br>    &lt;h3&gt;Thymeleaf Features&lt;/h3&gt;<br>    &lt;ul&gt;<br>        &lt;li th:each=&quot;i : ${#numbers.sequence(1, 5)}&quot;&gt;<br>            Item &lt;span th:text=&quot;${i}&quot;&gt;&lt;/span&gt;<br>        &lt;/li&gt;<br>    &lt;/ul&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;</pre><h4>Step 7: Run the Application</h4><p>1. Open `DemoApplication.java` (the main class) and run it.</p><p>2. Open your browser and go to `http://localhost:8080/`.</p><p>3. You should see the following output:</p><pre>Hello, Thymeleaf!<br>User Information<br>Name: John Doe<br>Email: john.doe@example.com<br>Thymeleaf Features<br>• Item 1<br>• Item 2<br>• Item 3<br>• Item 4<br>• Item 5</pre><h4>Step 8: Explanation of Thymeleaf Features</h4><p>1. Thymeleaf Attributes:</p><p>- `th:text`: Replaces the text content of an HTML element.</p><p>- `th:each`: Iterates over a collection (e.g., list, array).</p><p>- `th:if`: Conditionally displays an element.</p><p>2. Expression Utility Objects:</p><p>- `${numbers.sequence(1, 5)}`: Generates a sequence of numbers.</p><p>- `${dates.format(date, ‘dd/MM/yyyy’)}`: Formats a date.</p><p>3. Model Data:</p><p>- Data passed from the controller (`model.addAttribute`) can be accessed in the template using `${attributeName}`.</p><h4>Step 9: Add Static Resources</h4><p>1. Add a CSS file in `src/main/resources/static/css/styles.css`:</p><pre>body {<br>    font-family: Arial, sans-serif;<br>    background-color: #f0f0f0;<br>}<br>h1 {<br>    color: #333;<br>}</pre><p>2. Link the CSS file in `home.html`:</p><pre>&lt;link th:href=&quot;@{/css/styles.css}&quot; rel=&quot;stylesheet&quot;&gt;</pre><p>Step 10: Add Form Handling</p><p>1. Update the `HomeController` to handle form submissions:</p><pre>@GetMapping(&quot;/form&quot;)<br>public String showForm(Model model) {<br>    model.addAttribute(&quot;user&quot;, new User());<br>    return &quot;form&quot;;<br>}<br><br>@PostMapping(&quot;/submit&quot;)<br>public String submitForm(@ModelAttribute User user, Model model) {<br>    model.addAttribute(&quot;user&quot;, user);<br>    return &quot;result&quot;;<br>}</pre><p>2. Create a `form.html` template:</p><pre>&lt;!DOCTYPE html&gt;<br>&lt;html xmlns:th=&quot;http://www.thymeleaf.org&quot;&gt;<br>&lt;head&gt;<br>    &lt;meta charset=&quot;UTF-8&quot;&gt;<br>    &lt;title&gt;User Form&lt;/title&gt;<br>&lt;/head&gt;<br>&lt;body&gt;<br>    &lt;h1&gt;User Form&lt;/h1&gt;<br>    &lt;form th:action=&quot;@{/submit}&quot; th:object=&quot;${user}&quot; method=&quot;post&quot;&gt;<br>        &lt;label for=&quot;name&quot;&gt;Name:&lt;/label&gt;<br>        &lt;input type=&quot;text&quot; id=&quot;name&quot; th:field=&quot;*{name}&quot; required&gt;&lt;br&gt;<br><br>        &lt;label for=&quot;email&quot;&gt;Email:&lt;/label&gt;<br>        &lt;input type=&quot;email&quot; id=&quot;email&quot; th:field=&quot;*{email}&quot; required&gt;&lt;br&gt;<br><br>        &lt;button type=&quot;submit&quot;&gt;Submit&lt;/button&gt;<br>    &lt;/form&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;</pre><p>3. Create a `result.html` template to display the submitted data:</p><pre>&lt;!DOCTYPE html&gt;<br>&lt;html xmlns:th=&quot;http://www.thymeleaf.org&quot;&gt;<br>&lt;head&gt;<br>    &lt;meta charset=&quot;UTF-8&quot;&gt;<br>    &lt;title&gt;Result&lt;/title&gt;<br>&lt;/head&gt;<br>&lt;body&gt;<br>    &lt;h1&gt;Submitted User Information&lt;/h1&gt;<br>    &lt;p&gt;Name: &lt;span th:text=&quot;${user.name}&quot;&gt;&lt;/span&gt;&lt;/p&gt;<br>    &lt;p&gt;Email: &lt;span th:text=&quot;${user.email}&quot;&gt;&lt;/span&gt;&lt;/p&gt;<br>    &lt;a href=&quot;/form&quot;&gt;Back to Form&lt;/a&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;</pre><p>Step 11: Test the Application</p><p>1. Run the application and navigate to `http://localhost:8080/form`.</p><p>2. Fill out the form and submit it.</p><p>3. You should see the submitted data displayed on the `result.html` page.</p><h3>Advanced Features and Best Practices</h3><h4>1. Thymeleaf Layouts and Fragments</h4><p>One of the most powerful features of Thymeleaf is its support for layouts and fragments. This allows you to create reusable templates and avoid duplicating code.</p><p><strong>Step 1: Create a Layout Template</strong></p><p>Create a `layout.html` file in the `templates` folder. This will serve as the base template for your application.</p><pre>&lt;!DOCTYPE html&gt;<br>&lt;html xmlns:th=&quot;http://www.thymeleaf.org&quot;&gt;<br>&lt;head&gt;<br>    &lt;meta charset=&quot;UTF-8&quot;&gt;<br>    &lt;title&gt;My Application&lt;/title&gt;<br>    &lt;link th:href=&quot;@{/css/styles.css}&quot; rel=&quot;stylesheet&quot;&gt;<br>&lt;/head&gt;<br>&lt;body&gt;<br>    &lt;header&gt;<br>        &lt;h1&gt;My Application&lt;/h1&gt;<br>        &lt;nav&gt;<br>            &lt;a th:href=&quot;@{/}&quot;&gt;Home&lt;/a&gt;<br>            &lt;a th:href=&quot;@{/form}&quot;&gt;Form&lt;/a&gt;<br>        &lt;/nav&gt;<br>    &lt;/header&gt;<br><br>    &lt;main&gt;<br>        &lt;!-- Content will be inserted here --&gt;<br>        &lt;div th:replace=&quot;~{::content}&quot;&gt;&lt;/div&gt;<br>    &lt;/main&gt;<br><br>    &lt;footer&gt;<br>        &lt;p&gt;&amp;copy; 2023 My Application&lt;/p&gt;<br>    &lt;/footer&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;</pre><p>Step 2: Define Fragments</p><p>Fragments are reusable pieces of HTML that can be included in other templates. For example, create a `fragments.html` file:</p><pre>&lt;!DOCTYPE html&gt;<br>&lt;html xmlns:th=&quot;http://www.thymeleaf.org&quot;&gt;<br>&lt;body&gt;<br>    &lt;div th:fragment=&quot;header&quot;&gt;<br>        &lt;h1&gt;Welcome to My Application&lt;/h1&gt;<br>    &lt;/div&gt;<br><br>    &lt;div th:fragment=&quot;footer&quot;&gt;<br>        &lt;p&gt;&amp;copy; 2023 My Application&lt;/p&gt;<br>    &lt;/div&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;</pre><p>Step 3: Use Layouts and Fragments</p><p>Now, update your `home.html` to use the layout and fragments:</p><pre>&lt;!DOCTYPE html&gt;<br>&lt;html xmlns:th=&quot;http://www.thymeleaf.org&quot;<br>      th:replace=&quot;~{layout :: layout}&quot;&gt;<br>&lt;head&gt;<br>    &lt;title&gt;Home Page&lt;/title&gt;<br>&lt;/head&gt;<br>&lt;body&gt;<br>    &lt;div th:replace=&quot;~{fragments :: header}&quot;&gt;&lt;/div&gt;<br><br>    &lt;div th:fragment=&quot;content&quot;&gt;<br>        &lt;h2&gt;Home Page Content&lt;/h2&gt;<br>        &lt;p&gt;This is the home page of my application.&lt;/p&gt;<br>    &lt;/div&gt;<br><br>    &lt;div th:replace=&quot;~{fragments :: footer}&quot;&gt;&lt;/div&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;</pre><p>2. Conditional Rendering with `th:if` and `th:unless`</p><p>Thymeleaf provides `th:if` and `th:unless` for conditional rendering. This is useful for displaying content based on certain conditions.</p><p>Example: Conditional Rendering</p><pre>&lt;div th:if=&quot;${user != null}&quot;&gt;<br>    &lt;p&gt;Welcome, &lt;span th:text=&quot;${user.name}&quot;&gt;&lt;/span&gt;!&lt;/p&gt;<br>&lt;/div&gt;<br>&lt;div th:unless=&quot;${user != null}&quot;&gt;<br>    &lt;p&gt;Please &lt;a th:href=&quot;@{/login}&quot;&gt;log in&lt;/a&gt;.&lt;/p&gt;<br>&lt;/div&gt;</pre><p>3. Iteration with `th:each`</p><p>Thymeleaf’s `th:each` attribute allows you to iterate over collections (e.g., lists, arrays).</p><p>Example: Displaying a List of Users</p><pre>@GetMapping(&quot;/users&quot;)<br>public String showUsers(Model model) {<br>    List&lt;User&gt; users = Arrays.asList(<br>        new User(&quot;Alice&quot;, &quot;alice@example.com&quot;),<br>        new User(&quot;Bob&quot;, &quot;bob@example.com&quot;)<br>    );<br>    model.addAttribute(&quot;users&quot;, users);<br>    return &quot;users&quot;;<br>}</pre><p>In the `users.html` template:</p><pre>&lt;ul&gt;<br>    &lt;li th:each=&quot;user : ${users}&quot;&gt;<br>        &lt;span th:text=&quot;${user.name}&quot;&gt;&lt;/span&gt; - &lt;span th:text=&quot;${user.email}&quot;&gt;&lt;/span&gt;<br>    &lt;/li&gt;<br>&lt;/ul&gt;</pre><p>4. Form Validation and Error Handling</p><p>Thymeleaf integrates seamlessly with Spring’s validation framework to display validation errors.</p><p>Step 1: Add Validation Annotations</p><p>Update the `User` class with validation annotations:</p><pre>import javax.validation.constraints.NotEmpty;<br>import javax.validation.constraints.Email;<br><br>public class User {<br>    @NotEmpty(message = &quot;Name is required&quot;)<br>    private String name;<br><br>    @Email(message = &quot;Invalid email&quot;)<br>    private String email;<br><br>    // Getters and Setters<br>}</pre><p>Step 2: Handle Validation in the Controller</p><pre>@PostMapping(&quot;/submit&quot;)<br>public String submitForm(@Valid @ModelAttribute User user, BindingResult result, Model model) {<br>    if (result.hasErrors()) {<br>        return &quot;form&quot;; // Return to the form if there are errors<br>    }<br>    model.addAttribute(&quot;user&quot;, user);<br>    return &quot;result&quot;;<br>}</pre><p>Step 3: Display Validation Errors</p><p>Update the `form.html` template to show validation errors:</p><pre>&lt;form th:action=&quot;@{/submit}&quot; th:object=&quot;${user}&quot; method=&quot;post&quot;&gt;<br>    &lt;label for=&quot;name&quot;&gt;Name:&lt;/label&gt;<br>    &lt;input type=&quot;text&quot; id=&quot;name&quot; th:field=&quot;*{name}&quot; required&gt;<br>    &lt;span th:if=&quot;${#fields.hasErrors(&#39;name&#39;)}&quot; th:errors=&quot;*{name}&quot; class=&quot;error&quot;&gt;&lt;/span&gt;&lt;br&gt;<br><br>    &lt;label for=&quot;email&quot;&gt;Email:&lt;/label&gt;<br>    &lt;input type=&quot;email&quot; id=&quot;email&quot; th:field=&quot;*{email}&quot; required&gt;<br>    &lt;span th:if=&quot;${#fields.hasErrors(&#39;email&#39;)}&quot; th:errors=&quot;*{email}&quot; class=&quot;error&quot;&gt;&lt;/span&gt;&lt;br&gt;<br><br>    &lt;button type=&quot;submit&quot;&gt;Submit&lt;/button&gt;<br>&lt;/form&gt;</pre><p>5. Internationalization (i18n)</p><p>Thymeleaf supports internationalization, allowing you to create multilingual applications.</p><p>Step 1: Add Message Files</p><p>Create `messages.properties` and `messages_fr.properties` in the `src/main/resources` folder.</p><p>messages.properties:</p><pre>welcome.message=Welcome to My Application</pre><p>messages_fr.properties:</p><pre>welcome.message=Bienvenue sur Mon Application</pre><p>Step 2: Use Messages in Templates</p><pre>&lt;h1 th:text=&quot;{welcome.message}&quot;&gt;Welcome&lt;/h1&gt;</pre><p>Step 3: Configure Locale Resolver</p><p>Add a `LocaleResolver` bean in your configuration:</p><pre>@Bean<br>public LocaleResolver localeResolver() {<br>    SessionLocaleResolver resolver = new SessionLocaleResolver();<br>    resolver.setDefaultLocale(Locale.US);<br>    return resolver;<br>}</pre><p>6. Best Practices</p><p>1. Use Fragments for Reusable Components: Avoid duplicating code by creating reusable fragments.</p><p>2. Keep Templates Clean: Use `th:replace` and `th:insert` to modularize your templates.</p><p>3. Leverage Internationalization: Use message files for text to support multiple languages.</p><p>4. Validate Inputs: Always validate user inputs and display meaningful error messages.</p><p>5. Use CSS and JavaScript: Organize static resources in the `static` folder and link them in your templates.</p><h4>Conclusion</h4><p>Thymeleaf is a powerful and flexible template engine that integrates seamlessly with Spring Boot. It simplifies the process of creating dynamic web pages and reduces the amount of boilerplate code required.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=cea17f0d5340" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How Spring JPA Works and Writing Custom Queries]]></title>
            <link>https://medium.com/@pratik.941/how-spring-jpa-works-and-writing-custom-queries-a3d9e67663bc?source=rss-7f42c99fe66f------2</link>
            <guid isPermaLink="false">https://medium.com/p/a3d9e67663bc</guid>
            <category><![CDATA[spring-boot]]></category>
            <category><![CDATA[backend-development]]></category>
            <category><![CDATA[java]]></category>
            <dc:creator><![CDATA[Pratik T]]></dc:creator>
            <pubDate>Sat, 25 Jan 2025 05:53:09 GMT</pubDate>
            <atom:updated>2025-01-25T05:53:09.767Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/474/0*FFGgmK3KV85yJ955" /></figure><p>Spring JPA is an essential tool in the Spring ecosystem that simplifies database interactions, enabling developers to focus on building features rather than managing boilerplate code. This article will explain how Spring JPA works, how to write custom queries using it, and when to use different approaches.</p><h3>Understanding How Spring JPA Works</h3><p>Spring JPA (Java Persistence API) is a module of Spring Data that abstracts the complexities of database interactions by offering a simple, unified approach to data persistence. It leverages JPA as the standard API and Hibernate as the default implementation for Object-Relational Mapping (ORM).</p><h4>Core Components of Spring JPA</h4><ol><li><strong>Entity Classes</strong>: Entity classes map to database tables. These are simple Java classes annotated with @Entity and optionally with @Table. Each field in the class corresponds to a column in the table, marked with annotations like @Id, @Column, and @GeneratedValue.</li><li><strong>Repositories</strong>: Spring JPA introduces repository interfaces, such as JpaRepository, CrudRepository, and PagingAndSortingRepository. These interfaces provide methods like save(), findById(), deleteById(), and more for basic CRUD operations.</li><li><strong>Hibernate ORM</strong>: Hibernate, as the default JPA implementation, manages the actual interaction between Java objects and database records. It converts Java objects into SQL statements and vice versa.</li><li><strong>Query Mechanisms</strong>: Spring JPA allows you to write queries in three primary ways:</li></ol><ul><li>Query methods (derived queries based on method names).</li><li>JPQL (Java Persistence Query Language).</li><li>Native SQL (raw SQL queries).</li></ul><ol><li><strong>Transaction Management</strong>: Spring manages transactions using the @Transactional annotation, ensuring data integrity across multiple operations.</li></ol><h3>Creating a Basic Spring JPA Application</h3><p>Let’s walk through a simple example to understand how Spring JPA works in practice.</p><h4>1. Define an Entity Class</h4><pre>import jakarta.persistence.*;<br>@Entity<br>@Table(name = &quot;students&quot;)<br>public class Student {<br>    @Id<br>    @GeneratedValue(strategy = GenerationType.IDENTITY)<br>    private Long id;<br>    @Column(name = &quot;name&quot;, nullable = false)<br>    private String name;<br>    @Column(name = &quot;email&quot;, unique = true, nullable = false)<br>    private String email;<br>    // Getters and Setters<br>}</pre><p>This class maps to a students table in the database.</p><h4>2. Define a Repository Interface</h4><pre>import org.springframework.data.jpa.repository.JpaRepository;<br><br>public interface StudentRepository extends JpaRepository&lt;Student, Long&gt; {<br>    // Custom queries can be added here<br>}</pre><p>The StudentRepository interface provides CRUD operations for the Student entity.</p><h4>3. Implement a Service Layer</h4><pre>import org.springframework.beans.factory.annotation.Autowired;<br>import org.springframework.stereotype.Service;<br><br>import java.util.List;<br>@Service<br>public class StudentService {<br>    @Autowired<br>    private StudentRepository studentRepository;<br>    public List&lt;Student&gt; getAllStudents() {<br>        return studentRepository.findAll();<br>    }<br>    public Student saveStudent(Student student) {<br>        return studentRepository.save(student);<br>    }<br>}</pre><p>The service layer acts as a bridge between the controller and the repository.</p><h4>4. Expose an API via a Controller</h4><pre>import org.springframework.beans.factory.annotation.Autowired;<br>import org.springframework.web.bind.annotation.*;<br><br>import java.util.List;<br>@RestController<br>@RequestMapping(&quot;/students&quot;)<br>public class StudentController {<br>    @Autowired<br>    private StudentService studentService;<br>    @GetMapping<br>    public List&lt;Student&gt; getAllStudents() {<br>        return studentService.getAllStudents();<br>    }<br>    @PostMapping<br>    public Student createStudent(@RequestBody Student student) {<br>        return studentService.saveStudent(student);<br>    }<br>}</pre><p>The controller handles HTTP requests and delegates them to the service layer.</p><h3>Writing Custom Queries in Spring JPA</h3><p>Spring JPA provides multiple ways to write custom queries depending on the complexity of the requirements. Let’s explore these methods in detail.</p><h4>1. Query Methods (Derived Queries)</h4><p>Spring JPA can automatically generate SQL queries based on method names in repository interfaces. These are known as query methods.</p><p>Example:</p><pre>import org.springframework.data.jpa.repository.JpaRepository;<br>import java.util.List;<br><br>public interface StudentRepository extends JpaRepository&lt;Student, Long&gt; {<br>    // Find students by name<br>    List&lt;Student&gt; findByName(String name);<br>    // Find students by name and email<br>    List&lt;Student&gt; findByNameAndEmail(String name, String email);<br>    // Find students whose name contains a keyword<br>    List&lt;Student&gt; findByNameContaining(String keyword);<br>    // Find all students and sort by name<br>    List&lt;Student&gt; findAllByOrderByNameAsc();<br>}</pre><p>Generated SQL Examples:</p><ul><li>findByName(String name) generates:</li></ul><pre>SELECT * FROM students WHERE name = :name</pre><ul><li>findByNameAndEmail(String name, String email) generates:</li></ul><pre>SELECT * FROM students WHERE name = :name AND email = :email</pre><h4>2. JPQL (Java Persistence Query Language)</h4><p>JPQL is an object-oriented query language that operates on entity objects and their fields, not directly on database tables.</p><p>Example:</p><pre>import org.springframework.data.jpa.repository.Query;<br>import org.springframework.data.repository.query.Param;<br>import java.util.List;<br><br>public interface StudentRepository extends JpaRepository&lt;Student, Long&gt; {<br>    // JPQL query to find students by name<br>    @Query(&quot;SELECT s FROM Student s WHERE s.name = :name&quot;)<br>    List&lt;Student&gt; findStudentsByName(@Param(&quot;name&quot;) String name);<br><br>    // JPQL query to find students with emails containing a keyword<br>    @Query(&quot;SELECT s FROM Student s WHERE s.email LIKE %:keyword%&quot;)<br>    List&lt;Student&gt; findStudentsByEmailKeyword(@Param(&quot;keyword&quot;) String keyword);<br>}</pre><p>Example Query Output:</p><ul><li>findStudentsByName(&quot;John&quot;) generates:</li></ul><pre>SELECT * FROM students WHERE name = &#39;John&#39;</pre><h4>3. Native SQL Queries</h4><p>When you need to use database-specific SQL or optimize performance, native SQL queries can be used with @Query.</p><p>Example:</p><pre>import org.springframework.data.jpa.repository.Query;<br>import org.springframework.data.repository.query.Param;<br>import java.util.List;<br><br>public interface StudentRepository extends JpaRepository&lt;Student, Long&gt; {<br>    // Native SQL query to find students by email<br>    @Query(value = &quot;SELECT * FROM students WHERE email = :email&quot;, nativeQuery = true)<br>    Student findStudentByEmail(@Param(&quot;email&quot;) String email);<br><br>    // Native SQL query to fetch students with pagination<br>    @Query(value = &quot;SELECT * FROM students ORDER BY name LIMIT :limit OFFSET :offset&quot;, nativeQuery = true)<br>    List&lt;Student&gt; fetchStudentsWithPagination(@Param(&quot;limit&quot;) int limit, @Param(&quot;offset&quot;) int offset);<br>}</pre><h3>Dynamic Queries Using Specifications</h3><p>For more complex queries involving dynamic filters, you can use the JpaSpecificationExecutor interface.</p><p>Example:</p><ol><li>Extend JpaSpecificationExecutor:</li></ol><pre>public interface StudentRepository extends JpaRepository&lt;Student, Long&gt;, JpaSpecificationExecutor&lt;Student&gt; {<br>}</pre><ol><li>Write Specifications:</li></ol><pre>import org.springframework.data.jpa.domain.Specification;<br><br>public class StudentSpecifications {<br>    public static Specification&lt;Student&gt; hasName(String name) {<br>        return (root, query, criteriaBuilder) -&gt;<br>                criteriaBuilder.equal(root.get(&quot;name&quot;), name);<br>    }<br>    public static Specification&lt;Student&gt; emailContains(String keyword) {<br>        return (root, query, criteriaBuilder) -&gt;<br>                criteriaBuilder.like(root.get(&quot;email&quot;), &quot;%&quot; + keyword + &quot;%&quot;);<br>    }<br>}</pre><ol><li>Use in Service:</li></ol><pre>import org.springframework.data.jpa.domain.Specification;<br>import java.util.List;<br><br>List&lt;Student&gt; students = studentRepository.findAll(Specification<br>    .where(StudentSpecifications.hasName(&quot;John&quot;))<br>    .and(StudentSpecifications.emailContains(&quot;gmail&quot;)));</pre><h3>When to Use Each Approach</h3><ul><li><strong>Query Methods</strong>: Use for simple and standard queries.</li><li><strong>JPQL</strong>: Use when you need flexibility or operate on entities.</li><li><strong>Native SQL</strong>: Use for database-specific optimizations or raw SQL.</li><li><strong>Specifications</strong>: Use for complex filtering with dynamic conditions.</li></ul><p>Spring JPA simplifies data access while giving you the flexibility to write custom queries as needed. Understanding these approaches will empower you to handle any database interaction with ease.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=a3d9e67663bc" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Method Overloading in Java: A Comprehensive Guide]]></title>
            <link>https://medium.com/@pratik.941/method-overloading-in-java-a-comprehensive-guide-09ad21baf54d?source=rss-7f42c99fe66f------2</link>
            <guid isPermaLink="false">https://medium.com/p/09ad21baf54d</guid>
            <category><![CDATA[backend]]></category>
            <category><![CDATA[java]]></category>
            <category><![CDATA[polymorphism]]></category>
            <dc:creator><![CDATA[Pratik T]]></dc:creator>
            <pubDate>Thu, 14 Nov 2024 06:16:18 GMT</pubDate>
            <atom:updated>2024-11-14T06:17:25.898Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/837/1*JdU76bjWjnUvgvRC1EPNsQ.png" /></figure><p>In Java, method overloading allows developers to define multiple methods with the same name but different parameters. This flexibility makes code more readable and adaptive, as different variations of a method can handle different argument types or quantities. However, understanding how Java picks which method to call is essential for writing bug-free code.</p><p>In this article, we’ll dive deep into Java’s method selection process and the rules it follows to resolve overloaded methods. We’ll cover exact matches, type promotion, varargs, boxing, and the infamous ambiguity errors that can arise in method overloading.</p><h4>The Basics of Method Overloading</h4><p>Method overloading in Java occurs when multiple methods in a class share the same name but differ in parameter type or count. Here’s a simple example:</p><pre>class Calculator {<br>    void add(int a, int b) {<br>        System.out.println(&quot;add(int, int) called: &quot; + (a + b));<br>    }<br><br>    void add(double a, double b) {<br>        System.out.println(&quot;add(double, double) called: &quot; + (a + b));<br>    }<br>}</pre><p>When calling add() with int or double arguments, Java determines which method to use based on the arguments passed. The compiler automatically selects the appropriate method.</p><p><strong>Method Resolution Rules</strong></p><p>Java follows a specific set of rules when choosing which overloaded method to call, and understanding these can help you avoid some common pitfalls.</p><p><strong>1. Exact Match — The Most Specific Method Wins</strong></p><p>When there’s an exact match between the argument types and a method’s parameters, Java uses this method directly.</p><pre>class Example {<br>    void print(int a) {<br>        System.out.println(&quot;print(int) called&quot;);<br>    }<br>    void print(double a) {<br>        System.out.println(&quot;print(double) called&quot;);<br>    }<br><br>    public static void main(String[] args) {<br>        Example ex = new Example();<br>        ex.print(10);    // Calls print(int)<br>        ex.print(10.5);  // Calls print(double)<br>    }<br>}</pre><p><strong>Output:</strong></p><pre>print(int) called<br>print(double) called</pre><p>When print() is called with an int, Java matches it directly to print(int), and similarly for double. This is the simplest case of method resolution.</p><p><strong>2. Type Promotion (Widening)</strong></p><p>When there’s no exact match, Java tries to promote the type to the next wider type in its type hierarchy, following this order:<br> — byte → short → int → long → float → double<br> — char → int</p><pre>class Example {<br>    void display(long a) {<br>        System.out.println(&quot;display(long) called&quot;);<br>    }<br>    void display(double a) {<br>        System.out.println(&quot;display(double) called&quot;);<br>    }<br><br>    public static void main(String[] args) {<br>        Example ex = new Example();<br>        ex.display(10);       // Promotes int to long and calls display(long)<br>        ex.display(10.5f);    // Promotes float to double and calls display(double)<br>    }<br>}<br></pre><p>Output:</p><pre>display(long) called<br>display(double) called</pre><p>Since no int or float method exists, int promotes to long, and float promotes to double.</p><p><strong>3. Varargs — The Fallback Option</strong></p><p>If there’s no exact or promotable match, Java uses a varargs method (variable-length argument list). Varargs are treated as a “catch-all” when no better match exists.</p><pre>class Example {<br>    void print(int... numbers) {<br>        System.out.println(&quot;print(int...) called with &quot; + numbers.length + &quot; arguments&quot;);<br>    }<br><br>    public static void main(String[] args) {<br>        Example ex = new Example();<br>        ex.print(10);          // Calls print(int...) with 1 argument<br>        ex.print(10, 20);      // Calls print(int...) with 2 arguments<br>    }<br>}</pre><p>Output:</p><pre>print(int…) called with 1 arguments<br>print(int…) called with 2 arguments</pre><p>Java calls print(int…) when there’s no match for (int) or (int, int). Varargs should ideally be used sparingly as they’re the least specific option.</p><p><strong>4. Ambiguity and Compile-Time Errors</strong></p><p>When overloaded methods are ambiguous, Java can’t decide which one to use, leading to a compile-time error. Ambiguity usually occurs when multiple methods match the provided arguments, but none is more specific.</p><pre>class Example {<br>    void print(int a, long b) {<br>        System.out.println(&quot;print(int, long) called&quot;);<br>    }<br>    void print(long a, int b) {<br>        System.out.println(&quot;print(long, int) called&quot;);<br>    }<br><br>    public static void main(String[] args) {<br>        Example ex = new Example();<br>        ex.print(10, 20);  // Compile-time error: reference to print is ambiguous<br>    }<br>}</pre><p>Error:<br> <br> error: reference to print is ambiguous</p><p>Since 10, 20 can match both print(int, long) and print(long, int), the compiler doesn’t know which to choose and throws an error.</p><p><strong>5. Boxing and Widening Together</strong></p><p>Java supports autoboxing (automatically converting primitives to their wrapper classes) and can combine widening with autoboxing when necessary, though this can add complexity.</p><pre>class Example {<br>    void print(Integer a) {<br>        System.out.println(&quot;print(Integer) called&quot;);<br>    }<br>    void print(long a) {<br>        System.out.println(&quot;print(long) called&quot;);<br>    }<br><br>    public static void main(String[] args) {<br>        Example ex = new Example();<br>        ex.print(10);   // Calls print(long) since widening (int → long) is preferred over autoboxing<br>    }<br>}</pre><p>Output:</p><pre>print(long) called</pre><p>Java prioritizes widening over boxing, so int is widened to long instead of being boxed to Integer.</p><p><strong>Summary of Method Resolution Rules</strong></p><p>To summarize Java’s priority when selecting an overloaded method:<br> 1. Exact match — Java directly chooses a method that matches the argument types.<br> 2. Type promotion — Java promotes the argument type to the next suitable primitive type.<br> 3. Autoboxing — Java boxes the primitive type into its wrapper class.<br> 4. Varargs — As the last option, Java uses varargs if all else fails.</p><p><strong>Final Thoughts</strong></p><p>Mastering method overloading is essential for writing flexible, efficient Java code. Remembering the priority of method resolution rules can help you avoid compile-time errors and unexpected behavior in your overloaded methods. Try experimenting with these scenarios in your own code to deepen your understanding.</p><p>Happy Coding!</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=09ad21baf54d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Guide to Servlet in Java]]></title>
            <link>https://medium.com/@pratik.941/servlet-48d76b4a23e1?source=rss-7f42c99fe66f------2</link>
            <guid isPermaLink="false">https://medium.com/p/48d76b4a23e1</guid>
            <category><![CDATA[backend]]></category>
            <category><![CDATA[java]]></category>
            <dc:creator><![CDATA[Pratik T]]></dc:creator>
            <pubDate>Wed, 16 Oct 2024 08:37:01 GMT</pubDate>
            <atom:updated>2024-10-16T08:48:15.048Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*76-6w8DQRe3B96rw.png" /></figure><p><strong>What are Servlets?</strong></p><p>- Servlets are Java-based web technologies that enable the creation of dynamic web applications. They run on the server side and handle the logic required to respond to requests from clients, usually web browsers.</p><p>- Servlets are used to develop web applications that can be accessed through a browser. Sun Microsystems originally developed Servlets (now managed by Oracle).</p><p><strong>OR</strong></p><p>A Servlet is a Java class that extends the capabilities of servers that host web applications. It responds to incoming requests (usually HTTP requests from web browsers or clients) and generates a response, often in HTML format, to send back to the client.</p><p><strong>What is a Web Application?</strong></p><p>- A web application is software hosted on a server that users can access using a browser over the internet or an intranet.</p><p>- In web applications, the server hosts all application logic, and the clients interact with it using a browser interface. This approach allows centralized data handling, making it easier to manage and update.</p><p><strong>Components in Web Applications</strong></p><p>1. Client-side components: These are developed using technologies like HTML, XHTML, JSP (Java Server Pages), JavaScript, CSS, etc. They define how the content is presented to the user in the browser.</p><p>2. Server-side components: These are developed using technologies like Servlets, JSP, Filters, and more. Server-side components handle the business logic, data processing, and other backend operations of the web application.</p><p><strong>How Web Requests Work</strong></p><p>- When you enter a URL in a browser, the browser sends a request to the DNS server to resolve the domain name to an IP address.</p><p>- Once the IP address is found, the request is forwarded to the appropriate server hosting the web application.</p><p>- The server processes the request and sends back a response to the client (browser), which is then displayed to the user.</p><p>- Servers determine the client’s IP address from the HTTP request to track user sessions or send customized responses.</p><p><strong>Versions of Servlets</strong></p><p>The evolution of the Servlets API has happened over different versions of Java EE:</p><p>1. Servlets 2.2 — Released with J2EE 1.2</p><p>2. Servlets 2.3 — Released with J2EE 1.3</p><p>3. Servlets 2.4 — Released with J2EE 1.4</p><p>4. Servlets 2.5 — Released with JEE 5</p><p>5. Servlets 3.0 — Released with JEE 6</p><p>6. Servlets 3.1 — Released with JEE 7</p><p>Each version of the Servlets API brings new features, improvements, and updates to enhance web application development.</p><p><strong>Types of Applications</strong></p><p>1. Standalone Applications: These are traditional software applications that run on a single computer. Examples include MS Word, music players, etc. The main drawback is that they require installation on each machine, and data sharing is not possible.</p><p>2. Client-Server Applications: These applications have two components: the server-side application and the client-side application installed on multiple machines. Examples include chat applications like Yahoo Messenger. Although data sharing is possible, client software must be maintained on each machine.</p><p>3. Web Applications: These applications solve the problems of client-server applications. They run on a central server, and users access them using a web browser. Examples include Gmail, Google Maps, etc. Web applications can be implemented using technologies like Servlets, JSP, and more. Maintenance is easier since updates only need to be done on the server.</p><p>4. Distributed Applications: These applications are designed to work across multiple servers or locations, allowing businesses to share information with partners in real time.</p><p>5. Enterprise Applications: These are large-scale software systems designed to support an organization’s core business processes. They are usually integrated with other software systems to ensure seamless business operations.</p><p><strong>Static vs. Dynamic Web Applications</strong></p><p>- Static Web Applications: These have a fixed view, and the content remains the same for all users. Static web pages are developed using HTML and do not involve data processing or interaction.</p><p>- Dynamic Web Applications: These allow users to interact with the server and send data that is processed to produce dynamic responses. Servlets are often used to create these applications.</p><p><strong>General Technical Terms Explained</strong></p><p>1. Web Server: Software that handles HTTP requests from clients and sends back HTTP responses. Examples include Apache Server, IIS (Internet Information Services).</p><p>2. Web Client: Software (typically a web browser) that makes HTTP requests to a web server and receives responses.</p><p>3. Web Container: Also known as a Servlet container, this is the component within the web server that manages the lifecycle of Servlets and JSPs. It handles low-level tasks like request handling, security, resource management, and more.</p><p>4. HTTP (Hypertext Transfer Protocol): Protocol used for communication between the client and the server.</p><p>5. TCP/IP: Network protocol stack used for data communication. IP is responsible for addressing, while TCP manages the data transmission.</p><p>6. DNS (Domain Name Server): Translates domain names into IP addresses to locate servers on the internet.</p><p><strong>Setting up Apache Tomcat</strong></p><p>Prerequisites</p><p>1. Java Development Kit (JDK): Ensure you have JDK installed on your machine (version 8 or later).</p><p>2. Apache Tomcat: Download the latest version of Apache Tomcat from the [official website](https://tomcat.apache.org/).</p><p>Step 1: Install Apache Tomcat</p><p>1. Download Tomcat:</p><p>- Choose the appropriate distribution (usually the `.zip` or `.tar.gz` file).</p><p>2. Extract the Archive:</p><p>- Unzip or untar the downloaded file to a directory of your choice (e.g., `C:\apache-tomcat-9.0.xx` or `/usr/local/tomcat`).</p><p>3. Set Environment Variables (optional but recommended):</p><p>- JAVA_HOME: Point this to your JDK installation.</p><p>- CATALINA_HOME: Point this to your Tomcat installation directory.</p><p>For example, on Linux:</p><pre>export JAVA_HOME=/path/to/jdk<br>export CATALINA_HOME=/path/to/tomcat</pre><p>Step 2: Start Tomcat</p><p>1. Navigate to the `bin` directory of your Tomcat installation:</p><pre>cd $CATALINA_HOME/bin</pre><p>2. Start Tomcat:</p><p>- On Windows:</p><pre>catalina.bat start</pre><p>- On Linux/Unix:</p><pre>./catalina.sh start</pre><p>3. Open a web browser and go to `http://localhost:8080`. You should see the Tomcat welcome page.</p><p>Step 3: Create a Servlet</p><p>1. Create a Dynamic Web Project:</p><p>- Use an IDE like Eclipse or IntelliJ IDEA to create a new Dynamic Web Project.</p><p>2. Add Servlet:</p><p>- Create a new Java class that extends `HttpServlet` and override the `doGet` or `doPost` methods. Example:</p><pre>import java.io.IOException;<br>import javax.servlet.ServletException;<br>import javax.servlet.annotation.WebServlet;<br>import javax.servlet.http.HttpServlet;<br>import javax.servlet.http.HttpServletRequest;<br>import javax.servlet.http.HttpServletResponse;<br><br>@WebServlet(&quot;/hello&quot;)<br>public class HelloServlet extends HttpServlet {<br>    protected void doGet(HttpServletRequest request, HttpServletResponse response)<br>            throws ServletException, IOException {<br>        response.setContentType(&quot;text/html&quot;);<br>        response.getWriter().println(&quot;&lt;h1&gt;Hello, World!&lt;/h1&gt;&quot;);<br>    }<br>}</pre><p><strong>Configure </strong><strong>web.xml</strong> (if not using annotations):</p><ul><li>If you’re not using servlet annotations, define your servlet in WEB-INF/web.xml:</li></ul><pre>&lt;servlet&gt;<br>    &lt;servlet-name&gt;HelloServlet&lt;/servlet-name&gt;<br>    &lt;servlet-class&gt;com.example.HelloServlet&lt;/servlet-class&gt;<br>&lt;/servlet&gt;<br>&lt;servlet-mapping&gt;<br>    &lt;servlet-name&gt;HelloServlet&lt;/servlet-name&gt;<br>    &lt;url-pattern&gt;/hello&lt;/url-pattern&gt;<br>&lt;/servlet-mapping&gt;</pre><p>Step 4: Deploy the Servlet</p><p>1. Compile the Project: Make sure your project compiles without errors.</p><p>2. Create a WAR file: If using an IDE, it typically has an option to export the project as a WAR file.</p><p>3. Deploy the WAR:</p><p>- Place the WAR file in the `webapps` directory of your Tomcat installation.</p><p>4. Restart Tomcat:</p><p>- After placing the WAR file, restart Tomcat for the changes to take effect.</p><p>Step 5: Access the Servlet</p><p>1. Open a web browser and go to:</p><pre>http://localhost:8080/your_project_name/hello</pre><p>Replace `your_project_name` with the name of your WAR file (without the `.war` extension).</p><p>Troubleshooting Tips</p><p>- Check the `logs` directory in your Tomcat installation for any error messages.</p><p>- Ensure the servlet is correctly mapped and that there are no typos in your URL.</p><h4>Java Servlets, classes and interfaces</h4><h4>Classes in Servlets</h4><p><strong>1. Servlet Class:</strong></p><p>- The core of a servlet is a class that extends HttpServlet. This class provides methods to handle HTTP requests and responses.</p><p>- Commonly overridden methods include:</p><p>- doGet(HttpServletRequest request, HttpServletResponse response): Handles GET requests.</p><p>- doPost(HttpServletRequest request, HttpServletResponse response): Handles POST requests.</p><p>- Example:</p><pre>import javax.servlet.*;<br>import javax.servlet.http.*;<br>import java.io.*;<br>public class MyServlet extends HttpServlet {<br>    protected void doGet(HttpServletRequest request, <br>                         HttpServletResponse response)<br>            throws ServletException, IOException {<br>        response.setContentType(&quot;text/html&quot;);<br>        PrintWriter out = response.getWriter();<br>        out.println(&quot;&lt;h1&gt;Hello, World!&lt;/h1&gt;&quot;);<br>    }<br>}</pre><p>2. Utility Classes:</p><p>- Often, utility classes are created to handle common tasks, such as database access, data processing, or configuration management.</p><h4>Interfaces in Servlets</h4><p>1. Servlet Interface:</p><p>- The Servlet interface defines the methods that must be implemented by any servlet class. It includes methods like init(), service(), and destroy().</p><p>- While developers typically extend HttpServlet, knowing the Servlet interface is important for understanding servlet lifecycle and behavior.</p><p>2. Other Interfaces:</p><p>- ServletConfig: This interface provides configuration information to the servlet. It allows access to initialization parameters and the servlet context.</p><p>- ServletContext: This interface provides information about the web application context. It allows servlets to interact with their environment, such as retrieving resources or attributes.</p><p>- HttpServletRequest and HttpServletResponse: These interfaces represent the request and response objects, respectively, enabling servlets to handle incoming requests and send responses back to clients.</p><h4>Step-by-Step Guide to Developing and Running a Servlets 2.x-Based Web Application</h4><p>1. Requirement Analysis</p><p>The application you’re building is a simple login page. When a user submits the form, the information will be processed by a servlet, which will display user details and some additional data.</p><p>2. Create a Dynamic Web Project in Eclipse</p><p>1. Open Eclipse.</p><p>2. Go to the menu and select File &gt; New &gt; Dynamic Web Project.</p><p>3. Provide the Project Name as lms1.</p><p>4. For the first-time setup:</p><p>- Click on the New Runtime button.</p><p>- Select Apache Tomcat 10.1 as the server and click on the Next button.</p><p>- Browse to the Tomcat Home Directory (e.g., E:\Tomcat 10.1) and click on Finish.</p><p>5. Click Finish again to create the project.</p><p><strong>3. Project Directory Structure</strong></p><p>Once the project is created, the default directory structure will look like this:</p><p><strong>lms1</strong></p><ul><li><strong>WebContent</strong></li><li>login.html</li><li><strong>src</strong></li><li>com.lmsindia.servlets (package)</li><li>LoginServlet.java</li><li><strong>WEB-INF</strong></li><li>web.xml</li></ul><p><strong>4. Create the Login Page (login.html)</strong></p><p>In the WebContent folder of your project, create a new HTML file named login.html. Here’s the code for the file:</p><pre>&lt;html&gt;<br>  &lt;head&gt;<br>    &lt;title&gt;Login Page&lt;/title&gt;<br>  &lt;/head&gt;<br>  &lt;body&gt;<br>    &lt;h1&gt;lms Test&lt;/h1&gt;<br>    &lt;hr&gt;<br>    &lt;form action=&quot;test.lms&quot; method=&quot;post&quot;&gt;<br>      &lt;table&gt;<br>        &lt;tr&gt;<br>          &lt;td&gt;UserName:&lt;/td&gt;<br>          &lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;uname&quot; /&gt;&lt;/td&gt;<br>        &lt;/tr&gt;<br>        &lt;tr&gt;<br>          &lt;td colspan=&quot;2&quot; align=&quot;center&quot;&gt;<br>            &lt;input type=&quot;submit&quot; value=&quot;Submit&quot; /&gt;<br>          &lt;/td&gt;<br>        &lt;/tr&gt;<br>      &lt;/table&gt;<br>    &lt;/form&gt;<br>  &lt;/body&gt;<br>&lt;/html&gt;</pre><p>This HTML form sends a POST request to the servlet when the user submits the form.</p><p><strong>5. Create the Servlet Class (LoginServlet.java)</strong></p><p>1. In the src folder, create a package named com.lmsindia.servlets.</p><p>2. Inside this package, create a Java class named lmsServlet.java. Use the following code:</p><pre>package com.lmsindia.Servlets;<br>import java.io.IOException;<br>import java.io.PrintWriter;<br>import javax.servlet.ServletConfig;<br>import javax.servlet.ServletContext;<br>import javax.servlet.ServletException;<br>import javax.servlet.http.HttpServlet;<br>import javax.servlet.http.HttpServletRequest;<br>import javax.servlet.http.HttpServletResponse;<br>public class lmsServlet extends HttpServlet {<br>   String phone;<br>   String email;<br>   String state;<br>   String country;<br>   public void init(ServletConfig sc) throws ServletException {<br>      System.out.println(&quot;lmsServlet - init()&quot;);<br>      // Config parameters<br>      phone = sc.getInitParameter(&quot;Phone&quot;);<br>      email = sc.getInitParameter(&quot;Email&quot;);<br>      // Context parameters<br>      ServletContext ctx = sc.getServletContext();<br>      state = ctx.getInitParameter(&quot;State&quot;);<br>      country = ctx.getInitParameter(&quot;country&quot;);<br>   }<br>   protected void service(HttpServletRequest req, HttpServletResponse res)<br>         throws IOException, ServletException {<br>      System.out.println(&quot;lmsServlet - service()&quot;);<br>      <br>      // Request parameter<br>      String un = req.getParameter(&quot;uname&quot;);<br>      <br>      // Display parameters<br>      res.setContentType(&quot;text/html&quot;);<br>      PrintWriter out = res.getWriter();<br>      out.println(&quot;&lt;h1&gt;Username: &quot; + un + &quot;&lt;/h1&gt;&quot;);<br>      out.println(&quot;&lt;h1&gt;Phone: &quot; + phone + &quot;&lt;/h1&gt;&quot;);<br>      out.println(&quot;&lt;h1&gt;Email: &quot; + email + &quot;&lt;/h1&gt;&quot;);<br>      out.println(&quot;&lt;h1&gt;State: &quot; + state + &quot;&lt;/h1&gt;&quot;);<br>      out.println(&quot;&lt;h1&gt;Country: &quot; + country + &quot;&lt;/h1&gt;&quot;);<br>   }<br>   public void destroy() {<br>      System.out.println(&quot;lmsServlet - destroy()&quot;);<br>   }<br>}</pre><p>This servlet retrieves and displays request parameters (username) as well as initialization and context parameters.</p><p>6. Update the Deployment Descriptor (web.xml)</p><p>In the WEB-INF folder, open the web.xml file and update it as follows:</p><pre>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;<br>&lt;web-app&gt;<br>  &lt;welcome-file-list&gt;<br>    &lt;welcome-file&gt;login.html&lt;/welcome-file&gt;<br>  &lt;/welcome-file-list&gt;<br>&lt;context-param&gt;<br>    &lt;param-name&gt;State&lt;/param-name&gt;<br>    &lt;param-value&gt;UTTAR PRADESH&lt;/param-value&gt;<br>  &lt;/context-param&gt;<br>  &lt;context-param&gt;<br>    &lt;param-name&gt;country&lt;/param-name&gt;<br>    &lt;param-value&gt;INDIA&lt;/param-value&gt;<br>  &lt;/context-param&gt;<br>  &lt;servlet&gt;<br>    &lt;servlet-name&gt;test&lt;/servlet-name&gt;<br>    &lt;servlet-class&gt;com.lmsindia.Servlets.lmsServlet&lt;/servlet-class&gt;<br>    &lt;init-param&gt;<br>      &lt;param-name&gt;Email&lt;/param-name&gt;<br>      &lt;param-value&gt;som@lmsindia.org&lt;/param-value&gt;<br>    &lt;/init-param&gt;<br>    &lt;init-param&gt;<br>      &lt;param-name&gt;Phone&lt;/param-name&gt;<br>      &lt;param-value&gt;33333&lt;/param-value&gt;<br>    &lt;/init-param&gt;<br>    &lt;load-on-startup&gt;1&lt;/load-on-startup&gt;<br>  &lt;/servlet&gt;<br>  &lt;servlet-mapping&gt;<br>    &lt;servlet-name&gt;test&lt;/servlet-name&gt;<br>    &lt;url-pattern&gt;/test.lms&lt;/url-pattern&gt;<br>  &lt;/servlet-mapping&gt;<br>&lt;/web-app&gt;</pre><p>This file defines the servlet configuration, context parameters, and servlet mappings. It maps requests to /test.lms to the lmsServlet.</p><p><strong>7. Deploy and Run the Project on Tomcat</strong></p><p>1. Right-click on your project (lms1) in Eclipse.</p><p>2. Select Run As &gt; Run on Server.</p><p>3. Choose Apache Tomcat 6.0 as the server and click Finish.</p><p>This step will deploy your web application to Tomcat and start the server.</p><p><strong>8. Access the Web Application</strong></p><p>- Open a web browser.</p><p>- Enter the URL: <a href="http://localhost:9999/jtc1/login.html">http://localhost:9999/lms1/login.html</a></p><p>- You should see the login form. Enter a username and submit the form to see the output from the servlet.</p><p>Summary of Required Files</p><p>1. Login.html: The HTML page that collects user input.</p><p>2. web.xml: The deployment descriptor that configures the servlet and mappings.</p><p>3. lmsServlet.java: The servlet class that handles the HTTP request and response.</p><p><strong>Creating a Simple Servlet using annotaions:</strong></p><p>Step 1: Create the Servlet Class</p><p>Here is a basic example of a servlet that generates a simple “Hello, World!” response.</p><pre>import java.io.IOException;<br>import javax.servlet.ServletException;<br>import javax.servlet.annotation.WebServlet;<br>import javax.servlet.http.HttpServlet;<br>import javax.servlet.http.HttpServletRequest;<br>import javax.servlet.http.HttpServletResponse;<br>@WebServlet(&quot;/hello&quot;) // URL pattern<br>public class HelloServlet extends HttpServlet {<br>    @Override<br>    protected void doGet(HttpServletRequest request, HttpServletResponse response)<br>            throws ServletException, IOException {<br>        // Set response content type<br>        response.setContentType(&quot;text/html&quot;);<br>        // Write output to the client<br>        response.getWriter().println(&quot;&lt;h1&gt;Hello, World!&lt;/h1&gt;&quot;);<br>    }<br>}</pre><p>Explanation:</p><p>- @WebServlet(“/hello”): This annotation maps the servlet to the URL pattern /hello.</p><p>- doGet() Method: Handles HTTP GET requests. When a client sends a request to the URL /hello, this method is executed.</p><p>- response.setContentType(“text/html”): Sets the response’s content type to HTML.</p><p>- response.getWriter().println(): Sends an HTML response back to the client.</p><p>Step 3: Deploy the Servlet</p><p>To deploy the servlet, you need to package it into a WAR (Web Application Archive) file or directly place it in the webapps directory of Tomcat.</p><p>1. Folder Structure for manual deployment:</p><pre>webapps/<br>    └── your_app_name/<br>        ├── WEB-INF/<br>        │   ├── web.xml<br>        │   └── classes/<br>        │       └── HelloServlet.class</pre><p>2. Configuration in web.xml:</p><pre>&lt;web-app xmlns=&quot;http://java.sun.com/xml/ns/javaee&quot;<br>         xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;<br>         xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/javaee <br>         http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd&quot;<br>         version=&quot;3.0&quot;&gt;<br>         <br>    &lt;servlet&gt;<br>        &lt;servlet-name&gt;HelloServlet&lt;/servlet-name&gt;<br>        &lt;servlet-class&gt;HelloServlet&lt;/servlet-class&gt;<br>    &lt;/servlet&gt;<br>    &lt;servlet-mapping&gt;<br>        &lt;servlet-name&gt;HelloServlet&lt;/servlet-name&gt;<br>        &lt;url-pattern&gt;/hello&lt;/url-pattern&gt;<br>    &lt;/servlet-mapping&gt;<br>&lt;/web-app&gt;</pre><p>This web.xml file configures your servlet with the name HelloServlet and maps it to the URL /hello.</p><p>Step 4: Access the Servlet</p><p>- Start the Apache Tomcat server.</p><p>- Open your web browser and visit <a href="http://localhost:8080/your_app_name/hello.">http://localhost:8080/your_app_name/hello.</a></p><p>You should see the response: Hello, World!</p><h4>Servlet Instance Creation</h4><p>1. Default Behavior:</p><p>- By default, a servlet instance is created when the first client request is received.</p><p>- Only one instance of the servlet is created, and it handles all client requests using multiple threads.</p><p>2. Eager Initialization:</p><p>- If you want a servlet instance to be created when the server or container starts (before any request is received), you can configure it using the following options:</p><p>In web.xml:</p><pre>&lt;servlet&gt;<br>    ...<br>    &lt;load-on-startup&gt;X&lt;/load-on-startup&gt;<br>&lt;/servlet&gt;</pre><p>Using Annotations:</p><pre>@WebServlet(urlPatterns = {&quot;/example&quot;}, loadOnStartup = X)</pre><p>- X is an integer value that determines the order of initialization. Lower values are given higher priority.</p><h4>Parameters in Servlets</h4><p>Parameters are key-value pairs used to pass information to a servlet. There are three types of parameters:</p><p>1. ServletRequest Parameters:</p><p>- These parameters are sent from the client to the server as part of the HTTP request.</p><p>- Useful for handling data entered by users in web forms.</p><p>Example of retrieving request parameters:</p><pre>String firstName = req.getParameter(&quot;fname&quot;);<br>String lastName = req.getParameter(&quot;lname&quot;);</pre><p>2. ServletConfig Parameters:</p><p>- These parameters are specific to a particular servlet and are defined in the web.xml file or using annotations.</p><p>- They are useful for data that is common to all users of a specific servlet.</p><p>In web.xml:</p><pre>&lt;servlet&gt;<br>    &lt;servlet-name&gt;HelloServlet&lt;/servlet-name&gt;<br>    &lt;servlet-class&gt;com.lmsindia.servlets.HelloServlet&lt;/servlet-class&gt;<br>    &lt;init-param&gt;<br>        &lt;param-name&gt;email&lt;/param-name&gt;<br>        &lt;param-value&gt;hellosom@lmsindia.org&lt;/param-value&gt;<br>    &lt;/init-param&gt;<br>&lt;/servlet&gt;</pre><p>Accessing ServletConfig parameters:</p><pre>String email = config.getInitParameter(&quot;email&quot;);</pre><p>3. ServletContext Parameters:</p><p>- These parameters are shared across all servlets in the web application.</p><p>- They are useful for data that needs to be accessed by multiple servlets.</p><p>Defining context parameters in web.xml:</p><pre>&lt;context-param&gt;<br>    &lt;param-name&gt;website&lt;/param-name&gt;<br>    &lt;param-value&gt;www.lmsindia.org&lt;/param-value&gt;<br>&lt;/context-param&gt;</pre><p>Accessing ServletContext parameters:</p><pre>String website = context.getInitParameter(&quot;website&quot;);</pre><p>Explanation of the Code</p><p>Login.html</p><pre>&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot; &quot;http://www.w3.org/TR/html4/loose.dtd&quot;&gt;<br>&lt;html&gt;<br>   &lt;head&gt;<br>      &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=ISO-8859-1&quot;&gt;<br>      &lt;title&gt;Insert title here&lt;/title&gt;<br>   &lt;/head&gt;<br>   &lt;body&gt;<br>      &lt;h1&gt;THIS IS INDEX HTML&lt;/h1&gt;<br>      &lt;form action=&quot;hello.lms&quot;&gt;<br>         &lt;h2&gt;Enter Name&lt;/h2&gt;<br>         &lt;input type=&quot;text&quot; name=&quot;fname&quot;&gt;<br>         &lt;br /&gt;<br>         &lt;input type=&quot;submit&quot; value=&quot;Hello Test&quot;&gt;<br>      &lt;/form&gt;<br>      &lt;form action=&quot;hai.lms&quot;&gt;<br>         &lt;h2&gt;Enter Phone&lt;/h2&gt;<br>         &lt;input type=&quot;text&quot; name=&quot;phone&quot;&gt;<br>         &lt;br /&gt;<br>         &lt;input type=&quot;submit&quot; value=&quot;Hai Test&quot;&gt;<br>      &lt;/form&gt;<br>   &lt;/body&gt;<br>&lt;/html&gt;</pre><p>Web.xml</p><pre>&lt;display-name&gt;lms2&lt;/display-name&gt;<br>&lt;welcome-file-list&gt;<br>   &lt;welcome-file&gt;index.html&lt;/welcome-file&gt;<br>&lt;/welcome-file-list&gt;<br>&lt;context-param&gt;<br>   &lt;param-name&gt;website&lt;/param-name&gt;<br>   &lt;param-value&gt;www.lmsindia.org&lt;/param-value&gt;<br>&lt;/context-param&gt;<br>&lt;servlet&gt;<br>   &lt;servlet-name&gt;helloSevlet&lt;/servlet-name&gt;<br>   &lt;servletclass&gt;com.lmsindia.servlet.HelloServlet&lt;/servletclass&gt;<br>   &lt;init-param&gt;<br>      &lt;param-name&gt;email&lt;/param-name&gt;<br>      &lt;param-value&gt;hellosom@lmsindia.org&lt;/param-value&gt;<br>   &lt;/init-param&gt;<br>&lt;/servlet&gt;<br>&lt;servlet-mapping&gt;<br>   &lt;servlet-name&gt;helloservlet&lt;/servlet-name&gt;<br>   &lt;url-pattern&gt;/hello.lms&lt;/url-pattern&gt;<br>&lt;/servlet-mapping&gt;<br>&lt;servlet&gt;<br>   &lt;servlet-name&gt;haiservlet&lt;/servlet-name&gt;<br>   &lt;servletclass&gt;com.lmsindia.servlet.HaiServlet&lt;/servletclass&gt;<br>   &lt;init-param&gt;<br>      &lt;param-name&gt;email&lt;/param-name&gt;<br>      &lt;param-value&gt;haisom@lmsindia.org&lt;/param-value&gt;<br>   &lt;/init-param&gt;<br>&lt;/servlet&gt;<br>&lt;servlet-mapping&gt;<br>   &lt;servlet-name&gt;haiservlet&lt;/servlet-name&gt;<br>   &lt;url-pattern&gt;/hai.lms&lt;/url-pattern&gt;<br>&lt;/servlet-mapping&gt;undefined&lt;/web-app&gt;</pre><p>Example Servlets</p><p>1. HelloServlet.java:</p><pre>package com.lmsindia.servlet;<br>import java.io.IOException;<br>import java.io.Writer;<br>import javax.servlet.ServletConfig;<br>import javax.servlet.ServletContext;<br>import javax.servlet.ServletException;<br>import javax.servlet.http.HttpServlet;<br>import javax.servlet.http.HttpServletRequest;<br>import javax.servlet.http.HttpServletResponse;<br>public class HelloServlet extends HttpServlet {<br>    ServletConfig cfg = null;<br>    @Override<br>    public void init(ServletConfig config) throws ServletException {<br>        this.cfg = config; // Corrected to use &#39;config&#39; instead of &#39;cfg&#39;<br>        System.out.println(&quot;init() method of HelloServlet&quot;);<br>    }<br>    @Override<br>    protected void service(HttpServletRequest req, HttpServletResponse res)<br>            throws ServletException, IOException {<br>        System.out.println(&quot;service() method of HelloServlet&quot;);<br>        String fname = req.getParameter(&quot;fname&quot;);<br>        String phone = req.getParameter(&quot;phone&quot;);<br>        Writer out = res.getWriter();<br>        res.setContentType(&quot;text/html&quot;);<br>        out.write(&quot;&lt;h1&gt;Response from HelloServlet&lt;/h1&gt;&quot;);<br>        out.write(&quot;&lt;hr/&gt;Request Parameters&quot;);<br>        out.write(&quot;&lt;br/&gt;Fname: &quot; + fname);<br>        out.write(&quot;&lt;br/&gt;Phone: &quot; + phone);<br>        out.write(&quot;&lt;hr/&gt;Servlet Config Parameters&quot;);<br>        String eml = cfg.getInitParameter(&quot;email&quot;);<br>        out.write(&quot;&lt;br/&gt;&quot; + cfg);<br>        out.write(&quot;&lt;br/&gt;Email: &quot; + eml);<br>        out.write(&quot;&lt;hr/&gt;Servlet Context Parameters&quot;);<br>        ServletContext ctx = cfg.getServletContext();<br>        String web = ctx.getInitParameter(&quot;website&quot;);<br>        out.write(&quot;&lt;br/&gt;&quot; + ctx);<br>        out.write(&quot;&lt;br/&gt;Web: &quot; + web);<br>    }<br>}</pre><p>This servlet handles requests and reads parameters from the HTTP request, ServletConfig, and ServletContext.</p><p>- It retrieves data like fname and phone from the request, email from ServletConfig, and website from ServletContext.</p><p>2. HaiServlet.java:</p><pre>package com.lmsindia.servlet;<br>import java.io.IOException;<br>import java.io.Writer;<br>import javax.servlet.ServletConfig;<br>import javax.servlet.ServletContext;<br>import javax.servlet.ServletException;<br>import javax.servlet.http.HttpServlet;<br>import javax.servlet.http.HttpServletRequest;<br>import javax.servlet.http.HttpServletResponse;<br>public class HaiServlet extends HttpServlet {<br>    @Override<br>    protected void service(HttpServletRequest req, HttpServletResponse res)<br>            throws ServletException, IOException {<br>        System.out.println(&quot;service() method of HelloServlet&quot;);<br>        String fname = req.getParameter(&quot;fname&quot;);<br>        String phone = req.getParameter(&quot;phone&quot;);<br>        Writer out = res.getWriter();<br>        res.setContentType(&quot;text/html&quot;);<br>        out.write(&quot;&lt;h1&gt;Response from HelloServlet&lt;/h1&gt;&quot;);<br>        out.write(&quot;&lt;hr/&gt;Request Parameters&quot;);<br>        out.write(&quot;&lt;br/&gt;Fname: &quot; + fname);<br>        out.write(&quot;&lt;br/&gt;Phone: &quot; + phone);<br>        out.write(&quot;&lt;hr/&gt;Servlet Config Parameters&quot;);<br>        ServletConfig cfg = getServletConfig();<br>        String eml = cfg.getInitParameter(&quot;email&quot;);<br>        out.write(&quot;&lt;br/&gt;&quot; + cfg);<br>        out.write(&quot;&lt;br/&gt;Email: &quot; + eml);<br>        out.write(&quot;&lt;hr/&gt;Servlet Context Parameters&quot;);<br>        ServletContext ctx = cfg.getServletContext();<br>        String web = ctx.getInitParameter(&quot;website&quot;);<br>        out.write(&quot;&lt;br/&gt;&quot; + ctx);<br>        out.write(&quot;&lt;br/&gt;Web: &quot; + web);<br>    }<br>}</pre><p>- Similar to HelloServlet, but handles different parameters and requests.</p><p>Key Points</p><p>- init() method:</p><p>- It initializes the servlet instance when it is created, either upon the first request or during server startup (if specified).</p><p>- If you override the init() method without calling super.init(config), the ServletConfig will not be initialized.</p><p>- Servlet Lifecycle:</p><p>- init(): Called once when the servlet is created.</p><p>- service(): Called for every request to handle the logic.</p><p>- destroy(): Called before the servlet instance is destroyed.</p><h3>Servlet Lifecycle Overview</h3><p>The servlet lifecycle includes three main phases:</p><p>1. Initialization (Container Startup)</p><p>2. Request Processing</p><p>3. Destruction (Container Shutdown)</p><p>1. Initialization Phase (Container Startup)</p><p>When the server starts, the following steps occur:</p><p>1. Reading the web.xml: The container reads the deployment descriptor (web.xml) and stores its data in memory using a parser. If any error occurs in web.xml, the container stops the initialization process and cannot handle requests.</p><p>2. Servlet Context Creation:</p><p>- The container creates a ServletContext object, initializing it with context parameters defined in the web.xml.</p><p>- The context object is shared among all servlets in the web application.</p><p>3. Thread Pool Creation: The container creates a thread pool to handle incoming requests efficiently.</p><p>4. Listener Initialization:</p><p>- All the listeners defined in web.xml are initialized. This involves loading the listener classes, creating instances, and performing any setup tasks specified.</p><p>5. Filter Initialization:</p><p>- All filters specified in the web.xml are initialized. This means the filter classes are loaded, instances are created, and initialization tasks are performed.</p><p>6. Servlet Initialization (load-on-startup):</p><p>- The container checks for servlets configured with the load-on-startup parameter.</p><p>- The HelloServlet has load-on-startup set to a positive value, so it will be initialized when the server starts.</p><p>- For HelloServlet, the container performs the following steps:</p><p>1. Loads the servlet class into memory.</p><p>2. Creates an instance of the servlet using the default constructor.</p><p>3. Creates a ServletConfig object with the servlet’s initialization parameters (city parameter).</p><p>4. Associates the ServletConfig object with the ServletContext object.</p><p>5. Calls the init() method of the servlet with the ServletConfig object, completing the initialization process.</p><p>- The HaiServlet does not have a load-on-startup parameter, so it will be initialized later when the first request is made.</p><p>2. Request Processing Phase</p><p>Case 1: First Request to HelloServlet</p><p>1. URL Pattern Matching: The container matches the incoming URL (/hello.lms) with the servlet mapping.</p><p>2. Thread Allocation: Since HelloServlet is already initialized, the container picks a thread from the thread pool.</p><p>3. Request and Response Creation:</p><p>- A ServletRequest object is created and populated with data from the client.</p><p>- A ServletResponse object is created to hold the response data.</p><p>4. Service Method Invocation:</p><p>- The service() method of the servlet is called with the ServletRequest and ServletResponse objects.</p><p>- The servlet processes the request and generates the response.</p><p>5. Response Delivery: The response is sent back to the client, and the request and response objects are destroyed.</p><p>6. Thread Return: The thread is returned to the thread pool for reuse.</p><p>Case 2: Second Request to HelloServlet</p><p>- The process is the same as Case 1 since HelloServlet is already initialized.</p><p>Case 3: First Request to HaiServlet</p><p>1. URL Pattern Matching: The container matches the URL (/hai.lms) with the servlet mapping.</p><p>2. Servlet Initialization: Since HaiServlet is not yet initialized, the container initializes it by:</p><p>- Loading the servlet class into memory.</p><p>- Creating an instance of the servlet.</p><p>- Creating a ServletConfig object with the initialization parameters.</p><p>- Associating the ServletConfig object with the ServletContext object.</p><p>- Calling the init() method of the servlet.</p><p>3. Thread Allocation: After initialization, a thread from the pool is assigned to handle the request.</p><p>4. Request and Response Creation: The ServletRequest and ServletResponse objects are created.</p><p>5. Service Method Invocation: The service() method of HaiServlet is invoked.</p><p>6. Response Delivery: The response is delivered to the client, and the request and response objects are destroyed.</p><p>7. Thread Return: The thread is returned to the thread pool.</p><p>Case 4: Second Request to HaiServlet</p><p>- The process is the same as the second request to HelloServlet since HaiServlet is now already initialized.</p><p>3. Destruction Phase (Container Shutdown)</p><p>When the server shuts down, the following steps occur:</p><p>1. Thread Pool Destruction: The container destroys the thread pool, stopping all threads.</p><p>2. Servlet Destruction:</p><p>- The container destroys each servlet by calling the destroy() method of each servlet instance.</p><p>- This ensures that the resources held by the servlet are properly released.</p><p>3. Filter Destruction: Each filter is destroyed by invoking its destroy() method.</p><p>4. Listener Destruction: All listeners are destroyed in this phase, releasing any resources they hold.</p><p>5. Session Object Cleanup: Any active session objects are destroyed.</p><p>Summary of the Lifecycle</p><p>1. Container Startup:</p><p>- Reads web.xml, initializes context, listeners, filters, and servlets with load-on-startup.</p><p>2. Request Processing:</p><p>- Servlets handle client requests, with the service method being executed for each request.</p><p>3. Container Shutdown:</p><ul><li>Proper cleanup of resources, threads, servlets, filters, listeners, and session objects.</li></ul><h3>RequestDispatcher Interface Overview</h3><p>- RequestDispatcher is an interface available in the javax.servlet package.</p><p>- It is used to forward a request from one resource (like a servlet, JSP, or HTML page) to another resource on the server or to include the content of one resource in another.</p><p>- This interface provides two key methods:</p><p>- forward(ServletRequest req, ServletResponse res): Forwards a request from one resource to another.</p><p>- include(ServletRequest req, ServletResponse res): Includes the content of a resource in the response.</p><p>forward() Method</p><p>- The forward() method is used to forward the request from:</p><p>- Servlet to HTML</p><p>- Servlet to JSP</p><p>- Servlet to another Servlet</p><p>- JSP to HTML</p><p>- JSP to another JSP</p><p>- JSP to a Servlet</p><p>- Only one forward() can be executed per request. If you try to invoke another forward after the response is committed, you will get a java.lang.IllegalStateException.</p><p>- It prevents response modification or writing content to the response stream after the forward operation.</p><p>Example Usage</p><pre>RequestDispatcher rd = null;<br>rd = req.getRequestDispatcher(&quot;test.html&quot;);<br>rd.forward(req, res);</pre><p>include() Method</p><p>- The include() method is used to include the response of one servlet or JSP in another servlet or JSP.</p><p>- Unlike forward(), you can have multiple include() statements within a servlet or JSP.</p><p>- The response stream remains open after the inclusion, so additional content can still be written.</p><p><strong>Files Required for Servlet Example</strong></p><p>Required Files for Program Example Using forward() Method</p><p>1. Index.html</p><pre>&lt;!DOCTYPE html&gt;<br>&lt;html lang=&quot;en&quot;&gt;<br>&lt;head&gt;<br>    &lt;meta charset=&quot;UTF-8&quot;&gt;<br>    &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1.0&quot;&gt;<br>    &lt;title&gt;Document&lt;/title&gt;<br>&lt;/head&gt;<br>&lt;body&gt;<br>    &lt;h1&gt;THIS IS INDEX HTML&lt;/h1&gt;<br>    &lt;a href=&quot;test.lms&quot;&gt;Test&lt;/a&gt;<br>    &lt;br/&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;</pre><p>2. web.xml</p><pre>&lt;web-app&gt;<br>    &lt;welcome-file-list&gt;<br>        &lt;welcome-file&gt;index.html&lt;/welcome-file&gt;<br>    &lt;/welcome-file-list&gt;<br>    &lt;servlet&gt;<br>        &lt;servlet-name&gt;helloservlet&lt;/servlet-name&gt;<br>        &lt;servlet-class&gt;com.lmsindia.servlet.HelloServlet&lt;/servlet-class&gt;<br>    &lt;/servlet&gt;<br>    &lt;servlet-mapping&gt;<br>        &lt;servlet-name&gt;helloservlet&lt;/servlet-name&gt;<br>        &lt;url-pattern&gt;/test.lms&lt;/url-pattern&gt;<br>    &lt;/servlet-mapping&gt;<br>&lt;/web-app&gt;</pre><p>3. TestServlet.java</p><pre>package com.lmsindia.servlet;<br>import java.io.IOException;<br>import javax.servlet.ServletException;<br>import javax.servlet.http.HttpServlet;<br>import javax.servlet.http.HttpServletRequest;<br>import javax.servlet.http.HttpServletResponse;<br>import java.io.Writer;<br>public class HelloServlet extends HttpServlet {<br>    @Override<br>    protected void service(HttpServletRequest req, HttpServletResponse res)<br>            throws ServletException, IOException {<br>        Writer out = res.getWriter();<br>        out.write(&quot;&lt;h1&gt;Hi, Welcome to lms&lt;/h1&gt;&quot;);<br>    }<br>}</pre><p>Required Files for Servlet Example Using include() Method</p><p>1. Index.html</p><pre>&lt;!DOCTYPE html&gt;<br>&lt;html&gt;<br>&lt;head&gt;<br>    &lt;title&gt;Insert title here&lt;/title&gt;<br>&lt;/head&gt;<br>&lt;body&gt;<br>    &lt;a href=&quot;showhome.lms&quot;&gt;GO TO HOME&lt;/a&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;</pre><p>2. Additional HTML files (Header.html, Footer.html, Menu.html, Home.html, etc.)</p><p>Each of these files contains simple HTML structure with content to be included, like:</p><pre>&lt;html&gt;<br>&lt;body&gt;<br>    &lt;h2&gt;Header Content&lt;/h2&gt;<br>&lt;/body&gt;<br>&lt;/html&gt;</pre><p>3. ShowHomeServlet.java</p><pre>package com.lmsindia.servlet;<br>import java.io.IOException;<br>import javax.servlet.RequestDispatcher;<br>import javax.servlet.ServletException;<br>import javax.servlet.http.HttpServlet;<br>import javax.servlet.http.HttpServletRequest;<br>import javax.servlet.http.HttpServletResponse;<br>public class ShowHomeServlet extends HttpServlet {<br>    @Override<br>    protected void service(HttpServletRequest req, HttpServletResponse res)<br>            throws ServletException, IOException {<br>        RequestDispatcher rd1 = req.getRequestDispatcher(&quot;header.html&quot;);<br>        rd1.include(req, res);<br>        <br>        RequestDispatcher rd2 = req.getRequestDispatcher(&quot;menu.html&quot;);<br>        rd2.include(req, res);<br>        <br>        RequestDispatcher rd3 = req.getRequestDispatcher(&quot;home.html&quot;);<br>        rd3.include(req, res);<br>        <br>        RequestDispatcher rd4 = req.getRequestDispatcher(&quot;footer.html&quot;);<br>        rd4.include(req, res);<br>    }<br>}</pre><p><strong>Key Differences between forward() and include() Methods</strong></p><p>- forward():</p><p>- Transfers control to another resource without returning to the original.</p><p>- Only one forward() is allowed per request.</p><p>- Response is not modifiable after forward() is executed.</p><p>- include():</p><p>- Includes the content of another resource within the response.</p><p>- Allows multiple include() statements.</p><p>- Response stream remains open for additional modifications.</p><h3>Servlet Thread Models</h3><p>Servlets in Java can be implemented using two main thread models:</p><p>1. Single Thread Model</p><p>2. Multi-Thread Model (default and preferred approach)</p><p>1. Single Thread Model</p><p>- The SingleThreadModel interface is a deprecated way to ensure that only one thread executes the servlet’s service() method at a time.</p><p>- Implementing this model means that the servlet container creates a new servlet instance for each request or uses a pool of instances to handle requests, which can lead to significant overhead and inefficiency.</p><p>- The SingleThreadModel interface has been deprecated in J2EE 1.4 due to performance concerns and better alternatives available through proper synchronization.</p><p>2. Multi-Thread Model (default)</p><p>- By default, servlets follow the multi-threaded model, where a single instance of the servlet handles all the requests.</p><p>- Each request is handled by a different thread, which allows multiple clients to access the servlet simultaneously.</p><p>- The servlet container manages threading, which is more efficient and provides better performance for handling concurrent requests.</p><p>Example: Single Thread Model Servlet</p><p>Required Files for Servlet 2.X Example</p><p>The example below demonstrates the use of the Single Thread Model with a servlet named TestServlet. The setup includes an HTML form, the servlet code, and the web configuration file.</p><p>1. Index.html</p><p>This HTML form allows the user to input a name and submit it to the servlet.</p><pre>&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot; &quot;http://www.w3.org/TR/html4/loose.dtd&quot;&gt;<br>&lt;html&gt;<br>   &lt;head&gt;<br>      &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html;charset=ISO-8859-1&quot;&gt;<br>      &lt;title&gt;Enter Name&lt;/title&gt;<br>   &lt;/head&gt;<br>   &lt;body&gt;<br>      &lt;form action=&quot;test.lms&quot;&gt;<br>         &lt;h1&gt;Enter Name&lt;/h1&gt;<br>         &lt;br&gt;<br>         &lt;input type=&quot;text&quot; name=&quot;uname&quot; /&gt;<br>         &lt;br&gt;<br>         &lt;input type=&quot;submit&quot; value=&quot;Check&quot;&gt;<br>      &lt;/form&gt;<br>   &lt;/body&gt;<br>&lt;/html&gt;</pre><p>2. TestServlet.java</p><p>This servlet implements the SingleThreadModel interface to demonstrate how it handles requests in a synchronized manner.</p><pre>package com.lmsindia.servlet;<br>import java.io.IOException;<br>import java.io.Writer;<br>import javax.servlet.ServletException;<br>import javax.servlet.SingleThreadModel;<br>import javax.servlet.http.HttpServlet;<br>import javax.servlet.http.HttpServletRequest;<br>import javax.servlet.http.HttpServletResponse;<br>public class TestServlet extends HttpServlet implements SingleThreadModel {<br>    public TestServlet() {<br>        System.out.println(&quot;**TestServlet Def Cons: &quot; + this);<br>    }<br>    @Override<br>    protected void service(HttpServletRequest req, HttpServletResponse res) <br>            throws ServletException, IOException {<br>        String uname = req.getParameter(&quot;uname&quot;);<br>        Writer out = res.getWriter();<br>        out.flush();<br>        Thread currentThread = Thread.currentThread();<br>        for (int i = 0; i &lt; 10; i++) {<br>            System.out.println(currentThread.getName() + &quot;\t&quot; + uname + &quot;\t&quot; + this);<br>            out.write(&quot;&lt;br/&gt;&quot; + currentThread.getName() + &quot;\t&quot; + uname + &quot;\t&quot; + this);<br>            try {<br>                Thread.sleep(1000); // Simulates a delay in processing<br>            } catch (InterruptedException e) {<br>                e.printStackTrace();<br>            }<br>            out.write(&quot;&lt;h1&gt;Hi &quot; + uname + &quot;&lt;br/&gt;Response from Server&lt;/h1&gt;&quot;);<br>        }<br>    }<br>}</pre><p>Explanation:</p><p>- This servlet uses the SingleThreadModel, meaning each request will be handled in a synchronized way, ensuring no two threads are executing the service method at the same time.</p><p>- The Thread.sleep(1000) statement adds a delay of 1 second to simulate a time-consuming operation.</p><p>- The servlet prints out the current thread name, the user input, and the servlet instance details to the response stream.</p><p>3. web.xml</p><p>The web.xml configuration file registers the servlet and maps it to a URL pattern.</p><pre>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;<br>&lt;web-app xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; <br>         xmlns=&quot;http://java.sun.com/xml/ns/javaee&quot; <br>         xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/webapp_3_0.xsd&quot; <br>         id=&quot;WebApp_ID&quot; <br>         version=&quot;3.0&quot;&gt;<br>   &lt;display-name&gt;lms13&lt;/display-name&gt;<br>   &lt;welcome-file-list&gt;<br>      &lt;welcome-file&gt;index.html&lt;/welcome-file&gt;<br>   &lt;/welcome-file-list&gt;<br>   &lt;servlet&gt;<br>      &lt;servlet-name&gt;TestServlet&lt;/servlet-name&gt;<br>      &lt;servlet-class&gt;com.lmsindia.servlet.TestServlet&lt;/servlet-class&gt;<br>   &lt;/servlet&gt;<br>   &lt;servlet-mapping&gt;<br>      &lt;servlet-name&gt;TestServlet&lt;/servlet-name&gt;<br>      &lt;url-pattern&gt;/test.lms&lt;/url-pattern&gt;<br>   &lt;/servlet-mapping&gt;<br>&lt;/web-app&gt;</pre><p>Key Points on Servlet Thread Models</p><p>- Multi-threaded model (default): Offers better performance and scalability by allowing a single instance of the servlet to handle multiple requests concurrently using multiple threads.</p><p>- SingleThreadModel (deprecated): Intended to simplify thread safety by serializing request handling but is not recommended due to performance drawbacks and higher resource consumption.</p><p>Creating a Servlet Class in Eclipse</p><p>1. Right-click on the src folder in the Eclipse project.</p><p>2. Select New -&gt; Servlet.</p><p>3. Provide the following details:</p><p>- Package name: Specify the package where the servlet will reside.</p><p>- Class name: Enter the name of the servlet class.</p><p>4. Change the superclass if needed, then click Next.</p><p>5. Provide the name of the servlet and the URL mapping.</p><p>6. Optionally, add any required init-parameters.</p><p>7. Click Finish to create the servlet.</p><p>This process sets up the servlet with default method signatures and configurations, making it ready for development.</p><h3>Understanding HttpServletRequest and HttpServletResponse</h3><p>HttpServletRequest and HttpServletResponse are interfaces provided by the Java Servlet API that represent the HTTP request and response in a servlet-based application. They are used to handle client-server communication using the HTTP protocol.</p><p>HttpServletRequest</p><p>- Represents an HTTP request sent by the client to the server.</p><p>- It contains information about the request, such as parameters, headers, cookies, and other data sent by the client.</p><p>Structure of an HTTP Request</p><p>1. Headers: Information about the request, such as the content type, user agent, cookies, and more.</p><p>2. Body: The main data of the request, used mainly in POST requests.</p><p>How Data is Transmitted</p><p>- When using the GET method, parameters are sent as a query string in the URL:</p><pre>http://localhost:9999/lms1/login.lms?username=som&amp;password=lmsindia</pre><p>- URL: <a href="http://localhost:9999/Jtc1/login.jtc">http://localhost:9999/lms1/login.lms</a></p><p>- Context Path: /lms1</p><p>- Protocol: http</p><p>- Host: localhost</p><p>- Port: 9999</p><p>- Query String: username=som&amp;password=lmsindia</p><p>- The data is visible in the URL.</p><p>- When using the POST method, parameters are placed in the request body:</p><p>- Data is not visible in the URL, making it more secure.</p><p>- Allows sending a larger amount of data compared to the GET method.</p><p>HttpServletResponse</p><p>- Represents the response sent by the server back to the client.</p><p>- It contains:</p><p>- Response Headers: Information about the response (e.g., content type, status code).</p><p>- Response Body: The actual content sent to the client (e.g., HTML, JSON).</p><p>Files Required for Program</p><p>1. Index.html</p><p>This HTML file contains a form that sends data using the POST method.</p><pre>&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD HTML 4.01Transitional//EN&quot; <br>&quot;http://www.w3.org/TR/html4/loose.dtd&quot;&gt;<br>&lt;html&gt;<br>   &lt;head&gt;<br>      &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html;charset=ISO-8859-1&quot;&gt;<br>      &lt;title&gt;Request &amp; Response Example&lt;/title&gt;<br>   &lt;/head&gt;<br>   &lt;body&gt;<br>      &lt;center&gt;<br>         &lt;h1&gt;Request &amp; Response Example&lt;/h1&gt;<br>      &lt;/center&gt;<br>      &lt;form action=&quot;test.lms&quot; method=&quot;post&quot;&gt;<br>         &lt;h2&gt;Enter Username&lt;/h2&gt;<br>         &lt;input type=&quot;text&quot; name=&quot;uname&quot; /&gt;<br>         &lt;h2&gt;Enter Password&lt;/h2&gt;<br>         &lt;input type=&quot;password&quot; name=&quot;password&quot; /&gt;<br>         &lt;input type=&quot;submit&quot; value=&quot;Test&quot; /&gt;<br>      &lt;/form&gt;<br>   &lt;/body&gt;<br>&lt;/html&gt;</pre><p>2. TestServlet.java</p><p>The servlet code that processes the request and sends the response.</p><pre>package com.lmsindia.servlet;<br>import java.io.IOException;<br>import java.io.PrintWriter;<br>import java.util.Enumeration;<br>import javax.servlet.ServletException;<br>import javax.servlet.http.HttpServlet;<br>import javax.servlet.http.HttpServletRequest;<br>import javax.servlet.http.HttpServletResponse;<br>public class TestServlet extends HttpServlet {<br>   @Override<br>   protected void service(HttpServletRequest req, HttpServletResponse res)<br>   throws ServletException, IOException {<br>      // 1. Request parameters<br>      String un = req.getParameter(&quot;uname&quot;);<br>      String pw = req.getParameter(&quot;password&quot;);<br>      // 2. Display request parameters<br>      PrintWriter out = res.getWriter();<br>      out.println(&quot;&lt;h1&gt;Username: &quot; + un);<br>      out.println(&quot;&lt;br&gt;Password: &quot; + pw);<br>      out.println(&quot;&lt;br&gt;Request Headers&quot;);<br>      // 3. Request Headers<br>      Enumeration&lt;String&gt; e = req.getHeaderNames();<br>      while (e.hasMoreElements()) {<br>         String hn = e.nextElement();<br>         String hv = req.getHeader(hn);<br>         out.println(&quot;&lt;br&gt;&quot; + hn + &quot;: &quot; + hv);<br>      }<br>      // 4. Locale information<br>      out.println(&quot;&lt;br&gt;Locale: &quot; + req.getLocale());<br>      // 5. Other information<br>      out.println(&quot;&lt;br&gt;Method: &quot; + req.getMethod());<br>      out.println(&quot;&lt;br&gt;RequestURI: &quot; + req.getRequestURI());<br>      out.println(&quot;&lt;br&gt;RequestURL: &quot; + req.getRequestURL());<br>      out.println(&quot;&lt;br&gt;Protocol: &quot; + req.getProtocol());<br>      out.println(&quot;&lt;br&gt;ContentLength: &quot; + req.getContentLength());<br>      out.println(&quot;&lt;br&gt;ContentType: &quot; + req.getContentType());<br>      out.println(&quot;&lt;br&gt;RemoteAddr: &quot; + req.getRemoteAddr());<br>      out.println(&quot;&lt;br&gt;RemotePort: &quot; + req.getRemotePort());<br>      out.println(&quot;&lt;br&gt;RemoteHost: &quot; + req.getRemoteHost());<br>      out.println(&quot;&lt;br&gt;ServerPort: &quot; + req.getServerPort());<br>      out.println(&quot;&lt;br&gt;ServerName: &quot; + req.getServerName());<br>      out.println(&quot;&lt;br&gt;QueryString: &quot; + req.getQueryString());<br>      out.println(&quot;&lt;br&gt;ServletPath: &quot; + req.getServletPath());<br>      out.println(&quot;&lt;br&gt;ContextPath: &quot; + req.getContextPath());<br>   }<br>}</pre><p>3. web.xml</p><p>Configuration file that registers the servlet and maps it to a specific URL pattern.</p><pre>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;<br>&lt;web-app xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; <br>         xmlns=&quot;http://java.sun.com/xml/ns/javaee&quot; <br>         xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/javaee <br>         http://java.sun.com/xml/ns/javaee/webapp_3_0.xsd&quot; <br>         id=&quot;WebApp_ID&quot; <br>         version=&quot;3.0&quot;&gt;<br>   &lt;display-name&gt;lms14&lt;/display-name&gt;<br>   &lt;welcome-file-list&gt;<br>      &lt;welcome-file&gt;index.html&lt;/welcome-file&gt;<br>   &lt;/welcome-file-list&gt;<br>   &lt;servlet&gt;<br>      &lt;servlet-name&gt;TestServlet&lt;/servlet-name&gt;<br>      &lt;servlet-class&gt;com.lmsindia.servlet.TestServlet&lt;/servlet-class&gt;<br>   &lt;/servlet&gt;<br>   &lt;servlet-mapping&gt;<br>      &lt;servlet-name&gt;TestServlet&lt;/servlet-name&gt;<br>      &lt;url-pattern&gt;/test.lms&lt;/url-pattern&gt;<br>   &lt;/servlet-mapping&gt;<br>&lt;/web-app&gt;</pre><p>Key Points</p><p>- GET Method:</p><p>- Data is sent as part of the URL.</p><p>- Limited data transmission capability.</p><p>- Less secure since data is visible in the URL.</p><p>- POST Method:</p><p>- Data is sent in the request body.</p><p>- Supports unlimited data transmission.</p><p>- More secure since data is not visible in the URL.</p><p>Working with Command Prompt</p><p>1. Set up the development directory structure.</p><p>2. Create and edit the required files.</p><p>3. Set the classpath for servlet-api.jar to compile the servlet class.</p><p>- Example:</p><pre>Set CLASSPATH=%CLASSPATH%;E:\Tomcat 6.0\lib\Servlet-api.jar;</pre><p>4. Compile the servlet class and place the files in the required directory.</p><p>5. Deploy the application to the webapps directory of Tomcat.</p><p>6. Start the Tomcat server and test the application using a web browser with the following URL:</p><pre>http://localhost:9999/lmsapp</pre><p><strong>Request Handling with HTTP</strong></p><p>Servlets interact with the HTTP protocol through the following key methods and objects:</p><p>1. HttpServletRequest:<br> — Represents the client’s request and contains information such as request parameters, HTTP headers, and request methods.<br> — Provides methods to access request data:<br> — getParameter(String name): Retrieves a request parameter.<br> — getHeader(String name): Retrieves an HTTP header.<br> — getMethod(): Returns the HTTP method (e.g., GET, POST).<br> — getInputStream(): Retrieves the request body as an input stream.</p><p>2. HttpServletResponse:<br> — Represents the response that will be sent to the client and provides methods to set response headers, status codes, and the response body.<br> — Provides methods to construct the response:<br> — setContentType(String type): Sets the MIME type of the response.<br> — setHeader(String name, String value): Sets a response header.<br> — getWriter(): Returns a PrintWriter to write character data to the response body.<br> — getOutputStream(): Returns an OutputStream to write binary data to the response body.</p><p>3. Handling Different HTTP Methods</p><p>Servlets can handle different HTTP methods by overriding specific methods:</p><p>- doGet(HttpServletRequest req, HttpServletResponse resp):<br> — Handles HTTP GET requests, typically used to retrieve data from the server.<br> — Example:</p><pre>@Override<br>protected void doGet(HttpServletRequest req, HttpServletResponse resp) <br>throws ServletException, IOException {<br>    String name = req.getParameter(&quot;name&quot;);<br>    resp.setContentType(&quot;text/plain&quot;);<br>    resp.getWriter().write(&quot;Hello, &quot; + name);<br>}</pre><p>doPost(HttpServletRequest req, HttpServletResponse resp):<br> — Handles HTTP POST requests, typically used to submit data to the server.<br> — Example:</p><pre>@Override<br>protected void doPost(HttpServletRequest req, HttpServletResponse resp) <br>throws ServletException, IOException {<br>    String data = req.getParameter(&quot;data&quot;);<br>    // Process the data<br>    resp.setContentType(&quot;text/plain&quot;);<br>    resp.getWriter().write(&quot;Data received&quot;);<br>}</pre><p>- doPut(HttpServletRequest req, HttpServletResponse resp):<br> — Handles HTTP PUT requests, which are often used to update resources.</p><p>- doDelete(HttpServletRequest req, HttpServletResponse resp):<br> — Handles HTTP DELETE requests, which are used to delete resources.</p><p>4. Example of a Simple Servlet</p><p>Here’s an example of a basic servlet that handles a GET request:</p><pre>import javax.servlet.*;<br>import javax.servlet.http.*;<br>import java.io.IOException;<br>public class HelloServlet extends HttpServlet {<br>    @Override<br>    protected void doGet(HttpServletRequest req, HttpServletResponse resp) <br>   throws ServletException, IOException {<br>        resp.setContentType(&quot;text/html&quot;);<br>        resp.setCharacterEncoding(&quot;UTF-8&quot;);<br>        resp.getWriter().write(&quot;&lt;html&gt;&lt;body&gt;&lt;h1&gt;Hello, World!&lt;/h1&gt;&lt;/body&gt;&lt;/html&gt;&quot;);<br>    }<br>}</pre><p>5. Request and Response Flow</p><p>1. Client Request:<br> — A client (browser) sends an HTTP request to the server.</p><p>2. Servlet Invocation:<br> — The servlet container receives the request, maps it to the appropriate servlet based on the URL pattern, and calls the service() method of the servlet.</p><p>3. Processing Request:<br> — The servlet processes the request using the HttpServletRequest object and generates a response using the HttpServletResponse object.</p><p>4. Sending Response:<br> — The servlet writes the response content to the HttpServletResponse object.</p><p>5. Client Response:<br> — The server sends the HTTP response back to the client.</p><p>In summary, servlets work with the HTTP protocol by managing the lifecycle of servlets, handling requests and responses through HttpServletRequest and HttpServletResponse objects, and processing different HTTP methods to generate appropriate responses for the client.</p><p><strong>7. What is the Role of the ServletConfig and ServletContext Interfaces?</strong></p><p>In the servlet API, two important interfaces — ServletConfig and ServletContext — provide access to configuration information for servlets and the overall web application. Both are used to share data across the servlet and application scope, but they serve different purposes.</p><p><strong>1. ServletConfig Interface</strong></p><p>ServletConfig is used to configure a specific servlet. It provides information that is specific to that servlet, such as initialization parameters defined in the web.xml file or through annotations. Each servlet in a web application has its own ServletConfig object, which is created by the servlet container when the servlet is initialized.</p><p>Key Methods of ServletConfig:<br> — getInitParameter(String name): Retrieves the value of a specific initialization parameter for the servlet.<br> — getInitParameterNames(): Returns an Enumeration of all initialization parameter names.<br> — getServletContext(): Provides access to the ServletContext object, allowing the servlet to access shared resources.<br> — getServletName(): Returns the name of the servlet as defined in the web.xml or by annotation.</p><p>Example Usage of ServletConfig:</p><pre>import javax.servlet.ServletConfig;<br>import javax.servlet.ServletException;<br>import javax.servlet.annotation.WebServlet;<br>import javax.servlet.http.HttpServlet;<br>import javax.servlet.http.HttpServletRequest;<br>import javax.servlet.http.HttpServletResponse;<br>import java.io.IOException;<br>import java.io.PrintWriter;<br>@WebServlet(&quot;/configExample&quot;)<br>public class ConfigExampleServlet extends HttpServlet {<br>    private String adminEmail;<br>    @Override<br>    public void init(ServletConfig config) throws ServletException {<br>        super.init(config);<br>        // Retrieve initialization parameter from web.xml<br>        adminEmail = config.getInitParameter(&quot;adminEmail&quot;);<br>    }<br>    @Override<br>    protected void doGet(HttpServletRequest request, HttpServletResponse<br>                         response)<br>            throws ServletException, IOException {<br>        response.setContentType(&quot;text/html&quot;);<br>        PrintWriter out = response.getWriter();<br>        out.println(&quot;&lt;html&gt;&lt;body&gt;&quot;);<br>        out.println(&quot;&lt;h1&gt;Servlet Config Example&lt;/h1&gt;&quot;);<br>        out.println(&quot;&lt;p&gt;Admin Email: &quot; + adminEmail + &quot;&lt;/p&gt;&quot;);<br>        out.println(&quot;&lt;/body&gt;&lt;/html&gt;&quot;);<br>    }<br>}</pre><p><strong>When to Use ServletConfig:</strong><br> — Use ServletConfig when you need to pass configuration parameters that are specific to a particular servlet (e.g., a database connection string, a file path, or an email address).</p><p><strong>2. ServletContext Interface</strong></p><p>ServletContext is used to share information across the entire web application. It represents the web application’s environment and can be used to access shared resources such as files, attributes, and initialization parameters that are global to the application. Unlike ServletConfig, there is only one ServletContext object per web application, and it is shared by all servlets in that application.</p><p>Key Methods of ServletContext:<br> — getInitParameter(String name): Retrieves the value of an initialization parameter that is global to the entire web application.<br> — getInitParameterNames(): Returns an Enumeration of all global initialization parameter names.<br> — getAttribute(String name): Retrieves an attribute that has been set in the servlet context.<br> — setAttribute(String name, Object object): Sets an attribute that can be shared across servlets.<br> — getResourceAsStream(String path): Retrieves a resource as an input stream (e.g., a file from the WEB-INF directory).<br> — getRealPath(String path): Converts a virtual path to a real path on the server’s filesystem.<br> — log(String message): Logs a message to the server’s log file.</p><p>Example Usage of ServletContext:</p><pre>import javax.servlet.ServletContext;<br>import javax.servlet.ServletException;<br>import javax.servlet.annotation.WebServlet;<br>import javax.servlet.http.HttpServlet;<br>import javax.servlet.http.HttpServletRequest;<br>import javax.servlet.http.HttpServletResponse;<br>import java.io.IOException;<br>import java.io.PrintWriter;<br>@WebServlet(&quot;/contextExample&quot;)<br>public class ContextExampleServlet extends HttpServlet {<br>    @Override<br>    protected void doGet(HttpServletRequest request, HttpServletResponse <br>                         response)<br>            throws ServletException, IOException {<br>        ServletContext context = getServletContext();<br>        <br>        // Get a global initialization parameter<br>        String supportEmail = context.getInitParameter(&quot;supportEmail&quot;);<br>        <br>        // Set an attribute that can be shared across servlets<br>        context.setAttribute(&quot;appName&quot;, &quot;My Web Application&quot;);<br>        <br>        response.setContentType(&quot;text/html&quot;);<br>        PrintWriter out = response.getWriter();<br>        out.println(&quot;&lt;html&gt;&lt;body&gt;&quot;);<br>        out.println(&quot;&lt;h1&gt;Servlet Context Example&lt;/h1&gt;&quot;);<br>        out.println(&quot;&lt;p&gt;Support Email: &quot; + supportEmail + &quot;&lt;/p&gt;&quot;);<br>        out.println(&quot;&lt;p&gt;Application Name: &quot; + context.getAttribute(&quot;appName&quot;) <br>                    + &quot;&lt;/p&gt;&quot;);<br>        out.println(&quot;&lt;/body&gt;&lt;/html&gt;&quot;);<br>    }<br>}</pre><p>When to Use ServletContext:<br> — Use ServletContext when you need to share data or configuration parameters across the entire web application. <br> — It is also used when you need to interact with resources at the application level (e.g., reading a file from WEB-INF or logging messages).</p><p>Differences Between ServletConfig and ServletContext:<br> <strong>— Scope: </strong><br> — ServletConfig is specific to a single servlet.<br> — ServletContext is shared by all servlets in the web application.<br> <strong>— Initialization Parameters:</strong><br> — ServletConfig provides initialization parameters specific to a servlet.<br> — ServletContext provides initialization parameters that are global to the entire application.<br> <strong>— Attributes:</strong><br> — ServletConfig does not manage attributes.<br> — ServletContext allows you to set and get attributes that are shared across servlets.</p><p><strong>Conclusion</strong><br> — ServletConfig is used for servlet-specific configuration, while ServletContext is used for application-wide configuration and shared resources.<br> — They both provide a way to access initialization parameters, but at different scopes: servlet-specific vs. application-wide.</p><h4>Introduction to JSP (Java Server Pages)</h4><p>Java Server Pages (JSP) is a technology that enables the creation of dynamic web content using a combination of HTML and Java code. JSP is commonly used for developing web applications that generate dynamic content, allowing you to embed Java code directly within HTML pages.</p><p><strong>Key Features of JSP</strong></p><p>1. Combination of HTML and Java Code: JSP allows the mixing of HTML tags with Java code to create web pages with dynamic content.</p><p>2. JSP Processing: The web container processes the JSP file by converting it into a Servlet, which is then compiled and executed to generate the HTML response.</p><p>3. File Extension: JSP files have the .jsp extension.</p><p>4. Predefined Objects: JSP provides several built-in objects that can be accessed without any explicit creation. Some of these objects include:</p><p>- request: Represents the HttpServletRequest object.</p><p>- session: Represents the HttpSession object for session tracking.</p><p>- out: Represents the PrintWriter object for sending data to the response.</p><p>- application: Represents the ServletContext object.</p><p><strong>JSP Scripting Elements</strong></p><p>JSP uses scripting elements to allow Java code to be embedded within the HTML. Here are the primary types of scripting elements:</p><p>1. Scriptlet: Allows you to write Java code that is valid inside a method.</p><pre>&lt;%<br>   // Java code here<br>   int sum = 5 + 3;<br>%&gt;</pre><p>- The code inside &lt;% %&gt; will be executed as part of the Servlet’s service method.</p><p>2. Expression: Outputs the result of an expression to the response.</p><pre>&lt;%= sum %&gt;</pre><p>- The &lt;%= %&gt; syntax evaluates the expression and converts it to a string that is directly inserted into the HTML.</p><p>3. Directive: Used to define page-level settings such as importing classes, content type, etc.</p><pre>&lt;%@ page import=&quot;java.util.Date&quot; %&gt;</pre><p>- Directives are used to import classes or set page properties.</p><p>Example JSP File (Index.jsp)</p><p>Below is an example of a simple JSP file that demonstrates the use of scriptlets, expressions, and directives.</p><pre>&lt;%@ page import=&quot;java.util.Date&quot; %&gt;<br>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=ISO-8859-1&quot; pageEncoding=&quot;ISO-8859-1&quot; %&gt;<br>&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot; &quot;http://www.w3.org/TR/html4/loose.dtd&quot;&gt;<br>&lt;html&gt;<br>   &lt;head&gt;<br>      &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=ISO-8859-1&quot;&gt;<br>      &lt;title&gt;JSP Example&lt;/title&gt;<br>   &lt;/head&gt;<br>   &lt;body&gt;<br>      &lt;h1&gt;THIS IS INDEX JSP&lt;/h1&gt;<br>      &lt;%<br>         for (int i = 0; i &lt; 5; i++) {<br>            System.out.println(i); // prints to server console<br>            out.write(&quot;&lt;br&gt;&quot; + i); // writes to the web page<br>         }<br>      %&gt;<br>      &lt;br&gt;Current Time: <br>      &lt;%<br>         Date dt = new Date();<br>         out.write(&quot;&lt;br&gt;&quot; + dt);<br>         String str = &quot;lms&quot;;<br>      %&gt;<br>      &lt;br&gt;<br>      &lt;font color=&quot;red&quot; size=&quot;5&quot;&gt;&lt;%= dt %&gt;&lt;/font&gt;<br>      &lt;br&gt;<br>      &lt;font color=&quot;red&quot; size=&quot;5&quot;&gt;&lt;%= str %&gt;&lt;/font&gt;<br>   &lt;/body&gt;<br>&lt;/html&gt;</pre><p><strong>Working with Multiple JSP Pages</strong></p><p>Sometimes, JSP pages interact with each other, passing data between them. Here’s an example using two JSP files: Index.jsp and Show.jsp.</p><p>Index.jsp</p><p>The Index.jsp file sets some attributes in the application context, which will be shared across multiple JSP pages.</p><pre>&lt;%@ page import=&quot;java.util.ArrayList&quot; %&gt;<br>&lt;%@ page import=&quot;java.util.List&quot; %&gt;<br>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=ISO-8859-1&quot; pageEncoding=&quot;ISO-8859-1&quot; %&gt;<br>&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD HTML 4.01Transitional//EN&quot; &quot;http://www.w3.org/TR/html4/loose.dtd&quot;&gt;<br>&lt;html&gt;<br>   &lt;head&gt;<br>      &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=ISO-8859-1&quot;&gt;<br>      &lt;title&gt;JSP Example&lt;/title&gt;<br>   &lt;/head&gt;<br>   &lt;body&gt;<br>      &lt;h1&gt;THIS IS INDEX JSP&lt;/h1&gt;<br>      &lt;%<br>         String str = &quot;lms&quot;;<br>         application.setAttribute(&quot;MSG&quot;, str);<br>         List&lt;String&gt; emails = new ArrayList&lt;&gt;();<br>         emails.add(&quot;som@lms.com&quot;);<br>         emails.add(&quot;Rahul@lms.com&quot;);<br>         emails.add(&quot;Neha@lms.com&quot;);<br>         application.setAttribute(&quot;EMAILS&quot;, emails);<br>      %&gt;<br>      &lt;a href=&quot;show.jsp&quot;&gt;Show Data&lt;/a&gt;<br>   &lt;/body&gt;<br>&lt;/html&gt;</pre><p>Show.jsp</p><p>The Show.jsp file retrieves the attributes set by Index.jsp and displays them on the page.</p><pre>&lt;%@ page import=&quot;java.util.List&quot; %&gt;<br>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=ISO-8859-1&quot; pageEncoding=&quot;ISO-8859-1&quot; %&gt;<br>&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD HTML 4.01Transitional//EN&quot; &quot;http://www.w3.org/TR/html4/loose.dtd&quot;&gt;<br>&lt;html&gt;<br>   &lt;head&gt;<br>      &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=ISO-8859-1&quot;&gt;<br>      &lt;title&gt;Show Data&lt;/title&gt;<br>   &lt;/head&gt;<br>   &lt;body&gt;<br>      &lt;h1&gt;THIS IS SHOW JSP&lt;/h1&gt;<br>      &lt;p&gt;Message: &lt;%= application.getAttribute(&quot;MSG&quot;) %&gt;&lt;/p&gt;<br>      &lt;%<br>         List&lt;String&gt; emails = (List&lt;String&gt;)application <br>                                               .getAttribute(&quot;EMAILS&quot;);<br>         for (String email : emails) {<br>      %&gt;<br>         &lt;font color=&quot;red&quot;&gt;&lt;br&gt;&lt;%= email %&gt;&lt;/font&gt;<br>      &lt;%<br>         }<br>      %&gt;<br>   &lt;/body&gt;<br>&lt;/html&gt;</pre><p>Key Concepts in JSP</p><p>- Scripting elements allow embedding Java code in HTML.</p><p>- Directives are used to import classes or set properties for the JSP page.</p><p>- Predefined objects like request, response, session, and application are automatically available in JSP.</p><p>Advantages of JSP</p><p>1. Separation of Content and Logic: Easier to maintain than traditional Servlets because the presentation logic (HTML) is separated from the business logic (Java code).</p><p>2. Predefined Objects: JSP provides implicit objects to handle common tasks like session management and output generation.</p><p>3. Easy to Use: JSP code is easier to write and understand as compared to Servlets.</p><p>Conclusion</p><p>JSP provides a convenient way to create dynamic web pages by combining HTML with Java code. It simplifies web application development by separating the presentation layer from the business logic, making it a popular choice for building Java-based web applications.</p><h4>Session Management in Web Applications</h4><p>Session management is crucial in web applications because HTTP and web servers are stateless by nature. This means they treat each request as a new one without knowing if it comes from the same user or a different one. Session management helps to maintain user information across multiple requests.</p><p>Key Concepts of Session Management</p><p><strong>1. Stateless Nature of HTTP</strong>: The HTTP protocol does not keep track of client interactions. Each request sent to the server is processed independently without any memory of previous requests.</p><p><strong>2. Need for Sessions:</strong> In many applications like shopping carts, user authentication, or personalized content, it’s necessary to track the user’s activity, such as which items they have added to the cart or which pages they have visited.</p><p><strong>3. Session:</strong> A session is a series of related requests and responses between a client and a server. Sessions store user-specific information so that it can be shared across multiple requests.</p><p><strong>How Sessions Work</strong></p><p>To maintain a session, the server uses a session ID to recognize the client. This session ID is generated when a session is created and is stored either in cookies or URL parameters. The server uses this ID to track the session.</p><p>To use sessions in a web application, the following two steps are performed:</p><p><strong>1. Identifying the Client:</strong> Check if the client has an existing session or needs a new one.</p><p><strong>2. Managing the Conversational State:</strong> Store and retrieve user-specific data throughout the session.</p><p>Using HttpSession in JSP/Servlet</p><p>- You can use the HttpServletRequest object to create or access the HttpSession object in JSP/Servlet.</p><p>- Methods to access the session object:</p><pre>HttpSession sess = request.getSession();<br>HttpSession sess = request.getSession(boolean);</pre><p><strong>Example of Session Management Techniques</strong></p><p>Session Management Techniques:</p><p>1. HttpSession (Most common way to store session data)</p><p>2. Cookies (Stores session ID in the client-side browser)</p><p>3. URL Rewriting (Carries session ID within the URL)</p><p>4. Hidden Fields (Uses hidden HTML fields to pass data between requests)</p><p><strong>Example Program for Session Management in a Shopping Cart</strong></p><p>Here’s a breakdown of a JSP/Servlet-based program for handling session management in a shopping cart application:</p><p>Directory:</p><pre>/ShoppingCartApp<br>├── /src<br>│   ├── /com<br>│   │   └── /lmsindia<br>│   │       └── /servlets<br>│   │           ├── AddToCartServlet.java<br>│   │           ├── ShowCartServlet.java<br>│   │           ├── RemoveFromCartServlet.java<br>│   │           └── SearchBooksServlet.java<br>│   ├── /META-INF<br>│   │   └── context.xml<br>│   └── /WEB-INF<br>│       ├── web.xml<br>│       └── classes<br>│           └── (compiled .class files)<br>├── /WebContent<br>│   ├── /jsp<br>│   │   ├── index.jsp<br>│   │   ├── showbooks.jsp<br>│   │   ├── showcart.jsp<br>│   │   └── placeorder.jsp<br>│   ├── /css<br>│   │   └── styles.css (optional CSS files for styling)<br>│   ├── /images<br>│   │   └── (any image files used in the project)<br>│   └── /scripts<br>│       └── scripts.js (optional JavaScript files for client-side logic)<br>└── /lib<br>    └── (external libraries or JAR files required for the project)</pre><p>1. Index.jsp</p><p>This file serves as the entry point for the shopping cart application. It displays a form where users can select a category of books and search for them.</p><pre>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=ISO8859-1&quot; pageEncoding=&quot;ISO-8859-1&quot;%&gt;<br>&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;&quot;http://www.w3.org/TR/html4/loose.dtd&quot;&gt;<br>&lt;html&gt;<br>   &lt;head&gt;<br>      &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=ISO-8859-1&quot;&gt;<br>      &lt;title&gt;lms Bookstore&lt;/title&gt;<br>   &lt;/head&gt;<br>   &lt;body&gt;<br>      &lt;center&gt;<br>         &lt;h1&gt;lms Bookstore&lt;/h1&gt;<br>         &lt;h2&gt;Book Search&lt;/h2&gt;<br>         &lt;form action=&quot;searchbooks.lms&quot; method=&quot;post&quot;&gt;<br>            &lt;table&gt;<br>               &lt;tr&gt;&lt;td&gt;&lt;h2&gt;Select Category&lt;/h2&gt;&lt;/td&gt;&lt;/tr&gt;<br>               &lt;tr&gt;<br>                  &lt;td&gt;<br>                     &lt;select name=&quot;category&quot;&gt;<br>                        &lt;option value=&quot;java&quot;&gt;Java&lt;/option&gt;<br>                        &lt;option value=&quot;Testing&quot;&gt;Testing&lt;/option&gt;<br>                        &lt;option value=&quot;.NET&quot;&gt;.NET&lt;/option&gt;<br>                        &lt;option value=&quot;SAP&quot;&gt;SAP&lt;/option&gt;<br>                     &lt;/select&gt;<br>                  &lt;/td&gt;<br>               &lt;/tr&gt;<br>               &lt;tr&gt;&lt;td&gt;&lt;input type=&quot;submit&quot; value=&quot;SearchBooks&quot;/&gt;&lt;/td&gt;&lt;/tr&gt;<br>            &lt;/table&gt;<br>         &lt;/form&gt;<br>      &lt;/center&gt;<br>   &lt;/body&gt;<br>&lt;/html&gt;</pre><p>Explanation: This JSP page displays a simple dropdown form where users can select a category of books. Upon submission, the form directs the request to the searchbooks.lms servlet to handle the search logic.</p><p>2. Showcart.jsp</p><p>This file is responsible for displaying the items currently in the user’s shopping cart.</p><pre>&lt;%@page import=&quot;java.util.*&quot;%&gt;<br>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=ISO8859-1&quot; pageEncoding=&quot;ISO-8859-1&quot;%&gt;<br>&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTDHTML 4.01 Transitional//EN&quot;&quot;http://www.w3.org/TR/html4/loose.dtd&quot;&gt;<br>&lt;html&gt;<br>   &lt;head&gt;<br>      &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=ISO-8859-1&quot;&gt;<br>      &lt;title&gt;lms BookStore - Shopping Cart&lt;/title&gt;<br>   &lt;/head&gt;<br>   &lt;body&gt;<br>      &lt;center&gt;<br>         &lt;h1&gt;lms BookStore&lt;/h1&gt;<br>         &lt;h2&gt;Your Shopping Cart&lt;/h2&gt;<br>      &lt;/center&gt;<br>      &lt;% <br>         Object object = request.getAttribute(&quot;MSG&quot;);<br>         if(object != null) {<br>      %&gt;<br>      &lt;br&gt;<br>      &lt;center&gt;<br>         &lt;font color=&quot;red&quot; size=&quot;6&quot;&gt;&lt;%= object %&gt;&lt;/font&gt;<br>      &lt;/center&gt;<br>      &lt;%<br>         } else {<br>            object = request.getAttribute(&quot;CART&quot;);<br>            ArrayList&lt;String&gt; blist = (ArrayList&lt;String&gt;) object;<br>            for(String bnm : blist) {<br>      %&gt;<br>      &lt;form action=&quot;removeformcart.lms&quot; method=&quot;post&quot;&gt;<br>         &lt;input type=&quot;hidden&quot; name=&quot;bname&quot; value=&quot;&lt;%= bnm %&gt;&quot;/&gt;<br>         &lt;font size=&quot;5&quot;&gt;&lt;%= bnm %&gt; &lt;input type=&quot;submit&quot; value=&quot;Remove From Cart&quot;/&gt;&lt;/font&gt;<br>      &lt;/form&gt;<br>      &lt;%<br>            }<br>         }<br>      %&gt;<br>      &lt;br&gt;<br>      &lt;center&gt;&lt;a href=&quot;Placeorder.jsp&quot;&gt;PLACE ORDER&lt;/a&gt;&lt;/center&gt;<br>      &lt;center&gt;&lt;br&gt;&lt;a href=&quot;showbooks.jsp&quot;&gt;ADD TO CART&lt;/a&gt;&lt;/center&gt;<br>   &lt;/body&gt;<br>&lt;/html&gt;</pre><p>Explanation: This page displays the list of items in the shopping cart. If the cart is empty or if there’s an error message, it displays the corresponding message. It also provides links to place the order or add more items to the cart.</p><p>3. Showbooks.jsp</p><p>Displays the list of available books based on the category selection.</p><pre>&lt;%@page import=&quot;java.util.*&quot;%&gt;<br>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html;charset=ISO-8859-1&quot; pageEncoding=&quot;ISO-8859-1&quot;%&gt;<br>&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD HTML 4.01Transitional//EN&quot;&quot;http://www.w3.org/TR/html4/loose.dtd&quot;&gt;<br>&lt;html&gt;<br>   &lt;head&gt;<br>      &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html;charset=ISO-8859-1&quot;&gt;<br>      &lt;title&gt;lms Bookstore - Available Books&lt;/title&gt;<br>   &lt;/head&gt;<br>   &lt;body&gt;<br>      &lt;center&gt;<br>         &lt;h1&gt;lms Bookstore&lt;/h1&gt;<br>         &lt;h2&gt;Book List&lt;/h2&gt;<br>         &lt;font color=&quot;green&quot; size=&quot;6&quot;&gt;${ADDED}&lt;/font&gt;<br>      &lt;/center&gt;<br>      &lt;br&gt;<br>      &lt;% Object obj = request.getAttribute(&quot;MSG&quot;);<br>         if (obj != null) { <br>      %&gt;<br>      &lt;br&gt;<br>      &lt;center&gt;<br>         &lt;font color=&quot;red&quot; size=&quot;6&quot;&gt;&lt;%= obj %&gt;&lt;/font&gt;<br>         &lt;br&gt;&lt;a href=&quot;index.jsp&quot;&gt;GO TO SEARCH PAGE&lt;/a&gt;<br>      &lt;/center&gt;<br>      &lt;%<br>         } else {<br>            obj = session.getAttribute(&quot;BOOKS&quot;);<br>            ArrayList&lt;String&gt; blist = (ArrayList&lt;String&gt;) obj;<br>            for (String bnm : blist) {<br>      %&gt;<br>      &lt;form action=&quot;addtocart.lms&quot; method=&quot;post&quot;&gt;<br>         &lt;input type=&quot;hidden&quot; name=&quot;name&quot; value=&quot;&lt;%= bnm %&gt;&quot;/&gt;<br>         &lt;font size=&quot;5&quot;&gt;&lt;%= bnm %&gt; &lt;input type=&quot;submit&quot; value=&quot;ADD TO CART&quot;/&gt;<br>         &lt;/font&gt;<br>      &lt;/form&gt;<br>      &lt;%<br>            }<br>         }<br>      %&gt;<br>      &lt;br&gt;<br>      &lt;form action=&quot;showcart.lms&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;SHOW CART&quot;&gt;&lt;/form&gt;<br>   &lt;/body&gt;<br>&lt;/html&gt;</pre><p>Explanation: This page lists the books based on the selected category. It provides an option to add each book to the shopping cart.</p><p>4. Placeorder.jsp</p><p>This JSP page confirms the order placement and then invalidates the session.</p><pre>&lt;%@page import=&quot;java.util.*&quot;%&gt;<br>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html;charset=ISO-8859-1&quot; pageEncoding=&quot;ISO-8859-1&quot;%&gt;<br>&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD HTML 4.01Transitional//EN&quot;&quot;http://www.w3.org/TR/html4/loose.dtd&quot;&gt;<br>&lt;html&gt;<br>   &lt;head&gt;<br>      &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html;charset=ISO-8859-1&quot;&gt;<br>      &lt;title&gt;Order Confirmation&lt;/title&gt;<br>   &lt;/head&gt;<br>   &lt;body&gt;<br>      &lt;center&gt;<br>         &lt;h1&gt;Bookstore&lt;/h1&gt;<br>         &lt;h2&gt;Your Order has been placed successfully&lt;/h2&gt;<br>         &lt;%<br>            session.invalidate();<br>         %&gt;<br>         &lt;br&gt;<br>         &lt;a href=&quot;index.jsp&quot;&gt;GO TO SEARCH PAGE&lt;/a&gt;<br>      &lt;/center&gt;<br>   &lt;/body&gt;<br>&lt;/html&gt;</pre><p>Explanation: Once the order is placed, the session is invalidated to clear the user’s cart, and a success message is displayed.</p><p>5. Web.xml</p><p>Deployment descriptor that configures the servlet mappings and application settings.</p><pre>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;<br>&lt;web-app xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; <br>   xmlns=&quot;http://java.sun.com/xml/ns/javaee&quot;<br>   xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/javaee <br>   http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd&quot;<br>   id=&quot;WebApp_ID&quot; version=&quot;3.0&quot;&gt;<br>   &lt;display-name&gt;Shopping Cart&lt;/display-name&gt;<br>   &lt;welcome-file-list&gt;<br>      &lt;welcome-file&gt;index.jsp&lt;/welcome-file&gt;<br>   &lt;/welcome-file-list&gt;<br>   &lt;servlet&gt;<br>      &lt;servlet-name&gt;SearchBooks&lt;/servlet-name&gt;<br>      &lt;servlet-class&gt;com.lmsindia.servlets.SearchBooksServlet&lt;/servlet-class&gt;<br>   &lt;/servlet&gt;<br>   &lt;servlet-mapping&gt;<br>      &lt;servlet-name&gt;SearchBooks&lt;/servlet-name&gt;<br>      &lt;url-pattern&gt;/searchbooks.lms&lt;/url-pattern&gt;<br>   &lt;/servlet-mapping&gt;<br>   &lt;servlet&gt;<br>      &lt;servlet-name&gt;AddToCartServlet&lt;/servlet-name&gt;<br>      &lt;servlet-class&gt;com.lmsindia.servlets.AddToCartServlet&lt;/servlet-class&gt;<br>   &lt;/servlet&gt;<br>   &lt;servlet-mapping&gt;<br>      &lt;servlet-name&gt;AddToCartServlet&lt;/servlet-name&gt;<br>      &lt;url-pattern&gt;/addtocart.lms&lt;/url-pattern&gt;<br>   &lt;/servlet-mapping&gt;<br>   &lt;servlet&gt;<br>      &lt;servlet-name&gt;ShowCartServlet&lt;/servlet-name&gt;<br>      &lt;servlet-class&gt;com.lmsindia.servlets.ShowCartServlet&lt;/servlet-class&gt;<br>   &lt;/servlet&gt;<br>   &lt;servlet-mapping&gt;<br>      &lt;servlet-name&gt;ShowCartServlet&lt;/servlet-name&gt;<br>      &lt;url-pattern&gt;/showcart.lms&lt;/url-pattern&gt;<br>   &lt;/servlet-mapping&gt;<br>   &lt;servlet&gt;<br>      &lt;servlet-name&gt;RemoveFromCartServlet&lt;/servlet-name&gt;<br>      &lt;servlet-class&gt;com.lmsindia.servlets.RemoveFromCartServlet&lt;/servlet-class&gt;<br>   &lt;/servlet&gt;<br>   &lt;servlet-mapping&gt;<br>      &lt;servlet-name&gt;RemoveFromCartServlet&lt;/servlet-name&gt;<br>      &lt;url-pattern&gt;/removeformcart.lms&lt;/url-pattern&gt;<br>   &lt;/servlet-mapping&gt;<br>&lt;/web-app&gt;</pre><p>Explanation: This file maps specific URLs to their corresponding servlets and defines the application’s welcome file, which is the page users see first when they access the application.</p><p>Summary of Session Management</p><p>- HttpSession is the most common method for managing sessions.</p><p>- Cookies and URL Rewriting can be used to maintain session IDs.</p><p>- Hidden Fields can be used in forms to pass data between requests.</p><p>Session management is vital for building user-specific experiences in web applications like e-commerce sites, where tracking the user’s state and data is necessary for personalized interactions.</p><h4>Exploring HttpSession in Detail</h4><p>HttpSession is an interface that allows server-side session tracking in Java-based web applications. It helps maintain user data across multiple requests. Here’s a quick overview of its primary methods and uses:</p><p>1. Creating a Session:</p><p>- HttpSession getSession() — Retrieves the current session or creates a new session if none exists.</p><p>- HttpSession getSession(boolean create) — Retrieves the current session, and if create is true, it creates a new session if none exists.</p><p>2. Storing and Retrieving Data from the Session:</p><p>- void setAttribute(String name, Object value) — Stores data in the session as an attribute.</p><p>- Object getAttribute(String name) — Retrieves the value of an attribute stored in the session.</p><p>- void removeAttribute(String name) — Removes an attribute from the session.</p><p>- Enumeration getAttributeNames() — Returns an enumeration of attribute names stored in the session.</p><p>3. Session Management:</p><p>- public String getId() — Returns the unique session ID.</p><p>- public boolean isNew() — Checks if the session is newly created.</p><p>- public void invalidate() — Destroys the session immediately.</p><p>- public void setMaxInactiveInterval(int seconds) — Sets the maximum inactive interval for a session before it expires.</p><p>- public long getLastAccessedTime() — Returns the last time the session was accessed.</p><p>- public long getCreationTime() — Returns the time the session was created.</p><p>Now, let’s take a look at the program files using HttpSession.</p><p>1. Index.jsp</p><p>This JSP page demonstrates the usage of the session to display the session ID and check if the session is new.</p><pre>&lt;%@page session=&quot;false&quot; %&gt;<br>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html;charset=ISO-8859-1&quot; pageEncoding=&quot;ISO-8859-1&quot;%&gt;<br>&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot;&quot;http://www.w3.org/TR/html4/loose.dtd&quot;&gt;<br>&lt;html&gt;<br>   &lt;head&gt;<br>      &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html;charset=ISO-8859-1&quot;&gt;<br>      &lt;title&gt;Session Test&lt;/title&gt;<br>   &lt;/head&gt;<br>   &lt;body&gt;<br>      &lt;h1&gt;<br>         &lt;br&gt;Session ID: &lt;%= session.getId() %&gt;<br>         &lt;br&gt;Is New Session: &lt;%= session.isNew() %&gt;<br>         &lt;br&gt;&lt;a href=&quot;test.lms&quot;&gt;TEST&lt;/a&gt;<br>      &lt;/h1&gt;<br>   &lt;/body&gt;<br>&lt;/html&gt;</pre><p>Explanation:</p><p>- This page retrieves and displays the session ID and checks if the session is new using the methods session.getId() and session.isNew().</p><p>- The link redirects to the TestServlet when clicked.</p><p>2. Web.xml</p><p>This configuration file sets up the servlet mapping and session timeout settings.</p><pre>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;<br>&lt;web-app xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; <br>         xmlns=&quot;http://java.sun.com/xml/ns/javaee&quot;<br>         xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/javaee <br>         http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd&quot; <br>         id=&quot;WebApp_ID&quot; version=&quot;3.0&quot;&gt;<br>   &lt;display-name&gt;lms_20&lt;/display-name&gt;<br>   &lt;welcome-file-list&gt;<br>      &lt;welcome-file&gt;index.jsp&lt;/welcome-file&gt;<br>   &lt;/welcome-file-list&gt;<br>   &lt;servlet&gt;<br>      &lt;servlet-name&gt;TestServlet&lt;/servlet-name&gt;<br>      &lt;servlet-class&gt;com.lmsindia.servlet.TestServlet&lt;/servlet-class&gt;<br>   &lt;/servlet&gt;<br>   &lt;servlet-mapping&gt;<br>      &lt;servlet-name&gt;TestServlet&lt;/servlet-name&gt;<br>      &lt;url-pattern&gt;/test.lms&lt;/url-pattern&gt;<br>   &lt;/servlet-mapping&gt;<br>   &lt;session-config&gt;<br>      &lt;session-timeout&gt;30&lt;/session-timeout&gt;<br>   &lt;/session-config&gt;<br>&lt;/web-app&gt;</pre><p>Explanation:</p><p>- The servlet mapping binds the TestServlet to the URL pattern /test.lms.</p><p>- The &lt;session-config&gt; section sets the session timeout to 30 minutes. This means that if the session remains inactive for 30 minutes, it will be automatically invalidated.</p><p>3. TestServlet.java</p><p>This servlet demonstrates the creation of a session and the use of its properties.</p><pre>package com.lmsindia.servlet;<br>import java.io.IOException;<br>import java.io.Writer;<br>import javax.servlet.ServletException;<br>import javax.servlet.http.HttpServlet;<br>import javax.servlet.http.HttpServletRequest;<br>import javax.servlet.http.HttpServletResponse;<br>import javax.servlet.http.HttpSession;<br>public class TestServlet extends HttpServlet {<br>   @Override<br>   protected void service(HttpServletRequest req, HttpServletResponse res) <br>         throws ServletException, IOException {<br>      HttpSession session = req.getSession(); // Retrieves or creates a new session<br>      Writer out = res.getWriter();<br>      out.write(&quot;&lt;h1&gt;&lt;br&gt;ID: &quot; + session.getId());<br>      out.write(&quot;&lt;br&gt;isNew: &quot; + session.isNew());<br>      // Checking if the session is new or already exists<br>   }<br>}</pre><p>Explanation:</p><p>- req.getSession() creates a new session if none exists or retrieves the current session.</p><p>- session.getId() displays the unique session identifier.</p><p>- session.isNew() checks if the session is newly created (returns true) or if it’s a pre-existing session.</p><p>Session Management Methods</p><p>To manage session expiration, you can use these methods:</p><p>1. Explicitly Destroying a Session:</p><pre>session.invalidate();</pre><p>This method destroys the session immediately.</p><p>2. Setting Session Timeout Interval:</p><pre>session.setMaxInactiveInterval(int intervalInSeconds);</pre><p>This sets the timeout interval, after which the session will expire if it remains inactive.</p><p>3. Session Timeout in Web.xml:</p><pre>&lt;session-config&gt;<br>   &lt;session-timeout&gt;30&lt;/session-timeout&gt;<br>&lt;/session-config&gt;</pre><p>This setting in web.xml defines the timeout interval in minutes for all sessions in the web application.</p><p>Summary</p><p>This example illustrates the basics of session management using HttpSession in a Java web application:</p><p>- Session Tracking: Create, track, and manage user sessions.</p><p>- Session Attributes: Store and retrieve user-specific data in session attributes.</p><p>- Session Invalidation: Destroy sessions explicitly or automatically using timeouts.</p><p>This approach helps maintain state across multiple client requests in stateless HTTP connections, making it fundamental for web applications requiring user-specific interactions.</p><h4>Servlet Scopes</h4><p>Servlets provide three main scopes for managing data: Request Scope, Session Scope, and Context (or Application) Scope. Each scope defines the visibility and lifespan of the data stored within it.</p><p>1. Request Scope</p><p>- Definition: Data stored in the HttpServletRequest object.</p><p>- Accessibility: Accessible only for the duration of a single request. Once the request is completed (e.g., after a response is sent to the client), the data is no longer available.</p><p>- Use Case: Ideal for temporary data that is only needed while processing a specific request, such as form input.</p><p>Methods:</p><p>- void setAttribute(String name, Object value): Stores an attribute in the request.</p><p>- void removeAttribute(String name): Removes an attribute from the request.</p><p>- Object getAttribute(String name): Retrieves an attribute from the request.</p><p>- Enumeration&lt;String&gt; getAttributeNames(): Gets the names of all attributes.</p><p>2. Session Scope</p><p>- Definition: Data stored in the HttpSession object.</p><p>- Accessibility: Accessible across multiple requests made by the same user during a session. A session typically lasts until the user logs out or the session times out.</p><p>- Use Case: Suitable for user-specific data that should persist across requests, such as user preferences or login status.</p><p>Methods:</p><p>- Similar to request scope but using the session object instead.</p><p>3. Context (or Application) Scope</p><p>- Definition: Data stored in the ServletContext object.</p><p>- Accessibility: Accessible by all users across multiple requests. The data persists as long as the application is running, making it suitable for shared resources or configuration settings.</p><p>- Use Case: Best for global data that needs to be accessed by multiple users, like application-wide settings or shared data.</p><p>Methods:</p><p>- Same as above but using the context object.</p><p>Summary</p><p>- Request Scope: Temporary data for a single request.</p><p>- Session Scope: User-specific data across multiple requests within a session.</p><p>- Context/Application Scope: Shared data available to all users and requests during the application’s lifecycle.</p><p>These scopes help manage data effectively in web applications, ensuring that data is available where and when it’s needed while also managing memory efficiently.</p><h4>Exploring Cookies</h4><p>Cookies are small pieces of data stored on the client-side, which help in maintaining session state between HTTP requests. They are used to store user-specific information like session IDs, preferences, or tracking data. Here are the key points:</p><p>1. Creating a Cookie:</p><p>- A cookie is created on the server with a name and value:</p><pre>Cookie ck = new Cookie(&quot;email&quot;, &quot;som@lms.com&quot;);</pre><p>- Cookies store information in key-value pairs, and both the name and value are strings.</p><p>2. Adding a Cookie to the Response:</p><p>- Once a cookie is created, it is added to the HTTP response to send it to the client:</p><pre>response.addCookie(ck);</pre><p>3. Accessing Cookies from a Request:</p><p>- Cookies that were stored on the client machine are sent back to the server with each HTTP request:</p><pre>Cookie[] cookies = request.getCookies();<br>for (Cookie c : cookies) {<br>    String cookieName = c.getName();<br>    String cookieValue = c.getValue();<br>    System.out.println(cookieName + &quot;: &quot; + cookieValue);<br>}</pre><p>4. Removing Cookies:</p><p>- To remove a cookie from the client’s browser, set its maximum age to 0 and add it to the response:</p><pre>Cookie c = new Cookie(&quot;cookieName&quot;, &quot;&quot;);<br>c.setMaxAge(0);<br>response.addCookie(c);</pre><h4>Understanding JSESSIONID Cookie</h4><p>The container manages sessions by using a special cookie named JSESSIONID. The process involves:</p><p>- Creating a cookie with the session ID when a session is created.</p><p>- Adding that cookie to the response to the client.</p><p>- Retrieving this cookie with subsequent requests to track the session.</p><p>Web Container’s Role in Session Management:</p><p>- The server generates a special cookie: JSESSIONID.</p><p>- It adds the JSESSIONID cookie to the response.</p><p>- It uses JSESSIONID to map the session ID to the corresponding session object.</p><p>Example Program Files</p><p>Let’s review the example files involved in demonstrating how to work with cookies in a Java web application.</p><p>1. Index.html</p><p>This file contains a form to add and remove cookies.</p><pre>&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD HTML4.01 Transitional//EN&quot; &quot;http://www.w3.org/TR/html4/loose.dtd&quot;&gt;<br>&lt;html&gt;<br>   &lt;head&gt;<br>      &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=ISO-8859-1&quot;&gt;<br>      &lt;title&gt;Cookie Example&lt;/title&gt;<br>   &lt;/head&gt;<br>   &lt;body&gt;<br>      &lt;h1&gt;Cookie Example&lt;/h1&gt;<br>      &lt;form action=&quot;add.lms&quot; method=&quot;post&quot;&gt;<br>         &lt;input type=&quot;text&quot; name=&quot;bname&quot; /&gt;&lt;br&gt;<br>         &lt;input type=&quot;submit&quot; value=&quot;ADD&quot; /&gt;<br>      &lt;/form&gt;<br>      &lt;hr&gt;<br>      &lt;form action=&quot;remove.lms&quot; method=&quot;post&quot;&gt;<br>         &lt;h2&gt;Enter Book Name&lt;/h2&gt;<br>         &lt;input type=&quot;text&quot; name=&quot;bname&quot; /&gt;&lt;br&gt;<br>         &lt;input type=&quot;submit&quot; value=&quot;Remove&quot; /&gt;<br>      &lt;/form&gt;<br>   &lt;/body&gt;<br>&lt;/html&gt;</pre><p>2. AddServlet.java</p><p>This servlet handles adding a new cookie.</p><pre>package com.lmsindia.servlet;<br>import java.io.IOException;<br>import java.io.Writer;<br>import javax.servlet.RequestDispatcher;<br>import javax.servlet.ServletException;<br>import javax.servlet.http.Cookie;<br>import javax.servlet.http.HttpServlet;<br>import javax.servlet.http.HttpServletRequest;<br>import javax.servlet.http.HttpServletResponse;<br>import javax.servlet.http.HttpSession;<br>public class AddServlet extends HttpServlet {<br>   protected void service(HttpServletRequest req, HttpServletResponse res) <br>                                   throws ServletException, IOException {<br>      Writer out = res.getWriter();<br>      String bnm = req.getParameter(&quot;bname&quot;);<br>      Cookie c1 = new Cookie(bnm, null);<br>      res.addCookie(c1);<br>      out.write(&quot;&lt;h1&gt;&quot; + bnm + &quot; added&lt;/h1&gt;&quot;);<br>      Cookie cs[] = req.getCookies();<br>      if (cs == null) {<br>         out.write(&quot;&lt;h2&gt;You are a new client&lt;/h2&gt;&quot;);<br>         HttpSession sess = req.getSession();<br>      } else {<br>         boolean found = false;<br>         for (Cookie c : cs) {<br>            String nm = c.getName();<br>            String val = c.getValue();<br>            out.write(&quot;&lt;h2&gt;&quot; + nm + &quot;: &quot; + val + &quot;&lt;/h2&gt;&quot;);<br>            if (nm.equals(&quot;JSESSIONID&quot;)) found = true;<br>         }<br>         if (found) {<br>            out.write(&quot;&lt;h2&gt;You are an existing client&lt;/h2&gt;&quot;);<br>         }<br>      }<br>      RequestDispatcher rd = req.getRequestDispatcher(&quot;index.html&quot;);<br>      rd.include(req, res);<br>   }<br>}</pre><p>3. RemoveServlet.java</p><p>This servlet handles removing a cookie.</p><pre>package com.lmsindia.servlet;<br>import java.io.IOException;<br>import java.io.Writer;<br>import javax.servlet.RequestDispatcher;<br>import javax.servlet.ServletException;<br>import javax.servlet.http.Cookie;<br>import javax.servlet.http.HttpServlet;<br>import javax.servlet.http.HttpServletRequest;<br>import javax.servlet.http.HttpServletResponse;<br>import javax.servlet.http.HttpSession;<br>public class RemoveServlet extends HttpServlet {<br>   protected void service(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {<br>      String bnm = req.getParameter(&quot;bname&quot;);<br>      Writer out = res.getWriter();<br>      Cookie[] cs = req.getCookies();<br>      if (cs == null) {<br>         out.write(&quot;&lt;h2&gt;You are a new client&lt;/h2&gt;&quot;);<br>         HttpSession sess = req.getSession();<br>      } else {<br>         boolean found = false;<br>         for (Cookie c : cs) {<br>            String nm = c.getName();<br>            if (nm.equals(bnm)) {<br>               c.setMaxAge(0);<br>               res.addCookie(c);<br>               out.write(&quot;&lt;h2&gt;Cookie &quot; + bnm + &quot; removed&lt;/h2&gt;&quot;);<br>            } else {<br>               out.write(&quot;&lt;h2&gt;&quot; + nm + &quot;: &quot; + c.getValue() + &quot;&lt;/h2&gt;&quot;);<br>            }<br>         }<br>      }<br>      RequestDispatcher rd = req.getRequestDispatcher(&quot;index.html&quot;);<br>      rd.include(req, res);<br>   }<br>}</pre><p>4. Web.xml</p><p>The web descriptor file with servlet mappings.</p><pre>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;<br>&lt;web-app xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;<br>         xmlns=&quot;http://java.sun.com/xml/ns/javaee&quot;<br>         xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd&quot;<br>         id=&quot;WebApp_ID&quot; version=&quot;3.0&quot;&gt;<br>   &lt;display-name&gt;lms22&lt;/display-name&gt;<br>   &lt;welcome-file-list&gt;<br>      &lt;welcome-file&gt;index.html&lt;/welcome-file&gt;<br>   &lt;/welcome-file-list&gt;<br>   &lt;servlet&gt;<br>      &lt;servlet-name&gt;AddServlet&lt;/servlet-name&gt;<br>      &lt;servlet-class&gt;com.lmsindia.servlet.AddServlet&lt;/servlet-class&gt;<br>   &lt;/servlet&gt;<br>   &lt;servlet-mapping&gt;<br>      &lt;servlet-name&gt;AddServlet&lt;/servlet-name&gt;<br>      &lt;url-pattern&gt;/add.lms&lt;/url-pattern&gt;<br>   &lt;/servlet-mapping&gt;<br>   &lt;servlet&gt;<br>      &lt;servlet-name&gt;RemoveServlet&lt;/servlet-name&gt;<br>      &lt;servlet-class&gt;com.lmsindia.servlet.RemoveServlet&lt;/servlet-class&gt;<br>   &lt;/servlet&gt;<br>   &lt;servlet-mapping&gt;<br>      &lt;servlet-name&gt;RemoveServlet&lt;/servlet-name&gt;<br>      &lt;url-pattern&gt;/remove.lms&lt;/url-pattern&gt;<br>   &lt;/servlet-mapping&gt;<br>&lt;/web-app&gt;</pre><p>When dealing with web applications, maintaining a session state between the client and the server is crucial. Cookies are a common method to store session information, but they aren’t always reliable because users can disable them, or certain browsers might not support them. In such scenarios, alternatives like URL Rewriting and Hidden Fields are used to manage session tracking. Let’s explore these two techniques in detail.</p><p>1. URL Rewriting</p><p>URL Rewriting is a technique where the session information (usually the session ID) is appended to the URL of every link or form action in the web application. This way, the session ID is carried in the URL, ensuring that it is passed from the client to the server with each request, even if cookies are disabled.</p><p>How URL Rewriting Works</p><p>When a session is created, the server generates a unique session ID for each user. Instead of relying on cookies to carry this session ID, URL rewriting explicitly appends the session ID to every URL as a query parameter. For example:</p><p>- Original URL: <a href="http://example.com/page.jsp">http://example.com/page.jsp</a></p><p>- Rewritten URL: <a href="http://example.com/page.jsp;jsessionid=12345ABCDEF">http://example.com/page.jsp;jsessionid=12345ABCDEF</a></p><p>The session ID (jsessionid=12345ABCDEF) is appended to the URL. The web server or servlet container recognizes the session ID in the URL and associates it with the correct session object.</p><p><strong>URL Encoding in Java Servlets</strong></p><p>To encode URLs with the session ID automatically, you can use the encodeURL() method provided by the HttpServletResponse class in Java servlets. This method checks whether the client supports cookies and, if not, adds the session ID to the URL.</p><p>Example code:</p><pre>String encodedURL = response.encodeURL(&quot;page.jsp&quot;);</pre><p>- If cookies are enabled, the encoded URL remains as page.jsp.</p><p>- If cookies are disabled, the URL will be rewritten to something like page.jsp;jsessionid=12345ABCDEF.</p><p>The encodeURL() method ensures that the session ID is included only when necessary.</p><p><strong>Advantages of URL Rewriting</strong></p><p>- Works even if cookies are disabled: Since the session ID is carried directly in the URL, it doesn’t rely on cookies.</p><p>- Simple to implement: Most servlet containers handle URL rewriting automatically when you use encodeURL().</p><p>Disadvantages of URL Rewriting</p><p>- URL visibility: The session ID is visible in the URL, which could be a security risk if the URL is shared.</p><p>- Manual intervention: If the web page has many links, each link must be rewritten with the session ID, which can be error-prone.</p><p>- Session expiration: Once the browser is closed, the session ID may be lost if not managed properly.</p><p>2. Hidden Fields</p><p>Hidden Fields are another way to manage session tracking by storing the session ID in a form’s hidden input field. Hidden fields allow data to be passed from the client to the server without displaying it to the user.</p><p>How Hidden Fields Work</p><p>The hidden field is added to the HTML form, and when the form is submitted, the session ID is sent to the server as part of the request. Here is an example of an HTML form with a hidden field:</p><pre>&lt;form action=&quot;page.jsp&quot; method=&quot;post&quot;&gt;<br>    &lt;input type=&quot;hidden&quot; name=&quot;JSESSIONID&quot; value=&quot;&lt;%= session.getId() %&gt;&quot;&gt;<br>    &lt;input type=&quot;text&quot; name=&quot;username&quot; placeholder=&quot;Enter Username&quot;&gt;<br>    &lt;input type=&quot;submit&quot; value=&quot;Submit&quot;&gt;<br>&lt;/form&gt;</pre><p>In this example:</p><p>- The hidden field (&lt;input type=”hidden” name=”JSESSIONID” value=”&lt;%= session.getId() %&gt;”&gt;) holds the session ID.</p><p>- When the form is submitted, the session ID is sent to the server along with the other form data.</p><p>The server can then use the session ID from the hidden field to retrieve the session object associated with the user.</p><p>Advantages of Hidden Fields</p><p>- Compatible with all browsers: Since hidden fields are part of the HTML form, they work with all browsers and are not affected by cookie settings.</p><p>- Easy to use with form submissions: Hidden fields integrate seamlessly with form-based interactions in web applications.</p><p>Disadvantages of Hidden Fields</p><p>- Limited to form submissions: Hidden fields only work when the data is sent via form submissions, making them unsuitable for links or navigation between pages.</p><p>- Manual updates required: You need to ensure that the hidden field is included in every form, which can be cumbersome for large applications.</p><p>- Security risks: Although hidden fields are not visible to the user, they can still be viewed or modified using browser developer tools, so they are not completely secure.</p><p>Comparison of URL Rewriting and Hidden Fields</p><p>When to Use URL Rewriting or Hidden Fields</p><p>- URL Rewriting:</p><p>- Use it when you need to track sessions across multiple pages using links.</p><p>- It is more flexible since it works with any type of HTTP request.</p><p>- Hidden Fields:</p><p>- Use it primarily for form-based interactions.</p><p>- It is ideal when you do not want the session ID to appear in the URL.</p><p>Combining Techniques for Session Management</p><p>For robust session management, it is common to use a combination of cookies, URL rewriting, and hidden fields. Here’s a strategy:</p><p>1. Default to Cookies: Use cookies as the primary method for session tracking since they are simple and widely supported.</p><p>2. Fallback to URL Rewriting: If cookies are disabled, use URL rewriting to carry the session ID in the URL.</p><p>3. Use Hidden Fields: For form submissions, use hidden fields to ensure the session ID is always included in the request.</p><p>By combining these techniques, you can ensure that your web application can maintain sessions effectively even if cookies are not supported or are disabled by the user.</p><p>Conclusion</p><p>URL Rewriting and Hidden Fields are essential alternatives for session tracking when cookies cannot be used. Both techniques have their own use cases and limitations, and understanding their advantages and disadvantages allows you to design more flexible and robust web applications.</p><h4>Filters in Java Servlets</h4><p>Filters are web components similar to servlets but designed to perform tasks before and after the core request processing by a servlet. They allow for pre-processing (before request handling) and post-processing (after response handling) of HTTP requests and responses.</p><p>Why Use Filters?</p><p>Instead of writing the same code for logging, security checks, or other common tasks in multiple servlets, you can use filters to centralize these tasks. This approach reduces code duplication and simplifies maintenance.</p><p>Common Tasks Using Filters</p><p><strong>- Pre-processing tasks (before core request processing):</strong></p><p>- Logging: Keeping track of incoming requests for debugging or auditing.</p><p>- Security checks: Implementing authentication and authorization checks to secure resources.</p><p>- Session validation: Ensuring that user sessions are valid before allowing access to certain parts of the application.</p><p><strong>- Post-processing tasks (after core request processing):</strong></p><p>- Data compression: Compressing the response to improve network efficiency.</p><p>- Data encoding/encryption: Securing sensitive data in the response.</p><p>- URL Rewriting: Modifying URLs in the response, if needed.</p><p><strong>Developing Filters with Servlet 2.x</strong></p><p>To create a filter using Servlet 2.x, you need to:</p><p>1. Create a Filter Class: Implement the javax.servlet.Filter interface.</p><p>2. Override Filter Methods: Implement three lifecycle methods:</p><p>- init(FilterConfig fc): Initializes the filter.</p><p>- doFilter(ServletRequest req, ServletResponse res, FilterChain chain): Handles the request and response.</p><p>- destroy(): Releases resources when the filter is destroyed.</p><p>3. Configure the Filter in web.xml: Register the filter in the web.xml deployment descriptor.</p><p>Example Configuration (web.xml):</p><pre>&lt;filter&gt;<br>    &lt;filter-name&gt;demoFilter&lt;/filter-name&gt;<br>    &lt;filter-class&gt;com.lmsindia.servlet.DemoFilter&lt;/filter-class&gt;<br>    &lt;init-param&gt;<br>        &lt;param-name&gt;city&lt;/param-name&gt;<br>        &lt;param-value&gt;Noida&lt;/param-value&gt;<br>    &lt;/init-param&gt;<br>&lt;/filter&gt;<br>&lt;filter-mapping&gt;<br>    &lt;filter-name&gt;demoFilter&lt;/filter-name&gt;<br>    &lt;url-pattern&gt;/test&lt;/url-pattern&gt;<br>&lt;/filter-mapping&gt;</pre><p>Developing Filters with Servlet 3.0 Annotations</p><p>Servlet 3.0 introduced annotations, making it easier to configure filters directly in the Java code without modifying the web.xml file.</p><p>Steps to develop a filter using Servlet 3.0:</p><p>1. Create a Filter Class: Implement the javax.servlet.Filter interface.</p><p>2. Use Annotations: Configure the filter with the @WebFilter annotation.</p><p>Example Using Annotations:</p><pre>import javax.servlet.Filter;<br>import javax.servlet.FilterChain;<br>import javax.servlet.FilterConfig;<br>import javax.servlet.ServletException;<br>import javax.servlet.annotation.WebFilter;<br>import javax.servlet.annotation.WebInitParam;<br>import javax.servlet.ServletRequest;<br>import javax.servlet.ServletResponse;<br>import java.io.IOException;<br>@WebFilter(filterName=&quot;demoFilter&quot;, urlPatterns={&quot;/demo.lms&quot;},<br>           initParams={@WebInitParam(name=&quot;city&quot;, value=&quot;Noida&quot;)})<br>public class DemoFilter implements Filter {<br>    @Override<br>    public void init(FilterConfig config) throws ServletException {<br>        System.out.println(&quot;**DemoFilter..Init()&quot;);<br>        String city = config.getInitParameter(&quot;city&quot;);<br>        System.out.println(city);<br>    }<br>    @Override<br>    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)<br>            throws IOException, ServletException {<br>        String name = req.getParameter(&quot;name&quot;);<br>        String email = req.getParameter(&quot;email&quot;);<br>        String ip = req.getRemoteAddr();<br>        System.out.println(name);<br>        System.out.println(email);<br>        System.out.println(ip);<br>        chain.doFilter(req, res);  // Continue with the next filter or servlet in the chain<br>        System.out.println(&quot;DemoFilter doFilter()-after&quot;);<br>    }<br>    @Override<br>    public void destroy() {<br>        System.out.println(&quot;destroy()&quot;);<br>    }<br>}</pre><p>Lifecycle of a Filter</p><p>1. Initialization: During server startup, filters are initialized with the init() method.</p><p>- The container loads the filter class and creates an instance.</p><p>- It creates a FilterConfig object containing initialization parameters and a reference to the ServletContext.</p><p>- The init() method is called with the FilterConfig object.</p><p>2. Request Processing:</p><p>- The doFilter() method is invoked for each incoming request.</p><p>- It performs pre-processing tasks and then forwards the request to the next filter or the target servlet using chain.doFilter().</p><p>- Post-processing tasks are performed after the servlet processes the request.</p><p>3. Destruction: When the server shuts down, the filter’s destroy() method is called to release any resources.</p><h4>Filter Configuration Options</h4><p>Filters can be configured to apply to multiple servlets in different ways:</p><p>1. Mapping by URL pattern:</p><pre>&lt;filter-mapping&gt;<br>    &lt;filter-name&gt;filterC&lt;/filter-name&gt;<br>    &lt;url-pattern&gt;/add.lms&lt;/url-pattern&gt;<br>&lt;/filter-mapping&gt;</pre><p>2. Mapping by servlet name:</p><pre>&lt;filter-mapping&gt;<br>    &lt;filter-name&gt;lmsSessionFilter&lt;/filter-name&gt;<br>    &lt;servlet-name&gt;removeServlet&lt;/servlet-name&gt;<br>&lt;/filter-mapping&gt;</pre><p>3. Mapping to multiple URLs:</p><pre>&lt;filter-mapping&gt;<br>    &lt;filter-name&gt;filterC&lt;/filter-name&gt;<br>    &lt;url-pattern&gt;/add.lms&lt;/url-pattern&gt;<br>    &lt;url-pattern&gt;/remove.lms&lt;/url-pattern&gt;<br>&lt;/filter-mapping&gt;</pre><p>4. Mapping to URL patterns with wildcards:</p><pre>&lt;filter-mapping&gt;<br>    &lt;filter-name&gt;lmsSessionFilter&lt;/filter-name&gt;<br>    &lt;url-pattern&gt;*.lms&lt;/url-pattern&gt;<br>&lt;/filter-mapping&gt;</pre><p>Example Files for the Filter Program</p><p>1. Index.html: HTML form for user input.</p><p>2. DemoServlet.java: Servlet handling the core request processing.</p><p>3. DemoFilter.java: Filter for pre-processing and post-processing tasks.</p><p>4. web.xml: Servlet configuration file (if not using annotations).</p><p>Conclusion</p><p>Filters are a powerful way to manage request processing in web applications, allowing developers to handle cross-cutting concerns like security, logging, and data manipulation in a centralized and efficient manner. They help reduce code duplication and make maintenance easier by keeping the logic separate from the core servlet processing.</p><h4>Explanation of Listener Concepts in Servlet API</h4><p>Listeners in the Servlet API are a powerful mechanism that allows developers to monitor and respond to specific events in a web application’s lifecycle. They can track various changes in the application, such as the creation or destruction of objects like ServletContext, HttpSession, or request attributes. Here’s a detailed explanation of listeners and their usage:</p><p>1. Core Tasks Monitored by Listeners</p><p>When a web application is running within a web container, the following tasks can be monitored using listeners:</p><p>1. ServletContext Events:</p><p>- Creating and destroying the ServletContext object.</p><p>- Adding, removing, or replacing attributes in the ServletContext.</p><p>2. HttpServletRequest Events:</p><p>- Creating and destroying the HttpServletRequest object.</p><p>- Adding, removing, or replacing attributes in the HttpServletRequest.</p><p>3. HttpSession Events:</p><p>- Creating and destroying the HttpSession object.</p><p>- Adding, removing, or replacing attributes in the HttpSession.</p><p>- Passivating (serializing) and activating (deserializing) the HttpSession.</p><p>2. List of Listener Interfaces in the Servlet API</p><p>The Servlet API provides several listener interfaces to handle these events. Each listener interface is paired with an event class that encapsulates the event information. Here are the commonly used listener interfaces:</p><p>3. Steps to Create a Listener in Servlet 2.x</p><p>1. Create a Listener Class: Write your own listener class by implementing the required listener interface.</p><p>2. Override the Listener Methods: Implement the methods defined in the listener interface.</p><p>Example:</p><pre>public class MyListener implements ServletContextListener {<br>    @Override<br>    public void contextInitialized(ServletContextEvent sce) {<br>        // Code to execute when the context is initialized<br>    }<br>    @Override<br>    public void contextDestroyed(ServletContextEvent sce) {<br>        // Code to execute when the context is destroyed<br>    }<br>}</pre><p>3. Register the Listener in web.xml:</p><pre>&lt;listener&gt;<br>    &lt;listener-class&gt;com.lms.MyListener&lt;/listener-class&gt;<br>&lt;/listener&gt;</pre><p>4. Steps to Create a Listener in Servlet 3.0</p><p>1. Create a Listener Class: Implement the listener interface.</p><p>2. Override the Listener Methods.</p><p>3. Use Annotations to Register: Register the listener using the @WebListener annotation, eliminating the need to modify web.xml.</p><p>Example:</p><pre>@WebListener<br>public class MyListener implements ServletContextListener {<br>    @Override<br>    public void contextInitialized(ServletContextEvent sce) {<br>        // Code to execute when the context is initialized<br>    }<br>    @Override<br>    public void contextDestroyed(ServletContextEvent sce) {<br>        // Code to execute when the context is destroyed<br>    }<br>}</pre><p><strong>5. Container Tasks During Start-Up and Shutdown</strong></p><p>At Start-Up:</p><p>1. The ServletContext object is created.</p><p>2. Context parameters are retrieved from web.xml and stored.</p><p>3. A ServletContextEvent is created.</p><p>4. The ServletContextListener is created, and the contextInitialized() method is called.</p><p>At Shutdown:</p><p>1. The contextDestroyed() method is invoked on the ServletContextListener.</p><p>2. The ServletContext object is destroyed.</p><h4>Program Files Example Overview</h4><p>1. index.html</p><p>This file is the front-end of the web application. It is an HTML file that contains a simple form with a text field for the user to enter their email address and a submit button.</p><p>Explanation:</p><p>- When the user fills in the email address and clicks on the “Submit” button, the form data is sent to the TestServlet using a POST request.</p><p>- The action=”test.lms” in the form specifies that the request should be handled by the servlet mapped to /test.lms.</p><pre>&lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD HTML4.01 Transitional//EN&quot;&quot;http://www.w3.org/TR/html4/loose.dtd&quot;&gt;<br>&lt;html&gt;<br>   &lt;head&gt;<br>      &lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=ISO-8859-1&quot;&gt;<br>      &lt;title&gt;Insert title here&lt;/title&gt;<br>   &lt;/head&gt;<br>   &lt;body&gt;<br>      &lt;h1&gt;lms&lt;/h1&gt;<br>      &lt;h2&gt;Listener Example&lt;/h2&gt;<br>      &lt;form action=&quot;test.lms&quot; method=&quot;post&quot;&gt;<br>         Enter Email:&lt;input type=&quot;text&quot; name=&quot;email&quot;&gt;<br>         &lt;br/&gt;<br>         &lt;input type=&quot;submit&quot; value=&quot;submit&quot;&gt;<br>      &lt;/form&gt;<br>   &lt;/body&gt;<br>&lt;/html&gt;</pre><p>2. TestServlet.java</p><p>This is the servlet that processes the form submission from index.html. It interacts with the HttpSession and ServletContext to add, replace, and remove attributes.</p><p>Explanation:</p><p>- The servlet uses the service() method to handle the HTTP request.</p><p>- It retrieves the email parameter from the form and stores it as an attribute in the ServletContext.</p><p>- The servlet then performs operations like replacing and removing the attribute from the ServletContext.</p><p>- It also invalidates the current session to trigger the session destruction event.</p><pre>package com.lmsindia.Servlet;<br>import java.io.IOException;<br>import java.io.Writer;<br>import javax.servlet.ServletContext;<br>import javax.servlet.ServletException;<br>import javax.servlet.http.HttpServlet;<br>import javax.servlet.http.HttpServletRequest;<br>import javax.servlet.http.HttpServletResponse;<br>import javax.servlet.http.HttpSession;<br>public class TestServlet extends HttpServlet {<br>   @Override<br>   protected void service(HttpServletRequest req, HttpServletResponse res)<br>   throws ServletException, IOException {<br>      System.out.println(&quot;TestServlet-&gt; service()&quot;);<br>      System.out.println(&quot;Accessing Session object&quot;);<br>      HttpSession session = req.getSession();<br>      String eml = req.getParameter(&quot;email&quot;);<br>      ServletContext ctx = getServletContext();<br>      System.out.println(&quot;Storing attribute in Context&quot;);<br>      ctx.setAttribute(&quot;email&quot;, eml);<br>      System.out.println(&quot;Replacing attributes in Context&quot;);<br>      ctx.setAttribute(&quot;email&quot;, &quot;som@lms.com&quot;);<br>      System.out.println(&quot;Removing attribute in Context&quot;);<br>      ctx.removeAttribute(&quot;email&quot;);<br>      System.out.println(&quot;Validating Session Objects&quot;);<br>      session.invalidate();<br>      Writer out = res.getWriter();<br>      out.write(&quot;&lt;h1&gt;Verify the server console&lt;/h1&gt;&quot;);<br>   }<br>}</pre><p>3. MyContextListener.java</p><p>This listener class implements ServletContextListener and listens to the creation and destruction events of the ServletContext.</p><p>Explanation:</p><p>- contextInitialized() method: Executes when the ServletContext is initialized at the start-up of the web application.</p><p>- contextDestroyed() method: Executes when the ServletContext is destroyed during the shutdown of the web application.</p><pre>package com.lmsindia.Servlet;<br>import javax.servlet.ServletContext;<br>import javax.servlet.ServletContextEvent;<br>import javax.servlet.ServletContextListener;<br>public class MyContextListener implements ServletContextListener {<br>   public MyContextListener() {<br>      System.out.println(&quot;** MyContextListener() default constructor&quot;);<br>   }<br>   @Override<br>   public void contextDestroyed(ServletContextEvent event) {<br>      ServletContext ctx = event.getServletContext();<br>      System.out.println(&quot;ContextDestroyed: &quot; + ctx);<br>   }<br>   @Override<br>   public void contextInitialized(ServletContextEvent event) {<br>      ServletContext ctx = event.getServletContext();<br>      System.out.println(&quot;ContextInitialized: &quot; + ctx);<br>   }<br>}</pre><p>4. MyContextAttributeListener.java</p><p>This listener handles changes in attributes within the ServletContext. It implements ServletContextAttributeListener.</p><p>Explanation:</p><p>- attributeAdded(), attributeRemoved(), and attributeReplaced() methods handle the events of adding, removing, and replacing attributes in the ServletContext.</p><pre>package com.lmsindia.Servlet;<br>import javax.servlet.ServletContextAttributeEvent;<br>import javax.servlet.ServletContextAttributeListener;<br>public class MyContextAttributeListener implements ServletContextAttributeListener {<br>   public MyContextAttributeListener() {<br>      System.out.println(&quot;** MyContextAttributeListener() default constructor&quot;);<br>   }<br>   @Override<br>   public void attributeAdded(ServletContextAttributeEvent event) {<br>      String name = event.getName();<br>      String value = event.getValue().toString();<br>      System.out.println(&quot;Attribute Added: &quot; + name + &quot;\t&quot; + value);<br>   }<br>   @Override<br>   public void attributeRemoved(ServletContextAttributeEvent event) {<br>      String name = event.getName();<br>      String value = event.getValue().toString();<br>      System.out.println(&quot;Attribute Removed: &quot; + name + &quot;\t&quot; + value);<br>   }<br>   @Override<br>   public void attributeReplaced(ServletContextAttributeEvent event) {<br>      String name = event.getName();<br>      String value = event.getValue().toString();<br>      System.out.println(&quot;Attribute Replaced: &quot; + name + &quot;\t&quot; + value);<br>   }<br>}</pre><p>5. MySessionListener.java</p><p>This listener monitors session events. It implements HttpSessionListener.</p><p>Explanation:</p><p>- sessionCreated() method: Executes when a new session is created.</p><p>- sessionDestroyed() method: Executes when a session is destroyed.</p><pre>package com.lmsindia.Servlet;<br>import javax.servlet.http.HttpSessionEvent;<br>import javax.servlet.http.HttpSessionListener;<br>public class MySessionListener implements HttpSessionListener {<br>   public MySessionListener() {<br>      System.out.println(&quot;** MySessionListener() default constructor&quot;);<br>   }<br>   @Override<br>   public void sessionCreated(HttpSessionEvent event) {<br>      System.out.println(&quot;Session Created&quot;);<br>   }<br>   @Override<br>   public void sessionDestroyed(HttpSessionEvent event) {<br>      System.out.println(&quot;Session Destroyed&quot;);<br>   }<br>}</pre><p>6. MyRequestListener.java</p><p>This listener tracks the creation and destruction of HTTP requests. It implements ServletRequestListener.</p><p>Explanation:</p><p>- requestInitialized() method: Executes when a request is initialized.</p><p>- requestDestroyed() method: Executes when a request is destroyed.</p><pre>package com.lmsindia.Servlet;<br>import javax.servlet.ServletRequestEvent;<br>import javax.servlet.ServletRequestListener;<br>public class MyRequestListener implements ServletRequestListener {<br>   public MyRequestListener() {<br>      System.out.println(&quot;MyRequestListener() default constructor&quot;);<br>   }<br>   @Override<br>   public void requestDestroyed(ServletRequestEvent event) {<br>      System.out.println(&quot;Request Destroyed&quot;);<br>   }<br>   @Override<br>   public void requestInitialized(ServletRequestEvent event) {<br>      System.out.println(&quot;Request Initialized&quot;);<br>   }<br>}</pre><p>7. web.xml</p><p>This is the deployment descriptor file that configures the servlet and listener classes for the web application. It tells the web container which classes to use for handling specific events.</p><p>Explanation:</p><p>- It defines servlet mappings for TestServlet.</p><p>- It registers all the listeners (MyContextListener, MyContextAttributeListener, MyRequestListener, and MySessionListener).</p><pre>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;<br>&lt;web-app xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot; xmlns=&quot;http://java.sun.com/xml/ns/javaee&quot;<br>   xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd&quot;<br>   id=&quot;WebApp_ID&quot; version=&quot;3.0&quot;&gt;<br>   &lt;display-name&gt;lms27&lt;/display-name&gt;<br>   &lt;welcome-file-list&gt;<br>      &lt;welcome-file&gt;index.html&lt;/welcome-file&gt;<br>   &lt;/welcome-file-list&gt;<br>   &lt;servlet&gt;<br>      &lt;servlet-name&gt;testServlet&lt;/servlet-name&gt;<br>      &lt;servlet-class&gt;com.lmsindia.Servlet.TestServlet&lt;/servlet-class&gt;<br>   &lt;/servlet&gt;<br>   &lt;servlet-mapping&gt;<br>      &lt;servlet-name&gt;testServlet&lt;/servlet-name&gt;<br>      &lt;url-pattern&gt;/test.lms&lt;/url-pattern&gt;<br>   &lt;/servlet-mapping&gt;<br>   &lt;listener&gt;<br>      &lt;listener-class&gt;com.lmsindia.Servlet.MyContextListener&lt;/listener-class&gt;<br>   &lt;/listener&gt;<br>   &lt;listener&gt;<br>      &lt;listener-class&gt;com.lmsindia.Servlet.MyContextAttributeListener&lt;/listener-class&gt;<br>   &lt;/listener&gt;<br>   &lt;listener&gt;<br>      &lt;listener-class&gt;com.lmsindia.Servlet.MyRequestListener&lt;/listener-class&gt;<br>   &lt;/listener&gt;<br>   &lt;listener&gt;<br>      &lt;listener-class&gt;com.lmsindia.Servlet.MySessionListener&lt;/listener-class&gt;<br>   &lt;/listener&gt;<br>&lt;/web-app&gt;</pre><p>Summary</p><p>- index.html: Displays the form for user input.</p><p>- TestServlet.java: Processes the form submission and interacts with context and session attributes.</p><p>- Listener classes (MyContextListener, MyContextAttributeListener, MySessionListener, MyRequestListener): Handle various lifecycle events of the web application’s components.</p><p>- web.xml: Configures the servlet and listeners to handle requests and lifecycle events.</p><p>These files work together to demonstrate how listeners can be used to track and respond to different events in a Java web application’s lifecycle.</p><p>Here are the key components of a sample Servlet listener implementation:</p><p>1. HTML Form (index.html): Contains a simple form for user interaction.</p><p>2. TestServlet.java: Implements the core logic to interact with session and context attributes.</p><p>3. Listener Classes:</p><p>- MyContextListener.java: Tracks ServletContext initialization and destruction.</p><p>- MyContextAttributeListener.java: Tracks attribute changes in the ServletContext.</p><p>- MySessionListener.java: Monitors session creation and destruction.</p><p>- MyRequestListener.java: Monitors request creation and destruction.</p><p>4. Web Configuration (web.xml): Registers servlets and listeners to the application.</p><p>This approach helps you efficiently manage the different states of your web application’s objects while keeping the code modular and maintainable.</p><h4>Session Migration</h4><p>What is Session Migration?</p><p>Session migration is the process of transferring a user’s session data from one server to another in a distributed or clustered server environment. This is common in large-scale enterprise applications where multiple servers (nodes) are used to handle numerous user requests efficiently.</p><p>Why Session Migration is Needed?</p><p>In a clustered environment, load balancers distribute user requests across multiple servers to handle the load efficiently. If a user starts a session on one server and then their next request is handled by a different server, the session data must be migrated to maintain continuity.</p><p>How Session Migration Works:</p><p>- Session Creation: The user’s first request is processed by a server (e.g., Server 1), where a session object is created.</p><p>- Session Migration: If the subsequent request from the same user is handled by a different server (e.g., Server 3), the session object must be transferred from Server 1 to Server 3.</p><p>- Events in Session Migration: Two key events occur during session migration:</p><p>- Session Passivation: The session is passivated (temporarily stored or serialized) on Server 1 before being transferred.</p><p>- Session Activation: The session is activated (restored or deserialized) on Server 3 when it is needed.</p><p>Handling Session Events with HttpSessionActivationListener</p><p>To handle session passivation and activation events, you can use the HttpSessionActivationListener interface with the following methods:</p><p>- void sessionWillPassivate(HttpSessionEvent event): This method is called by the web container when the session is about to be passivated on the original server (e.g., Server 1).</p><p>- void sessionDidActivate(HttpSessionEvent event): This method is called by the web container when the session is activated on the new server (e.g., Server 3).</p><h4>Servlet API and Class Hierarchy</h4><p>Overview of the Servlet API:</p><p>- javax.servlet.Servlet Interface: This is the root interface for all servlets. It defines the service() method, which is responsible for handling requests from the client.</p><p>- javax.servlet.GenericServlet Class: This is an abstract class that implements the Servlet interface. It provides default implementations for some methods and leaves the service() method abstract. It is used as a base class for servlets that are not tied to any specific protocol.</p><p>- javax.servlet.http.HttpServlet Class: This class extends GenericServlet and is designed for HTTP-based servlets. It provides methods for handling HTTP-specific request types like GET, POST, PUT, and others.</p><p>Servlet Class Hierarchy:</p><p>1. Servlet Interface</p><p>- Contains the method: void service(ServletRequest req, ServletResponse res)</p><p>2. GenericServlet Class</p><p>- Extends the Servlet interface and provides a skeletal implementation.</p><p>- The service() method remains abstract in this class.</p><p>3. HttpServlet Class</p><p>- Extends GenericServlet.</p><p>- It provides implementations for HTTP-specific methods like doGet(), doPost(), and others.</p><p>3. Servlet Method Overriding Cases</p><p>Case 1: Extending HttpServlet and Overriding the Generic service() Method</p><p>If you extend HttpServlet and override the generic service() method, then that overridden method will be called for every request, regardless of the HTTP method (GET, POST, etc.).</p><pre>class HelloServlet extends HttpServlet {<br>    @Override<br>    public void service(ServletRequest req, ServletResponse res) {<br>        // This method will handle all incoming HTTP requests.<br>    }<br>}</pre><p>Case 2: Extending HttpServlet and Overriding the HTTP service() Method</p><p>In this scenario, you extend HttpServlet and override the HTTP-specific service() method, which handles incoming requests at the HTTP level. This method internally determines the HTTP method (GET, POST, etc.) and calls the appropriate doXXX() method.</p><pre>class HelloServlet extends HttpServlet {<br>    @Override<br>    protected void service(HttpServletRequest req, HttpServletResponse res) {<br>        // This method will handle all HTTP requests and delegate to doGet(), doPost(), etc.<br>    }<br>}</pre><p>Case 3: Extending GenericServlet and Overriding the service() Method</p><p>If you extend GenericServlet directly and override the service() method, you will handle all incoming requests generically, without any protocol-specific logic (like GET or POST).</p><pre>class HelloServlet extends GenericServlet {<br>    @Override<br>    public void service(ServletRequest req, ServletResponse res) {<br>        // Handles all requests as a generic servlet, not HTTP-specific.<br>    }<br>}</pre><p>Explanation:</p><p>- Extending GenericServlet means that your servlet is protocol-independent.</p><p>- Since you’re not tied to HTTP, you can’t use methods like doGet() or doPost().</p><p>Case 4: Extending HttpServlet and Overriding Both service() Methods</p><p>If you override both the generic service() method and the HTTP-specific service() method in HttpServlet, then both methods play different roles:</p><p>- The generic service() method will handle all incoming requests.</p><p>- The HTTP service() method will delegate to the appropriate doXXX() method based on the HTTP request type.</p><pre>class HelloServlet extends HttpServlet {<br>    @Override<br>    public void service(ServletRequest req, ServletResponse res) {<br>        // Generic service method<br>    }<br>    @Override<br>    protected void service(HttpServletRequest req, HttpServletResponse res) {<br>        // HTTP-specific service method<br>    }<br>}</pre><p>Explanation:</p><p>- The container first calls the generic service() method, which might call the HTTP-specific service() method.</p><p>- The HTTP-specific method then delegates to doGet(), doPost(), etc., depending on the request type.</p><p>Case 5: Extending HttpServlet and Overriding the doGet() Method</p><p>When you extend HttpServlet and only override the doGet() method, the container automatically determines which HTTP method is being requested and calls the appropriate doXXX() method.</p><pre>class HelloServlet extends HttpServlet {<br>    @Override<br>    protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {<br>        // Handle GET request<br>    }<br>}</pre><p>Explanation:</p><p>- The container invokes the HTTP service() method of HttpServlet.</p><p>- The service() method checks the HTTP method of the request and calls doGet(), doPost(), or other doXXX() methods.</p><p>Key Points to Remember:</p><p>- Generic service() Method: If you override this method in your servlet, it will handle all incoming requests regardless of the HTTP method.</p><p>- HTTP service() Method: If you override this method, it can delegate to HTTP-specific methods like doGet() or doPost().</p><p>- doXXX() Methods: These methods (doGet(), doPost(), etc.) are specifically designed to handle HTTP requests based on the method type. Overriding these methods allows you to handle requests in a more structured and organized way.</p><p>HTTP Status Code 405 Error</p><p>- HTTP Status 405: This error indicates that the HTTP method (e.g., POST) is not supported by the requested URL. This happens when you try to handle a request with a method that your servlet does not support or has not overridden.</p><p>Understanding these cases helps you write more efficient and robust servlets, taking advantage of the servlet lifecycle and session management features to handle HTTP requests properly in your web applications.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=48d76b4a23e1" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Java Essentials: A Deep Dive into the java.lang Package]]></title>
            <link>https://medium.com/@pratik.941/java-lang-package-in-java-04c77e1d3ca7?source=rss-7f42c99fe66f------2</link>
            <guid isPermaLink="false">https://medium.com/p/04c77e1d3ca7</guid>
            <category><![CDATA[backend-development]]></category>
            <category><![CDATA[java]]></category>
            <dc:creator><![CDATA[Pratik T]]></dc:creator>
            <pubDate>Fri, 11 Oct 2024 11:03:16 GMT</pubDate>
            <atom:updated>2024-11-06T02:12:31.997Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*7RhidChjpQwgzKxFc6iW8g.png" /></figure><p>The java.lang package is one of the most fundamental packages in Java and is automatically imported into every Java program. It contains essential classes, interfaces, and methods that are commonly used in Java applications, making it the backbone of the Java language.</p><p><strong>Key Characteristics of the java.lang Package</strong></p><p>1. Default Package: The java.lang package is automatically available to all Java programs, so you don’t need to explicitly import it. This is why you can directly use classes like String, System, Math, and others without importing them.</p><p>2. Purpose: It provides a wide range of classes and interfaces that perform basic and essential operations, such as string manipulation, mathematical operations, system operations, and object manipulation.</p><p>3. Essential Classes: The classes in the java.lang package are fundamental to Java programming. These classes and interfaces provide critical functionalities that form the foundation for creating Java applications.</p><p><strong>Example: Usage of java.lang Classes</strong></p><p>Here’s a simple example demonstrating the use of some classes from the java.lang package:</p><pre>package com.P1;<br>class LMS {<br>    public static void main(String arg[]) {<br>        Object o1 = new Object(); // java.lang.Object class object<br>        String s1 = new String(); // java.lang.String class object<br>    }<br>}</pre><p>In the example above:</p><p>- We are creating an object of the Object class and the String class, both of which belong to the java.lang package.</p><p>- We do not need to import the java.lang.Object or java.lang.String classes, proving that the java.lang package is always available by default.</p><p><strong>Important Classes, Interfaces, and Enums in java.lang</strong></p><p>Here are some of the most commonly used classes, interfaces, and enums in the java.lang package:</p><p>1. java.lang.Object: The root class of the Java class hierarchy. Every class in Java directly or indirectly inherits from this class.</p><p>2. java.lang.String: Represents immutable sequences of characters. Widely used for string manipulations.</p><p>3. java.lang.StringBuffer: A thread-safe, mutable sequence of characters used for string manipulations.</p><p>4. java.lang.StringBuilder: A mutable sequence of characters, similar to StringBuffer but not synchronized, making it faster in single-threaded scenarios.</p><p>5. java.lang.System: Provides access to system resources, standard input/output, and other system-level properties.</p><p>6. java.lang.Runtime: Provides methods that interface with the Java runtime environment.</p><p>7. java.lang.Class: Used to obtain information about classes and objects at runtime.</p><p>8. java.lang.Throwable: The superclass of all errors and exceptions in Java.</p><p>9. java.lang.Exception: The base class for all checked exceptions.</p><p>10. java.lang.Error: Represents serious problems that a reasonable application should not try to catch.</p><p>11. java.lang.RuntimeException: Represents exceptions that can be thrown during the normal operation of the Java Virtual Machine (JVM).</p><p>12. java.lang.Math: Provides methods for performing basic numeric operations such as trigonometry, logarithms, square roots, and random number generation.</p><p>13. java.lang.Thread: Represents a thread of execution in a program.</p><p>14. java.lang.Runnable: An interface that should be implemented by any class whose instances are intended to be executed by a thread.</p><p><strong>Wrapper Classes in java.lang</strong></p><p>Java also provides wrapper classes for the eight primitive data types, and all these classes are part of the java.lang package. Wrapper classes allow you to treat primitive data types as objects.</p><p>1. java.lang.Byte: Wraps the primitive data type byte.</p><p>2. java.lang.Short: Wraps the primitive data type short.</p><p>3. java.lang.Integer: Wraps the primitive data type int.</p><p>4. java.lang.Long: Wraps the primitive data type long.</p><p>5. java.lang.Float: Wraps the primitive data type float.</p><p>6. java.lang.Double: Wraps the primitive data type double.</p><p>7. java.lang.Boolean: Wraps the primitive data type boolean.</p><p>8. java.lang.Character: Wraps the primitive data type char.</p><p><strong>Why is java.lang a Default Package?</strong></p><p>The java.lang package is included by default in every Java program because it contains the most fundamental classes and methods that are required for basic operations in Java. Without these classes, it would be difficult to perform even the simplest tasks in Java, such as:</p><p>- System Operations: Using the System class for input/output operations.</p><p>- String Manipulation: Using String, StringBuffer, and StringBuilder for handling text.</p><p>- Mathematical Calculations: Using the Math class for basic arithmetic operations.</p><p>- Object Methods: Using methods like toString(), equals(), and hashCode() from the Object class.</p><p>The availability of these classes by default ensures that Java developers have easy access to the essential tools needed to build applications without the hassle of manually importing basic classes.</p><h4>java.lang.Object Class</h4><p><strong>Importance of java.lang.Object Class</strong></p><p>- The java.lang.Object class is the root of the Java class hierarchy. Every class in Java implicitly inherits from the Object class unless it explicitly extends another class.</p><p>- This means that all classes in Java, directly or indirectly, are subclasses of Object.</p><p><strong>Members of java.lang.Object Class</strong></p><p>The java.lang.Object class contains several important methods that are frequently used in Java programming. Here is a detailed explanation of these methods:</p><p><strong>1. public java.lang.Object()</strong></p><p>- Type: Constructor</p><p>- Access Modifier: public</p><p>- Description: This is the default constructor of the Object class. It initializes a new instance of the class.</p><p><strong>2. public final native java.lang.Class&lt;?&gt; getClass()</strong></p><p>- Type: Final Instance Method</p><p>- Access Modifier: public</p><p>- Description: Returns the Class object associated with the object’s runtime class. This method is used to get information about the object such as its class name, superclass, interfaces, and other details.</p><p><strong>3. public native int hashCode()</strong></p><p>- Type: Instance Method</p><p>- Access Modifier: public</p><p>- Description: Returns a unique hash code for the object. The hash code is used for efficient storage and retrieval of objects in data structures like hash tables.</p><p><strong>4. public boolean equals(Object obj)</strong></p><p>- Type: Instance Method</p><p>- Access Modifier: public</p><p>- Description: Compares the current object with the specified object for equality. By default, it checks if both objects refer to the same memory location.</p><p><strong>5. protected native Object clone() throws CloneNotSupportedException</strong></p><p>- Type: Instance Method</p><p>- Access Modifier: protected</p><p>- Description: Creates and returns a copy (or clone) of the object. The clone() method is used to perform shallow copying.</p><p><strong>6. public String toString()</strong></p><p>- Type: Instance Method</p><p>- Access Modifier: public</p><p>- Description: Returns a string representation of the object. The default implementation of toString() prints the class name and the hash code in hexadecimal form.</p><p><strong>7. public final native void notify()</strong></p><p>- Type: Instance Method</p><p>- Access Modifier: public</p><p>- Description: Wakes up a single thread that is waiting on the object’s monitor (typically used in thread synchronization).</p><p><strong>8. public final native void notifyAll()</strong></p><p>- Type: Instance Method</p><p>- Access Modifier: public</p><p>- Description: Wakes up all threads that are waiting on the object’s monitor.</p><p><strong>9. public final native void wait(long timeout) throws InterruptedException</strong></p><p>- Type: Instance Method</p><p>- Access Modifier: public</p><p>- Description: Causes the current thread to wait until another thread invokes the notify() or notifyAll() methods for this object, or a specified amount of time has passed.</p><p><strong>10. public final void wait(long timeout, int nanos) throws InterruptedException</strong></p><p>- Type: Instance Method</p><p>- Access Modifier: public</p><p>- Description: Similar to the previous method, but allows for greater precision with the inclusion of nanoseconds.</p><p><strong>11. protected void finalize() throws Throwable</strong></p><p>- Type: Instance Method</p><p>- Access Modifier: protected</p><p>- Description: This method is called by the garbage collector before an object is destroyed to perform any cleanup activities.</p><p>Example Program Demonstrating Object Class Methods</p><pre>class LMS {<br>    public static void main(String arg[]) {<br>        A a1 = new A();<br>        System.out.println(a1.hashCode());<br>        System.out.println(a1.toString());<br>    }<br>}<br>class A {<br>}</pre><p>Explanation:</p><p>- Since class A does not explicitly extend any other class, Object is its superclass by default.</p><p>- We create an object of class A using A a1 = new A(); and use it to call hashCode() and toString(), which are inherited from the Object class.</p><p>Exploring the getClass() Method</p><p>Example:</p><pre>package com.P1;<br>interface I1 {}<br>interface I2 {}<br>interface I3 {}<br>class A implements I1, I2, I3 {}<br>class LMS {<br>    public static void main(String arg[]) {<br>        A a1 = new A();<br>        Class c1 = a1.getClass();<br>        System.out.println(&quot;----A.class file information----&quot;);<br>        System.out.println(&quot;Class Name :- &quot; + c1.getName());<br>        System.out.println(&quot;Class Simple Name :- &quot; + c1.getSimpleName());<br>        System.out.println(&quot;Package Name :- &quot; + c1.getPackage().getName());<br>        System.out.println(&quot;Super Class Name :- &quot; + c1.getSuperclass().getName());<br>        <br>        System.out.println(&quot;---A.class interface information----&quot;);<br>        Class&lt;?&gt;[] interfaces = c1.getInterfaces();<br>        for (Class&lt;?&gt; iface : interfaces) {<br>            System.out.println(&quot;Interface implemented by class A :- &quot; + iface.getName());<br>        }<br>    }<br>}</pre><p>Output:</p><pre>----A.class file information----<br>Class Name :- com.P1.A<br>Class Simple Name :- A<br>Package Name :- com.P1<br>Super Class Name :- java.lang.Object<br>Super Class Package Name :- java.lang<br>---A.class interface information----<br>Interface implemented by class A :- com.P1.I1<br>Interface implemented by class A :- com.P1.I2<br>Interface implemented by class A :- com.P1.I3</pre><p>Explanation:</p><ul><li>This code demonstrates the use of the getClass() method to get detailed information about the A class, including its package, superclass, and interfaces.</li></ul><h4>Garbage collection in Java</h4><p>Garbage collection in Java is an automatic memory management process that handles the cleanup of unused or unreferenced objects from the heap.</p><p><strong>Key Concepts of Garbage Collection in Java</strong></p><p>1. Dynamic Memory Allocation</p><p>- Java uses dynamic memory allocation, primarily in the heap area, where memory for objects is allocated when the new keyword is used.</p><p>- Unlike C/C++, where you have to manually deallocate memory using free() or delete, Java automates this cleanup process using garbage collection.</p><p>2. Garbage Collection Mechanism</p><p>- Purpose: Garbage collection is used to identify and dispose of objects that are no longer referenced, making their memory available for future allocation.</p><p>- The JVM automatically performs this task when it detects that memory resources are low or inefficiently utilized.</p><p><strong>How JVM Identifies Unreferenced Objects</strong></p><p>Here are two examples illustrating when an object becomes eligible for garbage collection:</p><p>Example 1</p><pre>class LMS {<br>    public static void main(String arg[]) {<br>        A a1 = new A();<br>        A a2 = new A();<br>        a1 = null; // line - 7<br>    }<br>}<br>class A {<br>}</pre><p>- In this example, two objects of class A are created.</p><p>- When a1 is set to null at line 7, the first object becomes eligible for garbage collection because it no longer has a reference.</p><p>Example 2</p><pre>class A {<br>    static void m1() {<br>        A a1 = new A();<br>        A a2 = new A();<br>    }<br>    public static void main(String arg[]) {<br>        m1();<br>    }<br>}</pre><p>- Here, the objects created inside the m1() method are local to that method.</p><p>- Once the m1() method execution completes, the local variables a1 and a2 go out of scope, and their objects in the heap become eligible for garbage collection.</p><p><strong>When Does Garbage Collection Occur?</strong></p><p>- The JVM triggers the garbage collection process when it detects that memory resources are low or when there’s a need to reclaim space for new object creation.</p><p>- Garbage collection is not guaranteed to run immediately upon request but is managed by the JVM based on memory availability and the CPU scheduler.</p><p><strong>Important Garbage Collection Methods</strong></p><p><strong>1. System.gc()</strong></p><p>- Syntax: public static void gc()</p><p>- This method suggests that the JVM should make an effort to start the garbage collection process.</p><p>- Internally, it calls Runtime.getRuntime().gc().</p><p>- Note: Calling System.gc() does not guarantee immediate garbage collection.</p><p><strong>2. System.runFinalization()</strong></p><p>- Syntax: public static void runFinalization()</p><p>- This method requests the JVM to run the finalization methods of objects that have been discarded but not yet finalized.</p><p>- Internally, it calls Runtime.getRuntime().runFinalization().</p><p><strong>Steps Followed by JVM for Garbage Collection</strong></p><p>1. Listing Unused Objects: The JVM first identifies objects that are no longer referenced.</p><p>2. gc() Method Invocation: If there is insufficient memory, the JVM calls the System.gc() method to start garbage collection.</p><p>3. Finalization: The JVM may also call runFinalization() to ensure that any necessary cleanup operations for discarded objects are completed.</p><p><strong>Key Points to Remember</strong></p><p>- Garbage collection is automatic in Java and does not require manual intervention like in languages such as C or C++.</p><p>- Although you can request garbage collection using System.gc(), the timing of the actual cleanup depends on the JVM’s memory management strategy.</p><p>- Understanding garbage collection is crucial for efficient memory management and to avoid memory leaks in Java applications.</p><p>Garbage collection ensures that Java applications run smoothly without running out of memory, helping developers focus on logic without worrying about memory cleanup.</p><h3>Cloning</h3><p><a href="https://medium.com/@pratik.941/understanding-the-cloneable-interface-shallow-copy-and-deep-copy-in-java-73c45066ecb1">Please Refer this article</a></p><p>Cloning in Java is a technique to create a copy of an existing object. This process ensures that the new object is a separate instance with its own memory space, even though it may contain the same data as the original object. Java provides two main types of cloning: Shallow Cloning and Deep Cloning. Let’s explore both in detail with examples.</p><p><strong>Shallow Cloning</strong></p><p>Shallow Cloning creates a new object and copies the values of the instance variables from the original object to the new one. However, if the object contains references to other objects (nested objects), only the references are copied, not the actual objects. This means that the cloned object and the original object share references to the same memory locations for nested objects.</p><p>Example of Shallow Cloning</p><pre>class A {<br>    int a;<br>    A(int a) {<br>        this.a = a;<br>    }<br>}<br>class B {<br>    int b;<br>    A a1;<br>    B(int b, A a1) {<br>        this.b = b;<br>        this.a1 = a1;<br>    }<br>}<br>class C implements Cloneable {<br>    int c;<br>    B b1;<br>    C(int c, B b1) {<br>        this.c = c;<br>        this.b1 = b1;<br>    }<br>    C getClone() throws CloneNotSupportedException {<br>        return (C) this.clone();<br>    }<br>}<br>public class LMS {<br>    public static void main(String arg[]) throws CloneNotSupportedException {<br>        A a1 = new A(101);<br>        B b1 = new B(202, a1);<br>        C c1 = new C(303, b1);<br>        C clone = c1.getClone();<br>        System.out.println(&quot;c1.b1.a1.hashCode: &quot; + c1.b1.a1.hashCode());<br>        System.out.println(&quot;clone.b1.a1.hashCode: &quot; + clone.b1.a1.hashCode());<br>    }<br>}</pre><p>Output:</p><pre>c1.b1.a1.hashCode: 123456<br>clone.b1.a1.hashCode: 123456</pre><p>In this example, c1.b1.a1 and clone.b1.a1 have the same hash code, indicating that both objects share the same reference. This is a clear indication of shallow cloning.</p><p><strong>Deep Cloning</strong></p><p>Deep Cloning involves creating a copy of the object as well as all objects that are referenced by the original object. It creates an entirely new instance of the object, including any nested objects, ensuring that the clone and the original object do not share any references.</p><p>Example of Deep Cloning</p><pre>class A {<br>    int a;<br>    A(int a) {<br>        this.a = a;<br>    }<br>}<br>class B {<br>    int b;<br>    A a1;<br>    B(int b, A a1) {<br>        this.b = b;<br>        this.a1 = a1;<br>    }<br>}<br>class C implements Cloneable {<br>    int c;<br>    B b1;<br>    C(int c, B b1) {<br>        this.c = c;<br>        this.b1 = b1;<br>    }<br>    @Override<br>    protected Object clone() throws CloneNotSupportedException {<br>        A clonedA = new A(this.b1.a1.a);<br>        B clonedB = new B(this.b1.b, clonedA);<br>        return new C(this.c, clonedB);<br>    }<br>    C getClone() throws CloneNotSupportedException {<br>        return (C) this.clone();<br>    }<br>}<br>public class LMS {<br>    public static void main(String arg[]) throws CloneNotSupportedException {<br>        A a1 = new A(101);<br>        B b1 = new B(202, a1);<br>        C c1 = new C(303, b1);<br>        C clone = c1.getClone();<br>        System.out.println(&quot;c1.b1.a1.hashCode: &quot; + c1.b1.a1.hashCode());<br>        System.out.println(&quot;clone.b1.a1.hashCode: &quot; + clone.b1.a1.hashCode());<br>    }<br>}</pre><p>Output:</p><pre>c1.b1.a1.hashCode: 123456<br>clone.b1.a1.hashCode: 789012</pre><p>In this example, c1.b1.a1 and clone.b1.a1 have different hash codes, indicating that they are distinct objects. This demonstrates that deep cloning was successfully implemented.</p><p>Key Differences between Shallow and Deep Cloning</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/894/1*k8vS6coD0WaLecAbQwIGPg.png" /></figure><p>Conclusion</p><p>- Shallow Cloning is useful when you are only concerned with creating a copy of the top-level object.</p><p>- Deep Cloning is necessary when the nested objects should also be independently cloned to avoid unwanted reference sharing.</p><p>In Java, deep cloning typically requires manually overriding the clone() method, as the default implementation only provides shallow cloning.</p><h3>java.lang.String</h3><p>The java.lang.String class in Java is a powerful and fundamental part of the Java programming language, used to create and manipulate strings. Here’s a detailed breakdown of its characteristics and important methods:</p><p>Key Characteristics of java.lang.String Class</p><p><strong>1. Not a Primitive Data Type:</strong></p><p>- String is not a primitive data type but a class in the java.lang package.</p><p>- It is one of the most commonly used classes in Java for handling sequences of characters.</p><p><strong>2. Immutable Nature:</strong></p><p>- String objects are immutable, meaning that once a String object is created, its value cannot be changed.</p><p>- If you perform operations like concatenation or modification on a String, a new object is created instead of modifying the existing one.</p><p><strong>3. Final Class:</strong></p><p>- The String class is declared as final, which means it cannot be extended or subclassed.</p><p><strong>4. String Constant Pool (SCP):</strong></p><p>- Java uses a special memory area called the String Constant Pool (SCP) to store string literals.</p><p>- If two strings have the same value, they share the same object in the SCP, which helps save memory.</p><p><strong>5. String Creation:</strong></p><p>- Strings can be created in two ways:</p><p>1. Using String Literals:</p><pre>String s1 = &quot;Hello&quot;;</pre><p>2. Using the new Operator:</p><pre>String s2 = new String(&quot;Hello&quot;);</pre><p><strong>String Creation and SCP Behavior</strong></p><p>String Object Creation in Java</p><p>In Java, when you create String objects, the JVM treats them differently based on whether you use the new keyword or string literals.</p><p>1. String Literal Creation:</p><p>When you create a String using a string literal (e.g., String s3 = “Hello”;), the JVM checks the String Constant Pool (SCP) to see if an object with that value already exists.</p><p>- If it exists: It reuses that existing object.</p><p>- If it does not exist: A new String object is created in the SCP.</p><p>2. Using the new Operator:</p><p>When you use the new keyword (e.g., String s1 = new String(“Hello”);), the following steps occur:</p><p>- The JVM checks the SCP for the string literal “Hello”.</p><p>- If it exists: The existing object in the SCP is not used; instead, a new String object is created on the heap.</p><p>- If it does not exist: A new object is created both in the SCP and on the heap.</p><p>Example Breakdown</p><p>Consider the following code snippet:</p><pre>class A {<br>    public static void main(String arg[]) {<br>        String s1 = new String(&quot;Hello&quot;);<br>        String s2 = new String(&quot;Hello&quot;);<br>        String s3 = &quot;Hello&quot;;<br>        <br>        System.out.println(&quot;s1 == s2 :- &quot; + (s1 == s2));<br>        System.out.println(&quot;s1 == s3 :- &quot; + (s1 == s3));<br>        System.out.println(&quot;s2 == s3 :- &quot; + (s2 == s3));<br>    }<br>}</pre><p>Analysis of the Code:</p><p>- String s1 = new String(“Hello”);:</p><p>- A new String object is created on the heap.</p><p>- The SCP is checked, and since “Hello” might not exist there yet, it’s also added to the SCP.</p><p>- s1 refers to the heap object.</p><p>- String s2 = new String(“Hello”);:</p><p>- Again, a new String object is created on the heap.</p><p>- The SCP is checked, but since “Hello” already exists there (created by s1), it does not create a new SCP object.</p><p>- s2 refers to a different heap object than s1.</p><p>- String s3 = “Hello”;:</p><p>- The SCP is checked for “Hello”, which now exists.</p><p>- s3 refers to the String object in the SCP, not a new object.</p><p>Comparison Results</p><p>Now, when you perform comparisons:</p><p>- s1 == s2:</p><p>- s1 and s2 reference different objects (both created in the heap).</p><p>- Output: false</p><p>- s1 == s3:</p><p>- s1 references the heap object, while s3 references the SCP object.</p><p>- Output: false</p><p>- s2 == s3:</p><p>- s2 also references a different heap object than the SCP object referenced by s3.</p><p>- Output: false</p><p><strong>Why are strings immutable in Java?</strong></p><p>Strings in Java are immutable for several reasons:</p><p>1. Security: Prevents sensitive data from being altered. For example, if a password string is passed to a method, it can’t be changed accidentally within that method.</p><p>2. Hashing and Caching: Ensures consistent hash codes, which is crucial for using strings as keys in hash maps. For example, if String key = “example”; is used as a key, it will always hash the same way.</p><p>3. Thread Safety: Multiple threads can access the same string without concern for it being modified, making it easier to write safe concurrent code.</p><p>4. Performance Optimization: Allows string interning. For example, String s1 = “Hello”; and String s2 = “Hello”; will refer to the same object in memory, saving space.</p><p>5. Simplified Code: Code is easier to reason about. If a method returns a string, you can trust it won’t change after being returned.</p><p>Example:</p><pre>String s1 = &quot;Hello&quot;;<br>String s2 = s1.toUpperCase(); // s1 remains &quot;Hello&quot;, s2 becomes &quot;HELLO&quot;</pre><p>In this example, s1 is unchanged, demonstrating immutability in action.</p><p><strong>Important Methods in java.lang.String</strong></p><p><strong>1. hashCode():</strong></p><p>- The hashCode() method in the String class is overridden to generate a hash code based on the string’s content.</p><p>- Two strings with the same content will have the same hash code.</p><p>Example:</p><pre>String s1 = new String(&quot;abc&quot;);<br>String s2 = new String(&quot;abc&quot;);<br>System.out.println(s1 == s2); // false<br>System.out.println(s1.hashCode()); // 96354<br>System.out.println(s2.hashCode()); // 96354</pre><p><strong>2. equals():</strong></p><p>- The equals() method in the String class is overridden to compare the actual content of strings rather than their references.</p><p>Example:</p><pre>String s1 = new String(&quot;abc&quot;);<br>String s2 = new String(&quot;abc&quot;);<br>System.out.println(s1 == s2); // false<br>System.out.println(s1.equals(s2)); // true</pre><p><strong>3. compareTo():</strong></p><p>- The compareTo() method compares two strings lexicographically based on their Unicode values.</p><p>- It returns:</p><p>- 0 if the strings are equal.</p><p>- A negative number if the first string is lexicographically less than the second.</p><p>- A positive number if the first string is lexicographically greater than the second.</p><p>Example:</p><pre>String s1 = &quot;ABC&quot;;<br>String s2 = &quot;ABC&quot;;<br>String s3 = &quot;ACC&quot;;<br>String s4 = &quot;ABCLMS&quot;;<br>System.out.println(s1.compareTo(s2)); // 0<br>System.out.println(s1.compareTo(s3)); // -1<br>System.out.println(s1.compareTo(s4)); // -3<br>System.out.println(s3.compareTo(s4)); // 1</pre><p><strong>4. split():</strong></p><p>- The split() method splits a string into an array of substrings based on a specified delimiter.</p><p>Example:</p><pre>String s1 = &quot;Hello Welcome to the LMS Tutorial&quot;;<br>String[] ar1 = s1.split(&quot; &quot;);<br>for (int i = 0; i &lt; ar1.length; i++) {<br>    System.out.println(&quot;Index: &quot; + i + &quot; Value: &quot; + ar1[i]);<br>}</pre><p>Output:</p><pre>Index: 0 Value: Hello<br>Index: 1 Value: Welcome<br>Index: 2 Value: to<br>Index: 3 Value: the<br>Index: 4 Value: LMS<br>Index: 5 Value: Tutorial</pre><p>Immutability in Action</p><p>- When you concatenate strings, a new string is created:</p><pre>String s1 = &quot;Hello&quot;;<br>String s2 = &quot;LMS&quot;;<br>String s3 = s1 + s2;<br>String s4 = &quot;HelloLMS&quot;;<br>System.out.println(s3 == s4); // false</pre><p>In this example, the comparison s3 == s4 evaluates to false because of how Java handles string creation and memory allocation.</p><p>1. String Creation:<br> — String s1 = “Hello”; creates a String literal in the String Constant Pool (SCP).<br> — String s2 = “LMS”; also creates another String literal in the SCP.<br> — String s3 = s1 + s2; creates a new String object in the heap, as it results from concatenation. Even though s3 will contain the value “HelloLMS”, it is a different object in memory.</p><p>2. String Literal:<br> — String s4 = “HelloLMS”; creates another String literal in the SCP.</p><p>Comparison:<br> — The expression s3 == s4 checks if both s3 and s4 reference the same object in memory.<br> — Since s3 is a new object created by concatenation and s4 is a literal in the SCP, they are two distinct objects.</p><pre>System.out.println(s3.equals(s4)); // true</pre><p>This will return true since both strings have the same content.</p><p>Using final makes the concatenated strings refer to the same object:</p><pre>final String s1 = &quot;Hello&quot;;<br>final String s2 = &quot;LMS&quot;;<br>String s3 = s1 + s2;<br>String s4 = &quot;HelloLMS&quot;;<br>System.out.println(s3 == s4); // true</pre><p>In this example, the expression s3 == s4 evaluates to true due to the use of final keywords for s1 and s2. Here’s a detailed explanation:</p><p>1. Final Variables:<br> — The final keyword indicates that the variables s1 and s2 cannot be reassigned. This means their values are known at compile time.</p><p>2. String Concatenation:<br> — When you create String s3 = s1 + s2;, the Java compiler recognizes that both s1 and s2 are final. Therefore, it can optimize the concatenation at compile time.<br> — The compiler effectively replaces s1 + s2 with the literal ”HelloLMS” during the compilation process.</p><p>3. String Literal:<br> — String s4 = “HelloLMS”; creates a String literal in the String Constant Pool (SCP).</p><p>Memory Reference:<br> — Since both s3 (the result of the concatenation) and s4 (the literal) resolve to the same string literal ”HelloLMS” in the SCP, they reference the same memory object.</p><p>Comparison:<br> — The expression s3 == s4 checks if both references point to the same object.<br> — In this case, they do, so the result is true.</p><pre>System.out.println(s3.equals(s4)); // true</pre><h4>StringBuffer</h4><p>The StringBuffer class in Java, which is part of the java.lang package, is designed for mutable string manipulation. Here’s a breakdown of the key points regarding StringBuffer:</p><p><strong>Key Characteristics of StringBuffer</strong></p><p>1. Mutability: Unlike String objects, StringBuffer objects are mutable, meaning they can be modified after creation without creating a new object.</p><p>2. Memory Allocation: Objects of StringBuffer are stored in the heap area and do not use the string pool like String objects.</p><p>3. Final Class: StringBuffer is a final class, so it cannot be extended.</p><p>4. Thread-Safety: All methods in StringBuffer are synchronized, making it thread-safe, but this synchronization can lead to performance issues in a multi-threaded environment.</p><p><strong>Creating StringBuffer Objects</strong></p><p>- Default Constructor: When you create a StringBuffer using the default constructor, the initial capacity is set to 16.</p><pre>StringBuffer s1 = new StringBuffer(); // Capacity is 16</pre><p>- Custom Capacity: You can also specify a custom initial capacity.</p><pre>StringBuffer s2 = new StringBuffer(20); // Capacity is 20</pre><p>- With String Literal: If you create a StringBuffer with a string literal, the initial capacity is set to the length of the string plus 16.</p><pre>StringBuffer s3 = new StringBuffer(&quot;LMS&quot;); // Capacity is 19 (3 + 16)</pre><p>Example of StringBuffer’s Mutable Behavior</p><p>Here’s a demonstration of how mutability works with the append() method:</p><pre>class LMS {<br>    public static void main(String arg[]) {<br>        StringBuffer s1 = new StringBuffer(&quot;Hello&quot;);<br>        StringBuffer s2 = s1.append(&quot;LMS&quot;);<br>        System.out.println(&quot;s1 :- &quot; + s1); // Output: HelloLMS<br>        System.out.println(&quot;s2 :- &quot; + s2); // Output: HelloLMS<br>        System.out.println(&quot;s1 == s2 :- &quot; + (s1 == s2)); // Output: true<br>    }<br>}</pre><p>In this example, both s1 and s2 reference the same object. Since StringBuffer objects are mutable, the append() operation modifies the original object itself.</p><p><strong>Capacity and Growth Mechanism</strong></p><p>The capacity of a StringBuffer can increase as more characters are added. The formula to calculate the new capacity when the current capacity is exceeded is:</p><pre>New Capacity = (Current Capacity + 1) *2</pre><p>Example of Capacity Growth</p><pre>class LMS {<br>    public static void main(String arg[]) {<br>        StringBuffer s1 = new StringBuffer();<br>        System.out.println(&quot;s1.capacity :- &quot; + s1.capacity()); // 16<br>        System.out.println(&quot;s1.length :- &quot; + s1.length()); // 0<br>        s1.append(&quot;1234567890111213&quot;);<br>        System.out.println(&quot;s1.capacity :- &quot; + s1.capacity()); // 16<br>        System.out.println(&quot;s1.length :- &quot; + s1.length()); // 16<br>        s1.append(&quot;14&quot;);<br>        System.out.println(&quot;s1.capacity :- &quot; + s1.capacity()); // 34<br>        System.out.println(&quot;s1.length :- &quot; + s1.length()); // 18<br>        s1.append(&quot;1516171819202122232425&quot;);<br>        System.out.println(&quot;s1.capacity :- &quot; + s1.capacity()); // 70<br>        System.out.println(&quot;s1.length :- &quot; + s1.length()); // 40<br>        s1.append(&quot;1234567890123456789012345678901&quot;);<br>        System.out.println(&quot;s1.capacity :- &quot; + s1.capacity()); // 142<br>        System.out.println(&quot;s1.length :- &quot; + s1.length()); // 71<br>    }<br>}</pre><p>In this example, you can see how the capacity changes when the length of the StringBuffer exceeds its current capacity.</p><p><strong>Important Methods of StringBuffer</strong></p><p>1. length()</p><p>- Description: Returns the length of the string in the StringBuffer.</p><p>- Syntax: public synchronized int length();</p><p>2. capacity()</p><p>- Description: Returns the current capacity of the StringBuffer.</p><p>- Syntax: public synchronized int capacity();</p><p>3. append()</p><p>- Description: Appends the specified string to the existing StringBuffer and returns the same object.</p><p>- Syntax: public synchronized StringBuffer append(String str);</p><p><strong>Performance Consideration</strong></p><p>Although StringBuffer is thread-safe due to synchronization, this can cause performance issues in multi-threaded applications because only one thread can operate on a StringBuffer object at a time. To overcome this limitation, consider using StringBuilder, which is similar to StringBuffer but without synchronization, making it faster in single-threaded scenarios.</p><p><strong>Use Cases</strong></p><p>- Frequent String Modifications: Use StringBuffer when you need to perform frequent modifications to strings to avoid the overhead of creating multiple String objects.</p><p>- Thread Safety: If thread safety is required, StringBuffer is a better choice than StringBuilder.</p><p>Understanding when to use String, StringBuffer, or StringBuilder is crucial for writing efficient Java code, especially when dealing with string manipulation and concurrency.</p><h4>StringBuilder class</h4><p>The StringBuilder class in Java is a mutable sequence of characters, very similar to the StringBuffer class. It is part of the java.lang package and provides almost identical functionalities as StringBuffer but with a key difference in how it handles synchronization.</p><p><strong>Key Characteristics of StringBuilder</strong></p><p>1. Mutability: StringBuilder objects are mutable, meaning you can change the content of a StringBuilder object without creating a new object.</p><p>2. Thread-Unsafety: Unlike StringBuffer, StringBuilder is not synchronized, which means it is not thread-safe. This lack of synchronization makes StringBuilder faster than StringBuffer in single-threaded scenarios.</p><p>3. Memory Allocation: StringBuilder objects are stored in the heap area, similar to StringBuffer objects.</p><p>4. Final Class: StringBuilder is a final class, so it cannot be extended.</p><p><strong>Creating StringBuilder Objects</strong></p><p>- Default Constructor: When you create a StringBuilder using the default constructor, the initial capacity is set to 16.</p><pre>StringBuilder s1 = new StringBuilder(); // Capacity is 16</pre><p>- Custom Capacity: You can specify a custom initial capacity while creating a StringBuilder.</p><pre>StringBuilder s2 = new StringBuilder(20); // Capacity is 20</pre><p>- With String Literal: If you create a StringBuilder with a string literal, the initial capacity is set to the length of the string plus 16.</p><pre>StringBuilder s3 = new StringBuilder(&quot;LMS&quot;); // Capacity is 19 (3 + 16)</pre><p><strong>Example of StringBuilder’s Mutable Behavior</strong></p><p>Here’s a demonstration of how mutability works with the append() method:</p><pre>class LMS {<br>    public static void main(String arg[]) {<br>        StringBuilder s1 = new StringBuilder(&quot;Hello&quot;);<br>        StringBuilder s2 = s1.append(&quot;LMS&quot;);<br>        System.out.println(&quot;s1 :- &quot; + s1); // Output: HelloLMS<br>        System.out.println(&quot;s2 :- &quot; + s2); // Output: HelloLMS<br>        System.out.println(&quot;s1 == s2 :- &quot; + (s1 == s2)); // Output: true<br>    }<br>}</pre><p>In this example, both s1 and s2 reference the same object. Since StringBuilder objects are mutable, the append() operation modifies the original object itself, and s1 and s2 remain equal.</p><p><strong>Capacity and Growth Mechanism</strong></p><p>The capacity of a StringBuilder can grow dynamically when more characters are added. The formula used to calculate the new capacity when the current capacity is exceeded is:</p><pre>New Capacity = (Current Capacity + 1)*2</pre><p><strong>Example of Capacity Growth</strong></p><pre>class LMS {<br>    public static void main(String arg[]) {<br>        StringBuilder s1 = new StringBuilder();<br>        System.out.println(&quot;s1.capacity :- &quot; + s1.capacity()); // 16<br>        System.out.println(&quot;s1.length :- &quot; + s1.length()); // 0<br>        s1.append(&quot;1234567890111213&quot;);<br>        System.out.println(&quot;s1.capacity :- &quot; + s1.capacity()); // 16<br>        System.out.println(&quot;s1.length :- &quot; + s1.length()); // 16<br>        s1.append(&quot;14&quot;);<br>        System.out.println(&quot;s1.capacity :- &quot; + s1.capacity()); // 34<br>        System.out.println(&quot;s1.length :- &quot; + s1.length()); // 18<br>        s1.append(&quot;1516171819202122232425&quot;);<br>        System.out.println(&quot;s1.capacity :- &quot; + s1.capacity()); // 70<br>        System.out.println(&quot;s1.length :- &quot; + s1.length()); // 40<br>        s1.append(&quot;1234567890123456789012345678901&quot;);<br>        System.out.println(&quot;s1.capacity :- &quot; + s1.capacity()); // 142<br>        System.out.println(&quot;s1.length :- &quot; + s1.length()); // 71<br>    }<br>}</pre><p>In this example, you can see how the capacity of the StringBuilder changes as its length exceeds the current capacity, using the formula for dynamic growth.</p><p>Important Methods of StringBuilder</p><p>1. length()</p><p>- Description: Returns the length of the string contained in the StringBuilder.</p><p>- Syntax: public int length();</p><p>2. capacity()</p><p>- Description: Returns the current capacity of the StringBuilder.</p><p>- Syntax: public int capacity();</p><p>3. append()</p><p>- Description: Appends the specified string to the existing StringBuilder and returns the same object.</p><p>- Syntax: public StringBuilder append(String str);</p><p><strong>StringBuilder vs. StringBuffer</strong></p><p>- Synchronization: The primary difference between StringBuilder and StringBuffer is that StringBuilder methods are not synchronized, whereas StringBuffer methods are synchronized. This makes StringBuilder faster but not thread-safe.</p><p>- Use Case: Use StringBuilder when you do not require thread safety and want better performance. Use StringBuffer when working in a multi-threaded environment where synchronization is required.</p><p>Use Cases</p><p>- Frequent String Modifications: StringBuilder is ideal when you need to perform frequent string manipulations without the overhead of creating multiple String objects.</p><p>- Performance: It is preferred in single-threaded applications due to its better performance compared to StringBuffer.</p><h4>java.lang.System class</h4><p>The java.lang.System class is a crucial part of the Java programming language, providing methods and fields that interact with the system environment, manage input and output streams, perform system operations, and more. It is a part of the java.lang package and is automatically imported into all Java programs, making its methods and fields readily available for use.</p><p><strong>Key Characteristics of the System Class</strong></p><p>- Final Class: The System class is declared as final, which means it cannot be subclassed.</p><p>- Private Constructor: It has a private constructor, which means you cannot create an instance of the System class directly.</p><p>- Static Members: Most of the methods and fields of the System class are static, allowing them to be accessed directly through the class name without creating an object.</p><p><strong>Example of System Class Usage</strong></p><p>Here’s a basic example to illustrate the use of the System class:</p><pre>class LMS {<br>    public static void main(String arg[]) {<br>        StringBuilder s1 = new StringBuilder(&quot;Hello&quot;);<br>        StringBuilder s2 = s1.append(&quot;LMS&quot;);<br>        System.out.println(&quot;s1 :- &quot; + s1);<br>        System.out.println(&quot;s2 :- &quot; + s2);<br>        System.out.println(&quot;s1 == s2 :- &quot; + (s1 == s2));<br>    }<br>}</pre><p><strong>Important Members of the System Class</strong></p><p>The System class includes several fields and methods that are frequently used in Java programming. Let’s go through some of the most important members:</p><p><strong>1. public static final java.io.InputStream in</strong></p><p>- Description: The in field represents the standard input stream, typically linked to the keyboard.</p><p>- Usage: This field is used to take input from the user via the console.</p><p>Example:</p><pre>import java.util.Scanner;<br>class A {<br>    public static void main(String arg[]) {<br>        System.out.println(&quot;Enter Input: &quot;);<br>        Scanner s1 = new Scanner(System.in);<br>        String input = s1.nextLine();<br>        System.out.println(&quot;Input is: &quot; + input);<br>    }<br>}</pre><p><strong>2. public static void setIn(java.io.InputStream)</strong></p><p>- Description: This method allows you to change the standard input stream to another source.</p><p>- Usage: It is used when you need to take input from a file or other source instead of the keyboard.</p><p>Example:</p><pre>import java.io.FileInputStream;<br>class LMS {<br>    public static void main(String[] args) throws Exception {<br>        System.setIn(new FileInputStream(&quot;file.txt&quot;));<br>        char c1 = (char) System.in.read();<br>        System.out.println(c1);<br>    }<br>}</pre><p><strong>3. public static final java.io.PrintStream out</strong></p><p>- Description: The out field represents the standard output stream, usually linked to the console.</p><p>- Usage: It is used to print output to the console using methods like print() and println().</p><p>Example:</p><pre>System.out.println(&quot;This text will appear on the console.&quot;);</pre><p><strong>How System.out.println works?</strong></p><p>System.out.println() is a commonly used method in Java for printing output to the console. Here’s how it works, step by step:</p><p>Breakdown of System.out.println()</p><p>1. System Class:</p><p>- System is a final class in the java.lang package that provides various system-related utilities and resources, including standard input and output.</p><p>2. Out Field:</p><p>- out is a static field of type PrintStream within the System class. It represents the standard output stream (typically the console).</p><p>3. PrintStream Class:</p><p>- PrintStream is a class that provides methods for printing data to various output streams. It has several overloaded println() methods that accept different types of arguments (e.g., String, int, double, etc.).</p><p>4. println() Method:</p><p>- The println() method in PrintStream prints the argument passed to it, followed by a newline character. This means that after the output, the cursor moves to the next line.</p><p>- If no argument is provided (i.e., println() with no parameters), it simply moves to the next line.</p><p>How It Works Internally</p><p>1. Method Call:</p><p>- When you call System.out.println(someValue), the method is invoked on the PrintStream object referenced by System.out.</p><p>2. Type Handling:</p><p>- The println() method can take various data types:</p><p>- If you pass a String, it prints the string.</p><p>- If you pass a primitive type (like int, double, etc.), it converts the value to its string representation using String.valueOf().</p><p>- If you pass an object, it calls the object’s toString() method to get its string representation.</p><p>3. Output to Console:</p><p>- The formatted string is sent to the output stream that PrintStream is connected to, which is typically the console.</p><p>- After printing the string, a newline character (\n) is automatically appended.</p><p><strong>4. public static void setOut(java.io.PrintStream)</strong></p><p>- Description: This method changes the destination of the output stream.</p><p>- Usage: It is used to redirect output to a file or another destination instead of the console.</p><p>Example:</p><pre>import java.io.*;<br>class LMS {<br>    public static void main(String[] args) throws Exception {<br>        FileOutputStream f = new FileOutputStream(&quot;file.txt&quot;);<br>        System.setOut(new PrintStream(f));<br>        System.out.println(&quot;This text will be redirected to file.txt.&quot;);<br>    }<br>}</pre><p><strong>5. public static final java.io.PrintStream err</strong></p><p>- Description: The err field represents the standard error output stream, used to output error messages.</p><p>- Usage: It is often used to display error messages or debug information.</p><p>Example:</p><pre>System.err.println(&quot;This is an error message.&quot;);</pre><p><strong>6. public static void setErr(java.io.PrintStream)</strong></p><p>- Description: This method allows you to change the destination of the error output stream.</p><p>- Usage: It is used to redirect error messages to a file or another output stream.</p><p>Example:</p><pre>import java.io.*;<br>class LMS {<br>    public static void main(String[] args) throws Exception {<br>        FileOutputStream f = new FileOutputStream(&quot;file.txt&quot;);<br>        System.setErr(new PrintStream(f));<br>        System.err.println(&quot;This error message will be written to file.txt.&quot;);<br>    }<br>}</pre><p><strong>7. public static void exit(int)</strong></p><p>- Description: This method terminates the currently running Java Virtual Machine (JVM).</p><p>- Usage: It is often used to exit a program when a certain condition is met.</p><p>Example:</p><pre>class A {<br>    public static void main(String arg[]) {<br>        System.out.println(&quot;Before Exit()&quot;);<br>        System.exit(0);<br>        System.out.println(&quot;This line will not be executed.&quot;);<br>    }<br>}</pre><p><strong>8. public static native void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)</strong></p><p>- Description: This method copies data from one array to another.</p><p>- Usage: It is used for quickly copying array elements.</p><p>Example:</p><pre>class A {<br>    public static void main(String arg[]) {<br>        String source[] = {&quot;Welcome&quot;, &quot;To&quot;, &quot;LMS&quot;, &quot;Tutorial&quot;, &quot;This&quot;, &quot;Is&quot;, &quot;System&quot;, &quot;Class&quot;};<br>        String destination[] = new String[8];<br>        System.arraycopy(source, 1, destination, 1, 4);<br>        for (int i = 0; i &lt; destination.length; i++) {<br>            System.out.println(&quot;Index: &quot; + i + &quot; Value: &quot; + destination[i]);<br>        }<br>    }<br>}</pre><p>Other Notable Methods</p><p>- currentTimeMillis(): Returns the current time in milliseconds since the epoch (January 1, 1970, 00:00:00 GMT).</p><p>- nanoTime(): Returns the current time in nanoseconds for measuring time intervals.</p><p>- gc(): Requests the Java Virtual Machine to perform garbage collection.</p><p>- getProperty(String key): Retrieves system properties.</p><p>- load(String filename): Loads a specified file as a dynamic library.</p><p>Conclusion</p><p>The java.lang.System class is a powerful utility class in Java that provides essential methods and fields for interacting with the system environment, handling input and output streams, and performing other system-level operations. Its static fields and methods enable developers to control system I/O, manage properties, and handle system resources efficiently.</p><h4>java.lang.Runtime</h4><p><strong>1. java.lang.Runtime Class Overview</strong><br> The Runtime class is a built-in class provided by Java in the java.lang package. It allows Java applications to interface with the runtime environment in which they are executing. This class is based on the Singleton Design Pattern, which ensures that only one instance of the class can exist in the program.</p><p><strong>Singleton Design Pattern</strong>: This design pattern restricts the instantiation of a class to a single instance. It ensures that no matter how many times you try to create an object, the same instance is returned.<br> <strong><br> Private Constructor</strong>: The Runtime class has a private constructor to prevent the instantiation of objects outside the class. Instead, it provides a static method getRuntime() to return the same Runtime instance every time it is called.</p><p>Singleton Design Pattern Example<br> Let’s break down the example provided:</p><pre>class LMS {<br>    public static void main(String arg[]) {<br>        A a1 = A.getA();<br>        A a2 = A.getA();<br>        A a3 = A.getA();<br>        System.out.println(&quot;a1 hashcode :- &quot; + a1.hashCode());<br>        System.out.println(&quot;a2 hashcode :- &quot; + a2.hashCode());<br>        System.out.println(&quot;a3 hashcode :- &quot; + a3.hashCode());<br>        System.out.println(&quot;a1 == a2 :- &quot; + (a1 == a2));<br>        System.out.println(&quot;a2 == a3 :- &quot; + (a2 == a3));<br>        System.out.println(&quot;a1 == a3 :- &quot; + (a1 == a3));<br>    }<br>}<br>class A {<br>    static A a1 = null;<br>    // Private constructor prevents instantiation outside this class<br>    private A() {}<br>    // Static block to create a single instance<br>    static {<br>        a1 = new A();<br>    }<br>    // Static method to return the same instance<br>    static A getA() {<br>        return a1;<br>    }<br>}</pre><p>Explanation:<br> — The class A follows the Singleton Design Pattern. The constructor is private, so no new object can be created using new A().<br> — In the static block, a single instance of the class A is created and assigned to the static variable a1.<br> — The method getA() returns the same instance a1 every time it’s called.<br> — Since a1, a2, and a3 all point to the same object, their hashcodes are identical, and the comparison using == returns true.</p><pre>Output:<br>a1 hashcode :- 1652149987<br>a2 hashcode :- 1652149987<br>a3 hashcode :- 1652149987<br>a1 == a2 :- true<br>a2 == a3 :- true<br>a1 == a3 :- true</pre><p><strong>2. Runtime.getRuntime() Method</strong></p><p>The Runtime class is based on the Singleton pattern, and you can’t create its object using new. Instead, you call getRuntime() to get the single instance.</p><pre>class LMS {<br>    public static void main(String arg[]) {<br>        Runtime r1 = Runtime.getRuntime();<br>        System.out.println(&quot;r1 hashcode :- &quot; + r1.hashCode());<br>        Runtime r2 = Runtime.getRuntime();<br>        System.out.println(&quot;r2 hashcode :- &quot; + r2.hashCode());<br>        System.out.println(&quot;r1 == r2 :- &quot; + (r1 == r2));<br>    }<br>}</pre><p>Explanation:<br> — Runtime.getRuntime() is used to get the Runtime object. Every time you call it, it returns the same object (due to Singleton pattern).<br> — r1 and r2 refer to the same object, so the comparison using == returns true.</p><pre>Output:<br>r1 hashcode :- 123456789<br>r2 hashcode :- 123456789<br>r1 == r2 :- true</pre><h4>3. Key Methods in java.lang.Runtime</h4><p><strong>a. availableProcessors()</strong><br> This method returns the number of available processors for the current Java Virtual Machine (JVM).</p><pre>class LMS {<br>    public static void main(String arg[]) {<br>        System.out.println(&quot;Number of processors allocated to the current JVM: &quot;);<br>        System.out.println(Runtime.getRuntime().availableProcessors());<br>    }<br>}</pre><p>Explanation:<br> — Runtime.getRuntime().availableProcessors() returns the number of processors available to the JVM.</p><pre>Example Output:<br>Number of processors allocated to the current JVM: 8</pre><p><strong>b. freeMemory()</strong><br> This method returns the amount of free memory available in the JVM’s heap, measured in bytes.</p><pre>class LMS {<br>    public static void main(String arg[]) {<br>        System.out.println(&quot;Free heap memory: &quot; + Runtime.getRuntime().freeMemory() + &quot; bytes&quot;);<br>    }<br>}</pre><p>Explanation:<br> — Runtime.getRuntime().freeMemory() returns the amount of unused heap memory in the JVM, in bytes.<br> <br> Example Output:</p><pre>Free heap memory: 16548960 bytes</pre><p><strong>c. totalMemory()</strong><br> This method returns the total memory allocated to the JVM’s heap in bytes.</p><pre>class LMS {<br>    public static void main(String arg[]) {<br>        System.out.println(&quot;Total heap memory: &quot; + Runtime.getRuntime().totalMemory() + &quot; bytes&quot;);<br>    }<br>}</pre><p>Explanation:<br> — Runtime.getRuntime().totalMemory() returns the total memory allocated to the heap.</p><pre>Example Output:<br>Total heap memory: 25690112 bytes</pre><p><strong>d. maxMemory()</strong><br> This method returns the maximum memory the JVM will attempt to use for the heap.</p><pre>class LMS {<br>    public static void main(String arg[]) {<br>        System.out.println(&quot;Maximum heap memory limit: &quot; + Runtime.getRuntime().maxMemory() + &quot; bytes&quot;);<br>    }<br>}</pre><p>Explanation:<br> — Runtime.getRuntime().maxMemory() returns the maximum amount of memory that the JVM can use.</p><pre>Example Output:<br>Maximum heap memory limit: 536870912 bytes</pre><p><strong>e. exec(String command)</strong><br> This method allows running system commands directly from Java.</p><pre>class LMS {<br>    public static void main(String arg[]) throws Exception {<br>        Runtime.getRuntime().exec(&quot;notepad&quot;);<br>        Runtime.getRuntime().exec(&quot;calc&quot;);<br>    }<br>}</pre><p>Explanation:<br> — Runtime.getRuntime().exec() can execute commands like opening Notepad or Calculator on Windows.</p><h3>Conclusion</h3><p>The java.lang package is an integral part of Java&#39;s core functionality. It provides the basic classes and interfaces that form the foundation of Java programming. Understanding the methods in the java.lang.Object class and other classes within this package is crucial for writing efficient and robust Java applications.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=04c77e1d3ca7" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Collection Framework in Java revision]]></title>
            <link>https://medium.com/@pratik.941/collection-framework-in-java-revision-f641efc230b3?source=rss-7f42c99fe66f------2</link>
            <guid isPermaLink="false">https://medium.com/p/f641efc230b3</guid>
            <category><![CDATA[collections-framework]]></category>
            <category><![CDATA[java]]></category>
            <category><![CDATA[backend-development]]></category>
            <dc:creator><![CDATA[Pratik T]]></dc:creator>
            <pubDate>Tue, 08 Oct 2024 13:37:00 GMT</pubDate>
            <atom:updated>2025-03-15T07:29:12.483Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/796/0*Qp6FyVQerMI93s3W.png" /></figure><p><strong>Overview of ArrayList</strong></p><p>ArrayList is part of the java.util package and implements the List interface. Here are some important points:</p><p>1. Order Preservation: It stores elements in the order they are added.</p><p>2. Index-Based Access: Elements can be accessed using their index.</p><p>3. Type Flexibility: Different types of data can be stored.</p><p>4. Duplicates Allowed: It permits duplicate elements.</p><p>5. Iterators: Traversal can be done using Iterator and ListIterator.</p><p>6. Not Synchronized: Methods are not synchronized, affecting concurrency.</p><p>7. Random Access: Direct access to elements is allowed.</p><p>8. Cloning and Serialization: It supports cloning and serialization.</p><p>Basic Example</p><pre>import java.util.ArrayList;<br>import java.util.Iterator;<br>import java.util.ListIterator;<br>public class ArrayListExample {<br>    public static void main(String[] args) {<br>        ArrayList&lt;Object&gt; al1 = new ArrayList&lt;&gt;();<br>        al1.add(101);<br>        al1.add(102);<br>        al1.add(&quot;Hello&quot;);<br>        al1.add(true);<br>        System.out.println(&quot;al1: &quot; + al1);<br>        // Accessing elements by index<br>        for (int i = 0; i &lt; al1.size(); i++) {<br>            System.out.println(&quot;Index: &quot; + i + &quot; | Value: &quot; + al1.get(i));<br>        }<br>        // Using Iterator<br>        Iterator&lt;Object&gt; iterator = al1.iterator();<br>        System.out.print(&quot;Using Iterator: &quot;);<br>        while (iterator.hasNext()) {<br>            System.out.print(iterator.next() + &quot; &quot;);<br>        }<br>        System.out.println();<br>        // Using ListIterator<br>        ListIterator&lt;Object&gt; listIterator = al1.listIterator();<br>        System.out.print(&quot;In Forward Order: &quot;);<br>        while (listIterator.hasNext()) {<br>            System.out.print(listIterator.next() + &quot; &quot;);<br>        }<br>        System.out.println();<br>    }<br>}</pre><p><strong>java.util.Collection Interface:</strong></p><pre>public interface java.util.Collection&lt;E&gt; extends java.lang.Iterable&lt;E&gt; {<br>    public abstract int size();<br>    public abstract boolean isEmpty();<br>    public abstract boolean contains(java.lang.Object);<br>    public abstract java.util.Iterator&lt;E&gt; iterator();<br>    public abstract java.lang.Object[] toArray();<br>    public abstract &lt;T&gt; T[] toArray(T[]);<br>    public abstract boolean add(E);<br>    public abstract boolean remove(java.lang.Object);<br>    public abstract boolean containsAll(java.util.Collection&lt;?&gt;);<br>    public abstract boolean addAll(java.util.Collection&lt;? extends E&gt;);<br>    public abstract boolean removeAll(java.util.Collection&lt;?&gt;);<br>    public boolean removeIf(java.util.function.Predicate&lt;? super E&gt;);<br>    public abstract boolean retainAll(java.util.Collection&lt;?&gt;);<br>    public abstract void clear();<br>    public abstract boolean equals(java.lang.Object);<br>    public abstract int hashCode();<br>    public java.util.Spliterator&lt;E&gt; spliterator();<br>    public java.util.stream.Stream&lt;E&gt; stream();<br>    public java.util.stream.Stream&lt;E&gt; parallelStream();<br>}</pre><p><strong>java.util.ArrayList:</strong></p><pre>public class java.util.ArrayList&lt;E&gt; extends java.util.AbstractList&lt;E&gt;<br> implements java.util.List&lt;E&gt;, java.util.RandomAccess, java.lang.Cloneable, <br> java.io.Serializable {<br>      transient java.lang.Object[] elementData;<br>      public java.util.ArrayList(int);<br>      public java.util.ArrayList();<br>      public java.util.ArrayList(java.util.Collection&lt;? extends E&gt;);<br>      public void trimToSize();<br>      public void ensureCapacity(int);<br>      public int size();<br>      public boolean isEmpty();<br>      public boolean contains(java.lang.Object);<br>      public int indexOf(java.lang.Object);<br>      public int lastIndexOf(java.lang.Object);<br>      public java.lang.Object clone();<br>      public java.lang.Object[] toArray();<br>      public &lt;T&gt; T[] toArray(T[]);<br>      E elementData(int);<br>      public E get(int);<br>      public E set(int, E);<br>      public boolean add(E);<br>      public void add(int, E);<br>      public E remove(int);<br>      public boolean remove(java.lang.Object);<br>      public void clear();<br>      public boolean addAll(java.util.Collection&lt;? extends E&gt;);<br>      public boolean addAll(int, java.util.Collection&lt;? extends E&gt;);<br>      protected void removeRange(int, int);<br>      public boolean removeAll(java.util.Collection&lt;?&gt;);<br>      public boolean retainAll(java.util.Collection&lt;?&gt;);<br>      public java.util.ListIterator&lt;E&gt; listIterator(int);<br>      public java.util.ListIterator&lt;E&gt; listIterator();<br>      public java.util.Iterator&lt;E&gt; iterator();<br>      public java.util.List&lt;E&gt; subList(int, int);<br>      static void subListRangeCheck(int, int, int);<br>      public void forEach(java.util.function.Consumer&lt;? super E&gt;);<br>      public java.util.Spliterator&lt;E&gt; spliterator();<br>      public boolean removeIf(java.util.function.Predicate&lt;? super E&gt;);<br>      public void replaceAll(java.util.function.UnaryOperator&lt;E&gt;);<br>      public void sort(java.util.Comparator&lt;? super E&gt;);<br>      static int access$000(java.util.ArrayList);<br>      static {};<br>}</pre><h4>Constructors</h4><p>1. Default Constructor</p><pre>ArrayList&lt;Object&gt; al1 = new ArrayList&lt;&gt;(); // Default capacity is 10</pre><p>2. Constructor with Initial Capacity</p><pre>ArrayList&lt;Object&gt; al2 = new ArrayList&lt;&gt;(20); // Custom capacity</pre><p>3. Constructor from Collection</p><pre>ArrayList&lt;Object&gt; al3 = new ArrayList&lt;&gt;(al1); // Create from another collection</pre><h4>Important Methods</h4><p><strong>1. size()</strong></p><pre>System.out.println(&quot;Size of al1: &quot; + al1.size());</pre><p><strong>2. add(E)</strong></p><pre>al1.add(200); // Adds to the end</pre><p><strong>3. add(int index, E)</strong></p><pre>al1.add(1, &quot;Inserted Element&quot;); // Inserts at index 1</pre><p><strong>4. addAll(Collection&lt;? extends E&gt;)</strong></p><pre>ArrayList&lt;Object&gt; al4 = new ArrayList&lt;&gt;();<br>al4.add(&quot;A&quot;);<br>al4.add(&quot;B&quot;);<br>al1.addAll(al4); // Adds all elements from al4</pre><p><strong>5. remove(int index)</strong></p><pre>al1.remove(0); // Removes element at index 0</pre><p><strong>6. remove(Object o)</strong></p><pre>al1.remove(&quot;Hello&quot;); // Removes &quot;Hello&quot; from the list</pre><p><strong>7. removeAll(Collection&lt;?&gt;)</strong></p><pre>ArrayList&lt;Object&gt; toRemove = new ArrayList&lt;&gt;();<br>toRemove.add(101);<br>al1.removeAll(toRemove); // Removes all occurrences of elements in toRemove</pre><p><strong>8. toArray()</strong></p><pre>Object[] array = al1.toArray(); // Converts to array</pre><p><strong>9. sort(Comparator&lt;? super E&gt;)</strong></p><pre>ArrayList&lt;Integer&gt; al5 = new ArrayList&lt;&gt;();<br>al5.add(3);<br>al5.add(1);<br>al5.add(2);<br>al5.sort(Comparator.naturalOrder()); // Sorts in natural order<br>System.out.println(al5); // Output: [1, 2, 3]</pre><p><strong>Custom Sorting with Comparator</strong></p><pre>import java.util.ArrayList;<br>import java.util.Comparator;<br>class Student {<br>    int id;<br>    String name;<br>    public Student(int id, String name) {<br>        this.id = id;<br>        this.name = name;<br>    }<br>    @Override<br>    public String toString() {<br>        return &quot;Student{&quot; + &quot;id=&quot; + id + &quot;, name=&#39;&quot; + name + &#39;\&#39;&#39; + &#39;}&#39;;<br>    }<br>}<br>public class StudentSortExample {<br>    public static void main(String[] args) {<br>        ArrayList&lt;Student&gt; students = new ArrayList&lt;&gt;();<br>        students.add(new Student(2, &quot;Alice&quot;));<br>        students.add(new Student(1, &quot;Bob&quot;));<br>        students.add(new Student(3, &quot;Charlie&quot;));<br>        students.sort(Comparator.comparingInt(s -&gt; s.id)); // Sort by id<br>        System.out.println(students);<br>    }<br>}</pre><p>Summary</p><p>The ArrayList class in Java provides a flexible and dynamic way to store a collection of elements. It supports various methods for manipulating the list, making it a powerful tool for developers. Use the examples provided to understand how to work with ArrayList effectively!</p><h4>LinkedList</h4><p>- LinkedList is a class in the java.util package that implements the List interface. It stores elements in the form of nodes, where each node contains two parts:</p><p>- The data (the actual element).</p><p>- A reference (or link) to the next node in the list.</p><p><strong>Key Points:</strong></p><p>- Duplicate elements are allowed.</p><p>- Random access is not supported because LinkedList elements are stored in a chain, requiring sequential access.</p><p>- It can store elements of different types (just like ArrayList).</p><p>- It is not synchronized by default, meaning it’s not thread-safe without external synchronization.</p><p>- LinkedList implements java.io.Serializable (for serialization) and java.lang.Cloneable (for cloning).</p><p><strong>java.util.LinkedList:</strong></p><pre>public class java.util.LinkedList&lt;E&gt; extends <br>  java.util.AbstractSequentialList&lt;E&gt; implements java.util.List&lt;E&gt;,<br>  java.util.Deque&lt;E&gt;, java.lang.Cloneable, java.io.Serializable {<br>        transient int size;<br>        transient java.util.LinkedList$Node&lt;E&gt; first;<br>        transient java.util.LinkedList$Node&lt;E&gt; last;<br>        public java.util.LinkedList();<br>        public java.util.LinkedList(java.util.Collection&lt;? extends E&gt;);<br>        void linkLast(E);<br>        void linkBefore(E, java.util.LinkedList$Node&lt;E&gt;);<br>        E unlink(java.util.LinkedList$Node&lt;E&gt;);<br>        public E getFirst();<br>        public E getLast();<br>        public E removeFirst();<br>        public E removeLast();<br>        public void addFirst(E);<br>        public void addLast(E);<br>        public boolean contains(java.lang.Object);<br>        public int size();<br>        public boolean add(E);<br>        public boolean remove(java.lang.Object);<br>        public boolean addAll(java.util.Collection&lt;? extends E&gt;);<br>        public boolean addAll(int, java.util.Collection&lt;? extends E&gt;);<br>        public void clear();<br>        public E get(int);<br>        public E set(int, E);<br>        public void add(int, E);<br>        public E remove(int);<br>        java.util.LinkedList$Node&lt;E&gt; node(int);<br>        public int indexOf(java.lang.Object);<br>        public int lastIndexOf(java.lang.Object);<br>        public E peek();<br>        public E element();<br>        public E poll();<br>        public E remove();<br>        public boolean offer(E);<br>        public boolean offerFirst(E);<br>        public boolean offerLast(E);<br>        public E peekFirst();<br>        public E peekLast();<br>        public E pollFirst();<br>        public E pollLast();<br>        public void push(E);<br>        public E pop();<br>        public boolean removeFirstOccurrence(java.lang.Object);<br>        public boolean removeLastOccurrence(java.lang.Object);<br>        public java.util.ListIterator&lt;E&gt; listIterator(int);<br>        public java.util.Iterator&lt;E&gt; descendingIterator();<br>        public java.lang.Object clone();<br>        public java.lang.Object[] toArray();<br>        public &lt;T&gt; T[] toArray(T[]);<br>        public java.util.Spliterator&lt;E&gt; spliterator();<br>}</pre><p><strong>2. Basic LinkedList Operations</strong></p><p>Example Code:</p><pre>import java.util.LinkedList;<br>import java.util.Iterator;<br>import java.util.ListIterator;<br>public class JTC {<br>   public static void main(String[] args) {<br>      LinkedList l1 = new LinkedList();<br>      l1.add(&quot;10&quot;);<br>      l1.add(&quot;Hello&quot;);<br>      l1.add(12.34f);<br>      l1.add(13.678);<br>      l1.add(true);<br>      l1.add(&#39;A&#39;);<br>      l1.add(new JTC()); // Adding an object of the current class.<br>      l1.add(null); // Adding a null value.<br>      System.out.println(&quot;l1 :- &quot; + l1);<br>      <br>      // Traversing using Iterator.<br>      Iterator iterator = l1.iterator();<br>      while (iterator.hasNext()) {<br>         System.out.print(iterator.next() + &quot; &quot;);<br>      }<br>      <br>      // Traversing in forward order using ListIterator.<br>      System.out.print(&quot;\nForward :- &quot;);<br>      ListIterator iterator1 = l1.listIterator();<br>      while (iterator1.hasNext()) {<br>         System.out.print(iterator1.next() + &quot; &quot;);<br>      }<br>      <br>      // Traversing in reverse order using ListIterator.<br>      System.out.print(&quot;\nReverse :- &quot;);<br>      while (iterator1.hasPrevious()) {<br>         System.out.print(iterator1.previous() + &quot; &quot;);<br>      }<br>   }<br>}</pre><p>Output:</p><pre>l1 :- [10, Hello, 12.34, 13.678, true, A, com.P1.JTC@36aa7bc2, null]<br>10 Hello 12.34 13.678 true A com.P1.JTC@36aa7bc2 null <br>Forward :- 10 Hello 12.34 13.678 true A com.P1.JTC@36aa7bc2 null <br>Reverse :- null com.P1.JTC@36aa7bc2 A true 13.678 12.34 Hello 10</pre><p><strong>3. Constructors of LinkedList</strong></p><p>- Default Constructor:</p><pre>LinkedList l1 = new LinkedList();</pre><p>- Creates an empty LinkedList.</p><p>- Parameterized Constructor:</p><pre>ArrayList al1 = new ArrayList();<br>al1.add(101);<br>al1.add(&quot;Hello&quot;);<br>LinkedList l2 = new LinkedList&lt;&gt;(al1);</pre><p>- Creates a LinkedList l2 that copies all the elements from the ArrayList al1.</p><p><strong>4. Important Methods of LinkedList</strong></p><p>a. add(E e):</p><p>- Appends the specified element to the end of the list.</p><pre>l1.add(&quot;Hello&quot;);</pre><p>b. add(int index, E element):</p><p>- Inserts an element at a specified position, shifting subsequent elements.</p><pre>l1.add(1, &quot;New Element&quot;);</pre><p>c. addAll(Collection&lt;? extends E&gt; c):</p><p>- Adds all elements from another collection to the LinkedList.</p><pre>l1.addAll(al1);</pre><p>d. get(int index):</p><p>- Returns the element at the specified index.</p><pre>l1.get(0); // Returns the first element.</pre><p>e. set(int index, E element):</p><p>- Updates the element at the specified index.</p><pre>l1.set(2, &quot;Updated Element&quot;);</pre><p>f. descendingIterator():</p><p>- Returns an iterator to traverse the list in reverse order.</p><pre>Iterator i1 = l1.descendingIterator();</pre><p>5. Traversal Examples</p><p>Forward Traversal:</p><pre>ListIterator iterator1 = l1.listIterator();<br>while (iterator1.hasNext()) {<br>System.out.print(iterator1.next() + &quot; &quot;);<br>}</pre><p>Reverse Traversal:</p><pre>while (iterator1.hasPrevious()) {<br>System.out.print(iterator1.previous() + &quot; &quot;);<br>}</pre><p><strong>6. Common Exceptions</strong></p><p>- ConcurrentModificationException: If the LinkedList is modified while iterating over it, this exception is thrown.</p><pre>Iterator i1 = l1.iterator();<br>while (i1.hasNext()) {<br>   l1.add(606); // Causes ConcurrentModificationException<br>}</pre><p>- IndexOutOfBoundsException: Thrown if attempting to access an invalid index.</p><pre>l1.get(100); // Throws IndexOutOfBoundsException</pre><p><strong>Conclusion:</strong></p><p>- LinkedList is a versatile and commonly used data structure for storing elements in a non-contiguous memory space, linked via nodes.</p><p>- It supports adding, removing, and updating elements, and can be traversed using iterators.</p><p>However, random access is not efficient, and it’s prone to ConcurrentModificationException if modified during iteration without proper handling.</p><p>Here is a simplified explanation and breakdown of the Vector and Stack classes in Java, with code examples:</p><h4>Vector Class (Legacy Class)</h4><p>- Definition: The Vector class, found in the java.util package, is a part of the Java Collection Framework but was originally a part of Java before the framework was introduced. It is similar to ArrayList but with synchronized methods.</p><pre>java.util.Vector:<br>public class java.util.Vector&lt;E&gt; extends java.util.AbstractList&lt;E&gt; implements <br>java.util.List&lt;E&gt;, java.util.RandomAccess, java.lang.Cloneable, <br>java.io.Serializable {<br>    protected java.lang.Object[] elementData;<br>    protected int elementCount;<br>    protected int capacityIncrement;<br>    public java.util.Vector(int, int);<br>    public java.util.Vector(int);<br>    public java.util.Vector();<br>    public java.util.Vector(java.util.Collection&lt;? extends E&gt;);<br>    public synchronized void copyInto(java.lang.Object[]);<br>    public synchronized void trimToSize();<br>    public synchronized void ensureCapacity(int);<br>    public synchronized void setSize(int);<br>    public synchronized int capacity();<br>    public synchronized int size();<br>    public synchronized boolean isEmpty();<br>    public java.util.Enumeration&lt;E&gt; elements();<br>    public boolean contains(java.lang.Object);<br>    public int indexOf(java.lang.Object);<br>    public synchronized int indexOf(java.lang.Object, int);<br>    public synchronized int lastIndexOf(java.lang.Object);<br>    public synchronized int lastIndexOf(java.lang.Object, int);<br>    public synchronized E elementAt(int);<br>    public synchronized E firstElement();<br>    public synchronized E lastElement();<br>    public synchronized void setElementAt(E, int);<br>    public synchronized void removeElementAt(int);<br>    public synchronized void insertElementAt(E, int);<br>    public synchronized void addElement(E);<br>    public synchronized boolean removeElement(java.lang.Object);<br>    public synchronized void removeAllElements();<br>    public synchronized java.lang.Object clone();<br>    public synchronized java.lang.Object[] toArray();<br>    public synchronized &lt;T&gt; T[] toArray(T[]);<br>    E elementData(int);<br>    public synchronized E get(int);<br>    public synchronized E set(int, E);<br>    public synchronized boolean add(E);<br>    public boolean remove(java.lang.Object);<br>    public void add(int, E);<br>    public synchronized E remove(int);<br>    public void clear();<br>    public synchronized boolean containsAll(java.util.Collection&lt;?&gt;);<br>    public synchronized boolean addAll(java.util.Collection&lt;? extends E&gt;);<br>    public synchronized boolean removeAll(java.util.Collection&lt;?&gt;);<br>    public synchronized boolean retainAll(java.util.Collection&lt;?&gt;);<br>    public synchronized boolean addAll(int, java.util.Collection&lt;? extends E&gt;);<br>    public synchronized boolean equals(java.lang.Object);<br>    public synchronized int hashCode();<br>    public synchronized java.lang.String toString();<br>    public synchronized java.util.List&lt;E&gt; subList(int, int);<br>    protected synchronized void removeRange(int, int);<br>    public synchronized java.util.ListIterator&lt;E&gt; listIterator(int);<br>    public synchronized java.util.ListIterator&lt;E&gt; listIterator();<br>    public synchronized java.util.Iterator&lt;E&gt; iterator();<br>    public synchronized void forEach(java.util.function.Consumer&lt;? super E&gt;);<br>    public synchronized boolean removeIf(java.util.function.Predicate&lt;? super E&gt;);<br>    public synchronized void replaceAll(java.util.function.UnaryOperator&lt;E&gt;);<br>    public synchronized void sort(java.util.Comparator&lt;? super E&gt;);<br>    public java.util.Spliterator&lt;E&gt; spliterator();<br>}</pre><p>Key Features:</p><p>1. Index-Based Access: Like ArrayList, Vector allows random access to elements via index.</p><p>2. Synchronization: All methods in Vector are synchronized, making it thread-safe but with a performance cost due to synchronization overhead.</p><p>3. Traversal: You can traverse a Vector using Iterator, ListIterator, and Enumeration.</p><p>- Differences from ArrayList:</p><p>1. Synchronization: While ArrayList is not synchronized, Vector is.</p><p>2. Enumeration Support: Vector supports Enumeration, which is not supported by ArrayList.</p><p>- Example:</p><pre>import java.util.Iterator;<br>import java.util.ListIterator;<br>import java.util.Enumeration;<br>import java.util.Vector;<br>public class VectorExample {<br>    public static void main(String[] args) {<br>        Vector&lt;Integer&gt; vector = new Vector&lt;&gt;();<br>        vector.add(101);<br>        vector.add(102);<br>        vector.add(103);<br>        vector.add(104);<br>        vector.add(105);<br>        <br>        // Traversing using Iterator<br>        Iterator&lt;Integer&gt; iterator = vector.iterator();<br>        System.out.print(&quot;Iterator: &quot;);<br>        while (iterator.hasNext()) {<br>            System.out.print(iterator.next() + &quot; &quot;);<br>        }<br>        <br>        // Traversing using ListIterator (forward and reverse)<br>        ListIterator&lt;Integer&gt; listIterator = vector.listIterator();<br>        System.out.print(&quot;\nListIterator (forward): &quot;);<br>        while (listIterator.hasNext()) {<br>            System.out.print(listIterator.next() + &quot; &quot;);<br>        }<br>        <br>        System.out.print(&quot;\nListIterator (reverse): &quot;);<br>        while (listIterator.hasPrevious()) {<br>            System.out.print(listIterator.previous() + &quot; &quot;);<br>        }<br>        <br>        // Traversing using Enumeration<br>        Enumeration&lt;Integer&gt; enumeration = vector.elements();<br>        System.out.print(&quot;\nEnumeration: &quot;);<br>        while (enumeration.hasMoreElements()) {<br>            System.out.print(enumeration.nextElement() + &quot; &quot;);<br>        }<br>    }<br>}</pre><p>Output:</p><pre>Iterator: 101 102 103 104 105<br>ListIterator (forward): 101 102 103 104 105<br>ListIterator (reverse): 105 104 103 102 101<br>Enumeration: 101 102 103 104 105</pre><h4>Stack Class (LIFO Structure)</h4><p>- Definition: The Stack class extends the Vector class and represents a Last-In-First-Out (LIFO) stack. It inherits all Vector methods and adds several stack-specific methods.</p><p>- Key Features:</p><p>1. Push/Pop Operations: Items can be added using the push() method and removed using the pop() method, which follows LIFO order.</p><p>2. Peek: The peek() method returns the top element without removing it.</p><p>3. Empty Check: The empty() method checks if the stack is empty.</p><p>4. Search: The search() method returns the position of an element in the stack (distance from the top).</p><p>- Example 1: Basic Stack Operations:</p><pre>import java.util.Stack;<br>public class StackExample {<br>    public static void main(String[] args) {<br>        Stack&lt;Object&gt; stack = new Stack&lt;&gt;();<br>        stack.push(101);<br>        stack.push(&quot;Hello&quot;);<br>        stack.push(true);<br>        stack.push(&#39;A&#39;);<br>        stack.push(12.34);<br>        stack.push(-89.78f);<br>        <br>        // Pop operation<br>        System.out.println(&quot;Popped: &quot; + stack.pop());  // -89.78<br>        System.out.println(&quot;Popped: &quot; + stack.pop());  // 12.34<br>        <br>        // Peek operation<br>        System.out.println(&quot;Top Element: &quot; + stack.peek());  // A<br>        <br>        // Stack content<br>        System.out.println(&quot;Stack: &quot; + stack);  // [101, Hello, true, A]<br>    }<br>}</pre><p>Output:</p><pre>Popped: -89.78<br>Popped: 12.34<br>Top Element: A<br>Stack: [101, Hello, true, A]</pre><p>- Example 2: Searching in Stack:</p><pre>import java.util.Stack;<br>public class StackSearchExample {<br>    public static void main(String[] args) {<br>        Stack&lt;Object&gt; stack = new Stack&lt;&gt;();<br>        stack.push(101);<br>        stack.push(&quot;Hello&quot;);<br>        stack.push(true);<br>        stack.push(&#39;A&#39;);<br>        <br>        // Search operation<br>        System.out.println(&quot;Position of &#39;Hello&#39;: &quot; + stack.search(&quot;Hello&quot;));  // 3<br>        System.out.println(&quot;Position of 101: &quot; + stack.search(101));  // 4<br>        System.out.println(&quot;Position of &#39;NotFound&#39;: &quot; + stack.search(&quot;NotFound&quot;));  // -1<br>    }<br>}</pre><p>- Output:</p><pre>Position of &#39;Hello&#39;: 3<br>Position of 101: 4<br>Position of &#39;NotFound&#39;: -1</pre><p><strong>Key Methods in Stack:</strong></p><p>1. push(E item): Adds an element to the top of the stack.</p><p>2. pop(): Removes and returns the top element of the stack.</p><p>3. peek(): Returns the top element without removing it.</p><p>4. empty(): Checks if the stack is empty.</p><p>5. search(Object o): Searches for an element and returns its 1-based position from the top of the stack, or -1 if not found.</p><p>Conclusion:</p><p>- Vector is a legacy class that behaves like an ArrayList but with thread safety via synchronization.</p><p>- Stack, which extends Vector, adds stack-specific methods (push, pop, peek) and follows the LIFO principle.</p><h4>Set Interface in Java</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/721/0*TiCgRzftKHf1mTxu.png" /></figure><p>The Set interface is part of the java.util package, representing a collection that does not allow duplicate elements. It is implemented by various classes like HashSet and LinkedHashSet and is extended by the SortedSet interface, which is further implemented by the TreeSet class.</p><p><strong>HashSet Overview</strong></p><p>- HashSet is a collection that does not allow duplicate elements.</p><p>- It is part of the Set family, meaning it follows the contract of a Set (i.e., no duplicates allowed).</p><p>- HashSet can store various types of elements, including objects of different classes like String, Integer, Boolean, etc.</p><p><strong>Important Characteristics of HashSet</strong></p><p>1. <strong>No Duplicates:</strong> A HashSet ensures that each element is unique, which means adding a duplicate element will not change the set.</p><p>2.<strong> Forward Traversal with Iterator:</strong> A HashSet can be traversed in forward order using an Iterator, but not using ListIterator or Enumeration, which are available for lists or vectors.</p><p>3. <strong>Index Representation:</strong> Internally, HashSet uses index representation to store elements, similar to ArrayList or Vector. This allows for random access to elements based on their position in the hash table.</p><p>4. <strong>Not Synchronized:</strong> The methods of HashSet are not synchronized, meaning they are not thread-safe by default. If you need thread safety, you need to manually synchronize it using Collections.synchronizedSet().</p><p>5. <strong>Unordered Elements: </strong>HashSet does not store elements in the order they are added. The internal structure, based on a HashMap, determines the ordering.</p><p>6. <strong>Cloneable and Serializable:</strong> A HashSet is cloneable (implements Cloneable interface) and can be serialized (implements Serializable interface), which means it can be copied or saved to a stream for later retrieval.</p><p>7.<strong> Internally Uses a Map:</strong> All Set type collections, including HashSet, internally use a map (specifically HashMap).</p><p><strong>java.util.HashSet:</strong></p><pre>public class java.util.HashSet&lt;E&gt; extends java.util.AbstractSet&lt;E&gt; <br>implements java.util.Set&lt;E&gt;, java.lang.Cloneable, java.io.Serializable {<br>    static final long serialVersionUID;<br>    public java.util.HashSet();<br>    public java.util.HashSet(java.util.Collection&lt;? extends E&gt;);<br>    public java.util.HashSet(int, float);<br>    public java.util.HashSet(int);<br>    java.util.HashSet(int, float, boolean);<br>    public java.util.Iterator&lt;E&gt; iterator();<br>    public int size();<br>    public boolean isEmpty();<br>    public boolean contains(java.lang.Object);<br>    public boolean add(E);<br>    public boolean remove(java.lang.Object);<br>    public void clear();<br>    public java.lang.Object clone();<br>    public java.util.Spliterator&lt;E&gt; spliterator();<br>    static {};<br>}</pre><p><strong>Constructors of HashSet</strong></p><ol><li>Default Constructor:</li></ol><pre>public HashSet()</pre><p>- This constructor creates an empty HashSet with an initial capacity of 16 and a default load factor of 0.75.</p><p>2. Collection Constructor:</p><pre>public HashSet(Collection&lt;? extends E&gt;)</pre><p>- This constructor creates a HashSet containing all the elements of a specified collection (e.g., an ArrayList). It is used when you want to initialize a set from another collection.</p><p>Example:</p><pre>ArrayList list1 = new ArrayList();<br>list1.add(101);<br>list1.add(true);<br>list1.add(&quot;Hello&quot;);<br>HashSet set2 = new HashSet(list1);</pre><p>- Here, set2 contains all the elements from list1.</p><p>3. Initial Capacity Constructor:</p><pre>public HashSet(int initialCapacity)</pre><p>- This constructor creates an empty HashSet with a specified initial capacity.</p><p>4. Capacity and Load Factor Constructor:</p><pre>public HashSet(int initialCapacity, float loadFactor)</pre><p>- Allows you to set both the initial capacity and the load factor, which is a threshold for when the HashSet needs to expand.</p><p>Capacity and Load Factor</p><p>- Initial Capacity: Refers to the number of buckets (or slots) the HashSet starts with.</p><p>- Load Factor: Defines how full the set can get before it resizes. A default load factor of 0.75 means the HashSet will expand when 75% of its capacity is filled.</p><p>Important Methods in HashSet</p><p>1. Iterator Method:</p><pre>public Iterator&lt;E&gt; iterator()</pre><p>- Returns an Iterator for the elements in the set. This allows iteration over the set using a while loop and iterator.next().</p><p>2. Size Method:</p><pre>public int size()</pre><p>- Returns the number of elements in the HashSet.</p><p>3. isEmpty Method:</p><pre>public boolean isEmpty()</pre><p>- Returns true if the set contains no elements, otherwise false.</p><p>4. add Method:</p><pre>public boolean add(E element)</pre><p>- Adds an element to the HashSet. If the element is already present, it returns false.</p><p>5. remove Method:</p><pre>public boolean remove(Object element)</pre><p>- Removes the specified element from the set and returns true if the element was present, otherwise returns false.</p><p><strong>Example Code Explanation</strong></p><p>The provided examples showcase different methods and operations of HashSet:</p><pre>import java.util.ArrayList;<br>import java.util.HashSet;<br>public class JTC {<br>   public static void main(String[] args) {<br>      // Creating HashSet by default constructor.<br>      HashSet set1 = new HashSet();<br>      System.out.println(&quot;size of set1 :- &quot; + set1.size());<br>      System.out.println(&quot;set1 :- &quot; + set1);<br>      ArrayList list1 = new ArrayList();<br>      list1.add(101);<br>      list1.add(true);<br>      list1.add(12.34);<br>      list1.add(&quot;Hello&quot;);<br>      list1.add(&#39;A&#39;);<br>      // Creating HashSet using HashSet(Collection) constructor.<br>      HashSet set2 = new HashSet &lt; &gt; (list1);<br>      System.out.println(&quot;set2 :- &quot; + set2.size());<br>      System.out.println(&quot;set2 :- &quot; + set2);<br>   }<br>}</pre><p>Output</p><pre>size of set1 :- 0<br>    set1 :- []<br>    set2 :- 5<br>    set2 :- [A, 12.34, Hello, 101, true]</pre><p>- Creates an empty HashSet (set1).</p><p>- Creates an ArrayList (list1) and adds various types of elements to it.</p><p>- Initializes another HashSet (set2) with the contents of list1. Elements are stored in an unordered fashion.</p><p>2. Iterator Example:</p><pre>import java.util.ArrayList;<br>import java.util.HashSet;<br>import java.util.Iterator;<br>public class JTC {<br>   public static void main(String[] args) {<br>      HashSet set = new HashSet();<br>      set.add(101);<br>      set.add(&quot;Hello&quot;);<br>      set.add(&#39;A&#39;);<br>      set.add(true);<br>      set.add(new JTC());<br>      set.add(null);<br>      set.add(12.34);<br>      Iterator iterator = set.iterator();<br>      while (iterator.hasNext()) {<br>         System.out.println(iterator.next());<br>      }<br>   }<br>}</pre><p>Output:</p><pre>null<br>A<br>12.34<br>Hello<br>101<br>com.P1.JTC@3d012ddd<br>true</pre><p>Demonstrates the use of an Iterator to loop through and print each element in the HashSet.</p><p>3. Various HashSet Methods Example:</p><pre>import java.util.ArrayList;<br>import java.util.HashSet;<br>import java.util.Iterator;<br>public class JTC {<br>   public static void main(String[] args) {<br>      HashSet set = new HashSet();<br>      System.out.println(&quot;Added :- &quot; + set.add(101));<br>      System.out.println(&quot;Added :- &quot; + set.add(&quot;Hello&quot;));<br>      System.out.println(&quot;Added :- &quot; + set.add(&#39;A&#39;));<br>      System.out.println(&quot;Added :- &quot; + set.add(true));<br>      System.out.println(&quot;Added :- &quot; + set.add(101));<br>      System.out.println(&quot;Added :- &quot; + set.add(new JTC()));<br>      System.out.println(&quot;Added :- &quot; + set.add(null));<br>      System.out.println(&quot;Added :- &quot; + set.add(12.34));<br>      System.out.println(&quot;Number of elements :- &quot; + set.size());<br>      System.out.println(&quot;Empty Status :- &quot; + set.isEmpty());<br>      System.out.println(&quot;Elements availability :- &quot; + set.contains(&quot;Hello&quot;));<br>      System.out.println(&quot;Elements availability :- &quot; + set.contains(&quot;JTC&quot;));<br>      System.out.println(&quot;set :- &quot; + set);<br>      System.out.println(&quot;Removing Element :- &quot; + set.remove(101));<br>      System.out.println(&quot;set :- &quot; + set);<br>      System.out.println(&quot;Removing Element :- &quot; + set.remove(&quot;JTC&quot;));<br>   }<br>}</pre><p>Output:</p><pre>Added :- true<br>Added :- true<br>Added :- true<br>Added :- true<br>Added :- false<br>Added :- true<br>Added :- true<br>Added :- true<br>Number of elements :- 7<br>Empty Status :- false<br>Elements availability :- true<br>Elements availability :- false<br>set :- [null, A, 12.34, Hello, 101, com.P1.JTC@515f550a, true]<br>Removing Element :- true<br>set :- [null, A, 12.34, Hello, com.P1.JTC@515f550a, true]<br>Removing Element :- false</pre><p>Demonstrates adding elements, checking the size, testing for emptiness, checking for element presence (contains), and removing elements.</p><p>- Highlights the behavior of not adding duplicate elements (e.g., 101 was added once, and the second attempt to add it fails).</p><p>Key Takeaways for Set Collections</p><p>- No Duplicates: Set collections do not allow duplicate elements.</p><p>- Not Synchronized: They are not thread-safe by default.</p><p>- Cannot Use List-Specific Traversal Methods: You cannot use ListIterator or Enumeration with a set.</p><p>- Eligible for Cloning and Serialization: Since they implement the Cloneable and Serializable interfaces.</p><h4>LinkedHashSet Class</h4><p>LinkedHashSet is part of the java.util package and extends HashSet. It implements several interfaces: Set, Cloneable, and Serializable. This class maintains a linked list of the entries in the set, preserving the order of insertion.</p><pre>public class java.util.LinkedHashSet&lt;E&gt; extends java.util.HashSet&lt;E&gt; implements<br> java.util.Set&lt;E&gt;, java.lang.Cloneable, java.io.Serializable {<br>    public java.util.LinkedHashSet(int, float);<br>    public java.util.LinkedHashSet(int);<br>    public java.util.LinkedHashSet();<br>    public java.util.LinkedHashSet(java.util.Collection&lt;? extends E&gt;);<br>    public java.util.Spliterator spliterator();<br>}</pre><p><strong>Important Characteristics:</strong></p><p>1. Order of Elements:</p><p>- Elements are stored in the order they are added. This is a key feature that differentiates LinkedHashSet from HashSet, which does not guarantee order.</p><p>2. Node Representation:</p><p>- LinkedHashSet uses a node-based structure to store elements. Each node contains data and references to the next and previous nodes, forming a doubly linked list.</p><p>3. No Random Access:</p><p>- Unlike an array or ArrayList, you cannot access elements randomly in a LinkedHashSet. You must traverse the set in sequential order.</p><p>4. Iterator Access:</p><p>- The only way to traverse a LinkedHashSet is through an Iterator. Other methods like ListIterator or Enumeration are not available.</p><p>5. Cloning and Serialization:</p><p>- Since it implements Cloneable and Serializable, you can clone a LinkedHashSet or serialize it for storage or transmission.</p><p><strong>Constructors of LinkedHashSet</strong>:</p><p><strong>1. Default Constructor:</strong></p><p>- public LinkedHashSet()<strong>:</strong> Creates an empty LinkedHashSet with an initial capacity of 16 and a load factor of 0.75.</p><p><strong>2. Collection Constructor:</strong></p><p>- public LinkedHashSet(Collection&lt;? extends E&gt; c): Initializes the LinkedHashSet with elements from the specified collection. It removes any duplicates and maintains the insertion order.</p><p><strong>3. Capacity Constructor:</strong></p><p>- public LinkedHashSet(int initialCapacity): Creates an empty LinkedHashSet with a specified initial capacity and a default load factor of 0.75.</p><p><strong>4. Capacity and Load Factor Constructor:</strong></p><p>- public LinkedHashSet(int initialCapacity, float loadFactor): Constructs an empty LinkedHashSet with a specified initial capacity and load factor.</p><p>Example Code:</p><pre>import java.util.ArrayList;<br>import java.util.LinkedHashSet;<br>public class JTC {<br>   public static void main(String[] args) {<br>      // Creating an empty LinkedHashSet using the default constructor<br>      LinkedHashSet&lt;Object&gt; hashSet1 = new LinkedHashSet&lt;&gt;();<br>      System.out.println(&quot;hashSet1: &quot; + hashSet1);<br>      System.out.println(&quot;hashSet1 size: &quot; + hashSet1.size());<br>      System.out.println(&quot;hashSet1 is empty: &quot; + hashSet1.isEmpty());<br>      // Creating an ArrayList with various types<br>      ArrayList&lt;Object&gt; a1 = new ArrayList&lt;&gt;();<br>      a1.add(&quot;Hello&quot;);<br>      a1.add(101);<br>      a1.add(true);<br>      a1.add(101); // Duplicate<br>      a1.add(new JTC());<br>      a1.add(&#39;A&#39;);<br>      System.out.println(&quot;\nArrayList: &quot; + a1);<br>      // Creating LinkedHashSet using the Collection constructor<br>      LinkedHashSet&lt;Object&gt; hashSet2 = new LinkedHashSet&lt;&gt;(a1);<br>      System.out.println(&quot;hashSet2: &quot; + hashSet2);<br>      System.out.println(&quot;hashSet2 size: &quot; + hashSet2.size());<br>      System.out.println(&quot;hashSet2 is empty: &quot; + hashSet2.isEmpty());<br>   }<br>}</pre><p>Output:</p><pre>hasSet1 :- []<br>hashSet1 size :- 0<br>hashSet1 is empty :- true<br>Array List :- [Hello, 101, true, 101, com.P1.JTC@156643d4, A]<br>hashSet2 :- [Hello, 101, true, com.P1.JTC@156643d4, A]<br>hashSet2 size :- 5<br>hashSet2 is empty :- false</pre><p>Output Explanation:</p><p>1. Initial Empty Set:</p><p>- The first LinkedHashSet is empty, confirming its creation. It shows size 0 and indicates that it is empty.</p><p>2. ArrayList Creation:</p><p>- An ArrayList is created with mixed data types, including a duplicate integer.</p><p>3. Creating LinkedHashSet from ArrayList:</p><p>- A second LinkedHashSet is created from the ArrayList. This set preserves the order of elements from the ArrayList but omits the duplicate entry.</p><p>4. Final Output:</p><p>- The results demonstrate the order preservation and the removal of duplicates in hashSet2.</p><p>Conclusion:</p><p>The LinkedHashSet is a versatile collection that combines the properties of a hash set (for fast lookups) and a linked list (for maintaining order). It is particularly useful when you need to maintain insertion order while avoiding duplicates.</p><p><strong>SortedSet Interface</strong></p><p>The SortedSet interface extends Set and arranges the elements in natural order (or a custom order if provided). It is implemented by the TreeSet class.</p><p><strong>java.util.SortedSet:</strong></p><pre>public interface java.util.SortedSet&lt;E&gt; extends java.util.Set&lt;E&gt; {<br>    public abstract java.util.Comparator&lt;? super E&gt; comparator();<br>    public abstract java.util.SortedSet&lt;E&gt; subSet(E, E);<br>    public abstract java.util.SortedSet&lt;E&gt; headSet(E);<br>    public abstract java.util.SortedSet&lt;E&gt; tailSet(E);<br>    public abstract E first();<br>    public abstract E last();<br>    public java.util.Spliterator&lt;E&gt; spliterator();<br>}</pre><p><strong>TreeSet Class</strong></p><p>TreeSet is an implementation of SortedSet, meaning it stores elements in sorted order (either natural or via a comparator). It uses a Red-Black tree under the hood, making all operations (add, remove, search) log-time efficient.</p><h4>1. TreeSet Overview:</h4><p>- TreeSet is part of the java.util package and extends the AbstractSet class.</p><p>- It implements interfaces like NavigableSet, Cloneable, and Serializable.</p><p>- The TreeSet class does not directly implement Set, but because it implements NavigableSet (which extends SortedSet, and SortedSet extends Set), it behaves like a Set collection (like HashSet and LinkedHashSet).</p><pre>public class java.util.TreeSet&lt;E&gt; extends java.util.AbstractSet&lt;E&gt; implements<br> java.util.NavigableSet&lt;E&gt;, java.lang.Cloneable, java.io.Serializable {<br>      java.util.TreeSet(java.util.NavigableMap&lt;E, java.lang.Object&gt;);<br>      public java.util.TreeSet();<br>      public java.util.TreeSet(java.util.Comparator&lt;? super E&gt;);<br>      public java.util.TreeSet(java.util.Collection&lt;? extends E&gt;);<br>      public java.util.TreeSet(java.util.SortedSet&lt;E&gt;);<br>      public java.util.Iterator&lt;E&gt; iterator();<br>      public java.util.Iterator&lt;E&gt; descendingIterator();<br>      public java.util.NavigableSet&lt;E&gt; descendingSet();<br>      public int size();<br>      public boolean isEmpty();<br>      public boolean contains(java.lang.Object);<br>      public boolean add(E);<br>      public boolean remove(java.lang.Object);<br>      public void clear();<br>      public boolean addAll(java.util.Collection&lt;? extends E&gt;);<br>      public java.util.NavigableSet&lt;E&gt; subSet(E, boolean, E, boolean);<br>      public java.util.NavigableSet&lt;E&gt; headSet(E, boolean);<br>      public java.util.NavigableSet&lt;E&gt; tailSet(E, boolean);<br>      public java.util.SortedSet&lt;E&gt; subSet(E, E);<br>      public java.util.SortedSet&lt;E&gt; headSet(E);<br>      public java.util.SortedSet&lt;E&gt; tailSet(E);<br>      public java.util.Comparator&lt;? super E&gt; comparator();<br>      public E first();<br>      public E last();<br>      public E lower(E);<br>      public E floor(E);<br>      public E ceiling(E);<br>      public E higher(E);<br>      public E pollFirst();<br>      public E pollLast();<br>      public java.lang.Object clone();<br>      public java.util.Spliterator&lt;E&gt; spliterator();<br>      static {};<br>}</pre><p><strong>2. Characteristics of TreeSet:</strong></p><ul><li>No duplicate elements: Similar to other Set types, TreeSet does not allow duplicate elements.</li><li>TreeSet doesn’t store different types of data, unlike other Set-type collections such as HashSet and LinkedHashSet.</li><li>Natural sorting: By default, it sorts elements in their natural order (like numerical or lexicographical order).</li><li>No null values: You cannot store null values in a TreeSet.</li><li>Non-synchronized: TreeSet is not thread-safe. You need to synchronize it externally for multithreaded environments.</li><li>Backed by TreeMap: TreeSet uses TreeMap internally to store data.</li></ul><p><strong>3. Constructors and Key Methods:</strong></p><p>- Constructors:</p><p>- TreeSet(): Creates an empty set that sorts elements by natural order.</p><p>- TreeSet(Comparator): Accepts a custom comparator to define custom sorting logic.</p><p>- TreeSet(Collection): Creates a set from another collection.</p><p>- Key Methods:</p><p>- add(): Adds an element.</p><p>- remove(): Removes an element.</p><p>- subSet(), headSet(), tailSet(): Methods to get a portion of the set.</p><p>- pollFirst(), pollLast(): Retrieves and removes the first or last element.</p><p><strong>4. Natural Sorting and Comparable Interface:</strong></p><p>Natural Sorting:</p><p>Natural sorting refers to the automatic arrangement of elements in ascending order based on their natural order, which is defined by the Comparable interface in Java. When a class implements this interface, it can specify how its objects should be compared.</p><p>Comparable Interface</p><p>- The Comparable interface requires the implementation of the compareTo() method.</p><p>- Method Signature:</p><pre>public int compareTo(T o);</pre><p>Behavior of compareTo()</p><p>- Returns 0 if both objects are equal.</p><p>- Returns a positive integer if the current object is greater.</p><p>- Returns a negative integer if the current object is smaller.</p><p>Example: Natural Sorting with Integer and String</p><p>Here’s an example demonstrating the natural sorting of integers and strings:</p><pre>import java.util.TreeSet;<br>public class NaturalSortingExample {<br>    public static void main(String[] args) {<br>        // Using TreeSet for natural sorting of Integers<br>        TreeSet&lt;Integer&gt; integerSet = new TreeSet&lt;&gt;();<br>        integerSet.add(5);<br>        integerSet.add(1);<br>        integerSet.add(3);<br>        integerSet.add(4);<br>        integerSet.add(2);<br>        System.out.println(&quot;Sorted Integers: &quot; + integerSet);<br>        // Using TreeSet for natural sorting of Strings<br>        TreeSet&lt;String&gt; stringSet = new TreeSet&lt;&gt;();<br>        stringSet.add(&quot;Banana&quot;);<br>        stringSet.add(&quot;Apple&quot;);<br>        stringSet.add(&quot;Mango&quot;);<br>        stringSet.add(&quot;Orange&quot;);<br>        System.out.println(&quot;Sorted Strings: &quot; + stringSet);<br>    }<br>}</pre><p>Output:</p><pre>Sorted Integers: [1, 2, 3, 4, 5]<br>Sorted Strings: [Apple, Banana, Mango, Orange]</pre><p>In this example:</p><p>- The integers are sorted in ascending order.</p><p>- Strings are sorted based on their natural alphabetical order.</p><p><strong>In Descending Order</strong></p><pre>import java.util.*;<br><br>public class NaturalSortingExample {<br>    public static void main(String[] args) {<br>        // Using TreeSet for descending sorting of Integers with a named comparator class<br>        TreeSet&lt;Integer&gt; integerSet = new TreeSet&lt;&gt;(new DescendingIntegerComparator());<br><br>        // Adding elements to the set<br>        integerSet.add(5);<br>        integerSet.add(1);<br>        integerSet.add(3);<br>        integerSet.add(4);<br>        integerSet.add(2);<br>        System.out.println(&quot;Sorted Integers (Descending): &quot; + integerSet);<br><br>        // Using TreeSet for descending sorting of Strings with a named comparator class<br>        TreeSet&lt;String&gt; stringSet = new TreeSet&lt;&gt;(new DescendingStringComparator());<br><br>        // Adding elements to the set<br>        stringSet.add(&quot;Banana&quot;);<br>        stringSet.add(&quot;Apple&quot;);<br>        stringSet.add(&quot;Mango&quot;);<br>        stringSet.add(&quot;Orange&quot;);<br>        System.out.println(&quot;Sorted Strings (Descending): &quot; + stringSet);<br>    }<br>}<br><br>// Named comparator class for Integers (Descending Order)<br>class DescendingIntegerComparator implements Comparator&lt;Integer&gt; {<br>    @Override<br>    public int compare(Integer a, Integer b) {<br>        return b - a;  // Sort in descending order<br>    }<br>}<br><br>// Named comparator class for Strings (Descending Order)<br>class DescendingStringComparator implements Comparator&lt;String&gt; {<br>    @Override<br>    public int compare(String a, String b) {<br>        return b.compareTo(a);  // Sort in descending order<br>    }<br>}</pre><p><strong>Using Java 8</strong></p><pre>import java.util.*;<br><br>public class NaturalSortingExample {<br>    public static void main(String[] args) {<br>        // Using TreeSet for descending sorting of Integers with a custom Comparator<br>        TreeSet&lt;Integer&gt; integerSet = new TreeSet&lt;&gt;((a, b) -&gt; b - a);  // Custom comparator for descending order<br>        integerSet.add(5);<br>        integerSet.add(1);<br>        integerSet.add(3);<br>        integerSet.add(4);<br>        integerSet.add(2);<br>        System.out.println(&quot;Sorted Integers (Descending): &quot; + integerSet);<br>        <br>        // Using TreeSet for descending sorting of Strings with a custom Comparator<br>        TreeSet&lt;String&gt; stringSet = new TreeSet&lt;&gt;((a, b) -&gt; b.compareTo(a));  // Custom comparator for descending order<br>        stringSet.add(&quot;Banana&quot;);<br>        stringSet.add(&quot;Apple&quot;);<br>        stringSet.add(&quot;Mango&quot;);<br>        stringSet.add(&quot;Orange&quot;);<br>        System.out.println(&quot;Sorted Strings (Descending): &quot; + stringSet);<br>    }<br>}</pre><p><strong>5. Custom Sorting Using Comparator</strong></p><p>When you need to sort objects that don’t have a natural order, or if you want to sort them in a different way, you can use the Comparator interface.</p><p>Comparator Interface</p><p>- The Comparator interface provides the compare() method to define custom comparison logic.</p><p>- Method Signature:</p><pre>public int compare(T o1, T o2);</pre><p>Example: Custom Sorting with Student Class</p><p>Let’s create a Student class and sort Student objects by different fields using custom comparators.</p><pre>import java.util.*;<br>class Student {<br>    String name;<br>    int marks;<br>    public Student(String name, int marks) {<br>        this.name = name;<br>        this.marks = marks;<br>    }<br>    @Override<br>    public String toString() {<br>        return name + &quot;: &quot; + marks;<br>    }<br>}<br>class SortByName implements Comparator&lt;Student&gt; {<br>    @Override<br>    public int compare(Student s1, Student s2) {<br>        return s1.name.compareTo(s2.name); // Sort by name<br>    }<br>}<br><br>class SortByMarks implements Comparator&lt;Student&gt; {<br>    @Override<br>    public int compare(Student s1, Student s2) {<br>        return s1.marks - s2.marks; // Sort by marks <br>    }<br>}<br>public class CustomSortingExample {<br>    public static void main(String[] args) {<br>        List&lt;Student&gt; students = new ArrayList&lt;&gt;();<br>        students.add(new Student(&quot;Alice&quot;, 85));<br>        students.add(new Student(&quot;Bob&quot;, 72));<br>        students.add(new Student(&quot;Charlie&quot;, 90));<br>        students.add(new Student(&quot;David&quot;, 85));<br>        // Sort by name<br>        Collections.sort(students, new SortByName());<br>        System.out.println(&quot;Sorted by Name: &quot; + students);<br>        // Sort by marks<br>        Collections.sort(students, new SortByMarks());<br>        System.out.println(&quot;Sorted by Marks: &quot; + students);<br>    }<br>}</pre><p>Output:</p><pre>Sorted by Name: [Alice: 85, Bob: 72, Charlie: 90, David: 85]<br>Sorted by Marks: [Bob: 72, Alice: 85, David: 85, Charlie: 90]</pre><p>In this example:</p><p>- We define a Student class with name and marks attributes.</p><p>- Two custom comparators (SortByName and SortByMarks) are created to sort Student objects by name and marks, respectively.</p><p>- We use Collections.sort() to sort the list with these comparators.</p><p>Using lambda function :</p><pre>import java.util.*;<br><br>class Student {<br>    String name;<br>    int marks;<br><br>    public Student(String name, int marks) {<br>        this.name = name;<br>        this.marks = marks;<br>    }<br><br>    @Override<br>    public String toString() {<br>        return name + &quot;: &quot; + marks;<br>    }<br>}<br><br>public class CustomSortingExample {<br>    public static void main(String[] args) {<br>        List&lt;Student&gt; students = new ArrayList&lt;&gt;();<br>        students.add(new Student(&quot;Alice&quot;, 85));<br>        students.add(new Student(&quot;Bob&quot;, 72));<br>        students.add(new Student(&quot;Charlie&quot;, 90));<br>        students.add(new Student(&quot;David&quot;, 85));<br><br>        // Sort by name using lambda<br>        students.sort(Comparator.comparing(s -&gt; s.name));<br>        System.out.println(&quot;Sorted by Name: &quot; + students);<br><br>        // Sort by marks using lambda<br>        students.sort(Comparator.comparingInt(s -&gt; s.marks));<br>        System.out.println(&quot;Sorted by Marks: &quot; + students);<br>    }<br>}</pre><p><strong>6. Difference between Comparable and Comparator:</strong></p><p>- Comparable:</p><p>- Defines the natural order of objects within the class itself by implementing the Comparable interface and overriding the compareTo() method.</p><p>- Single sorting sequence (only one way to compare).</p><p>- Comparator:</p><p>- Defines custom order by implementing the Comparator interface and overriding the compare() method.</p><p>- Allows multiple sorting sequences (you can sort by different attributes by passing different comparators).</p><p>Example:</p><p>- Using Comparable, the natural sorting for integers is by value (1, 2, 3, etc.).</p><p>-Using Comparator, you could sort Student objects by either marks, name, or city based on custom logic.</p><h4>Queue Interface in Java</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/511/0*9uqFQlPjwSr-lO7L.gif" /></figure><p>The `Queue` interface is a part of the `java.util` package and extends the `Collection` interface. A `Queue` represents a data structure that follows the First-In-First-Out (FIFO) principle, where elements are added at the end and removed from the front. The `Queue` interface provides methods for adding, removing, and inspecting elements, as well as managing capacity and order.</p><p><strong>java.util.Queue:</strong></p><pre>public interface java.util.Queue&lt;E&gt; extends java.util.Collection&lt;E&gt; {<br> public abstract boolean add(E);<br> public abstract boolean offer(E);<br> public abstract E remove();<br> public abstract E poll();<br> public abstract E element();<br> public abstract E peek();<br>}</pre><p><strong>Key Points of Queue Interface</strong></p><p>1. FIFO Principle: Elements are processed in the order in which they are added.</p><p>2. Null Elements Not Allowed: `Queue` does not permit null elements.</p><p>3. Basic Operations:</p><p>- `add()`: Inserts an element into the queue.</p><p>- `offer()`: Similar to `add()`, but returns false if the queue is full.</p><p>- `poll()`: Retrieves and removes the head of the queue.</p><p>- `peek()`: Retrieves but does not remove the head of the queue.</p><p>- `remove()`: Removes the head of the queue.</p><p><strong>Queue Methods</strong></p><p>- `boolean add(E e)`: Inserts the specified element into the queue. Throws an exception if capacity is exceeded.</p><p>- `boolean offer(E e)`: Inserts the specified element into the queue without throwing an exception if the capacity is exceeded.</p><p>- `E remove()`: Removes and returns the head of the queue. Throws an exception if the queue is empty.</p><p>- `E poll()`: Retrieves and removes the head of the queue, returning null if the queue is empty.</p><p>- `E element()`: Retrieves, but does not remove, the head of the queue. Throws an exception if the queue is empty.</p><p>- `E peek()`: Retrieves, but does not remove, the head of the queue, returning null if the queue is empty.</p><p>Example of Queue Implementation Using LinkedList</p><pre>import java.util.Queue;<br>import java.util.LinkedList;<br><br>public class QueueExample {<br>    public static void main(String[] args) {<br>        Queue&lt;String&gt; queue = new LinkedList&lt;&gt;();<br>        <br>        // Adding elements to the Queue<br>        queue.add(&quot;Element 1&quot;);<br>        queue.add(&quot;Element 2&quot;);<br>        queue.add(&quot;Element 3&quot;);<br>        <br>        System.out.println(&quot;Queue: &quot; + queue);<br>        <br>        // Removing an element from the Queue<br>        System.out.println(&quot;Removed: &quot; + queue.remove());<br>        <br>        // Accessing the front element of the Queue<br>        System.out.println(&quot;Front element: &quot; + queue.peek());<br>        <br>        // Checking the state of the Queue after removal<br>        System.out.println(&quot;Queue after removal: &quot; + queue);<br>    }<br>}</pre><p>Output:</p><pre>Queue: [Element 1, Element 2, Element 3]<br>Removed: Element 1<br>Front element: Element 2<br>Queue after removal: [Element 2, Element 3]</pre><h4>ArrayDeque in Java</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/640/0*BfY6lYriXcdgczhm" /></figure><p>The `ArrayDeque` class is a resizable array that implements the `Deque` interface, allowing elements to be added or removed from both ends (double-ended queue). It provides better performance than `Stack` and `LinkedList` for adding and removing elements at both ends of the queue.</p><p><strong>java.util.Deque</strong></p><pre>public interface java.util.Deque&lt;E&gt; extends java.util.Queue&lt;E&gt; {<br>    public abstract void addFirst(E);<br>    public abstract void addLast(E);<br>    public abstract boolean offerFirst(E);<br>    public abstract boolean offerLast(E);<br>    public abstract E removeFirst();<br>    public abstract E removeLast();<br>    public abstract E pollFirst();<br>    public abstract E pollLast();<br>    public abstract E getFirst();<br>    public abstract E getLast();<br>    public abstract E peekFirst();<br>    public abstract E peekLast();<br>    public abstract boolean removeFirstOccurrence(java.lang.Object);<br>    public abstract boolean removeLastOccurrence(java.lang.Object);<br>    public abstract boolean add(E);<br>    public abstract boolean offer(E);<br>    public abstract E remove();<br>    public abstract E poll();<br>    public abstract E element();<br>    public abstract E peek();<br>    public abstract void push(E);<br>    public abstract E pop();<br>    public abstract boolean remove(java.lang.Object);<br>    public abstract boolean contains(java.lang.Object);<br>    public abstract int size();<br>    public abstract java.util.Iterator&lt;E&gt; iterator();<br>    public abstract java.util.Iterator&lt;E&gt; descendingIterator();<br>}</pre><p><strong>java.util.ArrayDeque:</strong></p><pre>public class java.util.ArrayDeque&lt;E&gt; extends java.util.AbstractCollection&lt;E&gt; <br>implements java.util.Deque&lt;E&gt;, java.lang.Cloneable, java.io.Serializable {<br>    transient java.lang.Object[] elements;<br>    transient int head;<br>    transient int tail;<br>    static final boolean $assertionsDisabled;<br>    public java.util.ArrayDeque();<br>    public java.util.ArrayDeque(int);<br>    public java.util.ArrayDeque(java.util.Collection&lt;? extends E&gt;);<br>    public void addFirst(E);<br>    public void addLast(E);<br>    public boolean offerFirst(E);<br>    public boolean offerLast(E);<br>    public E removeFirst();<br>    public E removeLast();<br>    public E pollFirst();<br>    public E pollLast();<br>    public E getFirst();<br>    public E getLast();<br>    public E peekFirst();<br>    public E peekLast();<br>    public boolean removeFirstOccurrence(java.lang.Object);<br>    public boolean removeLastOccurrence(java.lang.Object);<br>    public boolean add(E);<br>    public boolean offer(E);<br>    public E remove();<br>    public E poll();<br>    public E element();<br>    public E peek();<br>    public void push(E);<br>    public E pop();<br>    public int size();<br>    public boolean isEmpty();<br>    public java.util.Iterator&lt;E&gt; iterator();<br>    public java.util.Iterator&lt;E&gt; descendingIterator();<br>    public boolean contains(java.lang.Object);<br>    public boolean remove(java.lang.Object);<br>    public void clear();<br>    public java.lang.Object[] toArray();<br>    public &lt;T&gt; T[] toArray(T[]);<br>    public java.util.ArrayDeque&lt;E&gt; clone();<br>    public java.util.Spliterator&lt;E&gt; spliterator();<br>    public java.lang.Object clone() throws java.lang.CloneNotSupportedException;<br>    static boolean access$200(java.util.ArrayDeque, int);<br>    static {};<br>}</pre><p><strong>Key Points of ArrayDeque</strong></p><p>1. Resizable Array: It acts like a dynamic array, growing and shrinking as needed.</p><p>2. Constant Time for Add/Remove: Efficient insertion and removal from both ends.</p><p>3. Allows Duplicates: Elements can be duplicated.</p><p>4. Not Thread-Safe: `ArrayDeque` is not synchronized.</p><p>5. No Null Elements: Does not allow `null` elements.</p><p>6. No Support for ListIterator: `ArrayDeque` does not support iterating with `ListIterator` or `Enumeration`.</p><p><strong>Constructors of ArrayDeque</strong></p><p>1. `ArrayDeque()`: Creates an empty `ArrayDeque` with an initial capacity of 16.</p><p>2. `ArrayDeque(int capacity)`: Creates an empty `ArrayDeque` with the specified capacity.</p><p>3. `ArrayDeque(Collection&lt;? extends E&gt; c)`: Creates a `Deque` containing all elements from the specified collection.</p><p>Example of ArrayDeque</p><pre>import java.util.ArrayDeque;<br>import java.util.ArrayList;<br><br>public class ArrayDequeExample {<br>    public static void main(String[] args) {<br>        // Creating an ArrayDeque with default capacity<br>        ArrayDeque&lt;String&gt; deque = new ArrayDeque&lt;&gt;();<br>        deque.add(&quot;Element 1&quot;);<br>        deque.addFirst(&quot;Element 0&quot;);<br>        deque.addLast(&quot;Element 2&quot;);<br>        <br>        System.out.println(&quot;ArrayDeque: &quot; + deque);<br>        <br>        // Removing elements<br>        System.out.println(&quot;Removed First: &quot; + deque.removeFirst());<br>        System.out.println(&quot;Removed Last: &quot; + deque.removeLast());<br>        <br>        // Checking state after removal<br>        System.out.println(&quot;ArrayDeque after removal: &quot; + deque);<br>    }<br>}</pre><p>Output:</p><pre>ArrayDeque: [Element 0, Element 1, Element 2]<br>Removed First: Element 0<br>Removed Last: Element 2<br>ArrayDeque after removal: [Element 1]</pre><h4>PriorityQueue` in Java</h4><p>The `PriorityQueue` class in Java, part of the `java.util` package, is a specialized data structure used to process elements based on their priority. It is not a regular FIFO queue but allows elements to be processed based on their natural ordering or a custom ordering defined by a `Comparator`.</p><p><strong>java.util.PriorityQueue:</strong></p><pre>public class java.util.PriorityQueue&lt;E&gt; extends java.util.AbstractQueue&lt;E&gt; <br>implements java.io.Serializable {<br>    transient java.lang.Object[] queue;<br>    transient int modCount;<br>    public java.util.PriorityQueue();<br>    public java.util.PriorityQueue(int);<br>    public java.util.PriorityQueue(java.util.Comparator&lt;? super E&gt;);<br>    public java.util.PriorityQueue(int, java.util.Comparator&lt;? super E&gt;);<br>    public java.util.PriorityQueue(java.util.Collection&lt;? extends E&gt;);<br>    public java.util.PriorityQueue(java.util.PriorityQueue&lt;? extends E&gt;);<br>    public java.util.PriorityQueue(java.util.SortedSet&lt;? extends E&gt;);<br>    public boolean add(E);<br>    public boolean offer(E);<br>    public E peek();<br>    public boolean remove(java.lang.Object);<br>    boolean removeEq(java.lang.Object);<br>    public boolean contains(java.lang.Object);<br>    public java.lang.Object[] toArray();<br>    public &lt;T&gt; T[] toArray(T[]);<br>    public java.util.Iterator&lt;E&gt; iterator();<br>    public int size();<br>    public void clear();<br>    public E poll();<br>    public java.util.Comparator&lt;? super E&gt; comparator();<br>    public final java.util.Spliterator&lt;E&gt; spliterator();<br>    static int access$100(java.util.PriorityQueue);<br>    static java.lang.Object access$200(java.util.PriorityQueue, int);<br>}</pre><p><strong>Key Points about `PriorityQueue`:</strong></p><p>1. Priority-based Processing: Elements are processed based on their priority, not in the insertion order.</p><p>2. Sorting: It uses natural sorting (like the sorting order of numbers) or a custom sorting order defined by a `Comparator`.</p><p>3. Homogeneity in Natural Ordering: If the default sorting is used, all elements should be of the same type and implement the `Comparable` interface; otherwise, a `ClassCastException` will be thrown.</p><p>4. Custom Sorting: With a `Comparator`, the elements don’t need to be homogeneous or `Comparable`.</p><p>5. No Insertion Order Guarantee: Unlike other collections, the insertion order is not preserved.</p><p>6. Null Elements Not Allowed: Null values cannot be added to a `PriorityQueue`.</p><p>Example of Using a `PriorityQueue`</p><pre>import java.util.PriorityQueue;<br><br>public class PriorityQueueExample {<br>    public static void main(String[] args) {<br>        PriorityQueue&lt;Integer&gt; priorityQueue = new PriorityQueue&lt;&gt;();<br>        <br>        // Adding elements<br>        priorityQueue.add(101);<br>        priorityQueue.add(34);<br>        priorityQueue.add(67);<br>        priorityQueue.add(-90);<br>        priorityQueue.add(101); // Duplicate values are allowed<br>        <br>        // Printing PriorityQueue - note it does not follow insertion order<br>        System.out.println(&quot;PriorityQueue: &quot; + priorityQueue);<br>    }<br>}</pre><p>Output:</p><pre>PriorityQueue: [-90, 34, 67, 101, 101]</pre><p>In this example, the `PriorityQueue` organizes integers in ascending order, which is the natural ordering for integers.</p><p><strong>Custom Comparator Example</strong></p><p>You can define your own priority by using a `Comparator`. Here’s an example where we create a `PriorityQueue` of `Student` objects based on their marks in descending order.</p><p>Custom Comparator to Sort by Marks (Descending)</p><pre>import java.util.Comparator;<br>import java.util.PriorityQueue;<br><br>class Student {<br>    int id;<br>    String name;<br>    float marks;<br><br>    public Student(int id, String name, float marks) {<br>        this.id = id;<br>        this.name = name;<br>        this.marks = marks;<br>    }<br><br>    @Override<br>    public String toString() {<br>        return &quot;Student [ID=&quot; + id + &quot;, Name=&quot; + name + &quot;, Marks=&quot; + marks + &quot;]&quot;;<br>    }<br>}<br><br>// Comparator to sort students by marks in descending order<br>class MarksComparator implements Comparator&lt;Student&gt; {<br>    @Override<br>    public int compare(Student s1, Student s2) {<br>        return Float.compare(s2.marks, s1.marks);<br>    }<br>}<br><br>public class PriorityQueueWithComparator {<br>    public static void main(String[] args) {<br>        // Create a PriorityQueue with a custom comparator<br>        PriorityQueue&lt;Student&gt; studentQueue = new PriorityQueue&lt;&gt;<br>                                                      (new MarksComparator());<br><br>        // Adding students to the queue<br>        studentQueue.add(new Student(101, &quot;Alice&quot;, 85.0f));<br>        studentQueue.add(new Student(102, &quot;Bob&quot;, 90.0f));<br>        studentQueue.add(new Student(103, &quot;Charlie&quot;, 70.0f));<br><br>        // Processing students based on descending marks<br>        while (!studentQueue.isEmpty()) {<br>            System.out.println(studentQueue.poll()); // Removes and prints highest-priority element<br>        }<br>    }<br>}</pre><p>Output:</p><pre>Student [ID=102, Name=Bob, Marks=90.0]<br>Student [ID=101, Name=Alice, Marks=85.0]<br>Student [ID=103, Name=Charlie, Marks=70.0]</pre><p>Here, the `MarksComparator` sorts `Student` objects in descending order of marks.</p><p><strong>Constructors of `PriorityQueue`</strong></p><p>1. Default Constructor (`PriorityQueue()`):</p><p>- Creates an empty priority queue with a default capacity of 11 and natural ordering.</p><pre>PriorityQueue&lt;Integer&gt; pq = new PriorityQueue&lt;&gt;();</pre><p>2. Capacity Constructor (`PriorityQueue(int initialCapacity)`):</p><p>- Creates a `PriorityQueue` with a specified initial capacity.</p><pre>PriorityQueue&lt;Integer&gt; pq = new PriorityQueue&lt;&gt;(20);</pre><p>3. Comparator-based Constructor (`PriorityQueue(Comparator comparator)`):</p><p>- Constructs a priority queue with a custom `Comparator` for sorting.</p><pre>PriorityQueue&lt;Student&gt; pq = new PriorityQueue&lt;&gt;(new MarksComparator());</pre><p>4. Capacity + Comparator (`PriorityQueue(int initialCapacity, Comparator comparator)`):</p><p>- Creates a `PriorityQueue` with an initial capacity and custom comparator.</p><pre>PriorityQueue&lt;Student&gt; pq = new PriorityQueue&lt;&gt;(20, new MarksComparator());</pre><p>5. Collection-based Constructor (`PriorityQueue(Collection c)`):</p><p>- Creates a priority queue from an existing collection.</p><pre>List&lt;Integer&gt; list = Arrays.asList(3, 5, 1, 7);<br>PriorityQueue&lt;Integer&gt; pq = new PriorityQueue&lt;&gt;(list);</pre><p><strong>Key Methods of `PriorityQueue`</strong></p><p>1. `add(E element)`: Inserts the element into the queue.</p><p>2. `peek()`: Retrieves, but does not remove, the head of this queue, or returns `null` if the queue is empty.</p><p>3. `poll()`: Retrieves and removes the head of this queue, or returns `null` if the queue is empty.</p><p>4. `remove()`: Removes a specific element from the queue.</p><p>5. `clear()`: Removes all elements from the queue.</p><p>6. `size()`: Returns the number of elements in the queue.</p><p>7. `contains(Object o)`: Returns `true` if the queue contains the specified element.</p><p>8. `toArray()`: Returns an array containing all elements of the queue.</p><p>Conclusion</p><p>The `PriorityQueue` is an efficient way to manage elements based on priority instead of insertion order. It offers natural ordering or custom ordering through a `Comparator`. This makes it highly suitable for tasks like job scheduling, simulations, or any scenario where processing order depends on priority.</p><h3>`Iterator` in Java</h3><p>The `Iterator` interface, found in the `java.util` package, is a tool used to traverse elements of a collection, such as an `ArrayList`, `HashSet`, or any collection implementing `java.util.Collection`. It allows us to visit elements one by one, only in forward order.</p><p>Methods in `Iterator` Interface:</p><pre>public interface java.util.Iterator&lt;E&gt; {<br>    public abstract boolean hasNext();<br>    public abstract E next();<br>    public void remove();<br>    public void forEachRemaining(java.util.function.Consumer&lt;? super E&gt;);<br>}</pre><p>1. `hasNext()`:</p><p>- Returns `true` if there are more elements to iterate over.</p><p>2. `next()`:</p><p>- Returns the next element in the iteration.</p><p>- Throws `NoSuchElementException` if no more elements exist.</p><p>3. `remove()`:</p><p>- Removes the element that was returned by the last `next()` call.</p><p>- Throws `IllegalStateException` if called without a prior `next()` call or if `remove()` is called multiple times after one `next()` call.</p><p>4. `forEachRemaining(Consumer&lt;? super E&gt;)`:</p><p>- Performs the specified action on each remaining element until all elements have been processed.</p><p><strong>Important Points about Iterators:</strong></p><p>- An `Iterator` can only traverse the collection in forward order.</p><p>- Once an `Iterator` is used to traverse the collection, it cannot be reused to traverse it again.</p><p>- Modifying a collection while iterating (i.e., adding or removing elements directly through the collection’s methods) results in a `ConcurrentModificationException`.</p><p>Example of Using an `Iterator`:</p><pre>import java.util.ArrayList;<br>import java.util.Iterator;<br><br>public class IteratorExample {<br>    public static void main(String[] args) {<br>        ArrayList&lt;Integer&gt; list = new ArrayList&lt;&gt;();<br>        list.add(101);<br>        list.add(202);<br>        list.add(303);<br>        list.add(404);<br>        list.add(505);<br><br>        // Create an iterator<br>        Iterator&lt;Integer&gt; iterator = list.iterator();<br>        <br>        // Use the iterator to traverse the list<br>        while (iterator.hasNext()) {<br>            System.out.println(iterator.next());<br>        }<br><br>        // Trying to reuse the same iterator doesn&#39;t work<br>        System.out.println(&quot;--------&quot;);<br>        while (iterator.hasNext()) {<br>            System.out.println(iterator.next()); // No output as iterator is exhausted<br>        }<br>    }<br>}</pre><p>Output:</p><pre>101<br>202<br>303<br>404<br>505<br> - - - -</pre><p>In this example, the iterator can only be used once. The second attempt to traverse the list using the same iterator produces no output because the iterator has already reached the end of the collection.</p><p><strong>Handling Concurrent Modification Exception</strong></p><p>When iterating over a collection, adding or removing elements directly through the collection will lead to a `ConcurrentModificationException`. The following example demonstrates this:</p><pre>import java.util.ArrayList;<br>import java.util.Iterator;<br><br>public class ConcurrentModificationExample {<br>    public static void main(String[] args) {<br>        ArrayList&lt;Integer&gt; list = new ArrayList&lt;&gt;();<br>        list.add(101);<br>        list.add(202);<br>        list.add(303);<br>        list.add(404);<br>        list.add(505);<br><br>        // Attempting to modify the collection while iterating<br>        Iterator&lt;Integer&gt; iterator = list.iterator();<br>        while (iterator.hasNext()) {<br>            System.out.println(iterator.next());<br>            // Uncommenting either of these lines will throw <br>            // ConcurrentModificationException<br>            // list.remove(new Integer(303));<br>            // list.add(new Integer(606));<br>        }<br>    }<br>}</pre><p>Output:</p><pre>101<br>202<br>303<br>404<br>505</pre><p>The program works fine until we try to modify the collection (`list.add()` or `list.remove()`) while iterating, which would throw a `ConcurrentModificationException`. This occurs because the structure of the collection is altered during iteration.</p><p><strong>Removing Elements Using Iterator’s `remove()` Method</strong></p><p>The `Iterator` interface provides the `remove()` method to safely remove elements while iterating through the collection.</p><p>Example: Removing Elements Using `Iterator`</p><pre>import java.util.ArrayList;<br>import java.util.Iterator;<br><br>public class RemoveElementExample {<br>    public static void main(String[] args) {<br>        ArrayList&lt;Integer&gt; list = new ArrayList&lt;&gt;();<br>        list.add(101);<br>        list.add(202);<br>        list.add(303);<br>        list.add(404);<br>        list.add(505);<br><br>        System.out.println(&quot;Before Iteration list: &quot; + list);<br><br>        // Remove elements using iterator<br>        Iterator&lt;Integer&gt; iterator = list.iterator();<br>        while (iterator.hasNext()) {<br>            System.out.println(iterator.next());<br>            iterator.remove(); // Removes the current element<br>        }<br><br>        System.out.println(&quot;After Iteration list: &quot; + list);<br>    }<br>}</pre><p>Output:</p><pre>Before Iteration list: [101, 202, 303, 404, 505]<br>101<br>202<br>303<br>404<br>505<br>After Iteration list: []</pre><p>In this example, the `remove()` method of the `Iterator` is used to remove elements while iterating. The list is empty after the iteration is complete.</p><p><strong>Summary of Important Methods in `Iterator`</strong></p><p>1. `hasNext()`: Checks if there are more elements to iterate.</p><p>2. `next()`: Retrieves the next element in the collection.</p><p>3. `remove()`: Removes the element last returned by `next()`.</p><p>The `Iterator` interface is essential for traversing and manipulating collections in a safe and efficient manner, especially when removing elements from the collection while iterating. However, be cautious of concurrent modification errors if the collection is altered during iteration without using the `remove()` method.</p><h3>`ListIterator` in Java</h3><p>The `ListIterator` interface, available in the `java.util` package, extends the `Iterator` interface and is specifically designed for iterating over list-type collections. Unlike `Iterator`, which can only move forward through a collection, `ListIterator` can traverse a list in both forward and reverse directions.</p><p>Declaration of `ListIterator` Interface:</p><pre>public interface java.util.ListIterator&lt;E&gt; extends java.util.Iterator&lt;E&gt; {<br>    public abstract boolean hasNext();<br>    public abstract E next();<br>    public abstract boolean hasPrevious();<br>    public abstract E previous();<br>    public abstract int nextIndex();<br>    public abstract int previousIndex();<br>    public abstract void remove();<br>    public abstract void set(E e);<br>    public abstract void add(E e);<br>}</pre><p><strong>Key Features of `ListIterator`:</strong></p><p>1. Bidirectional Iteration: Unlike `Iterator`, which only allows forward iteration, `ListIterator` can iterate both forward and backward.</p><p>2. List-specific: `ListIterator` works only with list-type collections (`ArrayList`, `LinkedList`, etc.).</p><p>3. Supports Modifications: The `add()`, `set()`, and `remove()` methods allow modifying the list during iteration.</p><p>Example:</p><pre>import java.util.ArrayList;<br>import java.util.ListIterator;<br><br>public class ListIteratorExample {<br>    public static void main(String[] args) {<br>        ArrayList&lt;Integer&gt; list = new ArrayList&lt;&gt;();<br>        list.add(101);<br>        list.add(202);<br>        list.add(303);<br>        list.add(404);<br>        list.add(505);<br><br>        // Create a ListIterator<br>        ListIterator&lt;Integer&gt; iterator = list.listIterator();<br><br>        // Forward iteration<br>        System.out.println(&quot;Forward iteration:&quot;);<br>        while (iterator.hasNext()) {<br>            System.out.println(iterator.next());<br>        }<br><br>        // Reverse iteration<br>        System.out.println(&quot;Reverse iteration:&quot;);<br>        while (iterator.hasPrevious()) {<br>            System.out.println(iterator.previous());<br>        }<br>    }<br>}</pre><p>Output:</p><pre>Forward iteration:<br>101<br>202<br>303<br>404<br>505<br>Reverse iteration:<br>505<br>404<br>303<br>202<br>101</pre><p><strong>Important Methods of `ListIterator`:</strong></p><p>1. `boolean hasNext()`:</p><p>- Checks if there are more elements while iterating in the forward direction.</p><p>2. `E next()`:</p><p>- Returns the next element in the list and moves the cursor forward. Throws `NoSuchElementException` if there are no more elements.</p><p>3. `boolean hasPrevious()`:</p><p>- Checks if there are more elements while iterating in reverse order.</p><p>4. `E previous()`:</p><p>- Returns the previous element in the list and moves the cursor backward. Throws `NoSuchElementException` if no more previous elements exist.</p><p>5. `int nextIndex()`:</p><p>- Returns the index of the element that would be returned by the next call to `next()`.</p><p>6. `int previousIndex()`:</p><p>- Returns the index of the element that would be returned by the next call to `previous()`.</p><p>7. `void remove()`:</p><p>- Removes the last element returned by `next()` or `previous()` from the list. It can only be called once after a call to `next()` or `previous()`.</p><p>8. `void set(E e)`:</p><p>- Replaces the last element returned by `next()` or `previous()` with the specified element. This can be called only if neither `remove()` nor `add()` has been called after the last call to `next()` or `previous()`.</p><p>9. `void add(E e)`:</p><p>- Inserts the specified element into the list at the current cursor position. The new element is inserted before the element that would be returned by `next()` and after the element that would be returned by `previous()`.</p><p>Example: Using `add()` and `remove()` Methods in `ListIterator`</p><pre>import java.util.ArrayList;<br>import java.util.ListIterator;<br><br>public class ListIteratorAddRemove {<br>    public static void main(String[] args) {<br>        ArrayList&lt;Integer&gt; list = new ArrayList&lt;&gt;();<br>        list.add(101);<br>        list.add(202);<br>        list.add(303);<br>        list.add(404);<br>        list.add(505);<br><br>        // Create a ListIterator<br>        ListIterator&lt;Integer&gt; iterator = list.listIterator();<br><br>        // Add elements while iterating<br>        System.out.println(&quot;Adding element during iteration:&quot;);<br>        while (iterator.hasNext()) {<br>            Integer value = iterator.next();<br>            if (value == 303) {<br>                iterator.add(999);  // Adding 999 after 303<br>            }<br>            System.out.println(value);<br>        }<br><br>        // Removing elements while iterating<br>        iterator = list.listIterator();<br>        System.out.println(&quot;\nRemoving element during iteration:&quot;);<br>        while (iterator.hasNext()) {<br>            Integer value = iterator.next();<br>            if (value == 404) {<br>                iterator.remove();  // Removing 404<br>            }<br>            System.out.println(value);<br>        }<br><br>        // Final list<br>        System.out.println(&quot;\nFinal list: &quot; + list);<br>    }<br>}</pre><p>Output:</p><pre>Adding element during iteration:<br>101<br>202<br>303<br>999<br>404<br>505<br>Removing element during iteration:<br>101<br>202<br>303<br>999<br>404<br>505<br>Final list: [101, 202, 303, 999, 505]</pre><p><strong>Key Differences between `Iterator` and `ListIterator`:</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/855/1*heBTc6bhP7JKZ909ajXpjw.png" /></figure><p><strong>Summary:</strong></p><p>- `ListIterator` provides additional functionality over `Iterator` by allowing bidirectional traversal and list modifications (`add()`, `set()`, and `remove()`).</p><p>-`ListIterator` is particularly useful when you need more control over the iteration process, such as moving both forward and backward, modifying elements, and inserting new elements at specific positions.</p><h4>Enumeration in Java</h4><p>1. Definition:</p><p>- `Enumeration` is an interface that allows for iterating over a collection of objects, specifically legacy collections in Java, such as `Vector`, `Hashtable`, `Properties`, `Stack`, and `Dictionary`.</p><p>2. Methods:</p><p>- The `Enumeration` interface defines two main methods:</p><pre>public abstract boolean hasMoreElements();<br>public abstract E nextElement();</pre><p><strong>Important Points about `Enumeration`:</strong></p><p>1. Legacy Collection Traversal:</p><p>- `Enumeration` is designed to work with legacy classes in the Java Collections Framework. This means it’s not suitable for the newer collection classes introduced in Java 2, like `ArrayList`, `HashSet`, etc.</p><p>2. One-way Traversal:</p><p>- You can only traverse collections in one direction (forward) with `Enumeration`. Unlike some other iterators, you cannot go backward or modify the traversal order.</p><p>3. Safe Modifications:</p><p>- While traversing a collection using `Enumeration`, you can add or remove elements without encountering exceptions (like `ConcurrentModificationException`), which is a limitation when using `Iterator` or `ListIterator`.</p><p>Example Code Explained:</p><p>Here’s the provided example code broken down:</p><pre>import java.util.Enumeration;<br>import java.util.Vector;<br><br>public class JTC {<br>   public static void main(String[] args) {<br>      Vector vector = new Vector();<br>      vector.add(101);<br>      vector.add(&quot;Hello&quot;);<br>      vector.add(12.34f);<br>      vector.add(true);<br>      <br>      Enumeration enumeration = vector.elements();<br>      <br>      while (enumeration.hasMoreElements()) {<br>         System.out.println(enumeration.nextElement());<br>      }<br>      <br>      System.out.println(&quot;--------------------&quot;);<br>   }<br>}</pre><p>Output:</p><pre>101<br>Hello<br>12.34<br>true<br>--------------------</pre><p>Breakdown:</p><p>1. Vector Creation:</p><p>- A `Vector` is instantiated, which is a legacy collection that can hold objects of any type.</p><p>2. Adding Elements:</p><p>- Various elements are added to the vector (an `Integer`, a `String`, a `Float`, and a `Boolean`).</p><p>3. Creating Enumeration:</p><p>- The `elements()` method of the `Vector` class is called, which returns an `Enumeration` object that allows traversal of the `Vector`.</p><p>4. Traversing the Vector:</p><p>- A `while` loop is used to traverse the `Vector`. The `hasMoreElements()` method checks if there are more elements to read.</p><p>- The `nextElement()` method retrieves the next element in the enumeration and prints it.</p><p>5. Output:</p><p>- The output shows each element added to the vector, followed by a separator line.</p><p>Important Methods of `Enumeration`:</p><p>1. `hasMoreElements()`:</p><p>- Returns `true` if there are more elements to iterate over; otherwise, it returns `false`.</p><p>2. `nextElement()`:</p><p>- Returns the next element in the enumeration. If there are no more elements, it throws a `NoSuchElementException`.</p><p>Conclusion</p><p>`Enumeration` is a simple interface for iterating over legacy collections, providing a straightforward way to traverse elements. However, because it is less flexible than modern iterators, it is often recommended to use `Iterator` for newer collection types when possible.</p><h4>HashMap Overview</h4><p>The `HashMap` in Java, part of the `java.util` package, is a widely used collection that stores data as key-value pairs. It is an implementation of the `Map` interface and provides constant-time performance for basic operations like `get` and `put`. Here’s a deep dive into the key features, methods, and internal workings of `HashMap`:</p><p><strong>Key Points of `HashMap`</strong></p><p>1. Key-Value Pair Storage: HashMap stores data in key-value pairs.</p><p>2. Heterogeneous Keys and Values: It allows keys and values of any type, including custom objects.</p><p>3. Duplicate Keys: Only one value is associated with each key, but duplicate values are allowed.</p><p>4. Null Keys and Values: One `null` key and multiple `null` values are allowed.</p><p>5. Unordered Storage: Elements are not stored in any specific order.</p><p>6. Not Synchronized: HashMap is not synchronized, making it unsafe for concurrent use without external synchronization.</p><p>7. Cloneable and Serializable: HashMap can be cloned and serialized.</p><p>8. Random Access: HashMap provides random access to elements.</p><p>Important Constructors</p><p>1. Default Constructor: Creates an empty `HashMap` with an initial capacity of 16 and a default load factor of 0.75.</p><pre>HashMap&lt;K, V&gt; map = new HashMap&lt;&gt;();</pre><p>2. Parameterized Constructor (Capacity): Creates an empty `HashMap` with a specified initial capacity.</p><pre>HashMap&lt;K, V&gt; map = new HashMap&lt;&gt;(capacity);</pre><p>3. Parameterized Constructor (Capacity and Load Factor): Creates a `HashMap` with specified capacity and load factor.</p><pre>HashMap&lt;K, V&gt; map = new HashMap&lt;&gt;(capacity, loadFactor);</pre><p>4. Copy Constructor: Creates a `HashMap` with mappings identical to those in the specified map.</p><pre>HashMap&lt;K, V&gt; map = new HashMap&lt;&gt;(existingMap);</pre><p><strong>Common Methods</strong></p><p>`put()`</p><p>Adds a key-value pair to the map. If the key already exists, the new value replaces the old one.</p><pre>HashMap&lt;String, String&gt; map = new HashMap&lt;&gt;();<br>map.put(&quot;key1&quot;, &quot;value1&quot;);</pre><p>`putAll()`</p><p>Copies all key-value pairs from another map to the current map.</p><pre>HashMap&lt;String, String&gt; map2 = new HashMap&lt;&gt;();<br>map2.putAll(map);</pre><p>`remove()`</p><p>Removes a key (and its corresponding value) from the map.</p><pre>map.remove(&quot;key1&quot;);</pre><p>`keySet()`</p><p>Returns a `Set` view of the keys contained in the map.</p><pre>Set&lt;String&gt; keys = map.keySet();</pre><p>`values()`</p><p>Returns a `Collection` view of the values contained in the map.</p><pre>Collection&lt;String&gt; values = map.values();</pre><p>`entrySet()`</p><p>Returns a `Set` view of the key-value mappings.</p><pre>Set&lt;Map.Entry&lt;String, String&gt;&gt; entries = map.entrySet();</pre><p>`get()`</p><p>Retrieves the value associated with a given key. Returns `null` if the key is not found.</p><pre>String value = map.get(&quot;key1&quot;);</pre><p>`equals()`</p><p>Compares two maps for equality. Returns `true` if both maps contain the same key-value pairs.</p><pre>boolean isEqual = map1.equals(map2);</pre><p>`hashCode()`</p><p>Returns the hash code value for the map.</p><pre>int hashCode = map.hashCode();</pre><p><strong>Internal Working of `HashMap`</strong></p><p>1. Bucket Array: Internally, `HashMap` uses an array of `Node` objects (buckets) to store key-value pairs. Each bucket is a linked list (or a tree in case of high collision).</p><p>2. Hashing: The key’s hash code is computed using the `hash()` function and then the bucket index is determined using:</p><pre>index = hash(key) &amp; (n - 1);</pre><p>where `n` is the length of the array (bucket).</p><p>3. Collision Handling: If two keys have the same hash code, they are placed in the same bucket. A linked list or a tree structure is used to store multiple entries in the same bucket.</p><p>4. Load Factor: The load factor (default is 0.75) determines when to increase the capacity of the bucket array. Once the size of the map exceeds `capacity loadFactor`, the array is resized.</p><p>5. Rehashing: During resizing, all entries are redistributed into the new bucket array.</p><p>Example: Simple `HashMap` Implementation</p><pre>import java.util.HashMap;<br><br>public class HashMapExample {<br>   public static void main(String[] args) {<br>      HashMap&lt;Integer, String&gt; map = new HashMap&lt;&gt;();<br>      map.put(1, &quot;Apple&quot;);<br>      map.put(2, &quot;Banana&quot;);<br>      map.put(3, &quot;Cherry&quot;);<br><br>      System.out.println(&quot;Map: &quot; + map);<br>      System.out.println(&quot;Value for key 2: &quot; + map.get(2));<br>   }<br>}</pre><p><strong>Conclusion</strong></p><p>`HashMap` is a powerful data structure for storing and retrieving key-value pairs with constant-time complexity for most operations. Understanding its internal working is essential for optimizing its use in scenarios involving large datasets, custom objects, and performance-sensitive applications.</p><h4>LinkedHashMap</h4><p>A `LinkedHashMap` is a hybrid between a `HashMap` and a doubly-linked list, combining the performance benefits of a `HashMap` with the order-preserving characteristic of a linked list. Let’s break down the important points you’ve shared:</p><p><strong>Key Features of `LinkedHashMap`:</strong></p><p>1. Node Representation: It stores its entries as nodes of type `LinkedHashMap.Entry`, which extends `HashMap.Node`. This class keeps links to both the previous and next entries, preserving the insertion order.</p><p>2. Key-Value Pairs: Just like other `Map` implementations, `LinkedHashMap` maps unique keys to values. The values can be duplicated, but keys must be unique.</p><p>3. Null Keys and Values: It supports `null` as both keys and values. This feature is consistent with `HashMap`.</p><p>4. Order of Elements: Unlike `HashMap`, the entries in a `LinkedHashMap` are ordered based on their insertion order. This makes it deterministic, so when you iterate over the map, you will get the keys in the same order in which they were inserted.</p><p>5. Non-Synchronized: Similar to `HashMap`, none of the methods are synchronized, meaning `LinkedHashMap` is not thread-safe by default. If thread-safety is required, it needs to be externally synchronized.</p><p>6. Clonable and Serializable: Since it extends `HashMap`, which implements both `Cloneable` and `Serializable`, it can be cloned and serialized.</p><p><strong>Constructors of `LinkedHashMap`:</strong></p><p>- Default Constructor: Creates a `LinkedHashMap` with a default initial capacity of 16 and a load factor of 0.75.</p><p>- Parameterized Constructors: Allow specifying initial capacity and load factor, similar to `HashMap`. There’s also a constructor that accepts a `Map` to create a `LinkedHashMap` initialized with the mappings of the given `Map`.</p><p><strong>Internal Working of `LinkedHashMap`:</strong></p><p>The internal structure of `LinkedHashMap` is based on a doubly linked list that maintains insertion order. Each entry in the map is represented by an instance of `LinkedHashMap.Entry`, which extends `HashMap.Node` and adds two additional references:</p><p>- `before`: Reference to the previous entry.</p><p>- `after`: Reference to the next entry.</p><p>The entry class looks like this:</p><pre>static class Entry&lt;K,V&gt; extends HashMap.Node&lt;K,V&gt; { <br>    Entry&lt;K,V&gt; before, after; <br>    Entry(int hash, K key, V value, Node&lt;K,V&gt; next) { <br>        super(hash, key, value, next); <br>    } <br>}</pre><p>This structure ensures that all entries are linked together, maintaining the order of their insertion. The overhead of maintaining this linked list adds a slight performance cost compared to a standard `HashMap`, but the trade-off is the ability to iterate in insertion order.</p><p><strong>Code Example:</strong></p><p>The code you provided demonstrates how to add elements to a `LinkedHashMap` and then iterate over its entries:</p><pre>LinkedHashMap map = new LinkedHashMap();<br>map.put((byte) 101, (byte) 201);<br>map.put((short) 202, (short) 202);<br>map.put((int) 303, (int) 303);<br>map.put((long) 404, (long) 404);<br>map.put(12.34f, 67.89f);<br>map.put(34.56, -678.90);<br>map.put(true, false);<br>map.put(&#39;K&#39;, &#39;V&#39;);<br>map.put(&quot;key&quot;, &quot;value&quot;);<br>map.put(null, null);<br>map.put(new JTC(), new JTC());</pre><p>It demonstrates:</p><p>- Storing different types of keys and values (primitives, objects, and even `null`).</p><p>- Iterating over the entries using an iterator.</p><p>Output:</p><p>When this code runs, it prints each entry in the insertion order, verifying that the `LinkedHashMap` preserves the order of elements as they were added.</p><p>Overall, `LinkedHashMap` provides an easy way to combine the constant-time performance of `HashMap` with a predictable iteration order. This makes it particularly useful in scenarios where order is important, such as in caching systems.</p><h4>TreeMap</h4><p>`TreeMap` is a class in the `java.util` package that implements the `NavigableMap` interface, and it stores data in a sorted key-value pair format. Let’s break down the essential details you’ve shared:</p><p><strong>Key Features of `TreeMap`:</strong></p><p>1. Key-Value Format: Like all maps, `TreeMap` stores data in key-value pairs, where each key is unique, and values can be duplicated.</p><p>2. Type Consistency for Keys: All keys in a `TreeMap` must be of the same type to allow sorting. Different types of values are allowed.</p><p>3. No Null Keys or Values: Unlike `HashMap` and `LinkedHashMap`, `TreeMap` does not allow `null` keys or values. Trying to insert a `null` key or value will result in a `NullPointerException`.</p><p>4. Sorted Order: The entries are stored in sorted order according to the natural ordering of the keys or by a specified `Comparator`. The natural order is defined by the `Comparable` interface (like the `compareTo()` method).</p><p>5. Non-Synchronized: Like other map implementations in Java, `TreeMap` is not synchronized. If multiple threads access a `TreeMap` concurrently, it must be externally synchronized.</p><p>6. Clonable and Serializable: Since `TreeMap` implements `Cloneable` and `Serializable`, it can be cloned and serialized for deep copying or persistent storage.</p><p>7. Red-Black Tree Data Structure: `TreeMap` internally uses a Red-Black Tree, which is a self-balancing binary search tree. This guarantees log(n) time complexity for basic operations like `get()`, `put()`, `remove()`, etc.</p><p><strong>Constructors of `TreeMap`:</strong></p><p>1. `TreeMap()`: Creates an empty `TreeMap` that sorts its elements according to the natural ordering of the keys. All key objects must implement `Comparable`.</p><p>Example 1: Integer Keys</p><pre>TreeMap map = new TreeMap();<br>map.put(1, &quot;V-1&quot;);<br>map.put(2, &quot;V-2&quot;);<br>map.put(3, &quot;V-3&quot;);<br>map.put(4, &quot;V-4&quot;);<br>map.put(5, &quot;V-5&quot;);<br>System.out.println(&quot;map :- &quot; + map);</pre><p>Output: The map will store entries sorted by the natural ordering of `Integer`, which is ascending order:</p><pre>map :- {1=V-1, 2=V-2, 3=V-3, 4=V-4, 5=V-5}</pre><p>Example 2: Custom Object with Natural Ordering</p><p>In this example, the `Student` class implements `Comparable` to define the natural sorting order based on student marks in descending order:</p><pre>import java.util.TreeMap;<br><br>class Student implements Comparable&lt;Student&gt; {<br>   String sname;<br>   int marks;<br><br>   public Student(String sname, int marks) {<br>      this.sname = sname;<br>      this.marks = marks;<br>   }<br><br>   @Override<br>   public int compareTo(Student s) {<br>      return Integer.compare(s.marks, this.marks); // Descending order<br>   }<br><br>   @Override<br>   public String toString() {<br>      return &quot;Student [sname=&quot; + sname + &quot;, marks=&quot; + marks + &quot;]&quot;;<br>   }<br>}<br><br>public class Main {<br>   public static void main(String[] args) {<br>      TreeMap&lt;Student, String&gt; map = new TreeMap&lt;&gt;();<br>      map.put(new Student(&quot;Vivek&quot;, 89), &quot;V-1&quot;);<br>      map.put(new Student(&quot;Amit&quot;, 123), &quot;V-2&quot;);<br>      map.put(new Student(&quot;Rahul&quot;, 93), &quot;V-3&quot;);<br>      map.put(new Student(&quot;Nandan&quot;, 103), &quot;V-4&quot;);<br>      map.put(new Student(&quot;Neha&quot;, 789), &quot;V-5&quot;);<br><br>      System.out.println(&quot;map :- &quot; + map);<br>   }<br>}</pre><p><strong>Using lambda function:</strong></p><pre>import java.util.Comparator;<br>import java.util.TreeMap;<br><br>class Student {<br>    String sname;<br>    int marks;<br><br>    public Student(String sname, int marks) {<br>        this.sname = sname;<br>        this.marks = marks;<br>    }<br><br>    @Override<br>    public String toString() {<br>        return &quot;Student [sname=&quot; + sname + &quot;, marks=&quot; + marks + &quot;]&quot;;<br>    }<br>}<br><br>public class Main {<br>    public static void main(String[] args) {<br>        // TreeMap with a custom comparator using a lambda expression<br>        TreeMap&lt;Student, String&gt; map = new TreeMap&lt;&gt;(<br>            (s1, s2) -&gt; Integer.compare(s2.marks, s1.marks) // Descending order<br>        );<br><br>        map.put(new Student(&quot;Vivek&quot;, 89), &quot;V-1&quot;);<br>        map.put(new Student(&quot;Amit&quot;, 123), &quot;V-2&quot;);<br>        map.put(new Student(&quot;Rahul&quot;, 93), &quot;V-3&quot;);<br>        map.put(new Student(&quot;Nandan&quot;, 103), &quot;V-4&quot;);<br>        map.put(new Student(&quot;Neha&quot;, 789), &quot;V-5&quot;);<br><br>        System.out.println(&quot;map :- &quot; + map);<br>    }<br>}</pre><p>Output: The map will store the students sorted in descending order of marks (based on the `compareTo()` method):</p><pre>map :- {Student [sname=Neha, marks=789]=V-5, Student [sname=Amit, marks=123]=V-2, Student [sname=Nandan, marks=103]=V-4, Student [sname=Rahul, marks=93]=V-3, Student [sname=Vivek, marks=89]=V-1}</pre><p>Custom Comparator Example:</p><p>You can define a custom comparator to alter the sorting behavior. In this example, a `Comparator` is used to sort students in ascending order of marks:</p><pre>class StudentMarksComparator implements Comparator&lt;Student&gt; {<br>   public int compare(Student s1, Student s2) {<br>      return Integer.compare(s1.marks, s2.marks); // Ascending order<br>   }<br>}<br><br>TreeMap map = new TreeMap(new StudentMarksComparator());<br>map.put(new Student(&quot;Vivek&quot;, 89), &quot;V-1&quot;);<br>map.put(new Student(&quot;Amit&quot;, 123), &quot;V-2&quot;);<br>map.put(new Student(&quot;Rahul&quot;, 93), &quot;V-3&quot;);<br>map.put(new Student(&quot;Nandan&quot;, 103), &quot;V-4&quot;);<br>map.put(new Student(&quot;Neha&quot;, 789), &quot;V-5&quot;);<br>System.out.println(&quot;map :- &quot; + map);</pre><p>Output: Now the `TreeMap` will sort the students in ascending order based on the custom comparator:</p><pre>map :- {Student [sname=Vivek, marks=89]=V-1, Student [sname=Rahul, marks=93]=V-3, Student [sname=Nandan, marks=103]=V-4, Student [sname=Amit, marks=123]=V-2, Student [sname=Neha, marks=789]=V-5}</pre><p>Summary:</p><p>- Natural Ordering: When no comparator is provided, the keys are sorted based on their natural order (e.g., `Integer`, `String`).</p><p>- Custom Comparator: Allows you to define your own sorting logic.</p><p>- Null Keys/Values: Not allowed, unlike `HashMap` or `LinkedHashMap`.</p><p>- Red-Black Tree: Provides efficient performance with a time complexity of O(log n) for most operations.</p><p>This makes `TreeMap` ideal when you need sorted data (like range queries or when maintaining order is critical) and can tolerate the slightly higher overhead compared to `HashMap`.</p><h4>`Hashtable` in Java</h4><p>The `Hashtable` class, part of the `java.util` package, is a legacy data structure that stores key-value pairs in a hash table. It is one of the original implementations of a map in Java and has been retrofitted to implement the `Map` interface. While similar to `HashMap`, `Hashtable` is synchronized and does not allow `null` keys or values.</p><p>Key Features of `Hashtable`</p><p>1. Legacy Class: `Hashtable` is a legacy class from earlier versions of Java, now included in the Collections Framework.</p><p>2. Key-Value Storage: Stores elements as key-value pairs.</p><p>3. Heterogeneous Keys and Values: Allows different types for keys and values.</p><p>4. No Null Keys or Values: Does not allow `null` as keys or values.</p><p>5. Indexed Storage: Uses an internal index representation for storing elements.</p><p>6. Random Access: Provides random access to elements.</p><p>7. Synchronized Methods: All methods are synchronized, making it thread-safe.</p><p>8. Unordered Storage: Does not guarantee any specific order for its elements.</p><p>9. Uses Enumeration: Iterates over keys and values using `Enumeration`.</p><p><strong>Constructors of `Hashtable`</strong></p><p>1. `Hashtable()`:</p><p>- Creates an empty hashtable with a default initial capacity (11) and a default load factor (0.75).</p><pre>Hashtable&lt;K, V&gt; hashtable = new Hashtable&lt;&gt;();</pre><p>2. `Hashtable(int initialCapacity)`:</p><p>- Creates a hashtable with the specified initial capacity and default load factor (0.75).</p><p>- Throws `IllegalArgumentException` if the initial capacity is negative.</p><pre>Hashtable&lt;K, V&gt; hashtable = new Hashtable&lt;&gt;(initialCapacity);</pre><p>3. `Hashtable(int initialCapacity, float loadFactor)`:</p><p>- Creates a hashtable with the specified initial capacity and load factor.</p><p>- Throws `IllegalArgumentException` if the initial capacity is negative or the load factor is non-positive.</p><pre>Hashtable&lt;K, V&gt; hashtable = new Hashtable&lt;&gt;(initialCapacity, loadFactor);</pre><p>4. `Hashtable(Map&lt;? extends K, ? extends V&gt; t)`:</p><p>- Creates a hashtable with the same mappings as the specified map.</p><p>- Throws `NullPointerException` if the specified map is `null`.</p><pre>Map&lt;K, V&gt; map = new HashMap&lt;&gt;();<br>Hashtable&lt;K, V&gt; hashtable = new Hashtable&lt;&gt;(map);</pre><p><strong>Common Methods of `Hashtable`</strong></p><p>1. `int size()`:</p><p>- Returns the number of key-value pairs in the hashtable.</p><pre>int size = hashtable.size();</pre><p>2. `boolean isEmpty()`:</p><p>- Checks if the hashtable is empty.</p><pre>boolean empty = hashtable.isEmpty();</pre><p>3. `Enumeration&lt;K&gt; keys()`:</p><p>- Returns an enumeration of the keys.</p><pre>Enumeration&lt;K&gt; keys = hashtable.keys();</pre><p>4. `Enumeration&lt;V&gt; elements()`:</p><p>- Returns an enumeration of the values.</p><pre>Enumeration&lt;V&gt; values = hashtable.elements();</pre><p>5. `boolean contains(Object value)`:</p><p>- Checks if the specified value is mapped in the hashtable.</p><p>- Throws `NullPointerException` if the value is `null`.</p><pre>boolean containsValue = hashtable.contains(&quot;Value&quot;);</pre><p>6. `boolean containsKey(Object key)`:</p><p>- Checks if the specified key exists.</p><p>- Throws `NullPointerException` if the key is `null`.</p><pre>boolean containsKey = hashtable.containsKey(&quot;Key&quot;);</pre><p>7. `V get(Object key)`:</p><p>- Retrieves the value associated with the specified key.</p><p>- Returns `null` if the key is not found.</p><p>- Throws `NullPointerException` if the key is `null`.</p><pre>V value = hashtable.get(&quot;Key&quot;);</pre><p>8. `V put(K key, V value)`:</p><p>- Maps the specified key to the specified value.</p><p>- Returns the previous value associated with the key or `null` if none.</p><p>- Throws `NullPointerException` if the key or value is `null`.</p><pre>V previousValue = hashtable.put(&quot;Key&quot;, &quot;Value&quot;);</pre><p>9. `V remove(Object key)`:</p><p>- Removes the key (and its corresponding value) from the hashtable.</p><p>- Returns the value that was removed or `null` if the key didn’t exist.</p><p>- Throws `NullPointerException` if the key is `null`.</p><pre>V removedValue = hashtable.remove(&quot;Key&quot;);</pre><p>10. `void putAll(Map&lt;? extends K, ? extends V&gt; t)`:</p><p>- Copies all mappings from the specified map to this hashtable.</p><p>- Throws `NullPointerException` if the specified map is `null`.</p><pre>hashtable.putAll(anotherMap);</pre><p>11. `void clear()`:</p><p>- Clears the hashtable.</p><pre>hashtable.clear();</pre><p>12. `V getOrDefault(Object key, V defaultValue)`:</p><p>- Returns the value to which the specified key is mapped, or `defaultValue` if the key is not present.</p><p>- Throws `NullPointerException` if the key is `null`.</p><pre>V value = hashtable.getOrDefault(&quot;Key&quot;, defaultValue);</pre><p>Example Code</p><pre>import java.util.Enumeration;<br>import java.util.Hashtable;<br><br>public class HashtableExample {<br>   public static void main(String[] args) {<br>      // Creating an empty Hashtable<br>      Hashtable&lt;Object, Object&gt; hashtable = new Hashtable&lt;&gt;();<br><br>      // Adding elements using put() method<br>      hashtable.put(&quot;K-1&quot;, &quot;V-1&quot;);<br>      hashtable.put(101, true);<br>      hashtable.put((byte) 78, 12.34f);<br>      hashtable.put(&#39;A&#39;, new HashtableExample());<br>      hashtable.put(new HashtableExample(), &#39;V&#39;);<br>      hashtable.put((byte) 78, &#39;N&#39;); // Overwrites previous value for key 78<br><br>      // Displaying the hashtable<br>      System.out.println(&quot;Hashtable: &quot; + hashtable);<br><br>      // Size of the hashtable<br>      System.out.println(&quot;Size: &quot; + hashtable.size());<br><br>      // Check if hashtable is empty<br>      System.out.println(&quot;Is Empty: &quot; + hashtable.isEmpty());<br><br>      // Enumerate keys<br>      System.out.println(&quot;-----Keys-----&quot;);<br>      Enumeration&lt;Object&gt; keys = hashtable.keys();<br>      while (keys.hasMoreElements()) {<br>         System.out.println(keys.nextElement());<br>      }<br><br>      // Enumerate values<br>      System.out.println(&quot;----Values-----&quot;);<br>      Enumeration&lt;Object&gt; values = hashtable.elements();<br>      while (values.hasMoreElements()) {<br>         System.out.println(values.nextElement());<br>      }<br><br>      // Check for a value<br>      System.out.println(&quot;Contains &#39;V-1&#39;: &quot; + hashtable.contains(&quot;V-1&quot;));<br>      System.out.println(&quot;Contains &#39;K-1&#39;: &quot; + hashtable.contains(&quot;K-1&quot;));<br><br>      // Check for a key<br>      System.out.println(&quot;Contains key &#39;K-1&#39;: &quot; + hashtable.containsKey(&quot;K-1&quot;));<br>      System.out.println(&quot;Contains key &#39;V-1&#39;: &quot; + hashtable.containsKey(&quot;V-1&quot;));<br><br>      // Retrieve a value<br>      System.out.println(&quot;Value for &#39;K-1&#39;: &quot; + hashtable.get(&quot;K-1&quot;));<br>      System.out.println(&quot;Value for &#39;V-1&#39;: &quot; + hashtable.get(&quot;V-1&quot;));<br><br>      // Remove a key<br>      System.out.println(&quot;Before Remove Operation: &quot; + hashtable);<br>      System.out.println(&quot;Removed Value: &quot; + hashtable.remove(&quot;K-1&quot;));<br>      System.out.println(&quot;After Remove Operation: &quot; + hashtable);<br>      System.out.println(&quot;Removed Value: &quot; + hashtable.remove(&quot;V-1&quot;));<br><br>      // Adding all the mappings from another hashtable<br>      Hashtable&lt;Object, Object&gt; hashtable2 = new Hashtable&lt;&gt;();<br>      hashtable2.put(&#39;A&#39;, &quot;Value - 1&quot;);<br>      hashtable2.put(&quot;Key-2&quot;, &quot;Value-2&quot;);<br>      hashtable.put(&quot;Key-3&quot;, &quot;Value-3&quot;);<br>      System.out.println(&quot;Hashtable2: &quot; + hashtable2);<br><br>      hashtable.putAll(hashtable2);<br>      System.out.println(&quot;Updated Hashtable: &quot; + hashtable);<br><br>      // Clear the second hashtable<br>      System.out.println(&quot;Hashtable2 size before clear: &quot; + hashtable2.size());<br>      hashtable2.clear();<br>      System.out.println(&quot;Hashtable2 size after clear: &quot; + hashtable2.size());<br><br>      // Using getOrDefault()<br>      System.out.println(&quot;Value for &#39;Key-2&#39;: &quot; + hashtable.getOrDefault(&quot;Key-2&quot;, &quot;DEFAULT_VALUE&quot;));<br>      System.out.println(&quot;Value for &#39;Key-N&#39;: &quot; + hashtable.getOrDefault(&quot;Key-N&quot;, &quot;DEFAULT_VALUE&quot;));<br>   }<br>}</pre><p>Explanation of the Code</p><p>- Adding Elements:</p><p>- Various key-value pairs are added using the `put()` method.</p><p>- Overwriting a value: Adding a new value with an existing key replaces the old value.</p><p>- Note: Attempting to use `null` as a key or value will throw a `NullPointerException`.</p><p>- Size and Emptiness:</p><p>- `size()` returns the number of entries.</p><p>- `isEmpty()` checks if the hashtable is empty.</p><p>- Enumerations:</p><p>- `keys()` and `elements()` return enumerations of the keys and values, respectively.</p><p>- Containment Checks:</p><p>- `contains(Object value)` checks if a value exists.</p><p>- `containsKey(Object key)` checks if a key exists.</p><p>- Retrieval and Removal:</p><p>- `get(Object key)` retrieves the value associated with a key.</p><p>- `remove(Object key)` removes the key-value pair and returns the value.</p><p>- Merging Hashtables:</p><p>- `putAll(Map&lt;? extends K, ? extends V&gt; t)` adds all mappings from another hashtable.</p><p>- Clearing:</p><p>- `clear()` removes all entries from the hashtable.</p><p>- Default Values:</p><p>- `getOrDefault(Object key, V defaultValue)` returns the value associated with the key or the default value if the key is not found.</p><p>Sample Output</p><pre>Hashtable: {A=HashtableExample@15db9742, HashtableExample@6d06d69c=V, K-1=V-1,<br> 101=true, 78=N}<br>Size: 5<br>Is Empty: false<br> - - -Keys - - -<br>A<br>HashtableExample@6d06d69c<br>K-1<br>101<br>78<br> - - Values - - -<br>HashtableExample@15db9742<br>V<br>V-1<br>true<br>N<br>Contains &#39;V-1&#39;: true<br>Contains &#39;K-1&#39;: false<br>Contains key &#39;K-1&#39;: true<br>Contains key &#39;V-1&#39;: false<br>Value for &#39;K-1&#39;: V-1<br>Value for &#39;V-1&#39;: null<br>Before Remove Operation: {A=HashtableExample@15db9742, <br>HashtableExample@6d06d69c=V, K-1=V-1, 101=true, 78=N}<br>Removed Value: V-1<br>After Remove Operation: {A=HashtableExample@15db9742, <br>HashtableExample@6d06d69c=V, 101=true, 78=N}<br>Removed Value: null<br>Hashtable2: {A=Value - 1, Key-2=Value-2}<br>Updated Hashtable: {A=Value - 1, HashtableExample@6d06d69c=V,<br> 101=true, 78=N, Key-2=Value-2, Key-3=Value-3}<br>Hashtable2 size before clear: 2<br>Hashtable2 size after clear: 0<br>Value for &#39;Key-2&#39;: Value-2<br>Value for &#39;Key-N&#39;: DEFAULT_VALUE</pre><p><strong>Important Notes</strong></p><p>- Null Keys and Values:</p><p>- `Hashtable` does not allow `null` keys or values.</p><p>- Attempting to insert a `null` key or value will result in a `NullPointerException`.</p><p>- Thread Safety:</p><p>- All methods in `Hashtable` are synchronized.</p><p>- Suitable for single-threaded applications or simple multi-threaded scenarios.</p><p>- May lead to performance overhead in highly concurrent applications.</p><p>- Enumeration vs. Iterator:</p><p>- `Hashtable` uses `Enumeration` for traversal, which is considered legacy.</p><p>- Modern collections use `Iterator` or `Iterator` with generics for type safety.</p><p>- Ordering:</p><p>- `Hashtable` does not guarantee any specific order of its elements.</p><p>- If ordering is required, consider using `LinkedHashMap`.</p><p>When to Use `Hashtable`</p><p>- Legacy Systems: When maintaining older Java applications that already use `Hashtable`.</p><p>- Simple Thread Safety: When you need a thread-safe map without external synchronization and the performance impact is acceptable.</p><p><strong>Alternatives</strong></p><p>- `HashMap`:</p><p>- Not synchronized, allows `null` keys and values.</p><p>- Better performance in single-threaded environments.</p><p>- `ConcurrentHashMap`:</p><p>- Thread-safe and optimized for concurrent access.</p><p>- Does not allow `null` keys or values.</p><p>- `LinkedHashMap`:</p><p>- Maintains insertion order.</p><p>- Not synchronized, allows `null` keys and values.</p><p><strong>Conclusion</strong></p><p>The `Hashtable` class provides a synchronized key-value data structure that is part of Java’s legacy collections. While newer implementations like `HashMap` and `ConcurrentHashMap` offer improved performance and flexibility, understanding `Hashtable` is important for maintaining legacy code and understanding the evolution of Java’s Collections Framework. When thread safety is required without the need for `null` keys or values, and performance is not the primary concern, `Hashtable` can still be a suitable choice.</p><h4>Properties</h4><p>The `Properties` class in Java, part of the `java.util` package, is used to store key-value pairs where both the key and value are `String` objects. It extends `Hashtable&lt;Object, Object&gt;`, offering additional functionality specifically for managing property files. These files are often used to store configuration details in a Java application.</p><p><strong>Key Features of the `Properties` Class:</strong></p><p>1. String-only key-value pairs: The keys and values in the `Properties` class must be `String` objects.</p><p>2. File Operations: Provides methods for reading from and writing to property files or XML files.</p><p>3. Default Values: A `Properties` object can be created with a default `Properties` object to provide fallback values.</p><p>4. Synchronization: Methods in the `Properties` class are synchronized, making it thread-safe.</p><p><strong>Important Constructors:</strong></p><p>1. `Properties()`: Creates an empty property list.</p><p>2. `Properties(Properties defaults)`: Creates a property list with specified default properties.</p><p><strong>Key Methods:</strong></p><p>1. `setProperty(String key, String value)`: Maps the specified key to the specified value, returning the previous value associated with the key if one exists.</p><p>2. `getProperty(String key)`: Returns the value associated with the specified key. If the key is not found, it returns `null`.</p><p>3. `getProperty(String key, String defaultValue)`: Returns the value associated with the key or the default value if the key is not found.</p><p>4. `load(InputStream inStream)`: Reads a property list from the input stream in a simple line-oriented format.</p><p>5. `loadFromXML(InputStream in)`: Loads properties from an XML file.</p><p>6. `store(OutputStream out, String comments)`: Writes the properties to an output stream, optionally with comments.</p><p>7. `storeToXML(OutputStream os, String comment)`: Stores the properties in an XML format.</p><p>8. `propertyNames()`: Returns an enumeration of all the keys in the property list.</p><p>9. `stringPropertyNames()`: Returns a set of keys where both the key and corresponding value are strings.</p><p>Example:</p><p>This program demonstrates basic usage of `Properties`, including reading from a file and saving properties:</p><pre>import java.io.FileInputStream;<br>import java.io.FileOutputStream;<br>import java.io.IOException;<br>import java.util.Properties;<br><br>public class PropertiesExample {<br>    public static void main(String[] args) throws IOException {<br>        // Create a Properties object<br>        Properties properties = new Properties();<br><br>        // Load properties from a file<br>        properties.load(new FileInputStream(&quot;config.properties&quot;));<br><br>        // Display property values<br>        System.out.println(&quot;Username: &quot; + properties.getProperty(&quot;UserName&quot;));<br>        System.out.println(&quot;Password: &quot; + properties.getProperty(&quot;Password&quot;));<br><br>        // Add a new property<br>        properties.setProperty(&quot;Theme&quot;, &quot;Dark&quot;);<br><br>        // Store updated properties back to the file<br>        properties.store(new FileOutputStream(&quot;config.properties&quot;), &quot;Updated theme setting&quot;);<br><br>        // Store properties in XML format<br>        properties.storeToXML(new FileOutputStream(&quot;config.xml&quot;), &quot;Application Settings&quot;);<br>    }<br>}</pre><p>Working with `.properties` File:</p><p>A `.properties` file is a text file where each line represents a key-value pair, often used for configuration purposes in applications.</p><p>Sample `.properties` File:</p><pre>UserName=JTC<br>Password=JTC@123<br>Theme=Dark</pre><p><strong>XML Format:</strong></p><p>The `Properties` class can also store and load properties in an XML format, providing a more structured alternative to the traditional `.properties` format.</p><pre>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;<br>&lt;!DOCTYPE properties SYSTEM &quot;http://java.sun.com/dtd/properties.dtd&quot;&gt;<br>&lt;properties&gt;<br>    &lt;comment&gt;Application Settings&lt;/comment&gt;<br>    &lt;entry key=&quot;UserName&quot;&gt;JTC&lt;/entry&gt;<br>    &lt;entry key=&quot;Password&quot;&gt;JTC@123&lt;/entry&gt;<br>    &lt;entry key=&quot;Theme&quot;&gt;Dark&lt;/entry&gt;<br>&lt;/properties&gt;</pre><p><strong>Practical Uses:</strong></p><p>- Configuration Management: Storing and retrieving application settings like database connection strings, user preferences, etc.</p><p>- Internationalization: Managing language-specific resources.</p><p>This overview provides a clear understanding of the `Properties` class and how to use it in various file formats.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f641efc230b3" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[JAVA Basics]]></title>
            <link>https://medium.com/@pratik.941/java-basics-0308ddc391cd?source=rss-7f42c99fe66f------2</link>
            <guid isPermaLink="false">https://medium.com/p/0308ddc391cd</guid>
            <category><![CDATA[java]]></category>
            <category><![CDATA[backend-development]]></category>
            <dc:creator><![CDATA[Pratik T]]></dc:creator>
            <pubDate>Tue, 08 Oct 2024 07:05:31 GMT</pubDate>
            <atom:updated>2024-10-26T05:39:52.007Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*O5NppO2vaiTk1AGD.png" /></figure><h4>1. Introduction to Java</h4><p>Java is a high-level, object-oriented programming language developed by Sun Microsystems (now owned by Oracle) in 1995. It is platform-independent, meaning you can write Java code on one system and run it on any other system that supports Java.</p><p><strong>Key Features of Java:</strong></p><ul><li><strong>Object-Oriented</strong>: Java supports concepts such as inheritance, encapsulation, polymorphism, and abstraction.</li><li><strong>Platform-Independent</strong>: Java’s “Write Once, Run Anywhere” capability allows code to run on any device that has the Java Virtual Machine (JVM).</li><li><strong>Secure</strong>: Java has built-in security features like bytecode verification and a security manager.</li><li><strong>Robust</strong>: It handles memory management and supports garbage collection to prevent memory leaks.</li><li><strong>Multi-threaded</strong>: Java supports multithreading, allowing multiple tasks to run concurrently.</li></ul><h4>2. Setting Up the Java Development Environment</h4><h3>Installing Java</h3><ol><li>Download and install the <strong>Java Development Kit (JDK)</strong> from the <a href="https://www.oracle.com/java/technologies/javase-downloads.html">Oracle website</a> or use <a href="https://openjdk.java.net/">OpenJDK</a> (an open-source implementation of Java).</li><li>Set the environment variable JAVA_HOME to the installation directory of the JDK.</li><li>Add the bin directory of the JDK to your system&#39;s PATH environment variable.</li></ol><h3>Setting Up an Integrated Development Environment (IDE)</h3><p>Popular IDEs for Java development:</p><ul><li><strong>Eclipse</strong> (eclipse.org)</li><li><strong>IntelliJ IDEA</strong> (jetbrains.com)</li><li><strong>NetBeans</strong> (netbeans.apache.org)</li></ul><p>You can also use a simple text editor and run Java code from the command line if you prefer.</p><h3>3. Basic Syntax</h3><h3>Writing Your First Java Program</h3><p>Here is a simple Java program that prints “Hello, World!” to the console:</p><pre>public class Demo {<br>    public static void main(String[] args) {<br>        System.out.println(&quot;Hello, World!&quot;);<br>    }<br>}</pre><p><strong>Explanation:</strong></p><p><strong>1. Class Declaration</strong></p><p>Example: `public class Demo`</p><p>- Access Modifier:</p><p>- Definition: Indicates the visibility of the class.</p><p>- Types:</p><p>- public: Accessible from any other class.</p><p>- private: Accessible only within the defined class.</p><p>- protected: Accessible within the same package and by subclasses.</p><p>- default: No modifier; accessible only within the same package.</p><p>- In Our Example: `public` allows `Demo` to be accessed from anywhere.</p><p>- Class Keyword:</p><p>- `class` is a reserved keyword in Java.</p><p>- It must be in lowercase.</p><p>- Every Java program must define a class.</p><p>- Class Name:</p><p>- The name of the class (`Demo` in this case) should start with a capital letter by convention.</p><p>- The file name should match the class name (`Demo.java`).</p><p>- Class names can include letters, digits, `$`, and `_`, but must begin with a letter.</p><p><strong>2. Defining the Main Method</strong></p><p>Example: `public static void main(String args[])`</p><p>- Access Modifier: Similar to the class, here it is `public`, allowing the method to be accessible from anywhere.</p><p>- Non-Access Modifier:</p><p>- static: This allows the method to be called without creating an instance of the class. It belongs to the class itself.</p><p>- Non-static methods require an object of the class to be called.</p><p>- Return Type:</p><p>- `void` indicates that this method does not return a value.</p><p>- Method Name:</p><p>- The name `main` is predefined in Java as the entry point for any Java application.</p><p>- Any method name can be identified by parentheses `()`.</p><p>- Command Line Arguments:</p><p>- `String args[]` allows the program to accept command line arguments.</p><p>- This can also be written as:</p><p>1. `String args[]`</p><p>2. `String[] args`</p><p>3. `String [] args`</p><p>- The capital `S` in `String` is crucial, as Java is case-sensitive.</p><p><strong>3. Printing Statement</strong></p><p>Example: `System.out.println(“This is my first program”);`</p><p>- System Class:</p><p>- `System` is a predefined class in Java.</p><p>- Dot Operator (.):</p><p>- Used to access members (methods or variables) of a class.</p><p>- Out Object:</p><p>- `out` is a static member of the `System` class, which is an instance of `PrintStream`.</p><p>- println() Method:</p><p>- A method of `PrintStream` that prints the provided string followed by a new line.</p><p>- String Literal:</p><p>- `”Hello World”` is the message to be printed. It is enclosed in double quotes.</p><h4>Compiling and Running Java Code</h4><ul><li><strong>Compile</strong>: javac HelloWorld.java</li><li><strong>Run</strong>: java HelloWorld</li></ul><p><strong>1) Difference Between C and Java Programs:</strong></p><p>Key differences between C and Java revolve around their design, usage, and features:</p><p><strong>- Platform Independence:</strong></p><p>- C: C programs are compiled into machine-specific binary code, meaning a C program compiled on one platform cannot run on another without recompilation.</p><p>- Java: Java is platform-independent, as it is compiled into an intermediate bytecode that can run on any system with a Java Virtual Machine (JVM).</p><p><strong>- Memory Management:</strong></p><p>- C: In C, memory management is manual. The programmer has to explicitly allocate and deallocate memory using functions like malloc() and free().</p><p>- Java: Java has automatic memory management with its Garbage Collector, which automatically frees up memory when objects are no longer in use.</p><p><strong>- Syntax:</strong></p><p>- C: C uses procedural programming, and concepts like pointers and structures play a significant role.</p><p>- Java: Java uses object-oriented programming (OOP), where the focus is on classes, objects, and inheritance. Java does not have pointers or structures as C does.</p><p><strong>- Execution Model:</strong></p><p>- C: C compiles directly to machine code, which is specific to the processor.</p><p>- Java: Java code is compiled into bytecode, which is interpreted or compiled by the JVM at runtime.</p><p><strong>- Low-Level Operations:</strong></p><p>- C: C allows low-level programming (e.g., direct memory access via pointers), making it suitable for system programming.</p><p>- Java: Java abstracts away low-level operations, so direct memory access is not allowed for security and simplicity.</p><p><strong>2) How Java Is Platform Independent:</strong></p><p>Java is platform-independent because of its use of bytecode and the Java Virtual Machine (JVM). Here’s how it works:</p><p>1. Source Code Compilation: Java source code (.java files) is compiled into bytecode (.class files) by the Java compiler (javac). This bytecode is not machine-specific.</p><p>2. Bytecode Execution: The bytecode can run on any machine that has a JVM. The JVM interprets or JIT compiles the bytecode into machine code that is specific to the platform it is running on (Windows, Linux, macOS, etc.).</p><p>3. Write Once, Run Anywhere (WORA): Because the JVM is platform-specific but the bytecode is the same across platforms, the same compiled Java program can run on any device with a JVM, making Java platform-independent.</p><p><strong>3) Why Native Code is Available in C but Not in Java:</strong></p><p>- C Programs: C programs are compiled into native machine code that is specific to the operating system and processor architecture. This means that the code can directly interact with the hardware, giving C high performance but making the code non-portable across platforms without recompilation.</p><p>- Java Programs: Java does not compile into native code directly. Instead, Java compiles to bytecode, which runs on the JVM. This abstraction allows Java to be platform-independent. While Java can still call native code using the Java Native Interface (JNI), Java’s design avoids directly compiling into platform-specific machine code to maintain portability.</p><p><strong>4) How to Compile and Run Java Programs Using Command Prompt:</strong></p><p>To compile and run a Java program using the command prompt:</p><p><strong>1. Write the Java Program:</strong></p><p>Create a Java file (HelloWorld.java) with the following content:</p><pre>public class HelloWorld {<br>    public static void main(String[] args) {<br>        System.out.println(&quot;Hello, World!&quot;);<br>  }<br>}</pre><p><strong>2. Compile the Program:</strong></p><p>Open the command prompt and navigate to the directory where the .java file is saved. Use the following command to compile the program:</p><pre>javac HelloWorld.java</pre><p>This will create a HelloWorld.class file (bytecode).</p><p><strong>3. Run the Program:</strong></p><p>After compiling, run the program using:</p><pre>java HelloWorld</pre><p>Note: Do not include the .class extension while running the program with the java command.</p><p><strong>5) What Happens if We Save a Blank File as a .java File?</strong></p><p>- If you save a blank file with a .java extension and try to compile it using javac, the compiler will return an error:</p><pre>error: Class names, &#39;filename.java&#39;, are only accepted if annotation <br>processing is explicitly requested</pre><p>A .java file must contain at least one class or interface declaration. A blank file will not be considered a valid Java program by the compiler.</p><p><strong>6) Can We Perform Changes in Bytecode? What Are the Issues?</strong></p><p>Yes, you can make changes to bytecode manually, but it’s highly discouraged due to several issues:</p><p>- How Bytecode Can Be Modified:</p><p>- You can use bytecode editors or tools like javap (Java bytecode disassembler) to decompile and modify .class files.</p><p>- Libraries like ASM or Javassist allow programmatic manipulation of bytecode during runtime.</p><p><strong>- Issues with Modifying Bytecode:</strong></p><p>- Complexity: Bytecode is a low-level representation of Java code, and modifying it directly is error-prone and difficult to manage.</p><p>- ClassLoader Violations: Tampering with bytecode can lead to issues with the Java ClassLoader, especially if the changes break the internal structure or violate the Java specification.</p><p>- Security Risks: Bytecode manipulation opens up the program to security vulnerabilities, as malicious code could be injected.</p><p>- Loss of Original Source Mapping: Changes made directly to bytecode will not be reflected in the original Java source code, which can lead to confusion during debugging.</p><p>In general, bytecode manipulation should be reserved for advanced use cases like creating dynamic proxies or frameworks (e.g., AOP) and should be handled with great care.</p><h4>Java Character Set</h4><p><strong>What is a Character Set?</strong></p><p>A character set is a collection of characters that Java can recognize and work with. These characters are letters, numbers, symbols, and whitespace that are used in Java programs. Every character is internally stored using a numeric code in a character set, and Java supports Unicode, which makes it compatible with characters from different languages.</p><p><strong>Java’s Character Set</strong></p><p>Java uses Unicode as its character set. Unicode is a universal character encoding standard that assigns a unique number to every character, regardless of platform, language, or program. Java originally used 16-bit Unicode characters (UTF-16), allowing it to support many world languages.</p><p>Unicode can represent over 140,000 characters, including alphabets like Latin, Greek, Cyrillic, Han (Chinese characters), and more. Java specifically supports the UTF-16 encoding by default.</p><p><strong>Why Unicode?</strong></p><p>Java chose Unicode to make the language truly platform-independent and suitable for internationalization. As Java applications are used worldwide, Unicode provides a standardized way of encoding all the world’s characters.</p><h4>Data Types in Java</h4><p>A data type is a classification of data that informs the compiler or interpreter how the data will be used in a program. Each data type specifies a range of values it can store and the operations that can be performed on that data. Programming languages typically support various data types like integers, floating-point numbers, characters, strings, and booleans.</p><p><strong>Data Types in Java</strong></p><p>Data types in Java are divided into two main categories:</p><p>1. Primitive Data Types (Built-In Data Types)</p><p>2. User-Defined Data Types (Non-Primitive Data Types)</p><p><strong>Primitive Data Types (Built-In Data Types)</strong></p><p>Java supports eight primitive data types, which are the basic data types built into the language. These data types are predefined by Java and named by a keyword. They are used to store simple values directly.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/865/1*JSJwvu5cM1PVtiUWsggLwQ.png" /></figure><p><strong>Explanation of Code Example</strong></p><p>Here is a Java program demonstrating some primitive data types:</p><pre>package com.jtcindia.org;<br><br>/* Size of Data Type */<br><br>public class Jtc {<br>    public void dataType2() {<br>        System.out.println(&quot;---dataType2() in Jtc class---&quot;);<br>        byte b11 = 127;<br>        byte b22 = -128;<br>        // byte b33 = 128; // Error: 128 is out of range for byte<br>        // byte b44 = -129; // Error: -129 is out of range for byte<br>        int i11 = 2147483647;<br>        int i12 = -2147483648;<br>        // int i13 = 2147483648; // Error: 2147483648 is out of range for int<br>        // long l14 = 2147483649; // Error: 2147483649 is interpreted as int by default<br>        long l12 = 2147483648L; // Correct usage for long type<br>        // float f11 = 11.11; // Error: 11.11 is interpreted as double by default<br>        float f12 = 11.11f; // Correct usage for float type<br>        double d11 = 11.12;<br>        double d12 = 11.13d;<br>        <br>        System.out.println(b11);<br>        System.out.println(b22);<br>        System.out.println(i11);<br>        System.out.println(i12);<br>        System.out.println(l12);<br>        System.out.println(f12);<br>        System.out.println(d12);<br>    }<br><br>    public static void main(String[] args) {<br>        Jtc jtc = new Jtc();<br>        jtc.dataType2();<br>    }<br>}</pre><p>Explanation of the Errors in the Commented Code:</p><p>1. `byte b33 = 128;`</p><p>- Error: `128` is outside the range of the `byte` data type, which can only hold values from `-128` to `127`.</p><p>2. `byte b44 = -129;`</p><p>- Error: `-129` is also outside the range of the `byte` data type.</p><p>3. `int i13 = 2147483648;`</p><p>- Error: `2147483648` is out of range for the `int` type, which supports values from `-2147483648` to `2147483647`.</p><p>4. `long l14 = 2147483649;`</p><p>- Error: Although `2147483649` fits within the `long` range, it is treated as an `int` by default in Java. Adding an `L` at the end like `2147483648L` tells the compiler to treat it as a `long`.</p><p>5. `float f11 = 11.11;`</p><p>- Error: By default, decimal numbers in Java are treated as `double`. To store a value as a `float`, you must append `f` or `F` at the end, like `11.11f`.</p><p><strong>Range of Primitive Data Types</strong></p><p>The range of a data type defines the maximum and minimum values that the type can hold. Here is another example demonstrating the range of different data types in Java:</p><pre>package com.jtcindia.org;<br><br>/* Data Type Minimum and Maximum value */<br><br>public class Jtc {<br>    public void dataType3() {<br>        System.out.println(&quot;Byte Range: &quot; + Byte.MIN_VALUE + &quot; to &quot; + Byte.MAX_VALUE);<br>        System.out.println(&quot;Short Range: &quot; + Short.MIN_VALUE + &quot; to &quot; + Short.MAX_VALUE);<br>        System.out.println(&quot;int Range: &quot; + Integer.MIN_VALUE + &quot; to &quot; + Integer.MAX_VALUE);<br>        System.out.println(&quot;Long Range: &quot; + Long.MIN_VALUE + &quot; to &quot; + Long.MAX_VALUE);<br>        System.out.println(&quot;Float Range: &quot; + Float.MIN_VALUE + &quot; to &quot; + Float.MAX_VALUE);<br>        System.out.println(&quot;Double Range: &quot; + Double.MIN_VALUE + &quot; to &quot; + Double.MAX_VALUE);<br>    }<br><br>    public static void main(String[] args) {<br>        Jtc jtc = new Jtc();<br>        jtc.dataType3();<br>    }<br>}</pre><p><strong>User-Defined Data Types (Non-Primitive Data Types)</strong></p><p>User-defined data types in Java are created by the programmer to store multiple values, either of the same or different types. They include:</p><p>1. Classes: A class is a blueprint for creating objects with fields (variables) and methods (functions).</p><p>- Syntax:</p><pre>class ClassName {<br>    // fields<br>    // methods<br>}</pre><p>2. Interfaces: An interface is a fully abstract data type that defines a contract for classes. An interface can contain abstract methods and constants.</p><p>- Syntax:</p><pre>interface InterfaceName {<br>    // abstract methods<br>    // constants<br>}</pre><p>3. Enums: An enum is a special data type that represents a group of constants (unchangeable values).</p><p>- Syntax:</p><pre>enum EnumName {<br>    VALUE1, VALUE2, VALUE3<br>}</pre><p>Enum Example</p><pre>enum Day {<br>    SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY<br>}<br><br>public class Jtc {<br>    public static void main(String[] args) {<br>        Day today = Day.SUNDAY;<br>        System.out.println(today);<br>    }<br>}</pre><h4>Using print and println</h4><ul><li><strong>print()</strong>: Outputs text on the same line.</li><li><strong>println()</strong>: Outputs text and then moves to the next line.</li></ul><p>Example:</p><pre>System.out.print(&quot;Hello, &quot;);<br>System.out.println(&quot;World!&quot;);<br><br>// Output:<br>// Hello, World!</pre><h4>Commenting Code in Java</h4><p>Comments are notes ignored by the compiler, useful for explaining code.</p><ul><li><strong>Single-line comment</strong>: // This is a single-line comment</li><li><strong>Multi-line comment</strong></li></ul><pre>/*<br>This is a <br>multi-line comment<br>*/</pre><ul><li><strong>Documentation comment</strong> (used in JavaDoc):</li></ul><pre>/**<br> * This is a documentation comment<br> * which can be used for JavaDoc.<br> */</pre><h3>Interview Questions Related to Java Basics</h3><p><strong>Can we change the syntax of the </strong><strong>main method?</strong></p><ul><li>No, JVM recognizes public static void main(String[] args) as the entry point, so it must remain unchanged for Java applications to run.</li></ul><p><strong>Can we keep the </strong><strong>main method as private?</strong></p><p>No, because JVM needs to access the main method from outside the class. If it’s private, the program will compile but not execute, resulting in an error.</p><p><strong>Can we keep the </strong><strong>main method non-static?</strong></p><ul><li>No, main is static so JVM can call it without creating an object. If it’s non-static, JVM cannot call it directly, and the program will not execute.</li></ul><p><strong>Why do we need </strong><strong>f for float literals?</strong></p><ul><li>By default, decimal numbers are considered double. Adding f tells Java to treat the number as a float.</li></ul><h4>Keywords in Java</h4><p>Keywords are predefined, reserved words in Java that have special meanings. You cannot use keywords as identifiers (like variable names, class names, etc.). Here are a few important ones:</p><p>- Control flow: if, else, switch, for, while, do, break, continue, return</p><p>- Modifiers: public, private, protected, static, final, abstract</p><p>- Object-oriented keywords: class, interface, extends, implements, this, super</p><p>- Exception handling: try, catch, finally, throw, throws</p><p>- Others: void, null, true, false</p><p>Java has a total of 50+ keywords, and each serves a specific role in program flow, object creation, and behavior definition.</p><h4>Identifiers in Java</h4><p>In Java, identifiers are names given to various elements in a program, such as classes, methods, variables, and packages. Identifiers are essential as they help distinguish different parts of a program and make code more readable. They are defined by the programmer and must follow specific rules and conventions.</p><p>Examples of Identifiers</p><p>- Class name: `MyClass`</p><p>- Variable name: `totalSum`</p><p>- Method name: `calculateInterest`</p><p>- Package name: `com.example.application`</p><p><strong>Rules and Conventions for Identifiers</strong></p><p>Rules (mandatory):</p><p>1. Character Set: Identifiers can include letters (A-Z, a-z), digits (0–9), dollar signs (`$`), and underscores (`_`).</p><p>- Example: `myValue`, `total_sum`, `$price`</p><p>2. No Spaces: Spaces are not allowed within identifiers.</p><p>- Invalid Example: `my Value`, `public static void display details`</p><p>- Valid Example: `myValue`, `displayDetails`</p><p>3. Cannot Start with Digits: Identifiers cannot begin with a number.</p><p>- Invalid Example: `1stVariable`, `10a`</p><p>- Valid Example: `variable1`, `a10`</p><p>4. Cannot Use Keywords: Keywords in Java, such as `int`, `class`, `static`, etc., cannot be used as identifiers.</p><p>- Invalid Example: `class className {}`, `int static;`</p><p>- Valid Example: `className`, `isStatic`</p><p><strong>Conventions (recommended but not enforced):</strong></p><p>1. Class Names: Begin with an uppercase letter. If the name contains multiple words, capitalize the first letter of each word (Pascal case).</p><p>- Example: `MyFirstProgram`, `CustomerOrder`</p><p>2. Variable and Method Names: Begin with a lowercase letter. If the name contains multiple words, capitalize the first letter of each subsequent word (camel case).</p><p>- Example: `totalAmount`, `calculateInterest`</p><p>3. Package Names: Use lowercase letters. If multiple words are used, separate them by dots.</p><p>- Example: `com.mycompany.application`</p><p>4. Constants: Use uppercase letters with words separated by underscores for constant values.</p><p>- Example: `MAX_HEIGHT`, `MIN_AGE`</p><p><strong>Important Notes</strong></p><p>1. Default Access Modifier: Java does not have a keyword `default` as an access modifier, but it exists as a meaning. For example:</p><p>2. Non-Static Members: The term “non-static” isn’t a keyword in Java, but any member that is not defined with the `static` keyword is implicitly non-static. For example:</p><p>3. Java Keywords: All Java keywords are lowercase, so any identifier starting with uppercase letters will not conflict with keywords.</p><p><strong>Rules for Multi-Word Identifiers</strong></p><p>1. No Spaces in Identifiers: If the identifier contains multiple words, use conventions like Pascal case for classes and camel case for variables and methods.</p><p>- Invalid Example: `class My program {}`</p><p>- Valid Example: `class MyProgram {}`</p><p>2. Method and Variable Naming Conventions: When using multiple words in method or variable names, capitalize the first letter of each subsequent word (camel case).</p><p>- Example: `int myTotalMarks;`</p><p>- Method Example: `public void calculateInterest() {}`</p><p><strong>Declaring Variables</strong></p><p>Variables in Java can be declared with the following syntax:</p><pre>&lt;data_type&gt; &lt;variable_name&gt;;</pre><p>For example:</p><pre>int number;<br>String name;</pre><p><strong>Final Keyword</strong></p><p>The `final` keyword in Java is used to create constants. When a variable is declared as `final`, its value cannot be changed once it is initialized. Attempting to modify a `final` variable will result in a compilation error.</p><p>Example of a final variable:</p><pre>class Jtc {<br>    public static void main(String[] args) {<br>        final int a = 10;<br>        System.out.println(a);<br>        // a = 4000; // Error: cannot assign a value to a final variable<br>        // a = -56;  // Error: cannot assign a value to a final variable<br>    }<br>}</pre><p>Explanation:</p><p>- The variable `a` is declared as `final` and initialized with a value of `10`.</p><p>- Once `a` is declared as `final`, any attempt to modify its value (e.g., `a = 4000` or `a = -56`) will result in a compilation error.</p><p><strong>Types of Variables in Java</strong></p><p>Variables in Java can be classified into the following types:</p><p>1. Class Level Variables</p><p>2. Local Variables</p><p><strong>Class Level Variables</strong></p><p>- Class level variables are declared directly within a class but outside of any method, constructor, or block.</p><p>- They can be accessed from any method or block within the class.</p><p>- Memory for class-level variables is allocated in the heap.</p><p>- If not initialized, they are assigned default values by the Java Virtual Machine (JVM).</p><p><strong>Class level variables are further divided into:</strong></p><p>1. Instance Variables: Variables that are specific to each object of a class.</p><p>2. Static Variables: Variables that are shared among all objects of a class.</p><p>Example of Class Level Variables:</p><pre>public class JtcClassLevelVariableExample {<br>    public static void main(String[] args) {<br>        Variable vl = new Variable();<br>        vl.variable_m2();<br>    }<br>}<br><br>class Variable {<br>    // Class level variables<br>    byte b;<br>    short s;<br>    int i;<br>    long l;<br>    float f;<br>    double d;<br>    boolean bl;<br>    char c;<br><br>    void variable_m2() {<br>        System.out.println(&quot;byte : &quot; + b);<br>        System.out.println(&quot;short : &quot; + s);<br>        System.out.println(&quot;int : &quot; + i);<br>        System.out.println(&quot;long : &quot; + l);<br>        System.out.println(&quot;float : &quot; + f);<br>        System.out.println(&quot;double : &quot; + d);<br>        System.out.println(&quot;boolean : &quot; + bl);<br>        System.out.println(&quot;char : &quot; + c);<br>    }<br>}</pre><p>Output:</p><pre>byte : 0<br>short : 0<br>int : 0<br>long : 0<br>float : 0.0<br>double : 0.0<br>boolean : false<br>char :</pre><p><strong>Explanation:</strong></p><p>- The variables are not explicitly initialized, so the JVM assigns them default values.</p><p>- The default values depend on the data type (e.g., `0` for integers, `false` for boolean, etc.).</p><p>Let’s break down the conclusion points regarding static and non-static members in Java, explaining each point in detail.</p><p><strong>Conclusion</strong></p><p><strong>1. Static Variables Can Be Accessed Directly in Static Methods</strong></p><p>- Static variables belong to the class rather than any specific instance. Therefore, they can be accessed directly within static methods, as both are associated with the class.</p><p><strong>2. Static Variables Can Be Accessed Directly in Non-Static Methods</strong></p><p>- Non-static methods are associated with instances of the class but still have access to static variables. They can directly access static variables without needing to create an instance.</p><p><strong>3. Non-Static Variables Cannot Be Accessed Directly in Static Methods</strong></p><p>- Non-static variables belong to specific instances of a class. Static methods do not have an instance context, so they cannot access non-static variables directly.</p><p><strong>4. Non-Static Variables Can Be Accessed Directly in Non-Static Methods</strong></p><p>- Non-static methods have access to both static and non-static variables. They can access non-static variables directly because they operate within the context of an instance.</p><p><strong>5. Static Methods Can Be Called Directly from Static Methods</strong></p><p>- Since both methods are associated with the class itself, a static method can directly call another static method without creating an instance.</p><p><strong>6. Static Methods Can Be Called Directly from Non-Static Methods</strong></p><p>- Non-static methods can call static methods directly because they have access to the class context, which includes static methods.</p><p><strong>7. Non-Static Methods Cannot Be Called Directly from Static Methods</strong></p><p>- Static methods do not have access to instance-specific data, so they cannot call non-static methods directly without an instance of the class.</p><p><strong>8. Non-Static Methods Can Be Called Directly from Non-Static Methods</strong></p><p>- Non-static methods can freely call each other because they operate within the context of the same instance of the class.</p><p><strong>Local Variables</strong></p><p>- Local variables are declared within a method, constructor, or block.</p><p>They must be initialized before use, as they do not have default values.</p><p><strong>Is Intialisation of local variable is mandatory ??</strong><br>Yes,it is mandatory to intialise local variables, if we did not intialise we will get compile time error saying that“Variable might not intialised”.</p><p>- Memory for local variables is allocated only when the method or block is executed and is released when it ends.</p><p>-Local variables can only be default or final i.e we cannot declare a local variable as private,public or protected</p><p>Example of Local Variables:</p><pre>package com.jtcindia.org;<br><br>class LocalVariable {<br>    int a = 10; // Class level variable<br><br>    void localVariable_m1() {<br>        int b = 20; // Local variable<br>        System.out.println(&quot;--localVariable_m1() in LocalVariable class--&quot;);<br>        System.out.println(b);<br>    }<br><br>    void localVariable_m2() {<br>        int c = 30; // Local variable<br>        System.out.println(&quot;--localVariable_m2() in LocalVariable class--&quot;);<br>        System.out.println(c);<br>    }<br><br>    void localVariable_m3() {<br>        int d = 40; // Local variable<br>        System.out.println(&quot;--localVariable_m3() in LocalVariable class--&quot;);<br>        System.out.println(d);<br>    }<br>}<br><br>public class Jtc {<br>    public static void main(String[] args) {<br>        System.out.println(new LocalVariable().a);<br>        new LocalVariable().localVariable_m1();<br>        new LocalVariable().localVariable_m2();<br>        new LocalVariable().localVariable_m3();<br>    }<br>}</pre><p>Output:</p><pre>10<br> - localVariable_m1() in LocalVariable class - <br>20<br> - localVariable_m2() in LocalVariable class - <br>30<br> - localVariable_m3() in LocalVariable class - <br>40</pre><p>Explanation:</p><p>- The variable `a` is a class level variable, while `b`, `c`, and `d` are local variables declared within different methods.</p><p>- Local variables must be explicitly initialized before they are used.</p><p><strong>Key Differences Between Class Level and Local Variables:</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/844/1*bfEyAkWGJqbyf_XYnLAfyQ.png" /></figure><p><strong>Q. What if local variable and global variable names are same?</strong><br>A. If local var and global var names are same first priority is always given to local variables because they are inside method and nearer for execution to JVM.</p><p>Conclusion</p><p>- Class Level Variables are used when you need to store data that can be accessed across multiple methods.</p><p>- Local Variables are used for temporary storage of data within a specific method or block.</p><p>- Using the `final` keyword makes a variable a constant that cannot be changed after its initial assignment.</p><h4>Constants in Java</h4><p>Constants are fixed values that cannot be changed once assigned. Java supports constants using the final keyword. A final variable cannot be re-assigned a new value after initialization.</p><p>Example:</p><pre>final int MAX_VALUE = 100;</pre><p>Once you declare MAX_VALUE as final, it cannot be modified.</p><h4>Final Variables in Java</h4><p>A final variable is a constant, and its value can’t be changed once it’s initialized.</p><p><strong>Can we change the value of a final variable?</strong></p><p>No, you cannot change the value of a final variable once it’s initialized. If you try to, the compiler will throw an error.</p><p><strong>Is it necessary to initialize the value of a final variable at the time of declaration?</strong></p><p>No, it’s not necessary to initialize a final variable at the time of declaration. However, it must be initialized before the constructor finishes execution, ensuring that the final variable gets a value before the object is fully constructed.</p><p>This covers the basics of Java character set, data types, keywords, identifiers, variables, constants, and final variables. Let me know if you need more detail on any section!</p><h3>Java Literals</h3><p>Literals in Java are values that can be directly assigned to variables. These values can be used in the program as per the requirement. They come in different types, and each type has its own rules for representation.</p><p>Types of Literals:</p><p>1. Integral Literals</p><p>2. Floating-Point Literals</p><p>3. Boolean Literals</p><p>4. Character Literals</p><p>5. Null Literals</p><p>6. String Literals</p><p><strong>1. Integral Literals</strong></p><p>Integral literals are exact numeric values without a decimal point. They can be positive or negative, such as `234`, `-56`, `+45`. Integral literals are represented using different number systems:</p><p>- Decimal literals: A standard number system (0–9). It should not start with `0`.</p><p>- Octal literals: Values represented in base 8 (digits 0–7) and must start with `0`.</p><p>- Hexadecimal literals: Represented in base 16 (0–9 and a-f/A-F). It must start with `0x` or `0X`.</p><p>- Binary literals: Introduced in JDK 1.7, uses base 2 (0 and 1) and must start with `0b` or `0B`.</p><p>Example:</p><pre>public class IntegralLiterals {<br>    public static void main(String[] args) {<br>        int decimal = 12345; // Valid decimal literal<br>        int octal = 012345; // Valid octal literal, starts with 0<br>        // int invalidOctal = 018; // Not valid, 8 is not an octal digit<br>        int hex = 0xABC; // Valid hexadecimal literal, starts with 0x<br>        // int invalidHex = 123AF; // Not valid, missing 0x prefix for hexadecimal<br>        int binary = 0b10101; // Valid binary literal, starts with 0b<br>        // int invalidBinary = 2b10101; // Not valid, must start with 0b<br><br>        System.out.println(&quot;Decimal: &quot; + decimal);<br>        System.out.println(&quot;Octal: &quot; + octal);<br>        System.out.println(&quot;Hexadecimal: &quot; + hex);<br>        System.out.println(&quot;Binary: &quot; + binary);<br>    }<br>}</pre><p><strong>2. Floating-Point Literals</strong></p><p>Floating-point literals represent values with a decimal point. They can be specified using `float` or `double` data types:</p><p>- A float literal should end with `F` or `f`.</p><p>- A double literal can optionally end with `D` or `d`, but it is the default for decimal values.</p><p>- Scientific notation is also supported using `E` or `e`.</p><p>Example:</p><pre>public class FloatingPointLiterals {<br>    public static void main(String[] args) {<br>        double d1 = 12.34; // Valid double literal<br>        float f1 = 12.34f; // Valid float literal with suffix &#39;f&#39;<br>        // float invalidFloat = 12.34; // Not valid, float requires &#39;f&#39; suffix<br>        double scientificNotation = 1.23e2; // Valid scientific notation<br><br>        System.out.println(&quot;Double d1: &quot; + d1);<br>        System.out.println(&quot;Float f1: &quot; + f1);<br>        System.out.println(&quot;Scientific Notation: &quot; + scientificNotation);<br>    }<br>}</pre><p><strong>3. Boolean Literals</strong></p><p>Boolean literals have only two values: `true` or `false`. In Java, you cannot represent `true` by `1` and `false` by `0`.</p><p>Example:</p><pre>public class BooleanLiterals {<br>    public static void main(String[] args) {<br>        boolean isJavaFun = true; // Valid boolean literal<br>        boolean isFishTasty = false; // Valid boolean literal<br>        // boolean invalidBoolean = 1; // Not valid, Java does not accept 1 as true<br>        // boolean anotherInvalidBoolean = 0; // Not valid, Java does not accept 0 as false<br><br>        System.out.println(&quot;Is Java fun? &quot; + isJavaFun);<br>        System.out.println(&quot;Is fish tasty? &quot; + isFishTasty);<br>    }<br>}</pre><p><strong>4. Character Literals</strong></p><p>Character literals are enclosed in single quotes, like ’A’. Rules for character literals include:</p><p>- They cannot be empty.</p><p>- They must contain only one character.</p><p>- Special characters can be represented using escape sequences like `\n`, `\t`, etc.</p><pre>public class CharacterLiterals {<br>    public static void main(String[] args) {<br>        char ch1 = &#39;A&#39;; // Valid character literal<br>        char ch2 = &#39; &#39;; // Valid character literal with space<br>        char ch3 = &#39;\n&#39;; // Valid escape sequence for new line<br>        // char invalidChar1 = &#39;&#39;; // Not valid, empty character literal<br>        // char invalidChar2 = &#39;AB&#39;; // Not valid, multiple characters in single quotes<br><br>        System.out.println(&quot;Character ch1: &quot; + ch1);<br>        System.out.println(&quot;Character ch2 (space): [&quot; + ch2 + &quot;]&quot;);<br>        System.out.println(&quot;Character ch3 (newline): [&quot; + ch3 + &quot;]&quot;);<br>    }<br>}</pre><p>- Escape sequences: Character literals can include escape sequences like \n (new line), \t (tab), \’ (single quote), \” (double quote), \\ (backslash), etc.</p><pre>char newLine = &#39;\n&#39;;<br>char singleQuote = &#39;\&#39;&#39;;</pre><p>- Unicode characters: You can also use Unicode values for characters by using the \u prefix followed by the 4-digit hexadecimal value.</p><pre>char unicodeChar = &#39;\u0041&#39;; // Unicode representation of &#39;A&#39;</pre><p><strong>5. Null Literals</strong></p><p>Null literals represent the absence of a value for reference types. They are used to signify that a variable does not reference any object.</p><pre>public class NullLiterals {<br>    String str;<br>    NullLiterals nl;<br>    System s1;<br><br>    public static void main(String[] args) {<br>        NullLiterals obj = new NullLiterals();<br>        System.out.println(&quot;str: &quot; + obj.str); // Prints null<br>        System.out.println(&quot;nl: &quot; + obj.nl); // Prints null<br>        System.out.println(&quot;s1: &quot; + obj.s1); // Prints null<br>    }<br>}</pre><p><strong>6. String Literals</strong></p><p>String literals are enclosed in double quotes, like `”Hello”`. Strings are not primitive data types but are treated as objects of the `String` class.</p><p>Examples</p><pre>public class StringLiterals {<br>    public static void main(String[] args) {<br>        String s1 = &quot;Hello, World!&quot;; // Valid string literal<br>        String s2 = &quot;&quot;; // Valid empty string<br>        String s3 = &quot;Hello \n Java&quot;; // Valid string with escape sequence<br>        String s4 = &quot;C:\\Program Files\\Java&quot;; // Valid string with escaped backslashes<br>        // String invalidString = &quot;Hello&quot;; // Incorrect escape sequence<br><br>        System.out.println(&quot;String s1: &quot; + s1);<br>        System.out.println(&quot;String s2 (empty): [&quot; + s2 + &quot;]&quot;);<br>        System.out.println(&quot;String s3 (with newline): &quot; + s3);<br>        System.out.println(&quot;String s4 (with path): &quot; + s4);<br>    }<br>}</pre><h3>Explanation:</h3><ul><li><strong>String invalidString = &quot;Hello\&quot;;</strong>: This is incorrect due to improper use of escape sequences. In Java, double quotes inside strings must be escaped using \&quot;.</li><li><strong>String invalidString = &quot;Hello\&quot;;</strong>: This is incorrect due to improper use of escape sequences. In Java, double quotes inside strings must be escaped using \&quot;.</li></ul><p>- Underscore in numeric literals: Since Java 7, you can use underscores to improve the readability of large numbers.It should be not be used before or just after decimal.</p><pre>int largeNumber = 1_000_000; // Same as 1000000</pre><p>Detailed Examples of Java Literals</p><pre>public class LiteralExample {<br>    public static void main(String[] args) {<br>        // Integer Literals<br>        int decimal = 100;         // Decimal literal<br>        int octal = 0144;          // Octal literal<br>        int hex = 0x64;            // Hexadecimal literal<br>        int binary = 0b1100100;    // Binary literal<br>        // Floating-point Literals<br>        double pi = 3.14159;       // Double literal (default)<br>        float gravity = 9.81f;     // Float literal<br>        <br>        // Character Literals<br>        char letter = &#39;A&#39;;         // Character literal<br>        char newLine = &#39;\n&#39;;       // Escape sequence<br>        char unicodeChar = &#39;\u0041&#39;; // Unicode literal<br>        <br>        // String Literals<br>        String message = &quot;Hello, World!&quot;;  // String literal<br>        String empty = &quot;&quot;;                // Empty string<br>        <br>        // Boolean Literals<br>        boolean isJavaFun = true;  // Boolean literal (true)<br>        boolean isTired = false;   // Boolean literal (false)<br>        <br>        // Null Literal<br>        String nullString = null;  // Null literal<br>        <br>        // Printing literals<br>        System.out.println(&quot;Decimal Literal: &quot; + decimal);<br>        System.out.println(&quot;Octal Literal: &quot; + octal);<br>        System.out.println(&quot;Hexadecimal Literal: &quot; + hex);<br>        System.out.println(&quot;Binary Literal: &quot; + binary);<br>        <br>        System.out.println(&quot;Double Literal: &quot; + pi);<br>        System.out.println(&quot;Float Literal: &quot; + gravity);<br>        <br>        System.out.println(&quot;Character Literal: &quot; + letter);<br>        System.out.println(&quot;New Line: &quot; + newLine);<br>        System.out.println(&quot;Unicode Literal: &quot; + unicodeChar);<br>        <br>        System.out.println(&quot;String Literal: &quot; + message);<br>        System.out.println(&quot;Empty String Literal: &quot; + empty);<br>        <br>        System.out.println(&quot;Boolean Literal (true): &quot; + isJavaFun);<br>        System.out.println(&quot;Boolean Literal (false): &quot; + isTired);<br>        <br>        System.out.println(&quot;Null Literal: &quot; + nullString);<br>    }<br>}</pre><p>Output:</p><pre>Decimal Literal: 100<br>Octal Literal: 100<br>Hexadecimal Literal: 100<br>Binary Literal: 100<br>Double Literal: 3.14159<br>Float Literal: 9.81<br>Character Literal: A<br>New Line:<br>Unicode Literal: A<br>String Literal: Hello, World!<br>Empty String Literal:<br>Boolean Literal (true): true<br>Boolean Literal (false): false<br>Null Literal: null</pre><p>- Integer Literals: Represent whole numbers and can be in decimal, octal, hexadecimal, or binary format.</p><p>- Floating-point Literals: Represent numbers with fractional parts, default to double, and use the f suffix for float.</p><p>- Character Literals: Represent single characters and can include escape sequences and Unicode characters.</p><p>- String Literals: Represent sequences of characters, enclosed in double quotes.</p><p>- Boolean Literals: Represent logical values (true or false).</p><p>- Null Literal: Represents a null reference or no object.</p><p>Each type of literal has its purpose and allows you to express values clearly in Java code.</p><p><strong>Key Points:</strong></p><p>- No Empty Character Literal: You cannot create an empty character literal. For instance, char c = ‘’ will cause a compile-time error.</p><p>// This will give a compile-time error</p><p>char emptyChar = ‘’; // Error: unexpected type</p><p>- Valid Examples:</p><p>char letter = ‘a’;</p><p>char digit = ‘1’;</p><p>char symbol = ‘$’;</p><p><strong>2. String Literals</strong></p><p>Key Points:</p><p>- Strings are Objects: Unlike character literals, string literals are objects of the String class, which is part of the java.lang package.</p><p>String greeting = “Hello, World!”;</p><p>- Output: When printed, the string literal displays the text on the console.</p><p>System.out.println(greeting); // Output: Hello, World!</p><p>- Escape Sequences: Certain characters in strings need to be escaped, such as newlines (\n), tabs (\t), or quotes (\”).</p><p>String withEscape = “Line1\nLine2”; // \n creates a new line</p><p>System.out.println(withEscape);</p><p><strong>3. Handling Null and Reference Variables</strong></p><p>- Character Reference Variable: If you declare a character reference variable, you can assign it null, which indicates it doesn’t point to any character.</p><p>Character ch6 = null; // Valid: ch6 is a reference variable</p><p>- Null Assignment: Unlike primitive types, you can assign null to an object reference, which means it currently does not reference any object.</p><p><strong>4. Compiler Behavior and Comments</strong></p><p>- Comments: Lines that are commented out (using // or / /) are ignored by the compiler in terms of execution, but the compiler does not validate the syntax of these comments.</p><p>// This line is a comment and will not affect compilation</p><p>// char invalidChar = ‘’; // Error: unexpected type</p><p>Summary</p><p>- Character Literals: Use single quotes for single characters. No empty literals allowed.</p><p>- String Literals: Use double quotes. Strings are objects of the String class.</p><p>- Escape Sequences: Use backslashes to represent special characters.</p><p>- Reference Variables: You can assign null to reference variables, which is different from primitive types.</p><h4>Operators in Java</h4><p>Operators are symbols used to perform operations on variables and values. Operators act on operands (the values they manipulate) and return a result. There are several types of operators in Java, each serving different purposes.</p><p><strong>1. Arithmetic Operators</strong></p><p>Arithmetic operators perform basic mathematical operations such as addition, subtraction, multiplication, division, and modulus.</p><p>Common Arithmetic Operators:</p><p>- + : Addition</p><p>- — : Subtraction</p><p>- : Multiplication</p><p>- / : Division</p><p>- % : Modulus (returns remainder of division)</p><p>Example:</p><pre>public class ArithmeticOperator {<br>    public static void main(String[] args) {<br>        int a = 100;<br>        byte b = 20;<br>        <br>        System.out.println(a + b);  // 120<br>        System.out.println(a - b);  // 80<br>        System.out.println(a * b);  // 2000<br>        System.out.println(a / b);  // 5<br>        System.out.println(a % b);  // 0<br>    }<br>}</pre><p>In the above code, basic arithmetic operations are performed on two variables a and b.</p><p><strong>Arithmetic with Boolean:</strong></p><p>Arithmetic operations cannot be performed on non-numeric types like boolean. Attempting to do so will result in a compilation error.</p><pre>public class ArithmeticOperator {<br>    public static void main(String[] args) {<br>        int a = 100;<br>        boolean b = true;<br>        System.out.println(a + b);  // Error: incompatible types<br>    }<br>}</pre><p>Note:-</p><p>-The issue with performing byte b11 = b1 + b2 in Java (or similar languages) arises from the fact that the result of the addition of two byte values is promoted to an int. This means that the sum of b1 and b2 can exceed the range of a byte, which is from -128 to 127.</p><p>Here’s what happens in detail:</p><p>1. Promotion to int: When you add two byte values, Java first converts them to int. This is part of Java’s rules for arithmetic operations involving smaller data types.</p><p>2. Potential overflow: Since the result is an int, it can exceed the range of a byte. If the sum is greater than 127 or less than -128, you can’t directly assign that int value back to a byte without an explicit cast, which can lead to loss of data.</p><p>To correctly perform this operation while ensuring that it fits within the byte range, you should do the following:</p><pre>byte b11 = (byte) (b1 + b2);</pre><p>This way, you’re explicitly casting the result back to a byte, but be aware that if the sum exceeds the byte range, it will wrap around due to overflow.</p><p>-When you add two char values in Java, they are treated similarly to byte values in that they undergo numeric promotion. Here’s what happens:</p><p>1. Promotion to int: When you add two char values, they are first promoted to int. This means the addition is performed using their integer values (which correspond to their Unicode code points).</p><p>2. Result type: The result of the addition will be of type int. This can exceed the range of char, which is from 0 to 65535 (since char in Java is unsigned).</p><p>3. No implicit casting: You cannot directly assign the result of the addition back to a char without an explicit cast. If you try to do something like:</p><pre>char c1 = &#39;A&#39;; // Unicode 65<br>char c2 = &#39;B&#39;; // Unicode 66<br>char c3 = c1 + c2; // This will cause a compilation error</pre><p>This will result in a compilation error because you’re trying to assign an int to a char.</p><p>4. Correct way: If you want to store the result in a char, you should explicitly cast it:</p><pre>char c3 = (char) (c1 + c2); // c3 will be assigned the value of 131 (which corresponds to &#39;&#39;)</pre><p>5. Handling overflow: Be mindful that if the sum exceeds 65535, the resulting value will wrap around due to overflow, which may lead to unexpected characters.</p><p>In summary, adding two char values results in an int, and you need to handle the conversion back to char explicitly, being cautious of the range and potential overflow.</p><h4>Operator Overloading in Java</h4><p>Definition: Operator overloading is a feature that allows operators to have different meanings based on the context in which they are used. In many programming languages, this means that the same operator can perform different operations depending on the types of its operands.</p><h4>Java’s Approach</h4><p>Java does not support operator overloading in the way that some other languages (like C++ or Python) do. This design decision was made to keep the language simple and avoid ambiguity. However, the `+` operator is an exception, as it can serve two different roles: addition and concatenation.</p><p><strong>1. Addition with the `+` Operator</strong></p><p>When used with numeric types, the `+` operator performs addition. This applies to various numeric data types:</p><p>- Integers:</p><p>- Example:</p><pre>int result = 122 + 233; // result = 355</pre><p>- Floating Point Numbers:</p><p>- Example:</p><pre>double result = 445.33 + 556; // result = 1001.33</pre><p>- Mixed Types:</p><p>- Java automatically converts types to perform the operation:</p><pre>float result = 667 + 45.3f; // result = 712.3</pre><p><strong>Numeric Type Conversions</strong></p><p>Java supports arithmetic operations between different numeric types, like `int`, `float`, `double`, etc. The following rules apply:</p><p>- When two different numeric types are used, Java converts them to the larger type before performing the operation (e.g., `int` to `double`).</p><p>2. Character Addition</p><p>Java treats characters as numeric values based on their Unicode representations.</p><p>- Character Arithmetic:</p><p>- Characters can be added together:</p><pre>char ch = &#39;A&#39;; // Unicode 65<br>int sum = ch + 65; // 65 + 65 = 130 widen to int<br>System.out.println(sum); // Prints 130<br>char ch1 = &#39;a&#39;; // Unicode 97<br>char ch2 = &#39;z&#39;; // Unicode 122<br>int combined = ch1 + ch2; // 97 + 122 = 219<br>System.out.println(combined); // Prints 219</pre><p>- Casting Character to Char:</p><p>- If you assign a numeric value to a `char`, it will represent the corresponding character:</p><pre>char ch = 65; // &#39;A&#39;<br>System.out.println(ch); // Prints &#39;A&#39;</pre><p>3. Concatenation with the `+` Operator</p><p>When one of the operands is a `String`, the `+` operator behaves as a concatenation operator. This means it combines strings instead of performing arithmetic addition.</p><p>- String Concatenation:</p><p>- Example:</p><pre>String s = &quot;java&quot;;<br>int a = 123;<br>System.out.println(s + a); // &quot;java123&quot;</pre><p>- Multiple Strings:</p><p>- Concatenation can be chained:</p><pre>System.out.println(&quot;I am &quot; + s + &quot; developer&quot;); // &quot;I am java developer&quot;</pre><p>- Result Type:</p><p>- After concatenation, the result is always a `String`, even if the other operand is a number:</p><pre>System.out.println(123 + &quot; &quot;); // &quot;123 &quot;</pre><p><strong>Type Casting in Java</strong></p><p>Type casting in Java is the process of converting a variable from one data type to another. Java supports two types of casting:</p><p><strong>1. Widening Casting (Automatic):</strong> Converting a smaller data type to a larger data type (e.g., byte to int). This is done automatically by Java without any explicit cast.</p><p><strong>2. Narrowing Casting (Explicit): </strong>Converting a larger data type to a smaller data type (e.g., int to byte). This requires an explicit cast because it can lead to data loss.</p><p>Example: byte b1 = 10;</p><p>Here, you are declaring a byte variable b1 and initializing it with the value 10. The byte data type can hold values from -128 to 127.</p><p>Case: b1 += 10;</p><p>Now, when you perform the operation b1 += 10, here’s what happens:</p><p>1. Promotion: The += operator is a compound assignment operator. When you use b1 += 10, Java first promotes b1 to an int to perform the addition. This is because the right-hand side (10 in this case) is treated as an int.</p><p>2. Result Calculation: The addition is performed: 10 + 10, which equals 20.</p><p>3. Assignment: The result of the addition (20, which is an int) is then assigned back to b1. However, since b1 is a byte, Java automatically casts the int result back to byte.</p><p>4. No Explicit Cast Needed: In this case, no explicit cast is necessary because the result (20) is within the range of byte (-128 to 127).</p><p>Conclusion</p><p>- The operation b1 += 10 is valid and results in b1 holding the value 20.</p><p>- If you were to use a regular addition, like b1 = b1 + 10;, this would require an explicit cast back to byte because the expression b1 + 10 results in an int. Thus, it would look like this:</p><pre>b1 = (byte) (b1 + 10);</pre><p>In summary, b1 += 10 is a shorthand that handles type promotion and casting automatically, making it convenient for operations like this.</p><p>2. Assignment Operator (=)</p><p>The assignment operator assigns the value on the right-hand side (source) to the left-hand side (destination). The general syntax is:</p><pre>destination = source;</pre><p>Example:</p><pre>public class AssignmentOperator {<br>    public static void main(String[] args) {<br>        int a = 10;<br>        int b = a;  // Assign value of &#39;a&#39; to &#39;b&#39;<br>        System.out.println(b);  // 10<br>    }<br>}</pre><p><strong>Type Casting</strong></p><p>Type casting is the process of converting one data type into another. It can be:</p><p>- <strong>Implicit Type Casting</strong>: Happens automatically when assigning a smaller type to a larger type.</p><p>- <strong>Explicit Type Casting</strong>: Must be specified by the programmer when assigning a larger type to a smaller type.</p><p>Implicit Casting Example:</p><pre>public class AssignmentOperator {<br>    public static void main(String[] args) {<br>        byte b1 = 10;<br>        short s1 = b1;  // Implicit casting: byte to short<br>        System.out.println(s1);  // 10<br>    }<br>}</pre><p>Explicit Casting Example:</p><pre>public class AssignmentOperator {<br>    public static void main(String[] args) {<br>        short s2 = 260;<br>        byte b2 = (byte) s2;  // Explicit casting: short to byte<br>        System.out.println(b2);  // Output may show data loss (result: 4)<br>    }<br>}</pre><p>Since byte can only hold values from -128 to 127, converting 260 causes data loss.</p><p><strong>3. Relational Operators</strong></p><p>Relational operators are used to compare two values. They return a boolean value (true or false).</p><p>Relational Operators:</p><p>- &gt; : Greater than</p><p>- &lt; : Less than</p><p>- &gt;= : Greater than or equal to</p><p>- &lt;= : Less than or equal to</p><p>- == : Equal to</p><p>- != : Not equal to</p><p>Example:</p><pre>public class RelationalOperator {<br>    public static void main(String[] args) {<br>        int a = 20;<br>        int b = 10;<br>        <br>        System.out.println(a &gt; b);  // true<br>        System.out.println(a &lt; b);  // false<br>        System.out.println(a == b);  // false<br>    }<br>}</pre><p><strong>Relational Operators with Boolean:</strong></p><p>Relational operators cannot be used with boolean values.</p><pre>public class RelationalOperator {<br>    public static void main(String[] args) {<br>        boolean a = true;<br>        boolean b = false;<br>        <br>        System.out.println(a &gt; b);  // Error: cannot compare booleans<br>    }<br>}</pre><p><strong>4. Logical Operators</strong></p><p>Logical operators are used to perform logical operations on boolean expressions. They are:</p><p>- &amp;&amp; : Logical AND</p><p>- || : Logical OR</p><p>- ! : Logical NOT</p><p>Example:</p><pre>public class LogicalOperators {<br>    public static void main(String[] args) {<br>        boolean x = true;<br>        boolean y = false;<br>        System.out.println(x &amp;&amp; y);  // false<br>        System.out.println(x || y);  // true<br>        System.out.println(!x);  // false<br>    }<br>}</pre><p>Logical operators can be used to combine multiple conditions.</p><p><strong>5. Bitwise Operators</strong></p><p>Bitwise operators work on binary representations of integers. They perform bit-level operations.</p><p>Common Bitwise Operators:</p><p>- &amp; : Bitwise AND</p><p>- | : Bitwise OR</p><p>- ^ : Bitwise XOR</p><p>- &lt;&lt; : Left shift</p><p>- &gt;&gt; : Right shift</p><p>- ~ : Bitwise NOT</p><p>Example:</p><pre>public class BitwiseOperator {<br>    public static void main(String[] args) {<br>        int number1 = 5;  // 00000101 in binary<br>        int number2 = 7;  // 00000111 in binary<br>        System.out.println(number1 &amp; number2);  // Bitwise AND: 00000101 -&gt; 5<br>        System.out.println(number1 | number2);  // Bitwise OR: 00000111 -&gt; 7<br>        System.out.println(number1 ^ number2);  // Bitwise XOR: 00000010 -&gt; 2<br>    }<br>}</pre><p>The XOR (exclusive OR) operation is a fundamental binary operation that compares two bits and produces a result based on their values. Here’s how it works:</p><p>- Input: Two bits (0 or 1).</p><p>- Output: The result is 1 if the bits are different, and 0 if they are the same.</p><p>Truth Table for XOR</p><p>Explanation</p><p>- If both bits are 0 (0 XOR 0), the result is 0.</p><p>- If one bit is 0 and the other is 1 (0 XOR 1 or 1 XOR 0), the result is 1.</p><p>- If both bits are 1 (1 XOR 1), the result is 0.</p><p>Properties of XOR</p><p>1. Commutative: A XOR B = B XOR A</p><p>2. Associative: (A XOR B) XOR C = A XOR (B XOR C)</p><p>3. Identity: A XOR 0 = A</p><p>4. Self-inverse: A XOR A = 0</p><p>Example</p><p>Let’s say you want to perform XOR on two 4-bit binary numbers:</p><p>- A = 1101</p><p>- B = 1011</p><p>You would compare each corresponding bit:</p><pre>1 1 0 1<br>XOR<br>1 0 1 1<br>-----------<br>0 1 1 0</pre><p>So, 1101 XOR 1011 = 0110.</p><p><strong>Note:-</strong></p><p>The logical AND (&amp;&amp;) and bitwise AND (&amp;) operators serve different purposes and are used in different contexts in programming. Here’s a breakdown of their differences:</p><p>Logical AND (&amp;&amp;)</p><p>1. Usage: Primarily used with boolean expressions.</p><p>2. Short-circuiting: If the first operand evaluates to false, the second operand is not evaluated. This means if the first condition is false, the overall expression is guaranteed to be false, and the second condition is not checked.</p><p>3. Return type: Always returns a boolean value (true or false).</p><p>4. Example:</p><pre>boolean result = (a &gt; 0) &amp;&amp; (b &lt; 10);</pre><p>If a is not greater than 0, the condition (b &lt; 10) won’t be evaluated.</p><p>Bitwise AND (&amp;)</p><p>1. Usage: Can be used with integer types (like int, byte, char, etc.) as well as boolean types.</p><p>2. No short-circuiting: Both operands are always evaluated, regardless of the value of the first operand. This means that both bits (or boolean values) are always checked.</p><p>3. Return type: When used with integers, it returns an integer; when used with booleans, it returns a boolean.</p><p>4. Example with integers:</p><pre>int result = a &amp; b; // Performs a bitwise AND on the binary representations <br>                    // of a and b.</pre><p>If a is 5 (binary 0101) and b is 3 (binary 0011), the result would be 1 (binary 0001).</p><p><strong>6. Ternary Operator (?:)</strong></p><p>This operator is a shorthand for if-else statements. It evaluates a boolean expression and returns one of two values depending on whether the expression is true or false.</p><p>Syntax:</p><pre>condition ? value_if_true : value_if_false;</pre><p>Example:</p><pre>public class TernaryOperator {<br>    public static void main(String[] args) {<br>        int a = 10, b = 20;<br>        int result = (a &gt; b) ? a : b;  // Returns b if a is not greater than b<br>        System.out.println(result);  // 20<br>    }<br>}</pre><p>Example of a Nested Ternary Operator</p><p>Here’s a simple example that determines a grade based on a score:</p><pre>int score = 85;<br>String grade = (score &gt;= 90) ? &quot;A&quot; :<br>               (score &gt;= 80) ? &quot;B&quot; :<br>               (score &gt;= 70) ? &quot;C&quot; :<br>               (score &gt;= 60) ? &quot;D&quot; : &quot;F&quot;;<br>System.out.println(&quot;Grade: &quot; + grade);</pre><p>Explanation</p><p>- First Condition: If score &gt;= 90, the grade is ”A”.</p><p>- Second Condition: If the first condition is false, it checks score &gt;= 80. If true, the grade is ”B”.</p><p>- Third Condition: If both previous conditions are false, it checks score &gt;= 70. If true, the grade is ”C”.</p><p>- Fourth Condition: If all previous conditions are false, it checks score &gt;= 60. If true, the grade is ”D”.</p><p>- Else: If none of the conditions are true, the grade is ”F”.</p><p>Output</p><p>For a score of 85, the output will be:</p><pre>Grade: B</pre><p><strong>7. Increment/Decrement Operator</strong></p><p>These are used to increase or decrease a value by one.</p><p>- ++ : Increment</p><p>- — : Decrement</p><p>They can be used in two forms:</p><p>- Pre-Increment/Pre-Decrement: ++a or — a</p><p>- Post-Increment/Post-Decrement: a++ or a —</p><p>Example:</p><pre>public class IncrementDecrement {<br>    public static void main(String[] args) {<br>        int a = 10;<br>        System.out.println(++a);  // Pre-increment: 11<br>        System.out.println(a++);  // Post-increment: 11 (prints before increment)<br>        System.out.println(a);    // 12<br>    }<br>}</pre><p><strong>Note :-</strong></p><p><strong>1. Using 10++</strong></p><p>In programming languages like Java, the expression 10++ is invalid. Here’s why:</p><p>- Literal Value: 10 is a literal constant, and you cannot increment a literal value. The increment operator (++) is intended to be used with variables, not constants.</p><p>- Increment Operator: The ++ operator increases the value of a variable by 1. Since 10 cannot be modified (it’s a fixed value), attempting to apply ++ to it results in a compilation error.</p><p>Example of Correct Usage:</p><p>Instead, you should use the increment operator with a variable:</p><pre>int num = 10;<br>num++; // This is valid and increments num to 11.</pre><p>2. Can it be Used with a final Variable?</p><p>You cannot use the increment operator with a final variable in Java. A final variable is a constant that cannot be modified once assigned. Therefore, attempting to use ++ on a final variable will result in a compilation error.</p><p>Example:</p><pre>final int num = 10;<br>num++; // This will cause a compilation error.</pre><p>3. What About ++i++?</p><p>The expression ++i++ is also invalid. Here’s why:</p><p>- Postfix and Prefix Increment: The expression tries to apply both prefix (++i) and postfix (i++) increment operators on the same variable i in a single statement. This is not allowed because the increment operators are not meant to be nested like this.</p><p>- Evaluation Order: The postfix increment (i++) returns the current value of i before incrementing, while the prefix increment (++i) increments the value of i before returning it. Combining these leads to ambiguity.</p><p>Example:</p><pre>int i = 5;<br>++i++; // This will cause a compilation error.</pre><p>The new operator is used to create new objects in Java.</p><p>Example:</p><pre>public class NewOperator {<br>    public static void main(String[] args) {<br>        String str = new String(&quot;Hello&quot;);<br>        System.out.println(str);<br>    }<br>}</pre><p>9. instanceof Operator</p><p>The instanceof operator checks whether an object is an instance of a specific class or subclass.</p><p>Example:</p><pre>public class NewOperator {<br>    public static void main(String[] args) {<br>        String str = new String(&quot;Hello&quot;);<br>        System.out.println(str);<br>    }<br>}</pre><p>In Java, both instanceof and the isInstance method (part of the Class class) are used to check if an object is an instance of a specified class. However, they have different syntax and use cases. Here’s a breakdown of their differences:</p><p>instanceof</p><p>1. Syntax:</p><pre>object instanceof ClassName</pre><p>2. Usage:</p><p>- Used in conditional expressions (like if statements).</p><p>- Directly checks whether the object is an instance of a specified class or its subclasses.</p><p>3. Example:</p><pre>class Animal {}<br>class Dog extends Animal {}<br>Animal animal = new Dog();<br>if (animal instanceof Dog) {<br>    System.out.println(&quot;animal is a Dog&quot;);<br>}</pre><p>4. Compile-time Check:</p><p>- The type on the right side of instanceof is checked at compile time for type safety.</p><p>- If the left operand is not compatible with the right operand, it results in a compile-time error.</p><p>isInstance</p><p>1. Syntax:</p><pre>ClassName.class.isInstance(object)</pre><p>2. Usage:</p><p>- A method of the Class class, allowing for more dynamic type checking.</p><p>- Useful when the class type is not known at compile time, such as when working with reflection or generic programming.</p><p>3. Example:</p><pre>Class&lt;?&gt; clazz = Dog.class;<br>Animal animal = new Dog();<br>if (clazz.isInstance(animal)) {<br>    System.out.println(&quot;animal is an instance of Dog&quot;);<br>}</pre><p>4. Dynamic Check:</p><p>- More flexible, as you can determine the class type at runtime, which is especially useful in situations involving reflection.</p><p>Key Differences</p><p>1. Syntax: instanceof is an operator, while isInstance is a method of the Class class.</p><p>2. Flexibility:</p><p>- isInstance can be more dynamic, allowing you to check against class types determined at runtime.</p><p>- instanceof is more straightforward and generally easier to read for simple type checks.</p><p>3. Compile-time vs. Runtime:</p><p>- instanceof performs a compile-time check for type safety.</p><p>- isInstance does not provide compile-time type safety, as the class type can be determined at runtime.</p><p>Summary</p><p>- Use instanceof for straightforward type checks when the class type is known at compile time.</p><p>- Use isInstance when you need dynamic type checking or when dealing with reflection, where the class type may not be known until runtime.</p><h4>Control Statements in Java</h4><p>In Java, control statements manage the flow of program execution. By default, the code execution follows a top-to-bottom order, but using control statements, you can alter this flow based on your requirements. Control statements are crucial for making decisions, repeating code, or jumping to specific parts of the program. Java control statements can be categorized into three main types:</p><p><strong>1. Conditional Control Statements</strong></p><p>Conditional statements execute code based on certain conditions (evaluated as true or false). If the condition is true, a specific block of code runs; if false, a different block may execute or the execution may skip that part entirely.</p><p><strong>Types of Conditional Control Statements:</strong></p><p>1. If Statement</p><p>- The simplest form of decision-making. It checks a condition and executes a block of code only if the condition is true.</p><p>Syntax:</p><pre>if (condition) {<br>    // block of code<br>}</pre><p>Example:</p><pre>if (number1 &gt; number2) {<br>  System.out.println(&quot;number1 is greater than number2&quot;);<br>}</pre><p>2. If-Else Statement</p><p>- Extends the if statement by adding an else block that executes if the condition is false.</p><p>Syntax:</p><pre>if (condition) {<br>    // code if condition is true<br>} else {<br>    // code if condition is false<br>}</pre><p>Example:</p><pre>if (number1 &lt; number2) {<br>    System.out.println(&quot;number1 is less than number2&quot;);<br>} else {<br>    System.out.println(&quot;number1 is greater than number2&quot;);<br>}</pre><p>3. Nested If Statement</p><p>- You can place an if statement inside another if to create complex decision-making scenarios.</p><p>Syntax:</p><pre>if (condition1) {<br>    if (condition2) {<br>        // code if both condition1 and condition2 are true<br>    }<br>}</pre><p>4. If-Else Ladder</p><p>- Multiple if-else statements chained together. Useful when you need to test several conditions.</p><p>Syntax:</p><pre>if (condition1) {<br>    // code if condition1 is true<br>} else if (condition2) {<br>    // code if condition2 is true<br>} else {<br>    // code if none of the above are true<br>}</pre><p>5. Switch Statement</p><p>- Useful when a variable can take multiple distinct values. The switch statement selects one of many blocks of code to execute.</p><p>Syntax:</p><pre>switch (variable) {<br>    case value1:<br>        // code block<br>        break;<br>    case value2:<br>        // code block<br>        break;<br>    default:<br>        // code block<br>}</pre><p>Example:</p><pre>switch (input) {<br>    case &quot;A&quot;:<br>        // Add operation<br>        break;<br>    case &quot;S&quot;:<br>        // Subtract operation<br>        break;<br>    default:<br>        // Invalid option<br>}</pre><p>In Java, the switch statement allows you to execute different blocks of code based on the value of a variable or expression. However, there are specific types of elements that are permitted in a switch statement:</p><p>1. Primitive Data Types</p><p>- int: You can use int (including byte, short, and char as they can be implicitly converted to int).</p><p>- char: The char type is allowed, representing single 16-bit Unicode characters.</p><p>- byte and short: Both can be used as they can fit within an int.</p><p>2. Wrapper Classes</p><p>- Integer: You can use Integer (the wrapper class for int).</p><p>- Character: You can use Character (the wrapper class for char).</p><p>3. String</p><p>- String: You can use String objects in a switch statement starting from Java 7. This allows for more readable code when working with string values.</p><p>4. Enums</p><p>- enum Types: You can use enum types, which are special Java types that represent a fixed set of constants. Each enum constant can be treated as a distinct case.</p><p>5. Disallowed Types</p><p>- float, double, long: These types are not allowed in a switch statement.</p><p>- boolean: The boolean type cannot be used in a switch statement.</p><p>- Any Object Type: While String and enums are allowed, other object types cannot be directly used.</p><p>Can We Use Variables in Case Statements?</p><p>In Java, you cannot use variables in the case labels of a switch statement. The case labels must be constant expressions, which means they must be known at compile time. This includes:</p><p>- Literals: Such as 1, ”Monday”, or Color.RED.</p><p>- Constant Variables: These are variables declared with the final keyword that have a fixed value.</p><p>Example of Valid Case Labels</p><pre>final int ONE = 1;<br>final int TWO = 2;<br>int number = 2;<br>switch (number) {<br>    case ONE: // Valid<br>        System.out.println(&quot;One&quot;);<br>        break;<br>    case TWO: // Valid<br>        System.out.println(&quot;Two&quot;);<br>        break;<br>    default:<br>        System.out.println(&quot;Not One or Two&quot;);<br>}</pre><p>Example of Invalid Case Labels</p><pre>int variable = 3;<br>switch (number) {<br>    case variable: // Invalid: cannot use variable in case label<br>        System.out.println(&quot;This will cause a compile-time error.&quot;);<br>        break;<br>}</pre><p>Example of a Switch Statement</p><p>Here’s an example using different allowed types:</p><pre>int number = 2;<br>switch (number) {<br>    case 1:<br>        System.out.println(&quot;One&quot;);<br>        break;<br>    case 2:<br>        System.out.println(&quot;Two&quot;);<br>        break;<br>    default:<br>        System.out.println(&quot;Not One or Two&quot;);<br>}<br>String day = &quot;Monday&quot;;<br>switch (day) {<br>    case &quot;Monday&quot;:<br>        System.out.println(&quot;Start of the week&quot;);<br>        break;<br>    case &quot;Friday&quot;:<br>        System.out.println(&quot;End of the week&quot;);<br>        break;<br>    default:<br>        System.out.println(&quot;Midweek day&quot;);<br>}<br>enum Color { RED, GREEN, BLUE }<br>Color color = Color.RED;<br>switch (color) {<br>    case RED:<br>        System.out.println(&quot;Red color&quot;);<br>        break;<br>    case GREEN:<br>        System.out.println(&quot;Green color&quot;);<br>        break;<br>}</pre><p>2. Looping Control Statements</p><p>These statements allow executing a block of code repeatedly until a certain condition is met or a certain number of times.</p><p>Types of Looping Control Statements:</p><p>1. For Loop</p><p>- Repeats a block of code a specific number of times.</p><p>Syntax:</p><pre>for (initialization; condition; update) {<br>    // code block<br>}</pre><p>Example:</p><pre>for (int i = 1; i &lt;= 100; i++) {<br>    if (i % 7 == 0) {<br>        sum += i;<br>    }<br>}</pre><p>2. While Loop</p><p>- Repeats code while a condition is true. It checks the condition before executing the loop body.</p><p>Syntax:</p><pre>while (condition) {<br>    // code block<br>}</pre><p>Example:</p><pre>while (i &lt;= 10) {<br>    System.out.println(&quot;2 x &quot; + i + &quot; = &quot; + (2 * i));<br>    i++;<br>}</pre><p>3. Do-While Loop</p><p>- Similar to the while loop, but it checks the condition after executing the loop body, ensuring it runs at least once.</p><p>Syntax:</p><pre>do {<br>    // code block<br>} while (condition);</pre><p>Example:</p><pre>do {<br>    System.out.println(&quot;Count is: &quot; + count);<br>    count++;<br>} while (count &lt; 11);</pre><p>3. Unconditional Control Statements</p><p>These statements cause the program to jump from one point to another unconditionally. They don’t check for conditions to decide the flow.</p><p>Types of Unconditional Control Statements:</p><p>1. Break Statement</p><p>- Used to exit a loop or switch statement prematurely.</p><p>Example:</p><pre>for (int i = 0; i &lt;= 10; i++) {<br>    if (i == 5) {<br>        break;<br>    }<br>    System.out.println(&quot;i -&gt; &quot; + i);<br>}</pre><p>2. Continue Statement</p><p>- Skips the current iteration of the loop and moves on to the next iteration.</p><p>Example:</p><pre>for (int i = 1; i &lt;= 10; i++) {<br>    if (i == 5) {<br>        continue;  // skips when i is 5<br>    }<br>    System.out.print(&quot;i -&gt; &quot; + i);<br>}</pre><p>Summary:</p><p>- Conditional statements control the flow based on conditions (if, if-else, switch).</p><p>- Looping statements repeat code (for, while, do-while).</p><p>-Unconditional statements manage abrupt changes in control (break, continue).</p><h4>Array in Java</h4><p>An array is a collection of similar data types stored in contiguous memory locations. Java arrays are objects and offer a structured way to store and access large amounts of data efficiently. Below is a detailed explanation of arrays in Java:</p><p><strong>Salient Features of Java Array:</strong></p><p>- Index-based storage: Each element in the array is stored at a specific index, and indexing begins from 0. For example, the first element is stored at index 0, the second at index 1, and so on.</p><p>- Preserves order: Arrays in Java follow the order in which elements are added. The first element is stored at index 0, and each subsequent element is stored at the next index.</p><p>- Random Access: You can access any element directly using its index, making arrays suitable for applications where fast retrieval is important.</p><p>- Homogeneous data type: Arrays store elements of the same type (e.g., int[] stores integers).</p><p>- Heap memory storage: Arrays are objects in Java and are stored in heap memory, which is managed by the JVM.</p><p>- Dynamic memory allocation: The size of an array is determined at runtime. JVM calculates the memory needed and allocates accordingly.</p><p>- Array length: The length property holds the number of elements in the array. This is a fixed value once the array is created.</p><p>- Maximum size: The maximum size of an array in Java is ²³¹ — 1, which equals 2,147,483,647.</p><p>Types of Array Declaration in Java</p><p>1. Static Array:</p><p>The array is initialized at the time of declaration with known values.</p><p>Syntax:</p><pre>&lt;data_type&gt; &lt;array_name&gt;[] = {value1, value2, value3, …};</pre><p>Example:</p><pre>int[] arr = {10, 20, 30, 40, 50};</pre><p>In this example, arr is an integer array of length 5, and it holds the values 10, 20, 30, 40, and 50.</p><p>2. Dynamic Array:</p><p>The array is initialized without knowing the exact values but specifying the size, and values can be added later dynamically.</p><p>Syntax:</p><pre>&lt;data_type&gt; &lt;array_name&gt;[] = new &lt;data_type&gt;[size];</pre><p>Example:</p><pre>int[] arr = new int[5];</pre><p>In this case, arr is an array of integers with a length of 5, but initially, it holds the default values for int (which is 0).</p><p>Types of Arrays</p><p>1. Single-Dimensional Array</p><p>A single-dimensional array stores elements linearly.</p><p>Example:</p><pre>public class Example {<br>    public static void main(String[] args) {<br>        int[] arr = {5, 6, 3, 2, 1};<br>        for (int i = 0; i &lt; arr.length; i++) {<br>            System.out.println(&quot;Index: &quot; + i + &quot;, Value: &quot; + arr[i]);<br>        }<br>    }<br>}</pre><p>Output:</p><pre>Index: 0, Value: 5<br>Index: 1, Value: 6<br>Index: 2, Value: 3<br>Index: 3, Value: 2<br>Index: 4, Value: 1</pre><p>In the example above, an integer array arr is initialized, and each element is printed using a for-loop.</p><p>2. Multi-Dimensional Array</p><p>A multi-dimensional array stores references to other arrays, which allows for representing matrices or higher-dimensional data.</p><p>Two-Dimensional Array (2D Array):</p><p>Syntax:</p><pre>&lt;data_type&gt; &lt;array_name&gt;[][] = {{value1, value2}, {value3, value4}, …};</pre><p>Example:</p><pre>int[][] matrix = {{101, 202, 303}, {404, 505, 606}, {707, 808, 909}};<br>for (int i = 0; i &lt; matrix.length; i++) {<br>    for (int j = 0; j &lt; matrix[i].length; j++) {<br>        System.out.print(&quot;matrix[&quot; + i + &quot;][&quot; + j + &quot;] = &quot; + matrix[i][j] + &quot; &quot;);<br>    }<br>    System.out.println();<br>}</pre><p>Output:</p><pre>matrix[0][0] = 101 matrix[0][1] = 202 matrix[0][2] = 303<br>matrix[1][0] = 404 matrix[1][1] = 505 matrix[1][2] = 606<br>matrix[2][0] = 707 matrix[2][1] = 808 matrix[2][2] = 909</pre><p>Three-Dimensional Array (3D Array):</p><p>Syntax:</p><pre>&lt;data_type&gt; &lt;array_name&gt;[][][] = {{{value1, value2}, {value3, value4}}, …};</pre><p>Example:</p><pre>int[][][] arr = {{{1, 2, 3}, {4, 5, 6}}, {{7, 8, 9}, {10, 11, 12}}};<br>for (int i = 0; i &lt; arr.length; i++) {<br>    for (int j = 0; j &lt; arr[i].length; j++) {<br>        for (int k = 0; k &lt; arr[i][j].length; k++) {<br>            System.out.print(arr[i][j][k] + &quot; &quot;);<br>        }<br>        System.out.println();<br>    }<br>}</pre><p>Output:</p><pre>1 2 3<br>4 5 6<br>7 8 9<br>10 11 12</pre><p>Command-Line Arguments</p><p>In Java, the main method accepts an array of strings (String[] args). These strings are the command-line arguments passed to the program during execution.</p><p>Example:</p><pre>public class CommandLineExample {<br>    public static void main(String[] args) {<br>        for (int i = 0; i &lt; args.length; i++) {<br>            System.out.println(&quot;arg[&quot; + i + &quot;] = &quot; + args[i]);<br>        }<br>    }<br>}</pre><p>Execution from Command Line:</p><pre>java CommandLineExample Hello World 123</pre><p>Output:</p><pre>arg[0] = Hello<br>arg[1] = World<br>arg[2] = 123</pre><p>Command-line arguments are passed as strings. If necessary, they can be converted into other data types using methods like Integer.parseInt(), Double.parseDouble(), etc.</p><p><strong>Why the main method parameter is a String Array?</strong></p><p>The JVM allows the main method to accept a String[] because strings are versatile and can represent any kind of input data (numbers, characters, booleans, etc.) in textual form. This allows the user to pass diverse data formats at runtime via the command line.</p><h4>Object-Oriented Programming (OOP) in Java</h4><p><strong>1. Class:</strong></p><p>A class in Java is a blueprint or template that defines the structure and behavior (data members and methods) for objects. It is a user-defined data type. The syntax for defining a class in Java is:</p><pre>class &lt;class_name&gt; {<br>    // Members (variables, methods, etc.)<br>}</pre><p>- Class members: The text lists members of a class, which include:</p><p>- Variables: Used to store data (e.g., int sid, String sname).</p><p>- Blocks: Sections of code (e.g., static blocks or instance initializer blocks).</p><p>- Methods: Functions that define behaviors.</p><p>- Constructors: Special methods that initialize objects.</p><p>- Enums: Used to define a set of named constants.</p><p>- Inner Classes: Classes defined within another class.</p><p>- Interfaces: Used to define a contract for implementing classes.</p><p>Example:</p><p>A class named Student is defined to represent a student and contains fields for storing student data (ID, name, and email):</p><pre>class Student {<br>    int sid;<br>    String sname;<br>    String semail;<br>}</pre><p>This class defines a category (students), and these fields represent the information to be stored for each student.</p><p><strong>Points to Remember</strong></p><p>1. Multiple Classes in a Program</p><p>- In Java, a program can consist of multiple classes. Each class defined will result in a separate `.class` file after compilation.</p><p>Example:</p><pre>class A {<br>    // Class A code<br>}<br><br>class B {<br>    // Class B code<br>}<br><br>class User {<br>    public static void main(String[] args) {<br>        // Main method code<br>    }<br>}</pre><p>- After Compilation: This program will generate three files:</p><p>- `A.class`</p><p>- `B.class`</p><p>- `User.class`</p><p>- File Naming Convention: The program should be saved as `User.java` since it contains the `main()` method, which serves as the entry point for execution.</p><p>2. Public Class and Main Method</p><p>- When multiple classes exist in a single program, only one class should be declared as `public`, and this class should contain the `main()` method.</p><p>- The filename must match the name of the public class.</p><p>Example:</p><pre>class A {<br>    public static void main(String[] args) {<br>        // Code for class A<br>    }<br>}<br><br>class B {<br>    public static void main(String[] args) {<br>        // Code for class B<br>    }<br>}<br><br>public class User {<br>    public static void main(String[] args) {<br>        // Code for main logic<br>    }<br>}</pre><p>- File Naming: This should be saved as `User.java`.</p><p>3. Executing Classes with Main Methods</p><p>- If there are multiple classes in a program, each with its own `main()` method, only one class should be public. Each class can still be executed individually if required.</p><p>Example:</p><pre>class A {<br>    public static void main(String[] args) {<br>        System.out.println(&quot;Main method of class A&quot;);<br>    }<br>}<br><br>class B {<br>    public static void main(String[] args) {<br>        System.out.println(&quot;Main method of class B&quot;);<br>    }<br>}<br><br>public class C {<br>    public static void main(String[] args) {<br>        System.out.println(&quot;Main method of class C&quot;);<br>    }<br>}</pre><p>- File Naming: Save as `C.java`.</p><p>- Execution: You can compile and execute each class individually:</p><p>- `java A`</p><p>- `java B`</p><p>- `java C`</p><p>4. Class Types</p><p>- Business Logic Class: A class that does not contain the `main()` method but contains business logic. These classes are often designed for specific tasks, such as data processing or calculations, and are used by user logic classes.</p><p>- User Logic Class: A class that contains the `main()` method. This is where the program execution begins and typically coordinates calls to business logic classes.</p><p><strong>2. Object:</strong></p><p>An object is an instance of a class. It is created dynamically and allocated memory on the heap. Each object stores its data and can access the class’s methods and attributes. Objects are referenced using reference variables.</p><p>- Object Creation: When we create an object, it is done using the new keyword.</p><p>Example:</p><pre>Student s1 = new Student();</pre><p>- s1 is the reference variable that holds the memory address of the Student object.</p><p>- new Student() allocates memory for a Student object and initializes it.</p><p>Objects are used to store and manipulate class-specific data.</p><p><strong>3. Class Loading Concept:</strong></p><p>Class loading refers to the process of loading a class into Java Virtual Machine (JVM) memory. Java uses Class Loaders to load classes dynamically when they are required by the program. Classes are not loaded all at once, but only when they are needed during the program’s execution.</p><p>Situations when a class is loaded:</p><p>1. Object Creation: When an object of a class is created, the JVM checks if the class is already loaded. If not, the class loader loads it first.</p><p>Example:</p><pre>Student s1 = new Student(); // loads the Student class if not already loaded</pre><p>2. Running a class with a main method: When the JVM starts an application, it loads the class containing the main() method and executes it.</p><p>3. Accessing static members: If a class’s static members (variables or methods) are accessed, the class is loaded if not already done so.</p><p><strong>Dynamic Class Loading:</strong></p><p>In Java, classes can be loaded dynamically at runtime using the Class.forName() method. This is useful when you want to load a class based on some runtime condition.</p><p>- The forName() method takes a class name as a string and loads that class into the JVM.</p><p>Example:</p><pre>Class.forName(&quot;A&quot;);</pre><p>- This method attempts to load the class A into memory. If the class is found, it is loaded; otherwise, a ClassNotFoundException is thrown.</p><p>Static Block Execution:</p><p>When a class is loaded into memory, any static blocks (code inside static { } block) are executed immediately.</p><p>Example:</p><pre>class A {<br>    static {<br>        System.out.println(&quot;SB in class A&quot;);<br>    }<br>}</pre><p>When Class.forName(“A”) is called, the static block inside class A is executed, printing “SB in class A.”</p><p>4. ClassNotFoundException:</p><p>When attempting to load a class that doesn’t exist (e.g., Class.forName(“ABC”)), Java throws a ClassNotFoundException. This is an exception that occurs when the JVM cannot locate the specified class file at runtime.</p><p>Example:</p><pre>Class.forName(&quot;ABC&quot;);</pre><p>Output:</p><pre>Exception in thread &quot;main&quot; java.lang.ClassNotFoundException: ABC</pre><h4>Instance variables and static variables</h4><p>1. Instance Variable:</p><p>An instance variable is a variable declared inside a class but outside any method and without the static keyword. It is also called a non-static variable. Each object of the class gets its own copy of the instance variable, meaning the value of the instance variable can differ between objects.</p><p>Key Points:</p><p>- Instance variables are created when an object of the class is instantiated.</p><p>- Each object of the class has its own separate memory allocation for instance variables.</p><p>-These variables hold unique data for each object.</p><p>-Instance variable cannot be directly accessed inside any static context.</p><p>Example:</p><pre>class Student {<br>    int sid;       // Instance variable for student ID<br>    String sname;  // Instance variable for student name<br>    String semail; // Instance variable for student email<br>}<br>class JTC {<br>    public static void main(String[] args) {<br>        // Creating two objects of the Student class<br>        Student s1 = new Student();<br>        s1.sid = 101;<br>        s1.sname = &quot;Vivek&quot;;<br>        s1.semail = &quot;vivek@jtcindia.org&quot;;<br>        Student s2 = new Student();<br>        s2.sid = 102;<br>        s2.sname = &quot;Rahul&quot;;<br>        s2.semail = &quot;rahul@jtcindia.org&quot;;<br>        // Displaying details for both students<br>        System.out.println(&quot;----Student Details----&quot;);<br>        System.out.println(&quot;s1.sid: &quot; + s1.sid);<br>        System.out.println(&quot;s1.sname: &quot; + s1.sname);<br>        System.out.println(&quot;s1.semail: &quot; + s1.semail);<br>        System.out.println(&quot;----Student Details----&quot;);<br>        System.out.println(&quot;s2.sid: &quot; + s2.sid);<br>        System.out.println(&quot;s2.sname: &quot; + s2.sname);<br>        System.out.println(&quot;s2.semail: &quot; + s2.semail);<br>    }<br>}</pre><p>Explanation:</p><p>- sid, sname, and semail are instance variables that hold unique data for each student.</p><p>- When two objects (s1 and s2) are created, each has its own memory space for sid, sname, and semail.</p><p>- The output shows that s1 and s2 have different values for these instance variables.</p><p>Output:</p><pre>- - Student Details - - <br>s1.sid: 101<br>s1.sname: Vivek<br>s1.semail: vivek@jtcindia.org<br> - - Student Details - - <br>s2.sid: 102<br>s2.sname: Rahul<br>s2.semail: rahul@jtcindia.org</pre><p>2. Static Variable:</p><p>A static variable is a class-level variable that is shared by all instances (objects) of the class. It is declared using the static keyword. Static variables are not specific to any object and get memory allocated when the class is loaded, rather than when objects are created.</p><p>Key Points:</p><p>- A static variable is shared by all objects of the class.</p><p>- It gets memory allocation once when the class is loaded, and its value is the same for all objects.</p><p>- Static variables are used to store data that is common across all instances of a class.</p><p>Example:</p><pre>class Student {<br>    int sid;             // Instance variable for student ID<br>    String sname;        // Instance variable for student name<br>    String semail;       // Instance variable for student email<br>    static String snationality = &quot;Indian&quot;; // Static variable shared by all students<br>}<br>class JTC {<br>    public static void main(String[] args) {<br>        // Creating two objects of the Student class<br>        Student s1 = new Student();<br>        s1.sid = 101;<br>        s1.sname = &quot;Vivek&quot;;<br>        s1.semail = &quot;vivek@jtcindia.org&quot;;<br>        Student s2 = new Student();<br>        s2.sid = 102;<br>        s2.sname = &quot;Rahul&quot;;<br>        s2.semail = &quot;rahul@jtcindia.org&quot;;<br>        // Displaying details for both students, including the static variable<br>        System.out.println(&quot;s1.sid: &quot; + s1.sid);<br>        System.out.println(&quot;s1.sname: &quot; + s1.sname);<br>        System.out.println(&quot;s1.semail: &quot; + s1.semail);<br>        System.out.println(&quot;s1.snationality: &quot; + s1.snationality);<br>        System.out.println(&quot;s2.sid: &quot; + s2.sid);<br>        System.out.println(&quot;s2.sname: &quot; + s2.sname);<br>        System.out.println(&quot;s2.semail: &quot; + s2.semail);<br>        System.out.println(&quot;s2.snationality: &quot; + s2.snationality);<br>    }<br>}</pre><p>Explanation:</p><p>- sid, sname, and semail are instance variables and differ for each object.</p><p>- snationality is a static variable that is shared by all instances of the Student class. Its value, “Indian”, is the same for both s1 and s2.</p><p>- All objects of the class share the same snationality value, as it is static.</p><p>Output:</p><pre>s1.sid: 101<br>s1.sname: Vivek<br>s1.semail: vivek@jtcindia.org<br>s1.snationality: Indian<br>s2.sid: 102<br>s2.sname: Rahul<br>s2.semail: rahul@jtcindia.org<br>s2.snationality: Indian</pre><p>3. Accessing Static Variables:</p><p>Static variables can be accessed in three different ways:</p><p>1. Using the class name:</p><p>- Access the static variable directly through the class name.</p><pre>System.out.println(A.a);</pre><p>2. Using a class reference variable (even if it contains a null value):</p><p>- A reference variable can be used to access a static variable, even if the reference variable is null.</p><pre>A a1 = null;<br>System.out.println(a1.a); // Still accesses the static variable</pre><p>3. Using a class object:</p><p>- Static variables can also be accessed using an object of the class.</p><pre>A a2 = new A();<br>System.out.println(a2.a);</pre><p>Example of Static Variable Access:</p><pre>class A {<br>    static int a = 10; // Static variable<br>}<br>class JTC {<br>    public static void main(String[] args) {<br>        // Accessing static variable using the class name<br>        System.out.println(&quot;A.a: &quot; + A.a);<br>        // Accessing static variable using a reference variable with a null value<br>        A a1 = null;<br>        System.out.println(&quot;a1.a: &quot; + a1.a);<br>        // Accessing static variable using an object<br>        A a2 = new A();<br>        System.out.println(&quot;a2.a: &quot; + a2.a);<br>    }<br>}</pre><p>Output:</p><pre>A.a: 10<br>a1.a: 10<br>a2.a: 10</pre><p>Explanation:</p><p>- The static variable a is accessed in all three ways, and the value 10 is printed each time because it is the same across all accesses.</p><p>Note:-</p><ul><li>Instance and static variable both can be declared as final variable.</li><li>Instance and static variable cannot be declared inside any local context and only local variable can be declared.</li><li>It means we can use static variable in static context(method and block-early binding).</li><li>Variable defined under instance or static block would be consided as local variable.</li><li>So, inside instance block or method we can access both.</li></ul><p>Thus we can say that,</p><p>- Instance Variables: Unique to each object, and memory is allocated when the object is created.</p><p>-Static Variables: Shared by all objects of the class, and memory is allocated once when the class is loaded. They can be accessed using the class name, a null reference, or an object of the class.</p><p>Note:-</p><p>In Java, a final variable is a variable whose value cannot be changed once it is assigned. Here’s a breakdown of how final and static final variables can be initialized:</p><p>Final Variables<br> 1. At the time of declaration:<br> <br> final int x = 10;<br> <br> 2. Using a block:</p><pre>final int y;<br> {<br>   y = 20; // Initialized in an instance initializer block<br> }</pre><p>3. In a constructor:</p><pre>final int z;<br>MyClass(int value) {<br>   z = value; // Initialized in the constructor<br> }</pre><p>Static Final Variables<br> For static final variables, they must be initialized as follows:</p><ol><li>At the time of declaration:<br> <br> static final int a = 100;</li><li>Static block:</li></ol><pre>static final int b;<br>static {<br>  b = 200; // Initialized in a static block<br>}</pre><p>If a static final variable is not initialized in either of these ways, it will lead to a compilation error. This ensures that the variable has a constant value at the class level.</p><p>-In Java, you can declare local variables as final, but you cannot declare them as private.</p><p>Final Local Variables</p><p>When you declare a local variable as final, it means that once it is initialized, its value cannot be changed. For example:</p><pre>public void myMethod() {<br>    final int number = 10;<br>    // number = 20; // This would cause a compile-time error<br>}</pre><p>Private Local Variables</p><p>Local variables are inherently not associated with an access modifier like private, protected, or public. Access modifiers apply to class members (fields, methods) but not to local variables defined within methods or blocks. Local variables are only accessible within the scope of the method or block in which they are defined.</p><p>Summary</p><p>- You can declare local variables as final.</p><p>- You cannot declare local variables as private. They are already limited in scope to the method in which they are defined.</p><h4>Blocks in Java</h4><p>A Block in Java is a group of statements enclosed within curly braces {}. Blocks can be declared in different parts of a class, including inside methods, constructors, or directly within the class. Java has three types of blocks:</p><p>1. Instance Block or Non-Static Block</p><p>2. Static Block</p><p>3. Local Block</p><p>1. Instance Block or Non-Static Block</p><p>- A block declared inside a class without the static keyword is called an instance block or non-static block.</p><p>- It is executed every time an object of the class is created.</p><p>- Multiple instance blocks can be declared within a class, and they are executed in the order they are written.</p><p>- Instance blocks can access both instance and static members of the class.</p><p>-Instance blocks are typically used to execute code during object initialization.</p><p><strong>Use Case</strong>: Useful for initializing instance variables or executing code that needs to run for every instance of a class.</p><p>Example:</p><pre>class JTC{<br>    public static void main(String arg[]){<br>        A a1 = new A();<br>        A a2 = new A();<br>        A a3 = new A();<br>    }<br>}<br>class A {<br>    int a = 10; // Instance Variable<br>    static int b = 20; // Static Variable<br>    <br>    // Instance Block 1<br>    {<br>        System.out.println(&quot;IB-1 in A class&quot;);<br>        System.out.println(&quot;a :- &quot; + a);<br>        System.out.println(&quot;b :- &quot; + b);<br>    }<br>    <br>    // Instance Block 2<br>    {<br>        System.out.println(&quot;IB-2 in A class&quot;);<br>        System.out.println(&quot;a :- &quot; + a);<br>        System.out.println(&quot;b :- &quot; + b);<br>    }<br>}</pre><p>Output:</p><pre>IB-1 in A class<br>a :- 10<br>b :- 20<br>IB-2 in A class<br>a :- 10<br>b :- 20<br>…</pre><p>2. Static Block</p><p>- A block declared with the static keyword is called a static block.</p><p>- Static blocks are executed once, when the class is loaded into memory (before any objects are created).</p><p>- Static blocks can only access static members directly. To access instance members, an object of the class must be created.</p><p>- Static blocks are useful when you want to perform operations at class loading time (e.g., initializing static variables).</p><p><strong>Use Case</strong>: Ideal for initializing static variables or performing actions that need to occur once for the class, such as loading configuration settings.</p><p>Example:</p><pre>class JTC{<br>    public static void main(String arg[]){<br>        new A();<br>    }<br>}<br>class A {<br>    int a = 10; // Instance Variable<br>    static int b = 20; // Static Variable<br>    <br>    // Static Block<br>    static {<br>        System.out.println(&quot;SB in A class&quot;);<br>        System.out.println(&quot;b :- &quot; + b);<br>    }<br>    <br>    // Instance Block<br>    {<br>        System.out.println(&quot;IB in A class&quot;);<br>        System.out.println(&quot;a :- &quot; + a);<br>        System.out.println(&quot;b :- &quot; + b);<br>    }<br>}</pre><p>Output:</p><pre>SB in A class<br>b :- 20<br>IB in A class<br>a :- 10<br>b :- 20</pre><p>3. Local Block</p><p>- A local block is a block of code defined inside a method or constructor.</p><p>- It is not static or an instance block and is executed when the containing method or constructor is invoked.</p><p>- Local blocks are typically used for block-level synchronization or scoping local variables.</p><p>-We cannot declare them as final.</p><p>Example:</p><pre>class JTC{<br>    public static void main(String arg[]){<br>        new A().m1();<br>    }<br>}<br>class A {<br>    void m1(){<br>        System.out.println(&quot;m1 method in A class&quot;);<br>        System.out.println(&quot;Before Local Block&quot;);<br>        <br>        // Local Block<br>        {<br>            System.out.println(&quot;Local Block in m1 method&quot;);<br>        }<br>        <br>        System.out.println(&quot;After Local Block&quot;);<br>    }<br>}</pre><p>Output:</p><pre>m1 method in A class<br>Before Local Block<br>Local Block in m1 method<br>After Local Block</pre><h4>Dynamic Class Loading</h4><p>Java provides a mechanism to load classes dynamically at runtime using the Class.forName() method. This method loads the class and executes the static blocks (if present) when the class is loaded. If the class is not found, it throws a ClassNotFoundException.</p><p>Example:</p><pre>class JTC{<br>    public static void main(String arg[]) throws ClassNotFoundException {<br>        Class.forName(&quot;A&quot;);<br>        Class.forName(&quot;B&quot;);<br>    }<br>}<br>class A {<br>    static {<br>        System.out.println(&quot;SB in A class&quot;);<br>    }<br>}<br>class B {<br>    static {<br>        System.out.println(&quot;SB in B class&quot;);<br>    }<br>}</pre><p>Output:</p><pre>SB in A class<br>SB in B class</pre><p>In this example, both A and B classes are dynamically loaded at runtime, and their static blocks are executed.</p><h4>Methods</h4><p>In Java, methods are blocks of code designed to perform specific tasks, and they are central to how programs are structured and executed.</p><p>1. Method Declaration and Syntax:</p><p>A method in Java is declared using the following syntax:</p><pre>&lt;Access Modifier&gt; &lt;Return Type&gt; &lt;Method Name&gt;(&lt;List of Parameters&gt;) {<br>    // Method body<br>}</pre><p>- Access Modifier: Determines the visibility of the method (e.g., public, private, protected).</p><p>- Return Type: The type of data the method returns to the caller (int, String, void, etc.).</p><p>- Method Name: A unique identifier used to invoke the method.</p><p>- Parameters: (Optional) Input values to the method, declared as a comma-separated list of types and names.</p><h4>Access Modifiers in Java</h4><p>Access modifiers in Java are keywords used to define the visibility and accessibility of classes, methods, and variables. They play a crucial role in encapsulation, allowing developers to control how the data is accessed and modified. There are four main access modifiers in Java:</p><p>1. Public</p><p>- Definition: The public access modifier allows the class, method, or variable to be accessible from any other class in any package.</p><p>- Use Case: When you want to expose a method or variable to be usable by any other code.</p><p>2. Private</p><p>- Definition: The private access modifier restricts the visibility of the method or variable to within the class itself. No other class can access private members.</p><p>- Use Case: Used to encapsulate data and provide a level of protection, ensuring that sensitive data is not accessible outside its class.</p><p>3. Protected</p><p>The protected access modifier in Java plays a crucial role in inheritance and encapsulation. It allows you to define the visibility of class members (fields and methods) in a way that balances accessibility and protection.</p><p>Characteristics of protected</p><p>1. Visibility:</p><p>- Members declared as protected are accessible within the same package.</p><p>- They are also accessible in subclasses, even if those subclasses are located in different packages.</p><p>2. Use in Inheritance:</p><p>- The primary use of protected is to allow subclasses to inherit and access members of a superclass while still preventing access from unrelated classes outside of the package.</p><p>3. Default Behavior:</p><p>- If no access modifier is specified, the default (package-private) access level applies, which allows access only within the same package. protected extends this visibility to subclasses, thus offering a more flexible approach.</p><p>Example of protected</p><p>Here’s an example to illustrate how the protected access modifier works:</p><pre>// Superclass<br>class Animal {<br>    protected void makeSound() {<br>        System.out.println(&quot;Animal makes a sound&quot;);<br>    }<br>}<br>// Subclass in the same package<br>class Dog extends Animal {<br>    public void bark() {<br>        makeSound(); // Accessing protected method from superclass<br>        System.out.println(&quot;Dog barks&quot;);<br>    }<br>}<br>// Subclass in a different package<br>package anotherPackage;<br>import somePackage.Animal; // Importing superclass<br>class Cat extends Animal {<br>    public void meow() {<br>        makeSound(); // Accessing protected method from superclass<br>        System.out.println(&quot;Cat meows&quot;);<br>    }<br>}</pre><p>Accessing protected Members</p><p>- Within the Same Package:</p><p>Classes in the same package can access protected members of other classes within the same package.</p><p>- From Subclasses:</p><p>Subclasses can access protected members, even if they are in a different package.</p><p>- From Non-Subclass in Different Package:</p><p>Non-subclass classes in different packages cannot access protected members.</p><p>Example Demonstration</p><pre>// File: Animal.java<br>package somePackage;<br>public class Animal {<br>    protected void makeSound() {<br>        System.out.println(&quot;Animal makes a sound&quot;);<br>    }<br>}<br>// File: Dog.java<br>package somePackage;<br>public class Dog extends Animal {<br>    public void bark() {<br>        makeSound(); // Accessing protected method from superclass<br>        System.out.println(&quot;Dog barks&quot;);<br>    }<br>}<br>// File: Cat.java<br>package anotherPackage;<br>import somePackage.Animal;<br>public class Cat extends Animal {<br>    public void meow() {<br>        makeSound(); // Accessing protected method from superclass<br>        System.out.println(&quot;Cat meows&quot;);<br>    }<br>}<br>// File: Main.java<br>package anotherPackage;<br>public class Main {<br>    public static void main(String[] args) {<br>        Dog dog = new Dog();<br>        dog.bark(); // Works fine<br>        Cat cat = new Cat();<br>        cat.meow(); // Works fine<br>    }<br>}</pre><p>Key Points</p><p>1. Encapsulation: Using protected can help maintain encapsulation while allowing subclasses to inherit and utilize superclass behavior.</p><p>2. Design Choice: protected is often used in class libraries and frameworks where you want to provide extensibility but still control how the members are accessed.</p><p>3. Avoid Overuse: While protected allows for more flexibility than private, it can lead to tighter coupling between classes. Consider the implications on design and maintainability before using it extensively.</p><p>4. Default (Package-Private)</p><p>- Definition: If no access modifier is specified, it defaults to “package-private,” meaning the class, method, or variable is accessible only within its own package.</p><p>- Use Case: When you want to restrict access to classes and methods to only those within the same package.</p><p>Example:</p><pre>class DefaultExample {<br>    void display() {<br>        System.out.println(&quot;Default method can only be accessed within the same package.&quot;);<br>    }<br>}</pre><p>Summary of Access Modifiers</p><p>2. Method Types:</p><p>Java methods can be classified into two main types:</p><p>a. Instance Methods (Non-Static Methods):</p><p>- These are declared without the static keyword and are associated with object instances.</p><p>- Instance methods work on late-binding (i.e., tied to specific instances of the class).</p><p>- Instance methods can access both instance and static members of the class directly.</p><p>- To invoke an instance method, an object of the class is required.</p><p>Example:</p><pre>class A {<br>    int a = 10;<br>    void display() {<br>        System.out.println(&quot;a: &quot; + a);<br>    }<br>}<br>public class Test {<br>    public static void main(String[] args) {<br>        A obj = new A();<br>        obj.display();  // Calls instance method &#39;display()&#39;<br>    }<br>}</pre><p>b. Static Methods:</p><p>- These are declared with the static keyword and belong to the class, not the instance.</p><p>- Static methods work on early-binding (executed when the class is loaded).</p><p>- They can only access static members of the class directly.</p><p>- A static method can be invoked using the class name or an object.</p><p>Example:</p><pre>class A {<br>    static int b = 20;<br>    static void show() {<br>        System.out.println(&quot;b: &quot; + b);<br>    }<br>}<br>public class Test {<br>    public static void main(String[] args) {<br>        A.show();  // Calls static method &#39;show()&#39;<br>    }<br>}</pre><p>3. Method Return Type:</p><p>The return type of a method indicates what type of value it will return to the caller:</p><p>- Primitive types: The method can return values like int, float, boolean, etc.</p><p>- Reference types: The method can return objects, arrays, or user-defined types.</p><p>- Void: If a method has a void return type, it does not return any value.</p><p>4. Method Invocation:</p><p>When invoking a method, you need to ensure that:</p><p>- The number of arguments matches the number of parameters.</p><p>- The types of arguments match the parameter types.</p><p>- The order of arguments corresponds to the parameter list.</p><pre>class Calculator {<br>    int add(int x, int y) {<br>        return x + y;<br>    }<br>}<br>public class Test {<br>    public static void main(String[] args) {<br>        Calculator calc = new Calculator();<br>        int result = calc.add(10, 20);  // Invokes the &#39;add&#39; method with arguments<br>        System.out.println(&quot;Result: &quot; + result);<br>    }<br>}</pre><p>5. Memory Management of Methods:</p><p>- When a method is invoked, it gets memory allocated in the stack area as a stack frame.</p><p>- The method’s stack frame is created when the method is called and released once it completes execution.</p><p>- Java stack follows the Last-In-First-Out (LIFO) principle, meaning the last method invoked will be the first to complete.</p><p>Method chaining example:</p><pre>class A {<br>    void m1() {<br>        System.out.println(&quot;m1 starts&quot;);<br>        m2();<br>        System.out.println(&quot;m1 ends&quot;);<br>    }<br>    <br>    void m2() {<br>        System.out.println(&quot;m2 starts&quot;);<br>        m3();<br>        System.out.println(&quot;m2 ends&quot;);<br>    }<br>    <br>    void m3() {<br>        System.out.println(&quot;m3 executes&quot;);<br>    }<br>}<br>public class Test {<br>    public static void main(String[] args) {<br>        A obj = new A();<br>        obj.m1();<br>    }<br>}</pre><p>Output:</p><pre>m1 starts<br>m2 starts<br>m3 executes<br>m2 ends<br>m1 ends</pre><p>6. Method Chaining:</p><p>Method chaining refers to calling multiple methods sequentially within another method, as demonstrated in the above example with m1, m2, and m3. The execution sequence depends on the order in which the methods are called.</p><p>Note:-</p><ul><li>we can access method inside method but we cannot create method inside method</li></ul><h4>main method</h4><p>In Java, the main method is the entry point of any standalone application. Its signature is:</p><pre>public static void main(String[] args)</pre><p><strong>Calling the main Method Explicitly</strong></p><p>You can indeed call the main method explicitly from another method. For example:</p><pre>public class MainExample {<br>    public static void main(String[] args) {<br>        System.out.println(&quot;Main method called&quot;);<br>    }<br>    public static void anotherMethod() {<br>        main(new String[]{&quot;arg1&quot;, &quot;arg2&quot;}); // Calling main explicitly<br>    }<br>    public static void main(String[] args) {<br>        anotherMethod();<br>    }<br>}</pre><p>In this example, calling main from anotherMethod will execute the main method again with the provided arguments.</p><p><strong>Overloading the main Method</strong></p><p>You can overload the main method by creating methods with the same name but different parameters. For example:</p><pre>public class OverloadedMain {<br>    public static void main(String[] args) {<br>        System.out.println(&quot;Main method with String[] args&quot;);<br>        main(5); // Calling the overloaded method<br>    }<br>    public static void main(int number) {<br>        System.out.println(&quot;Overloaded main method with int: &quot; + number);<br>    }<br>}</pre><p>In this case, when you run the program, it will only recognize the main method with the String[] args signature as the entry point. The overloaded main(int number) can be called from within the main method or other methods, but it won’t be invoked automatically by the Java runtime.</p><p><strong>Multiple main Methods in Different Classes</strong></p><p>If you have multiple classes each containing a main method, only the main method of the class specified when running the program will be executed. For example:</p><pre>public class FirstClass {<br>    public static void main(String[] args) {<br>        System.out.println(&quot;First Class Main&quot;);<br>    }<br>}<br>public class SecondClass {<br>    public static void main(String[] args) {<br>        System.out.println(&quot;Second Class Main&quot;);<br>    }<br>}</pre><p>When you run the program, you specify which class to execute:</p><pre>java FirstClass</pre><p>This will output:</p><pre>First Class Main</pre><p>If you run:</p><pre>java SecondClass</pre><p>You will see:</p><pre>Second Class Main</pre><p><strong>Q. Can we overload final methods ?</strong><br>A. Yes, we can overload final methods because final keyword says do not<br>change implementation and in overloading we are not changing<br>implementation rather we are changing arguments.<br><br><strong>Q. Can we overload private methods or not ?</strong><br>A. Yes, we can overload private methods because private methods are<br>accessible everywhere in same class and overloading also happens within<br>class.</p><p><strong>Q. Can we overload non static methods or not ?</strong><br>A. Yes, we can overload non static methods but to call them we have to<br>create an Object.</p><h4>Overview of the Scanner Class</h4><p>- Purpose: The Scanner class is a predefined class in Java used for reading input from various sources, such as the keyboard (System.in), files, or strings. It enables programs to accept user input at runtime, making applications interactive.</p><p><strong>Steps to Use the Scanner Class</strong></p><p>1. Importing the Scanner Class</p><p>- To use the Scanner class, you first need to import it from the `java.util` package. This can be done with one of the following statements:</p><pre>import java.util.Scanner; // Import only Scanner class</pre><p>or</p><pre>import java.util.*; // Import all classes in the java.util package</pre><p>- Package: A package is like a folder that groups related classes together. Importing is necessary to use classes defined in other packages.</p><p>2. Creating an Object of the Scanner Class</p><p>- After importing, you create an instance of the Scanner class to start reading input:</p><pre>Scanner s = new Scanner(System.in);</pre><p>- Here, `System.in` indicates that the input will be read from the standard input stream (usually the keyboard).</p><p>3. Using Scanner Class Methods</p><p>- The Scanner class provides various methods to read different types of input. Some commonly used methods include:</p><p>- `nextByte()`: Reads a byte value.</p><p>- `nextBoolean()`: Reads a boolean value (true/false).</p><p>- `nextShort()`: Reads a short integer.</p><p>- `nextInt()`: Reads an integer.</p><p>- `nextFloat()`: Reads a float value.</p><p>- `nextDouble()`: Reads a double value.</p><p>- `nextLong()`: Reads a long integer.</p><p>- `next()`: Reads a single word (string without spaces).</p><p>- `nextLine()`: Reads a whole line (string with spaces).</p><p><strong>Example Program</strong></p><p>Here’s a simple Java program using the Scanner class to collect student details:</p><pre>import java.util.Scanner;<br><br>class StdDetails {<br>    public static void main(String args[]) {<br>        Scanner s = new Scanner(System.in);<br><br>        System.out.println(&quot;Enter name: &quot;);<br>        String name = s.nextLine();<br><br>        System.out.println(&quot;Enter age: &quot;);<br>        int age = s.nextInt();<br><br>        System.out.println(&quot;Enter percentage: &quot;);<br>        float percentage = s.nextFloat();<br><br>        System.out.println(&quot;Enter result status (true/false): &quot;);<br>        boolean result = s.nextBoolean();<br><br>        System.out.println(&quot;Enter contact number: &quot;);<br>        long contact = s.nextLong();<br><br>        System.out.println(&quot;Enter Gender: &quot;);<br>        char gender = s.next().charAt(0);<br><br>        System.out.println(&quot;Student Details Entered by you are:&quot;);<br>        System.out.println(&quot;Name: &quot; + name);<br>        System.out.println(&quot;Age: &quot; + age);<br>        System.out.println(&quot;Gender: &quot; + gender);<br>        System.out.println(&quot;Contact: &quot; + contact);<br>        System.out.println(&quot;Score: &quot; + percentage);<br>        System.out.println(&quot;Result: &quot; + result);<br><br>        s.close(); // It&#39;s good practice to close the scanner<br>    }<br>}</pre><h3>Example Output</h3><p>When you run the program, it will prompt you to enter details:</p><pre>Enter name: <br>Pratik<br>Enter age: <br>27<br>Enter percentage: <br>86.80<br>Enter result status (true/false): <br>true<br>Enter contact number<br>12345678<br>Enter Gender: <br>M<br>Student Details Entered by you are:<br>Name: Pratik<br>Age: 27<br>Gender: M<br>Contact: 12345678<br>Score: 86.8<br>Result: trueCopy code</pre><h4>Important Notes</h4><ul><li><strong>InputMismatchException</strong>: If the user provides an input of a type that doesn’t match the expected type, a java.util.InputMismatchException will be thrown. For example, if you enter a float when an integer is expected:</li></ul><pre>Enter age:  44.5<br>Exception in thread &quot;main&quot; java.util.InputMismatchException</pre><ul><li><strong>No </strong><strong>nextChar() Method</strong>: There is no method named nextChar(). Instead, to get a character input, you can read a string using next() and then use charAt(index) to retrieve the desired character.</li><li>For example, if you input “Abcd”:</li></ul><pre>char gender = s.next().charAt(0); // &#39;A&#39;</pre><h4>Constructor Overview</h4><p><strong>Need of Constructor</strong><br>Non static variables plays a special role in every program i.e. non<br>static refers to muliple copies which means that for every object there<br>is a seperate memory allocated for non static variable, which means<br>programmer can intialise everytime new value to non static variable.</p><p>A constructor is a special method in Java used to initialize objects. It is distinct from normal methods due to the following properties:</p><p>1. Constructor Name: Must be the same as the class name.</p><p>2. No Return Type: A constructor cannot have a return type, not even void. If a return type is specified, it becomes a regular method.</p><p>3. Automatic Invocation: Unlike normal methods, constructors are invoked automatically when an object is created using the new keyword.</p><p>4. Parameters: Constructors can have parameters similar to methods, and these are used to initialize object properties during object creation.</p><p><strong>Key Points about Constructors:</strong></p><p>- No Explicit Invocation: Constructors are called automatically during object creation and cannot be called explicitly.</p><p>- Argument Matching: When a constructor is invoked, the number, types, and order of arguments passed must match the parameters defined in the constructor.</p><p>Example: Constructor Basics</p><pre>class LMS {<br>    public static void main(String[] args) {<br>        A a1 = new A();  // Invokes constructor A()<br>    }<br>}<br>class A {<br>    A() {  // Constructor<br>        System.out.println(&quot;Constructor in A class&quot;);<br>    }<br>    <br>    void A() {  // This is a method, not a constructor<br>        System.out.println(&quot;It is not a constructor, it is a method.&quot;);<br>    }<br>}</pre><p>Output:</p><pre>Constructor in A class</pre><p>In this example, the constructor A() is called when an object of class A is created. The method void A() is not a constructor because it has a return type (void).</p><p><strong>Constructor with Parameters</strong></p><p>⦁ One of the drawbacks of no argument constructor is, it provides<br>same value for every object.<br>⦁ Therefore to overcome this drawback, we go for parameterized<br>constructor.</p><p>Constructors can accept parameters, which are used to initialize object properties:</p><pre>class JTC {<br>    public static void main(String[] args) {<br>        Student s1 = new Student(101, &quot;Vishal&quot;, &quot;124@gmail.com&quot;, &quot;Indian&quot;);<br>        Student s2 = new Student(102, &quot;Rohan&quot;, &quot;r456@gmail.com&quot;, &quot;USA&quot;);<br>        s1.show();<br>        s2.show();<br>    }<br>}<br>class Student {<br>    int sid;<br>    String sname;<br>    String semail;<br>    static String snationality;<br>    // Constructor with parameters<br>    Student(int id, String name, String email, String nationality) {<br>        sid = id;<br>        sname = name;<br>        semail = email;<br>        snationality = nationality;<br>    }<br>    void show() {<br>        System.out.println(&quot;----Student Details----&quot;);<br>        System.out.println(&quot;sid :- &quot; + sid);<br>        System.out.println(&quot;sname :- &quot; + sname);<br>        System.out.println(&quot;semail :- &quot; + semail);<br>        System.out.println(&quot;snationality :- &quot; + snationality);<br>    }<br>}</pre><p>Here, each Student object is initialized with different values for sid, sname, and semail, but since snationality is a static variable, the last assigned value is shared across all objects.</p><p><strong>Default Constructor</strong></p><p>If no constructor is explicitly defined in a class, Java provides a default constructor that takes no parameters. However, if a parameterized constructor is defined, the default constructor is not automatically provided:</p><pre>class A {<br>    int a;<br>    void m1() {}<br>    public static void main(String[] args) {}<br>}</pre><p>Generated Default Constructor</p><pre>class A {<br>    int a;<br>    A();  // Default constructor added by compiler<br>    void m1();<br>    public static void main(String[] args);<br>}</pre><p>If a constructor is defined explicitly, the default constructor is not generated:</p><pre>class A {<br>    int a;<br>    A(int a) {}  // Explicit constructor<br>    void m1() {}<br>    public static void main(String[] args) {}<br>}</pre><p>Here, no default constructor is generated because A(int a) is explicitly defined.</p><p>Constructor Chaining</p><p>Constructor chaining occurs when one constructor calls another constructor in the same class using this():</p><pre>class JTC {<br>    public static void main(String[] args) {<br>        A a1 = new A(10, 20);  // Invokes the 2-parameter constructor<br>    }<br>}<br>class A {<br>    A() {<br>        System.out.println(&quot;No-parameter constructor in A class&quot;);<br>    }<br>    <br>    A(int a) {<br>        this();  // Calls the no-parameter constructor<br>        System.out.println(&quot;1-parameter constructor in A class&quot;);<br>    }<br>    A(int a, int b) {<br>        this(a);  // Calls the 1-parameter constructor<br>        System.out.println(&quot;2-parameter constructor in A class&quot;);<br>    }<br>}</pre><p>Output:</p><pre>No-parameter constructor in A class<br>1-parameter constructor in A class<br>2-parameter constructor in A class</pre><p>In this example:</p><p>1. The 2-parameter constructor A(int a, int b) calls the 1-parameter constructor A(int a) using this(a).</p><p>2. The 1-parameter constructor then calls the no-parameter constructor A() using this().</p><p>Rules for Constructor Chaining:</p><p>1. this() must be the first statement in the constructor.</p><p>2. Only one constructor call is allowed in each constructor.</p><p>3. Cyclic constructor calls are not allowed.</p><p>Note:-</p><p>You can declare a constructor as final or static in certain contexts, but it’s important to clarify what that means.</p><p>Final Constructor</p><p>In Java, you cannot declare a constructor as final. The final keyword is used to prevent inheritance of a class or overriding of a method, but it doesn’t apply to constructors. Constructors cannot be inherited, so making a constructor final is redundant and will result in a compilation error.</p><p>Static Constructor</p><p>Similarly, you cannot declare a constructor as static. Constructors are special methods used to initialize instances of a class and cannot be static. Static methods belong to the class itself rather than any specific instance. Since constructors are meant to create instances, they cannot be static.</p><p>Summary</p><p>- Final Constructor: Not allowed (will result in a compilation error).</p><p>- Static Constructor: Not allowed (will also result in a compilation error).</p><p>However, you can have static methods in your class (like a factory method) that can be used to create instances, and you can control access to the constructor by making it private (as in the Singleton example).</p><p>Note:-</p><p>You can declare a constructor as private in Java, and it’s actually quite common in certain design patterns like Singleton or Factory patterns. Let’s break down the concepts one by one.</p><p>1. Private Constructor in Java</p><p>A private constructor restricts the instantiation of a class from outside the class itself. This means that objects of the class cannot be created directly using the new keyword from outside the class. The main reasons for using a private constructor include:</p><p>- Singleton Pattern: Ensures that a class has only one instance and provides a global point of access to that instance.</p><p>- Factory Pattern: Controls how objects are created by using static methods to return instances.</p><p>- Utility Classes: Prevents instantiation of classes that only contain static methods (e.g., Math class in Java).</p><p>Example of a Singleton Pattern with a Private Constructor</p><pre>public class Singleton {<br>    private static Singleton instance;<br>    // Private constructor to prevent instantiation<br>    private Singleton() {}<br>    // Public method to provide access to the single instance<br>    public static Singleton getInstance() {<br>        if (instance == null) {<br>            instance = new Singleton();<br>        }<br>        return instance;<br>    }<br>}</pre><p>In this example:</p><p>- The constructor is private, so no other class can create an instance of Singleton.</p><p>- The only way to get the instance of the class is through the getInstance() method, which ensures only one instance is created.</p><p>Benefits of Using a Constructor for Initialization</p><p>Using a constructor for initializing an object’s state has several benefits:</p><p>1. Mandatory Initialization: Constructors allow you to make certain fields mandatory by requiring their values to be provided when the object is created. This prevents the object from being in an incomplete or invalid state.</p><p>2. Convenience: Initialization through constructors can be more concise and clear than using multiple setter methods.</p><p>3. Immutable Objects: If you only initialize fields through a constructor and don’t provide setters, you can create immutable objects. Immutability is a desirable property for objects in many situations, especially in multi-threaded applications.</p><p>Example of Using a Constructor for Initialization</p><pre>public class Student {<br>    private int id;<br>    private String name;<br>    // Constructor for initializing fields<br>    public Student(int id, String name) {<br>        this.id = id;<br>        this.name = name;<br>    }<br>    // Getters<br>    public int getId() {<br>        return id;<br>    }<br>    public String getName() {<br>        return name;<br>    }<br>}</pre><p>This approach ensures that both id and name must be provided when creating a Student object, making it clear what the state of the object will be.</p><p>Constructor vs. Getters and Setters for Initialization</p><p>Both constructors and getter/setter methods have their own use cases and benefits. Let’s compare them:</p><p>When to Use Constructors and When to Use Getters and Setters</p><p>- Use Constructors:</p><p>- When you need to ensure that an object is fully initialized at the time of creation.</p><p>- When you want to create immutable objects.</p><p>- When you need to initialize many fields at once.</p><p>- Use Getters and Setters:</p><p>- When you need to allow modification of fields after object creation.</p><p>- When you have optional fields that may or may not be set.</p><p>- When you need to perform specific actions or validation logic each time a field is changed.</p><p>Example Using Setters</p><pre>public class Student {<br>    private int id;<br>    private String name;<br>    // No-argument constructor<br>    public Student() {}<br>    // Setters for initialization<br>    public void setId(int id) {<br>        this.id = id;<br>    }<br>    public void setName(String name) {<br>        this.name = name;<br>    }<br>    // Getters<br>    public int getId() {<br>        return id;<br>    }<br>    public String getName() {<br>        return name;<br>    }<br>}</pre><p>This approach allows you to create a Student object and then set its fields later:</p><pre>Student student = new Student();<br>student.setId(101);<br>student.setName(&quot;John Doe&quot;);</pre><p>Which One Is Better?</p><p>- Use Constructors if you have fields that must be initialized for the object to be in a valid state. Constructors ensure that objects are created with all necessary data.</p><p>- Use Getters and Setters if you want to allow flexible object creation or if the object fields might need to be changed or updated after object creation.</p><p>In most scenarios, combining constructors with getters and setters provides a balanced approach. Use constructors to ensure required fields are initialized, and use setters for optional fields or to allow modifications after the object is created.</p><p><strong>Difference between method and constructor</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/994/1*sZvHKhw6DwYPQpKn6RllZg.png" /></figure><p><strong>Variable Arguments (Var-Args) in Java</strong></p><p>Variable Arguments, commonly known as var-args, allow methods to accept zero or more arguments of a specified type. This feature is particularly useful when you want to pass a varying number of arguments to a method. Before var-args were introduced in Java (starting with JDK 5), method overloading was necessary to handle methods with different numbers of parameters.</p><p>Key Points About Var-Args:</p><p>1. Syntax:</p><p>- The syntax of a variable argument is &lt;data_type&gt; … &lt;var_arg_name&gt;.</p><p>- Example: int… nums or String… words.</p><p>2. Internal Representation:</p><p>- Var-args are internally handled as a one-dimensional array. You can use array-style access to manipulate the arguments.</p><p>3. Order of Storage:</p><p>- Arguments are stored in the order in which they are passed.</p><p>4. Number of Arguments:</p><p>- You can pass any number of arguments, or even no arguments at all, and the method will still work. However, the arguments must be of the correct data type.</p><p>5. Restrictions:</p><p>- Positioning: The var-args parameter must always be the last in the parameter list. You cannot define another parameter after a var-args parameter.</p><p>- One Var-Args per Method: You can only have one var-args parameter in a method.</p><p>Example of Var-Args:</p><pre>class JTC {<br>    public static void main(String[] args) {<br>        A obj = new A();<br>        obj.m1();  // No argument<br>        obj.m1(10);  // One argument<br>        obj.m1(10, 20);  // Two arguments<br>        obj.m1(10, 20, 30, 40);  // Multiple arguments<br>    }<br>}<br>class A {<br>    void m1(int... a) {<br>        System.out.println(&quot;m1(int... a) called.&quot;);<br>        for (int i = 0; i &lt; a.length; i++) {<br>            System.out.println(&quot;Index: &quot; + i + &quot; Value: &quot; + a[i]);<br>        }<br>    }<br>}</pre><p>Output:</p><pre>m1(int… a) called.<br>m1(int… a) called.<br>Index: 0 Value: 10<br>m1(int… a) called.<br>Index: 0 Value: 10<br>Index: 1 Value: 20<br>m1(int… a) called.<br>Index: 0 Value: 10<br>Index: 1 Value: 20<br>Index: 2 Value: 30<br>Index: 3 Value: 40</pre><p>Combining Var-Args with Regular Parameters:</p><p>You can combine regular parameters and var-args in a method, but remember the var-args must always be the last parameter:</p><pre>void m1(String s, int... nums) {<br>    System.out.println(&quot;String: &quot; + s);<br>    for (int i = 0; i &lt; nums.length; i++) {<br>        System.out.println(&quot;Index: &quot; + i + &quot; Value: &quot; + nums[i]);<br>    }<br>}</pre><h4>this Keyword in Java</h4><p>The this keyword is a reference to the current object, the instance on which a method or constructor is being invoked. It is primarily used to distinguish between instance variables and parameters when they have the same names.</p><p>Key Characteristics of this:</p><p>1. Final Reference Variable: It is a final reference variable, meaning it always refers to the current object, and you cannot change its reference.</p><p>2. Usage:</p><p>- this can be used to access instance variables.</p><p>- It can also be used to call constructors from other constructors within the same class (constructor chaining).</p><p>3. Restrictions:</p><p>- this cannot be used in static methods or static contexts because static methods are class-level methods and do not have a reference to any instance.</p><p>Example Using this:</p><pre>class Student {<br>    int sid;<br>    String sname;<br>    String scity;<br>    Student(int sid, String sname, String scity) {<br>        this.sid = sid;<br>        this.sname = sname;<br>        this.scity = scity;<br>    }<br>    void show() {<br>        System.out.println(&quot;Sid: &quot; + sid);<br>        System.out.println(&quot;Sname: &quot; + sname);<br>        System.out.println(&quot;Scity: &quot; + scity);<br>    }<br>}<br>class JTC {<br>    public static void main(String[] args) {<br>        Student s1 = new Student(101, &quot;Vivek&quot;, &quot;Noida&quot;);<br>        s1.show();<br>    }<br>}</pre><p>Output:</p><pre>Sid: 101<br>Sname: Vivek<br>Scity: Noida</pre><p>In this example, this.sid = sid; ensures that the constructor parameter sid assigns its value to the instance variable sid.</p><p>Common Misconception:</p><p>If you do not use this in the constructor, like in the example below, the values won’t be assigned to the instance variables:</p><pre>Student(int sid, String sname, String scity) {<br>    sid = sid;<br>    sname = sname;<br>    scity = scity;<br>}</pre><p>This will result in the default values being printed (0 for integers and null for Strings) because the local variables (parameters) are being assigned to themselves, and the instance variables remain uninitialized.</p><p><strong>Components of Object-Oriented Programming (OOP)</strong></p><p>Object-Oriented Programming (OOP) is a programming paradigm that uses “objects” to design applications and software. It provides a clear modular structure, making it easier to understand, debug, and modify code. The four core principles of OOP are Encapsulation, Abstraction, Inheritance, and Polymorphism. Let’s go through each of these components in detail.</p><p><strong>1. Encapsulation</strong></p><p>Encapsulation is the concept of bundling data (variables) and methods (functions) that operate on the data into a single unit called an object. It restricts direct access to some of the object’s components, which is known as data hiding. Encapsulation helps in maintaining data integrity and makes code more modular.</p><p>- Example: If you have a Car object, the data (attributes like speed, fuel) and methods (like accelerate(), brake()) are bundled together within that object.</p><p>Key Concepts:</p><p>- Access Modifiers: Encapsulation often involves using access modifiers (such as private, public, and protected) to control access to the data.</p><p>- Getter and Setter Methods: These are used to access and modify private variables in a controlled way.</p><pre>class Car {<br>    private int speed; // Encapsulated data (private variable)<br>    // Getter method<br>    public int getSpeed() {<br>        return speed;<br>    }<br>    // Setter method<br>    public void setSpeed(int speed) {<br>        this.speed = speed;<br>    }<br>}</pre><p>2. Abstraction</p><p>Abstraction is the concept of hiding the complex implementation details of a system and exposing only the necessary and relevant parts to the user. It reduces complexity by allowing the user to interact with an interface without knowing its underlying implementation.</p><p>- Example: When you drive a car, you only need to know how to use the steering wheel, accelerator, and brake. You don’t need to understand how the engine or brake system works internally.</p><p>Key Concepts:</p><p>- Abstract Classes and Interfaces: In Java, abstraction is implemented using abstract classes and interfaces.</p><p>- Abstract methods in an abstract class have no body and must be implemented by subclasses.</p><pre>abstract class Vehicle {<br>    abstract void start(); // Abstract method<br>}<br>class Car extends Vehicle {<br>    void start() {<br>        System.out.println(&quot;Car starts with a key.&quot;);<br>    }<br>}</pre><p>3. Inheritance</p><p>Inheritance is a mechanism that allows one class to inherit properties (fields and methods) from another class. The class that is inherited from is called the parent or superclass, and the class that inherits is called the child or subclass. Inheritance promotes code reusability.</p><p>4. Polymorphism</p><p>Polymorphism is the ability of an object to take on multiple forms. It allows methods to do different things based on the object it is acting upon, even if they share the same name. Polymorphism is achieved in two ways: Method Overloading and Method Overriding.</p><p>Types of Polymorphism:</p><p>1. Compile-time Polymorphism (Method Overloading): Multiple methods have the same name but different parameters. The method to be called is determined at compile time.</p><pre>class Calculator {<br>    int add(int a, int b) {<br>        return a + b;<br>    }<br>    double add(double a, double b) {<br>        return a + b;<br>    }<br>}</pre><p>2. Runtime Polymorphism (Method Overriding): A subclass provides a specific implementation of a method that is already defined in its superclass. The method to be called is determined at runtime.</p><pre>class Animal {<br>    void makeSound() {<br>        System.out.println(&quot;Animal makes a sound&quot;);<br>    }<br>}<br>class Dog extends Animal {<br>    @Override<br>    void makeSound() {<br>        System.out.println(&quot;Dog barks&quot;);<br>    }<br>}<br>public class Main {<br>    public static void main(String[] args) {<br>        Animal myAnimal = new Dog();<br>        myAnimal.makeSound(); // Outputs: Dog barks<br>    }<br>}</pre><p>Summary of OOP Components</p><p>Benefits of OOP</p><p>1. Reusability: Code can be reused through inheritance.</p><p>2. Modularity: Each object can function as an independent entity.</p><p>3. Scalability: Easier to manage and scale large software systems.</p><p>4. Maintainability: Easy to update and modify code with minimal impact on other parts of the program.</p><p>These four principles form the foundation of Object-Oriented Programming and make it a powerful tool for designing software systems that are more structured, scalable, and easier to understand.</p><h4>Understanding Object Creation in Java</h4><p>When you create an object of a class in Java, several key processes occur regarding memory allocation, variable initialization, and the execution of various blocks and constructors. Here’s a breakdown of what happens step by step, including both static and instance variables, as well as static and instance initializer blocks.</p><p>1. Class Loading</p><p>When the class is referenced for the first time (e.g., when an object is created), the Java Virtual Machine (JVM) loads the class into memory. During this process:</p><p>- Memory Allocation for Static Variables: Memory is allocated in the method area (also called the static area) for all static variables. Each static variable is associated with the class itself rather than any instance.</p><p>- Static Block Execution: Any static blocks in the class are executed in the order they appear. This is where you can perform static initialization.</p><p>2. Memory Allocation for the Object</p><p>When you create an object using the new keyword (e.g., MyClass obj = new MyClass();):</p><p>- Memory Allocation on the Heap: Memory is allocated for the new object on the heap. This memory will hold the instance variables declared in the class.</p><p>3. Initialization of Instance Variables</p><p>Once memory is allocated for the object:</p><p>- Default Initialization: All instance variables of the object are initialized to their default values:</p><p>- Numeric types (e.g., int, double) are initialized to 0.</p><p>- boolean types are initialized to false.</p><p>- Object references are initialized to null.</p><p>4. Execution of Instance Initializer Blocks</p><p>If there are any instance initializer blocks in the class, they are executed in the order they appear, immediately after the default initialization of instance variables.</p><p>5. Execution of the Constructor</p><p>After all instance initializer blocks have been executed, the constructor is called. The constructor can perform further initialization, including setting values for instance variables based on parameters passed to it.</p><p>6. Finalization of Object Creation</p><p>Once the constructor has completed its execution, the object is fully constructed, and a reference to the newly created object is returned. You can then use this reference to interact with the object.</p><p>Memory Layout Overview</p><p>1. Static Variables:</p><p>- Location: Method area (static area of the heap).</p><p>- Initialization: Allocated and initialized when the class is loaded.</p><p>2. Instance Variables:</p><p>- Location: Heap (allocated when an object is created).</p><p>- Initialization: Initialized to default values, then possibly modified by initializer blocks or constructors.</p><p>Complete Example</p><p>Here’s a complete example that includes static variables, static blocks, instance variables, instance initializer blocks, and constructors:</p><pre>public class Example {<br>    static int staticVar; // Static variable<br>    static {<br>        staticVar = 20; // Static block initializing static variable<br>        System.out.println(&quot;Static block executed: staticVar = &quot; + staticVar);<br>    }<br>    int instanceVar; // Instance variable<br>    // Instance initializer block<br>    {<br>        instanceVar = 10; // Initializing instance variable<br>        System.out.println(&quot;Instance initializer block executed: instanceVar = &quot; + instanceVar);<br>    }<br>    // Constructor<br>    public Example(int value) {<br>        this.instanceVar = value; // Initializing instance variable with constructor parameter<br>        System.out.println(&quot;Constructor executed: instanceVar = &quot; + instanceVar);<br>    }<br>    public static void main(String[] args) {<br>        Example obj1 = new Example(30);<br>        System.out.println(&quot;obj1: staticVar = &quot; + Example.staticVar + &quot;, instanceVar = &quot; + obj1.instanceVar);<br>        Example obj2 = new Example(40);<br>        System.out.println(&quot;obj2: staticVar = &quot; + Example.staticVar + &quot;, instanceVar = &quot; + obj2.instanceVar);<br>    }<br>}</pre><p>Expected Output</p><pre>Static block executed: staticVar = 20<br>Instance initializer block executed: instanceVar = 10<br>Constructor executed: instanceVar = 30<br>obj1: staticVar = 20, instanceVar = 30<br>Instance initializer block executed: instanceVar = 10<br>Constructor executed: instanceVar = 40<br>obj2: staticVar = 20, instanceVar = 40</pre><p>Explanation of Output</p><p>1. Static Block Execution: The static block executes first when the class Example is loaded, initializing staticVar to 20.</p><p>2. First Object Creation (obj1):</p><p>- The instance initializer block executes, initializing instanceVar to 10.</p><p>- The constructor is called with the argument 30, setting instanceVar to 30.</p><p>- The values of staticVar and instanceVar are printed.</p><p>3. Second Object Creation (obj2):</p><p>- The instance initializer block executes again, initializing instanceVar to 10 (as part of the new object creation).</p><p>- The constructor is called with the argument 40, setting instanceVar to 40.</p><p>- The values are printed again.</p><p>Summary</p><p>- Static Variables: Shared across all instances of a class, stored in the method area, and initialized when the class is loaded.</p><p>- Static Blocks: Used for static initialization, executed when the class is loaded.</p><p>- Instance Variables: Unique to each instance, initialized when an object is created.</p><p>- Instance Initializer Blocks: Executed after default initialization of instance variables and before the constructor.</p><p>- Constructors: Called to further initialize an object after the instance initializer blocks.</p><p>Note:-1) Constructor cannot be defined under local context.</p><p>2) When accessing static variables in Java, the initialization behavior varies based on how the static variables are defined:</p><ol><li>Static Variable with Static Block:<br> — If you declare a static variable (like b) and initialize it in a static block, that block is executed when the class is loaded. Therefore, if you access b using the class name, the static block will be processed first.</li></ol><pre>class Example {<br> static int a = 10;<br> static int b;<br> static {<br> b = 20; // Static block is executed when the class is loaded<br> }<br> }</pre><p>2. Static Final Variable at Declaration:<br> — If you declare a static final variable (like c) and initialize it at the time of declaration, its value is available immediately, and there’s no need for a static block. Therefore, when you access c, it directly provides the initialized value without processing any static block.</p><pre>class Example {<br> static final int c = 30; // Initialized at declaration<br> }</pre><h4>Execution Process Overview</h4><p>When you execute a Java program, the Java Virtual Machine (JVM) creates two main memory areas:</p><p>1. Stack Area (Execution Area)</p><p>2. Heap Area (Storage Area)</p><p>These areas play crucial roles in managing memory for static and non-static members, method calls, and variable storage.</p><p><strong>Detailed Execution Steps</strong></p><p>1. JVM Enters the Stack Area</p><p>- The JVM starts by entering the stack area to manage method calls and local variables.</p><p>2. Class Loader Invocation</p><p>- The JVM calls the class loader, a special function responsible for loading classes into memory.</p><p>- Its main job is to load all static members of the class into the Static Pool Area (SPA).</p><p>3. Static Pool Area (SPA)</p><p>- SPA is a part of the heap area where all static variables and static methods are stored.</p><p>- The class loader loads the static members and prepares them for use.</p><p>4. Class Loader Completes Its Job</p><p>- After loading all static members, the class loader exits the stack area, as its task is complete.</p><p>5. JVM Calls the `main` Method</p><p>- The JVM locates the `main` method, which serves as the entry point of the program, and loads it into the stack area.</p><p>6. Method Area in the Stack</p><p>- When a method is called, it is placed in the stack area under the method area. The method’s local variables and parameters will be stored here.</p><p>7. Execution of `main` Method Begins</p><p>- The execution of the `main` method starts. This is where the program’s logic is processed.</p><p>8. Completion of `main` Method Execution</p><p>- Once all statements in the `main` method are executed, it exits the stack area, indicating that the method’s execution is complete.</p><p>9. Garbage Collection Call</p><p>- Before the JVM exits the stack area, it invokes the garbage collector. The garbage collector’s role is to clean up any unused memory, preparing for the next execution.</p><p><strong>Important Memory Management Points</strong></p><p>1. Static Members Availability</p><p>- Static methods and static variables are loaded into the SPA before execution begins, making them accessible without needing to create an object.</p><p>2. Non-Static Members Accessibility</p><p>- Non-static members (variables and methods) are not available until an object is created. You must use the `new` keyword to instantiate an object, which loads non-static members into memory.</p><p>3. Loading of Non-Static Members</p><p>- Non-static variables and methods are stored together in the object created. This is why non-static methods can access non-static variables directly, as they belong to the same instance.</p><p>4. Single Copy of Static Members</p><p>- Static members are loaded only once in the SPA, which is why they are referred to as single copies.</p><p>5. Multiple Copies of Non-Static Members</p><p>- Non-static members are loaded each time an object is created, resulting in multiple copies of these members across different instances.</p><p>6. Local vs. Global Variables</p><p>- Local variables (e.g., method parameters) reside in the stack area, while global variables (like static and instance variables) are stored in the heap area.</p><p>7. Location of Static and Non-Static Variables</p><p>- Static variables are stored in the SPA within the heap, whereas non-static variables are part of the object in the heap.</p><p>8. Reference Variables as Local Variables</p><p>- All reference variables (pointers to objects) are considered local variables and reside in the stack area.</p><p>9. Scope of Local Variables</p><p>- Local variables exist only during the execution of a method. Once the method completes, the local variables are removed from the stack, hence their scope is limited to the method itself.</p><h4>Volatile modifier in Java</h4><p>The volatile modifier in Java is used to ensure visibility and ordering of variables across multiple threads in a multi-threaded environment. When you declare a variable as volatile, you are telling the Java Virtual Machine (JVM) that this variable’s value may be modified by different threads and that any changes made to it should be visible to all other threads immediately.</p><p>Key Characteristics of volatile Modifier</p><p>1. Visibility:</p><p>- Normally, each thread in Java has its own local cache of variables. When one thread updates a variable, other threads might not see this change immediately.</p><p>- A volatile variable ensures that the value is always read from the main memory, not from a thread’s local cache. This means any update to a volatile variable by one thread is immediately visible to all other threads.</p><p>2. Ordering:</p><p>- The volatile keyword ensures that read and write operations on the variable are performed in order. It prevents the reordering of instructions by the compiler or the processor, which can sometimes occur to optimize performance.</p><p>Use Cases for volatile</p><p>1. Flags:</p><p>- One of the most common use cases for volatile is for flags or status indicators that are checked and modified by multiple threads.</p><pre>public class VolatileExample {<br>    private volatile boolean running = true;<br>    public void runTask() {<br>        while (running) {<br>            // Do some work<br>        }<br>    }<br>    public void stop() {<br>        running = false; // This change will be visible to the runTask() method<br>    }<br>}</pre><p>2. Double-Checked Locking Singleton:</p><p>- volatile is used in the implementation of the Singleton pattern to prevent the reordering of instructions.</p><pre>public class Singleton {<br>    private static volatile Singleton instance;<br>    private Singleton() {}<br>    public static Singleton getInstance() {<br>        if (instance == null) {<br>            synchronized (Singleton.class) {<br>                if (instance == null) {<br>                    instance = new Singleton(); // Prevents reordering issues<br>                }<br>            }<br>        }<br>        return instance;<br>    }<br>}</pre><p>Important Points to Remember</p><p>1. Atomicity:</p><p>- volatile does not guarantee atomicity of operations. For example, incrementing a volatile variable is not atomic.</p><pre>volatile int count = 0;<br>count++; // This operation is not atomic</pre><p>For atomic operations, you should use classes like AtomicInteger from the java.util.concurrent.atomic package.</p><p>2. Volatile vs. Synchronized:</p><p>- volatile ensures visibility of changes to variables across threads, while synchronized provides both visibility and mutual exclusion.</p><p>- synchronized blocks or methods are more expensive in terms of performance compared to using volatile.</p><p>- If you only need visibility without locking, use volatile. If you need atomicity and thread safety, use synchronized.</p><p>3. When to Use volatile:</p><p>- Use volatile when:</p><p>- You have a single variable being accessed and modified by multiple threads.</p><p>- The variable does not depend on its previous value (no compound actions like count++).</p><p>- You do not need to perform complex operations on the variable that require locking.</p><p>Example of Using volatile</p><pre>public class VolatileExample {<br>    private volatile boolean flag = true;<br>    public void printMessage() {<br>        while (flag) {<br>            System.out.println(&quot;Running...&quot;);<br>        }<br>    }<br>    public void stopPrinting() {<br>        flag = false; // This change will be visible to the printMessage method immediately<br>    }<br>    public static void main(String[] args) {<br>        VolatileExample example = new VolatileExample();<br>        new Thread(example::printMessage).start();<br>        try {<br>            Thread.sleep(1000); // Let the thread run for a second<br>        } catch (InterruptedException e) {<br>            e.printStackTrace();<br>        }<br>        example.stopPrinting(); // Stops the running thread<br>    }<br>}</pre><p>In this example:</p><p>- The flag variable is marked as volatile.</p><p>- The changes to the flag variable in the stopPrinting() method are immediately visible to the printMessage() method.</p><p>Summary</p><p>- volatile ensures that updates to a variable are immediately visible to other threads and prevents reordering of instructions.</p><p>- It does not provide atomicity, so it should be used when only visibility is required.</p><p>- It’s suitable for simple flags or status variables but not for complex operations that require synchronization.</p><p>Using the volatile keyword correctly can help in designing efficient multi-threaded applications without unnecessary synchronization overhead.</p><h4>Inheritance</h4><p>Inheritance is a key concept in object-oriented programming (OOP) that allows the creation of a new class using the properties and methods of an existing class. It helps in code reusability and the establishment of relationships between different classes. Below, let’s go through the details of inheritance concepts, its types, and some examples.</p><p><strong>Inheritance Overview</strong></p><p>- Definition: Inheritance allows a new class (called a derived class, child class, or subclass) to acquire properties and behavior from an existing class (called a base class, parent class, or superclass).</p><p>- Purpose: It is used to establish relationships between categories based on the logic of your application. It helps in reusing existing code, making software development more efficient.</p><p>- How It Works: In most programming languages like Java, inheritance is implemented using the extends keyword. This keyword indicates that a class is inheriting the features of another class.</p><p><strong>Terminology</strong></p><p>- Superclass (Parent Class / Base Class): The class whose properties and methods are inherited by another class.</p><p>- Subclass (Child Class / Derived Class): The class that inherits properties and methods from another class.</p><p><strong>Important Notes on Inheritance</strong></p><p>- The subclass contains all the functionalities of its superclass.</p><p>- The subclass can access all non-private members of the superclass.</p><p>- Private members of a superclass are not directly accessible from the subclass.</p><h4>Types of Inheritance</h4><p>1.Single Level<br>2.Multi Level<br>3.Hierarchical<br>4.Multiple<br>5.Hybrid</p><p>1. Single Inheritance</p><p>- A subclass inherits from one superclass.</p><p>Example:</p><pre>class A {<br>    int a = 10;<br>}<br>class B extends A {<br>    void display() {<br>        System.out.println(&quot;Value of a: &quot; + a);<br>    }<br>}<br>public class Test {<br>    public static void main(String[] args) {<br>        B obj = new B();<br>        obj.display();  // Output: Value of a: 10<br>    }<br>}</pre><p>- In this example, class B inherits the properties of class A.</p><p>2. Multiple Inheritance</p><p>- A class inherits from more than one class at the same time.</p><p>- Note: Java does not support multiple inheritance with classes to avoid ambiguity problems, but it can be achieved using interfaces.</p><p>- Example (Ambiguity Problem):</p><pre>class A { int a = 10; }<br>class B { int a = 20; }<br>// class C extends A, B { } // This is not allowed in Java</pre><p>3. Multi-Level Inheritance</p><p>- A class is derived from another class, which is also derived from another class.</p><p>- Example:</p><pre>class A {<br>    int a = 10;<br>}<br>class B extends A {<br>    int b = 20;<br>}<br>class C extends B {<br>    int c = 30;<br>}<br>public class Test {<br>    public static void main(String[] args) {<br>        C obj = new C();<br>        System.out.println(&quot;a: &quot; + obj.a + &quot;, b: &quot; + obj.b + &quot;, c: &quot; + obj.c);<br>        // Output: a: 10, b: 20, c: 30<br>    }<br>}</pre><p>4. Hierarchical Inheritance</p><p>- More than one class inherits from the same base class.</p><p>- Example:</p><pre>class A {<br>    int a = 10;<br>}<br>class B extends A {<br>    int b = 20;<br>}<br>class C extends A {<br>    int c = 30;<br>}<br>public class Test {<br>    public static void main(String[] args) {<br>        B objB = new B();<br>        C objC = new C();<br>        System.out.println(&quot;B: a = &quot; + objB.a + &quot;, b = &quot; + objB.b);<br>        System.out.println(&quot;C: a = &quot; + objC.a + &quot;, c = &quot; + objC.c);<br>        // Output:<br>        // B: a = 10, b = 20<br>        // C: a = 10, c = 30<br>    }<br>}</pre><p>5. Hybrid Inheritance</p><p>- It is a combination of two or more types of inheritance (e.g., multi-level and hierarchical).</p><p>- Java does not directly support hybrid inheritance using classes to avoid complexity but supports it using interfaces.</p><p>6. Cyclic Inheritance</p><p>- In cyclic inheritance, a class is inherited from itself or two classes extend each other, which is not allowed.</p><p>- Example:</p><pre>class A extends A { } // Not allowed<br>class B extends C { }<br>class C extends B { }</pre><p><strong>Understanding the super Keyword</strong></p><p>- Purpose: The super keyword is used to access members (variables and methods) of the superclass.</p><p>- Usage: It can be used to call the superclass’s constructor and to differentiate between superclass and subclass members if they have the same name.</p><p>Accessing Superclass Methods</p><p>You can use super to call methods defined in the superclass. This is especially useful if the subclass overrides a method and you still want to access the original method from the superclass.</p><pre>class Parent {<br>    void display() {<br>        System.out.println(&quot;Display from Parent&quot;);<br>    }<br>}<br>class Child extends Parent {<br>    void display() {<br>        super.display(); // Calls the Parent&#39;s display method<br>        System.out.println(&quot;Display from Child&quot;);<br>    }<br>}</pre><p>2. Accessing Superclass Constructors</p><p>You can use super() to call a constructor from the superclass. This must be the first statement in the subclass constructor. If you don’t explicitly call a superclass constructor, Java will automatically call the no-argument constructor of the superclass.</p><pre>class Parent {<br>    Parent(int value) {<br>        System.out.println(&quot;Parent Constructor: &quot; + value);<br>    }<br>}<br>class Child extends Parent {<br>    Child(int value) {<br>        super(value); // Calls Parent&#39;s constructor with an argument<br>        System.out.println(&quot;Child Constructor&quot;);<br>    }<br>}</pre><p>3. Accessing Superclass Fields</p><p>You can use super to access fields (variables) of the superclass, especially if they are shadowed by fields in the subclass.</p><pre>class Parent {<br>    int number = 10;<br>}<br>class Child extends Parent {<br>    int number = 20;<br>    void display() {<br>        System.out.println(&quot;Child number: &quot; + number);      // Prints 20<br>        System.out.println(&quot;Parent number: &quot; + super.number); // Prints 10<br>    }<br>}</pre><p>Summary</p><p>- super(): Calls a superclass constructor.</p><p>- super.methodName(): Calls a method from the superclass.</p><p>- super.fieldName: Accesses a field from the superclass.</p><p>Using super allows you to build upon the functionality of a parent class while still leveraging its existing methods and properties.</p><p><strong>Constructors and the super() Statement</strong></p><p>- If a constructor is not explicitly defined in the subclass, Java automatically calls the superclass’s no-argument constructor using super().</p><p>- The super() statement must always be the first line in the subclass constructor.</p><p>- If the superclass does not have a no-argument constructor, you must explicitly call the appropriate superclass constructor.</p><p><strong>Question. Can we inherit constructor?</strong></p><p>No we cannot inherit constructors because they are not member of a<br>class(members of classs are methods and variables) and constructors<br>are mainly used for intialistion of Non‐static variable.<br>Constructors cannot be inherited but they can be invoked by using<br>call to super.</p><h4>Note:-</h4><p><strong>Object Class in Java</strong><br> In Java, every class implicitly extends the java.lang.Object class, making it the root of the class hierarchy. When you extend a class, most of its members (methods and variables) are inherited, except for:<br> — private members: These are not accessible in the subclass.<br> — local members: These are not inherited because they are confined to the method where they are defined.<br> — final classes: A class declared as final cannot be inherited.</p><p><strong>Using super in Static Context</strong><br> — The super keyword is used to refer to the superclass and can only be used in instance contexts. You cannot use super in a static context (e.g., inside a static method or static block).<br> — Additionally, you cannot write super.super.variable, as Java does not support multi-level access to superclasses in this manner.</p><p>Thus,</p><p>We can inherit public,protected and default methods.<br>2. We cannot inherit private method because they are accessible only<br>within class.<br>3. We can inherit non static, final and abstract methods.<br>4. We cannot inherit static methds because they will be loaded only once<br>in SPA.<br>5. We cannot inherit constructors because they are mainly used for<br>initialisation and they are not member of class.</p><p><strong>Interview question: Tell me in ur Project where you used inheritance ??</strong></p><p><strong>Constructor Invocation Order in Multi-Level Inheritance</strong><br> In a multi-level inheritance scenario, the order of constructor invocation is from the top-most superclass to the subclass. For example:</p><pre>class A {<br>    A() {<br>        System.out.println(&quot;Constructor of A&quot;);<br>    }<br>}<br>class B extends A {<br>    B() {<br>        System.out.println(&quot;Constructor of B&quot;);<br>    }<br>}<br>class C extends B {<br>    C() {<br>        System.out.println(&quot;Constructor of C&quot;);<br>    }<br>}</pre><p>When you create an object of class C, the output will be:<br> Constructor of A<br> Constructor of B<br> Constructor of C<br> This shows that the constructors are invoked in the order of inheritance.</p><p><strong>Default Constructor Behavior<br> </strong>When you create an object of class Hello, the JVM checks for the presence of a default constructor. If none is found, it inserts a default constructor that includes a super() call to invoke the superclass’s default constructor. If the superclass does not have a default constructor and only has parameterized constructors, the JVM cannot provide an implicit call to the superclass constructor, resulting in a compilation error.</p><p><strong>Declaring a Class as Private</strong><br> In Java, top-level classes cannot be declared as private. However, you can declare inner classes as private. A private inner class is only accessible within its enclosing class.</p><p><strong>Difference Between super and this</strong><br> — super:<br> — Refers to the superclass of the current object.<br> — Used to access superclass methods and constructors.<br> <br> — this:<br> — Refers to the current object.<br> — Used to access instance variables and methods of the current class.</p><p>S-A Relationship (is-a relationship): This represents inheritance in Java. If class B extends class A, then B is a type of A. For example, Dog is an Animal.</p><ul><li>Coupling: Refers to the degree of interdependence between software modules. Low coupling is desirable as it allows modules to be understood and modified independently.</li><li>Aggregation: A form of association representing a “whole-part” relationship where the part can exist independently of the whole. For example, a Library has Books, but books can exist without the library.</li></ul><h4>Polymorphism</h4><p>Polymorphism in Java allows objects to be treated as instances of their parent class, making code more flexible and easier to maintain. The concept has two primary forms:</p><p>1. Compile-Time Polymorphism (Static Polymorphism)</p><p>2. Run-Time Polymorphism (Dynamic Polymorphism)</p><ol><li>Compile-Time Polymorphism (Static Polymorphism)</li></ol><p><strong>Technical definition :</strong><br>a. The process of resolving call to overloaded method during compile<br>time depending on type of arguments is called compile time<br>polymorphism.<br>b. It is also called as static polymorphism or compile time binding.</p><p><strong>1. Compile time binding :</strong><br><br>• The process of connecting method signature with method implementation during compile time is called as compile time binding.<br>• Since, binding is happening before execution it is called as Early<br>binding.<br>• All static and final methods will get binded during compile time<br>i.e,during compilation only method will come to know what is its<br>implementation.</p><p>Compile-time polymorphism is achieved using method overloading, where multiple methods share the same name but differ in their parameter lists.</p><p>Key points about Method Overloading:</p><p>- Method name: Must be the same for all overloaded methods.</p><p>- Parameters: Must differ in type, number, or order.</p><p>- Return type and access modifier: Can be different but do not affect overloading.</p><p>Example</p><pre>class A {<br>    void m1() {<br>        System.out.println(&quot;m1() in A class&quot;);<br>    }<br>    int m1(int a) {<br>        System.out.println(&quot;m1(int) in A class&quot;);<br>        return a;<br>    }<br>    public void m1(byte b) {<br>        System.out.println(&quot;m1(byte) in A class&quot;);<br>    }<br>}</pre><p>Here, the m1 method is overloaded with different parameter types. The compiler decides which method to call based on the argument types during method invocation.</p><p>2. Runtime Polymorphism (Dynamic Polymorphism)</p><p><strong>Technical definition :</strong><br>a. The process of resolving call to overridden method during run time<br>depending on type of object we create is called run time polymorphism.<br>b. It is also called dynamic binding or dynamic polymorphism.</p><p>Run time binding / Dynamic Binding:<br>• The process of connecting method signature with method implementation<br>during execution time is called as run time binding.<br>• Since binding is happening during execution it is called as Late<br>binding.<br>• All Non static and abstract methods will get binded during run time<br>i.e, until program will reason Non static and abstarct method can be<br>overridden.</p><p>Runtime polymorphism is achieved through method overriding and dynamic method dispatch.</p><p><strong>Method Overriding</strong></p><p>During Inheritance subclass has complete previlege to change the<br>(method)implementation of super class, this process is known as Method<br>Overriding.</p><p><strong>Q. Why do we go for Overriding ??</strong><br>A. When subclass want the properties of super class but does not want the<br>implementation of it. In such case, sub class can change implementation<br>by means of Overriding.</p><p>Key points about Method Overriding:</p><p>- The method in the subclass must have the same name, return type, and parameters as in the superclass.</p><p>- The access modifier of the overridden method must be the same or less restrictive than the superclass method.</p><p>In Java, the rules for overriding methods are as follows:</p><p>1. Private Methods:<br> — Cannot be overridden: Private methods are not visible to subclasses, so they cannot be overridden. They can be redefined in a subclass, but this is not overriding; it’s method hiding.</p><p>2. Static Methods:<br> — Cannot be overridden: Static methods are associated with the class rather than instances of the class. They can be redefined in a subclass (method hiding), but this does not constitute overriding. The static method of the superclass is not replaced by the subclass’s static method when called on an instance of the superclass.</p><p>3. Final Methods:<br> — Cannot be overridden: Final methods are declared with the final keyword, which prevents them from being overridden in subclasses. This is intended to maintain specific behavior in the superclass.</p><p>Summary:<br> — Private methods: Cannot be overridden (only redefined).<br> — Static methods: Cannot be overridden (only hidden).<br> — Final methods: Cannot be overridden.</p><p>These rules ensure encapsulation and control over method behavior in inheritance.</p><p>Dynamic Method Dispatch</p><p>Dynamic dispatch allows a superclass reference to refer to a subclass object, enabling the overridden method in the subclass to be called at runtime.</p><p>Example</p><pre>class A {<br>    void m1() {<br>        System.out.println(&quot;m1 in A class&quot;);<br>    }<br>}<br>class B extends A {<br>    @Override<br>    void m1() {<br>        System.out.println(&quot;m1 in B class&quot;);<br>    }<br>}<br>public class JTC {<br>    public static void main(String[] args) {<br>        A a = new B(); // Superclass reference to subclass object<br>        a.m1(); // Calls the overridden method in class B<br>    }<br>}</pre><p>Output:</p><pre>m1 in B class</pre><p>This code demonstrates how the method m1 from the subclass B is called even though the reference is of type A. This behavior is determined at runtime.</p><p>1. Dynamic Dispatch refers to the process of determining which method to execute at runtime based on the object’s actual type rather than the type of the reference variable.</p><p>2. Class Relationships:<br> — Superclass (A): A general class.<br> — Subclass (B): A specialized class that extends the superclass.</p><p>Code Examples Explained</p><p>1. Object Creation:<br> — A a1 = new A(); // ok <br> This is straightforward as you are creating an instance of A and assigning it to a reference of type A.</p><p>- B b1 = new B(); // ok <br> Similarly, this is valid because you are creating an instance of B, which is a subclass of A, and assigning it to a reference of type B.</p><p>2. Upcasting:<br> — A a2 = new B(); // ok <br> This is an example of upcasting. You can assign a subclass object (B) to a superclass reference (A). This is valid because a B is an A.</p><p>3. Downcasting:<br> — B b2 = new A(); // not ok <br> This is invalid because you cannot assign a superclass object to a subclass reference. A does not guarantee that it is a B.</p><p>Additional Class Examples</p><pre>// Superclass<br>class Hello {<br>    // Method in the superclass<br>    public void greet() {<br>        System.out.println(&quot;Hello from the Hello class!&quot;);<br>    }<br>}<br><br>// Subclass<br>class Hai extends Hello {<br>    // Method in the subclass<br>    public void greet() {<br>        System.out.println(&quot;Hello from the Hai class!&quot;);<br>    }<br><br>    // Additional method in the subclass<br>    public void sayHai() {<br>        System.out.println(&quot;Hai from the Hai class!&quot;);<br>    }<br>}<br></pre><p>- Hai hai2 = new Hello(); // ok <br> This is again upcasting, where a Hello object is assigned to a Hai reference.</p><p>- Hello h2 = new Hai(); // not ok <br> Similar to the previous example, you cannot downcast a superclass object (Hai) to a subclass reference (Hello).</p><p>Type Casting</p><p>- Upcasting: Allowed implicitly without type casting (e.g., Hai hai2 = new Hello();).<br> <br>- Downcasting: Must be explicit and is only valid if the object is actually an instance of the subclass:<br> — Hello h5 = (Hello) hai2; // not ok if hai2 is not an instance of Hello<br> <br>- ClassCastException: This runtime exception occurs when you try to downcast a superclass reference that doesn’t actually point to an instance of the subclass:<br> — In the case of Hello h3 = (Hello) hai1;, it throws a ClassCastException because hai1 is an instance of Hai, not Hello.</p><p><strong>Summary of Rules</strong></p><p>1. Upcasting (subclass to superclass) is safe and implicit.<br>2. Downcasting (superclass to subclass) requires explicit casting and can fail at runtime if the object isn’t of the expected subclass type.<br>3. Always check the actual type of an object before downcasting to avoid runtime exceptions.</p><p>Understanding these principles is crucial for effective use of inheritance and polymorphism in object-oriented programming.</p><p>Benefits of Polymorphism</p><p>- Code Reusability: Allows a general method to work on objects of different classes.</p><p>- Maintainability: Simplifies code updates and changes, as you can work with the superclass reference instead of individual subclass references.</p><p>- Flexibility: Makes it easy to introduce new classes without changing existing code.</p><p>Method Overloading vs. Overriding</p><p>- Method Overloading: Involves methods with the same name but different signatures within the same class. It’s determined at compile time.</p><p>- Method Overriding: Involves a subclass providing a specific implementation of a method that is already defined in its superclass. It’s determined at runtime.</p><p>Using these principles, Java enables robust and scalable applications, supporting a structured approach to code design that can handle complexity efficiently.</p><p>Note:-</p><p>Calling Methods with Superclass Reference</p><ol><li>Method Availability:<br> — When you call a method using a superclass reference that points to a subclass object, the method signature must be defined in the superclass. If the method is not present in the superclass, the compiler will throw an error.</li></ol><pre>class Superclass {<br>       void display() {<br>           System.out.println(&quot;Superclass display&quot;);<br>       }<br>   }<br>   class Subclass extends Superclass {<br>       void show() {<br>           System.out.println(&quot;Subclass show&quot;);<br>       }<br>   }<br>   Superclass obj = new Subclass();<br>   obj.display(); // This works, but obj.show(); will give an error.</pre><p>2. Method Resolution:<br> — When invoking a method on a superclass reference pointing to a subclass object, the JVM first checks if the method signature exists in the superclass. If it does, it then checks if there’s an overridden implementation in the subclass.<br> — If an overridden method exists in the subclass, that implementation will be executed (demonstrating runtime polymorphism).</p><p>Static Methods</p><p>1. Static Method Behavior:<br> — If you call a static method using a superclass reference that points to a subclass object, the superclass’s static method implementation will always be executed. This is because static methods are bound at compile time (early binding).<br> <br> 2. No Runtime Polymorphism with Static Methods:<br> — Static methods cannot be overridden; they can only be hidden. This means if a subclass defines a static method with the same name, it doesn’t override the method from the superclass — it hides it.<br> — This results in static methods being resolved at compile time, hence supporting early binding.</p><p>Binding Concepts</p><p>- Early Binding (Static Binding):<br> — Applies to static methods and method calls on primitive types and references. The method to be executed is determined at compile time.</p><p>- Late Binding (Dynamic Binding):<br> — Applies to instance methods. The method to be executed is determined at runtime, allowing for the flexibility of polymorphism.</p><p>Summary</p><p>-Method Availability: Superclass reference must have the method defined for it to be callable.<br> — Method Resolution: JVM checks superclass first, then subclass for method implementations.<br> — Static Methods: Always call the superclass’s static method when accessed via a superclass reference; they do not support runtime polymorphism and are resolved at compile time.</p><p>Note:-</p><pre>package Polymorphism5;<br>class Hello {<br>    void m1() {<br>        System.out.println(&quot;m1 in Hello&quot;);<br>    }<br>    void m2() {<br>        System.out.println(&quot;m2 in Hello&quot;);<br>    }<br>    void m3() {<br>        System.out.println(&quot;m3 in Hello&quot;);<br>    }<br>}<br>class Hai extends Hello {<br>    void m1() {<br>        System.out.println(&quot;m1 in Hai&quot;);<br>    }<br>    void m2() {<br>        System.out.println(&quot;m2 in Hai&quot;);<br>        super.m2(); // Calls the superclass implementation of m2<br>    }<br>}<br>public class Jtc114 {<br>    public static void main(String[] args) {<br>        Hai hai = new Hai();<br>        hai.m1(); // Calls m1 in Hai<br>        hai.m2(); // Calls m2 in Hai, which also calls m2 in Hello<br>        hai.m3(); // Calls m3 in Hello<br>    }<br>}</pre><p>The output of the program is:</p><pre>m1 in Hai<br>m2 in Hai<br>m2 in Hello<br>m3 in Hello</pre><p>Conceptual Explanation</p><p>1. Method Overriding:<br> — m1() Method: <br> — The m1() method in the Hai class overrides the m1() method in the Hello class. When hai.m1() is called, it executes the overridden version in Hai, resulting in m1 in Hai.<br> <br> 2. Using super to Access Superclass Implementation:<br> m2() Method:<br> — The m2() method in the Hai class overrides the m2() method in the Hello class. Inside this method, super.m2() is called, which invokes the m2() method in the Hello class.<br> — As a result, when hai.m2() is executed, it first prints m2 in Hai, then calls super.m2(), which prints m2 in Hello.<br> No Overriding:<br> m3() Method:<br> — The m3() method is not overridden in the Hai class. Therefore, when hai.m3() is called, it directly invokes the implementation in the Hello class, resulting in m3 in Hello.<br> — This illustrates that if you want to retain the superclass’s behavior, you can simply not override the method in the subclass.</p><p>Summary</p><p>Override to Change Behavior: If you want to change the behavior of a method from the superclass, you override it in the subclass (like m1()).<br> — Use super to Combine Behavior: If you want to extend the behavior (use both superclass and subclass implementations), you override the method and use super to call the superclass version (like m2()).<br> — Inherit as-is: If you want to use the superclass implementation without any changes, you simply don’t override the method (like m3()).</p><p>This structure allows for flexible and powerful use of polymorphism in Java, enabling you to define and refine behavior across class hierarchies.</p><p>-You cannot override the main method in Java in the way you might be thinking. The main method serves as the entry point for any Java application, and it has a specific signature:</p><p>public static void main(String[] args)<br> Key Points:</p><p>1. Static Context: The main method is static, meaning it belongs to the class itself rather than instances of the class. Because of this, it cannot be overridden in the traditional sense. Static methods can be hidden, but not overridden.</p><p>2. Method Hiding: If you define another main method in a subclass with the same signature, it won’t override the superclass’s main method; instead, it hides it. This means that when you run the program, the JVM will still call the main method of the class you specify on the command line.</p><p>3. Calling Main from Main: You can call the main method of the same class or a different class within the main method, but this does not constitute overriding. It simply involves invoking another method.</p><p>Example:</p><p>Here’s a simple example:</p><pre>class Parent {<br>    public static void main(String[] args) {<br>        System.out.println(&quot;Main method in Parent&quot;);<br>        Child.main(args); // Calling Child&#39;s main<br>    }<br>}<br>class Child extends Parent {<br>    public static void main(String[] args) {<br>        System.out.println(&quot;Main method in Child&quot;);<br>    }<br>}</pre><p>Output:</p><pre>Main method in Parent<br>Main method in Child</pre><p>In this example:<br> — The main method in Parent calls the main method in Child, but this does not mean Child overrides Parent’s main. <br> — The main method of Parent runs because it’s the one called when the program starts.</p><h4>Encapsulation</h4><p>Encapsulation is the practice of bundling the data (attributes) and methods (functions) that operate on the data into a single unit, typically a class. This approach helps protect the integrity of the data by restricting direct access to it.</p><p><strong>Key Concepts of Encapsulation</strong></p><p>1. Data Hiding: By making class attributes private, you prevent external code from accessing them directly.</p><p>2. Controlled Access: Use public methods (getters and setters) to allow controlled access to the private data.</p><p>Why Use Encapsulation?</p><p>- Protect Data: Prevent invalid data from being set.</p><p>- Maintain Control: Ensure that only valid data is assigned to attributes.</p><p>- Flexibility: Change internal implementations without affecting other parts of the code.</p><p>Example 1: Simple Encapsulation</p><p>Unencapsulated Class</p><pre>class App {<br>    int monthnum; // Not protected<br>}<br><br>public class Demo {<br>    public static void main(String[] args) {<br>        App a1 = new App();<br>        a1.monthnum = 22; // Invalid value for month<br>        System.out.println(&quot;Month number is &quot; + a1.monthnum); // Outputs 22<br>    }<br>}</pre><p>Problem: The user can set `monthnum` to an invalid value (like 22).</p><p><strong>Encapsulated Class</strong></p><pre>class Calendar {<br>    private int monthnum; // Data member is private<br><br>    // Setter method<br>    public void setMonthNum(int monthnum) {<br>        if (monthnum &gt;= 1 &amp;&amp; monthnum &lt;= 12) {<br>            this.monthnum = monthnum; // Valid month<br>        } else {<br>            System.out.println(&quot;Invalid month number&quot;); // Prevents invalid assignment<br>        }<br>    }<br><br>    // Getter method<br>    public int getMonthNum() {<br>        return monthnum; // Returns the valid month number<br>    }<br>}<br><br>public class UserCal {<br>    public static void main(String[] args) {<br>        Calendar c1 = new Calendar();<br>        c1.setMonthNum(22); // Invalid input<br>        System.out.println(&quot;Month number is &quot; + c1.getMonthNum()); // Outputs 0 (default value)<br>        <br>        c1.setMonthNum(5); // Valid input<br>        System.out.println(&quot;Month number is &quot; + c1.getMonthNum()); // Outputs 5<br>    }<br>}</pre><p>Explanation</p><p>- Private Data Member: The `monthnum` variable is private, so it can’t be accessed directly outside the `Calendar` class.</p><p>- Setter Method: `setMonthNum` checks if the input is valid (between 1 and 12) before assigning it.</p><p>- Getter Method: `getMonthNum` returns the value of `monthnum`.</p><p><strong>Java Bean Class</strong></p><p>A Java Bean class is a reusable software component that adheres to specific conventions in its structure. It encapsulates its properties (data members) and provides methods to access and modify those properties through getter and setter methods. This design promotes encapsulation and helps in maintaining data integrity.</p><p><strong>Characteristics of a Java Bean Class</strong></p><p>1. Private Data Members: All properties of the bean class should be declared private to restrict direct access from outside the class.</p><p>2. Public Setter and Getter Methods:</p><p>- Each private data member should have a corresponding setter method (to set the value) and a getter method (to retrieve the value).</p><p><strong>Setter Method</strong></p><p>A setter method is used to assign a value to a private data member. The characteristics of a setter method are:</p><p>1. Public Accessibility: The method must be declared `public` so that it can be accessed from outside the class.</p><p>2. No Return Type: The setter method does not return any value; its return type is `void`.</p><p>3. Arguments: It accepts one argument, which should be of the same type as the data member it is setting.</p><p>4. Naming Convention: The method name should start with “set” followed by the name of the data member (with the first letter capitalized).</p><p>Example of a Setter Method:</p><pre>public void setEidPF(long eidPF) {<br>    this.eidPF = eidPF; // &#39;this&#39; keyword distinguishes the class member from the parameter<br>}</pre><p><strong>Getter Method</strong></p><p>A getter method retrieves the value of a private data member. The characteristics of a getter method are:</p><p>1. Public Accessibility: Like setters, getters must also be public.</p><p>2. Return Type: The return type must match the data type of the data member.</p><p>3. No Arguments: The getter method does not accept any parameters.</p><p>4. Naming Convention: The method name should start with “get” followed by the name of the data member (with the first letter capitalized).</p><p>Example of a Getter Method:</p><pre>public long getEidPF() {<br>    return eidPF; // Returns the value of eidPF<br>}</pre><p>Example of a Java Bean Class</p><p>Here’s a complete example that illustrates the concept of a Java Bean class using an `EPF` (Employee Provident Fund) class:</p><pre>import java.util.Scanner;<br><br>class EPF {<br>    private long eidPF; // Employee ID<br>    private String pwd; // Password<br><br>    // Setter method for eidPF<br>    public void setEidPF(long eidPF) {<br>        this.eidPF = eidPF;<br>    }<br><br>    // Getter method for eidPF<br>    public long getEidPF() {<br>        if (eidPF == 101123458L) {<br>            System.out.println(&quot;Processing your EID, please wait...&quot;);<br>            return eidPF;<br>        } else {<br>            System.out.println(&quot;Incorrect EID&quot;);<br>            return 0;<br>        }<br>    }<br><br>    // Setter method for pwd<br>    public void setPwd(String pwd) {<br>        this.pwd = pwd;<br>    }<br><br>    // Getter method for pwd<br>    public String getPwd() {<br>        if (pwd.equals(&quot;Hari123&quot;)) {<br>            System.out.println(&quot;Processing your password, please wait...&quot;);<br>            return &quot;Password is Correct&quot;;<br>        } else {<br>            System.out.println(&quot;Incorrect Password&quot;);<br>            return &quot;Please check your Password again&quot;;<br>        }<br>    }<br>}<br><br>public class EmployeeEP {<br>    public static void main(String args[]) {<br>        Scanner sc = new Scanner(System.in);<br>        EPF e1 = new EPF();<br><br>        System.out.println(&quot;Please Enter your Employee PF-EID:&quot;);<br>        long eid = sc.nextLong();<br>        e1.setEidPF(eid);<br>        System.out.println(e1.getEidPF());<br><br>        System.out.println(&quot;Please Enter your Password:&quot;);<br>        String pwd = sc.next();<br>        e1.setPwd(pwd);<br>        System.out.println(e1.getPwd());<br>    }<br>}</pre><p>Output</p><p>When this program is executed, it will prompt the user for their Employee PF-EID and password, and return appropriate messages based on the inputs.</p><p><strong>Types of Encapsulation</strong></p><p><strong>1. Fully Encapsulated Class:</strong> All data members are private, and access is controlled through getter and setter methods.</p><pre>class A {<br>    private int i;<br>    private float f;<br>    private String s;<br>    // Getter and Setter methods<br>}</pre><p><strong>2. Partially Encapsulated Class:</strong> At least one data member is public, allowing direct access.</p><pre>class A {<br>    private String name;<br>    public int age; // Direct access allowed<br>}</pre><p><strong>3. No Encapsulated Class:</strong> All data members are public, allowing direct access without any control.</p><pre>class A {<br>    public String name;<br>    public int age;<br>}</pre><p><strong>Advantages of Encapsulation</strong></p><p>- Data Security: Protects the integrity of the data by restricting access.</p><p>- Control Over Data: You can enforce validation rules in setter methods.</p><p>- Flexibility: You can change the internal implementation without affecting external code.</p><p>- Read-Only or Write-Only: You can create classes that allow only reading (getters) or writing (setters).</p><p><strong>Disadvantages of Encapsulation</strong></p><p>- Increased Code Length: Requires more boilerplate code due to the need for getters and setters.</p><ul><li>Performance Overhead: Potentially slight overhead due to method calls, though usually negligible.</li></ul><h4>Object Casting in Java</h4><p>Object casting is the process of converting one type of object into another. In Java, this involves working with class hierarchies where classes can inherit from one another. There are two primary types of object casting: upcasting and downcasting</p><p><strong>1. Upcasting</strong></p><p>Definition: Upcasting refers to converting a subclass object to a superclass reference type. Essentially, you create an object of a subclass and store it in a reference variable of the superclass type.</p><p>Characteristics:</p><p>- Only the superclass’s methods are directly visible when upcasting.</p><p>- Subclass behavior is hidden (not accessible directly).</p><p>- Upcasting is implicit, meaning it does not require an explicit cast.</p><p>Example:</p><pre>class Animal {<br>    void sound() {<br>        System.out.println(&quot;Animal makes a sound&quot;);<br>    }<br>}<br><br>class Dog extends Animal {<br>    void sound() {<br>        System.out.println(&quot;Dog barks&quot;);<br>    }<br>}<br><br>public class UpcastingExample {<br>    public static void main(String[] args) {<br>        Animal animal = new Dog(); // Upcasting<br>        animal.sound(); // Outputs: Dog barks<br>    }<br>}</pre><p>Note: Even though the reference type is `Animal`, the actual object type is `Dog`. Therefore, the `Dog` class’s overridden `sound` method is execute</p><p><strong>2. Downcasting</strong></p><p>Definition: Downcasting is the process of converting a superclass reference back to a subclass reference. This allows access to the subclass-specific methods and properties.</p><p>Characteristics:</p><p>- Both superclass and subclass methods are accessible after downcasting.</p><p>- Downcasting is explicit, meaning you need to explicitly cast the reference.</p><p>Example:</p><pre>class Animal {<br>    void sound() {<br>        System.out.println(&quot;Animal makes a sound&quot;);<br>    }<br>}<br><br>class Dog extends Animal {<br>    void sound() {<br>        System.out.println(&quot;Dog barks&quot;);<br>    }<br>    <br>    void fetch() {<br>        System.out.println(&quot;Dog fetches the ball&quot;);<br>    }<br>}<br><br>public class DowncastingExample {<br>    public static void main(String[] args) {<br>        Animal animal = new Dog(); // Upcasting<br>        animal.sound(); // Outputs: Dog barks<br>        <br>        Dog dog = (Dog) animal; // Downcasting<br>        dog.fetch(); // Outputs: Dog fetches the ball<br>    }<br>}</pre><p>Note: The downcast is done using `(Dog) animal`. This allows you to access `Dog`-specific methods.</p><p>Important:</p><p>- If you try to downcast an object that is not an instance of the subclass, a `ClassCastException` will occur.</p><p><strong>Type Casting in Java</strong></p><p>In addition to object casting, Java supports type casting for primitive data types. This is divided into two types: widening and narrowing.</p><p><strong>1. Widening (Implicit Casting)</strong></p><p>Definition: Converting a smaller primitive data type to a larger one.</p><p>Types:</p><p>- `byte` → `short` → `int` → `long` → `float` → `double`</p><p>Characteristics:</p><p>- No loss of data.</p><p>- Automatic conversion by the compiler.</p><p>Example:</p><pre>byte byteValue = 10;<br>int intValue = byteValue; // Widening<br>System.out.println(intValue); // Outputs: 10</pre><p><strong>2. Narrowing (Explicit Casting)</strong></p><p>Definition: Converting a larger primitive data type to a smaller one.</p><p>Types:</p><p>- `double` → `float` → `long` → `int` → `short` → `byte`</p><p>Characteristics:</p><p>- Possible loss of data.</p><p>- Requires explicit casting by the programmer.</p><p>Example:</p><pre>double doubleValue = 9.78;<br>int intValue = (int) doubleValue; // Narrowing<br>System.out.println(intValue); // Outputs: 9</pre><p><strong>Abstraction in Java</strong></p><p>Abstraction is one of the core principles of Object-Oriented Programming (OOP) that focuses on hiding the complex implementation details while exposing only the necessary features to the user. This helps simplify the interaction with the software and enhances usability.</p><p><strong>Key Points:</strong></p><p>- Hiding Implementation: The internal workings of a method or a class are hidden from the user, who only needs to know how to interact with it.</p><p>- Simplification: By exposing only essential features, abstraction makes systems easier to use and understand.</p><p><strong>Everyday Examples:</strong></p><p>1. Email: When sending an email, the user interacts with a “send” button. The underlying process of how the email is sent (through servers, protocols, etc.) is hidden from the user.</p><p>2. Remote Controls: When using a remote for a TV or an AC, users operate it through buttons, without knowing the complex electronics and programming involved.</p><p>3. Driving a Car: A driver knows how to accelerate or brake, but they don’t need to understand the intricate mechanics of the car’s engine or braking system.</p><p><strong>Achieving Abstraction in Java</strong></p><p>In Java, abstraction can be achieved in two main ways:</p><p>1. Abstract Classes</p><p>2. Interfaces</p><p>An abstract class is a blueprint for other classes, allowing shared methods and properties to be defined in a way that provides a foundation for more specific classes. Let’s delve into the core concepts with an emphasis on the rules, usage, and structure of abstract classes and methods.</p><p><strong>What is an Abstract Class?</strong></p><p>An abstract class is a class that contains at least one abstract method, making it incomplete by nature. The keyword `abstract` signals this incompleteness and indicates that subclasses must provide the specific implementations for any abstract methods within the class.</p><p><strong>Abstract Method vs. Concrete Method</strong></p><p>1. Abstract (Incomplete) Method:</p><p>- This is a method declared with only its signature (the method name and parameters) but without a body or implementation.</p><p>- It must be marked with the `abstract` keyword, and it should end with a semicolon (`;`).</p><p>- Example:</p><pre>abstract public void run();</pre><p>2. Concrete (Complete) Method:</p><p>- This type of method includes both the method signature and the method body, containing actual logic.</p><p>- Example:</p><pre>public void fly() {<br>  System.out.println(&quot;Fly away&quot;);<br>}</pre><p>Rules for Abstract Classes and Methods</p><p>1. Instantiation:</p><p>- We cannot create an instance of an abstract class directly because it contains incomplete methods without bodies.</p><p>- Example:</p><pre>abstract class Vehicle {<br>    abstract public void noOfWheels();<br>}<br>// Vehicle v1 = new Vehicle(); // This would cause a compile-time error.</pre><p>2. Inheritance:</p><p>- A subclass can extend an abstract class and must provide implementations for all abstract methods.</p><p>- If a subclass does not implement all abstract methods, it must also be declared as abstract.</p><p>- This rule provides two approaches:</p><p>1. Implement all abstract methods in the subclass.</p><p>2. Declare the subclass as abstract and leave further implementation to subsequent subclasses.</p><p>3. Constructors:</p><p>- An abstract class can contain constructors, allowing initialization of instance variables, even though it cannot be instantiated directly.</p><p>- Example:</p><pre>abstract class Student {<br>    String name;<br>    int id;<br>    <br>    public Student(String name, int id) {<br>        this.name = name;<br>        this.id = id;<br>    }<br>    <br>    abstract public void details();<br>}</pre><p>4. Static, Non-static, and Final Members:</p><p>- An abstract class can include static, non-static, and final variables, allowing shared constants or values that subclasses can access without instantiation.</p><p>5. Absence of Abstract Methods:</p><p>- It’s possible for an abstract class not to have any abstract methods. This is often done if the class serves only as a superclass (like a blueprint), with only static methods or for providing shared functionality.</p><p><strong>Restrictions with Abstract Classes</strong></p><p>1. Final Keyword:</p><p>- An abstract class cannot be marked as `final` because final classes cannot be inherited, which conflicts with the purpose of an abstract class.</p><p>2. Static Abstract Methods:</p><p>- Abstract methods cannot be static because they are meant to be overridden in subclasses, while static methods belong to the class itself, not to instances.</p><p>3. Multiple Inheritance:</p><p>- Java does not support multiple inheritance for classes, including abstract classes, so a class cannot extend more than one abstract class.</p><p>Example Implementations</p><p>Example Using Rule 1 (Complete All Abstract Methods)</p><pre>abstract class Vehicle {<br>    abstract public void price();<br>    abstract public void noOfWheels();<br>}</pre><pre>class RoyalEnfield extends Vehicle {<br>    @Override<br>    public void price() {<br>        System.out.println(&quot;1.6 Lakhs&quot;);<br>    }<br>    <br>    @Override<br>    public void noOfWheels() {<br>        System.out.println(&quot;Two wheels&quot;);<br>    }<br>    <br>    public static void main(String[] args) {<br>        RoyalEnfield r = new RoyalEnfield();<br>        r.noOfWheels();<br>        r.price();<br>    }<br>}</pre><p>Example Using Rule 2 (Declare Subclass as Abstract)</p><pre>abstract class Vehicle {<br>    abstract public void price();<br>    abstract public void noOfWheels();<br>    abstract public void model();<br>}</pre><pre>abstract class RoyalEnfield extends Vehicle {<br>    @Override<br>    public void price() {<br>        System.out.println(&quot;1.6 Lakhs&quot;);<br>    }<br>    <br>    @Override<br>    public void noOfWheels() {<br>        System.out.println(&quot;Two wheels&quot;);<br>    }<br>}</pre><pre>class EnfieldModel extends RoyalEnfield {<br>    @Override<br>    public void model() {<br>        System.out.println(&quot;Classic 350&quot;);<br>        System.out.println(&quot;Interceptor 650&quot;);<br>    }<br>    <br>    public static void main(String[] args) {<br>        EnfieldModel r = new EnfieldModel();<br>        r.noOfWheels();<br>        r.price();<br>        r.model();<br>    }<br>}</pre><p>Key Points on Abstract Classes</p><p>- Partial Abstraction: Since abstract classes can contain both concrete and abstract methods, they offer partial abstraction (0–100% abstraction).</p><p>- Interfaces for Full Abstraction: To achieve full (100%) abstraction, interfaces are preferred over abstract classes because they only declare methods without implementing them.</p><p><strong>FAQ on Abstract Classes</strong></p><p><strong>1. Can we declare an abstract class without abstract methods?</strong></p><p>Yes, an abstract class may not contain any abstract methods. It’s typically done if we don’t want instances of the class, or we want a base class for other classes.</p><p><strong>2. Can we declare an abstract class as final?</strong></p><p>No, because making a class `final` prevents it from being subclassed, which contradicts the purpose of an abstract class (which is to be extended).</p><p><strong>3. Can an abstract method be declared as final?</strong></p><p>No, because `final` methods cannot be overridden, but abstract methods must be overridden in subclasses.</p><p><strong>4. Can an abstract method be declared as static?</strong></p><p>No, because static methods belong to the class, not instances, and abstract methods are meant to be overridden.</p><p><strong>5. Can we achieve multiple inheritance with abstract classes?</strong></p><p>No, Java does not support multiple inheritance with classes, abstract or otherwise. However, multiple inheritance can be achieved through interfaces.</p><p><strong>Key Points to remember:</strong></p><p>- Abstract classes are used to provide a template for other classes.</p><p>- You cannot create an instance of an abstract class.</p><p>- Subclasses of an abstract class must override its abstract methods or be declared as abstract themselves.</p><p>- Abstract classes can have both abstract methods and concrete methods.</p><p>- Illegal Combinations:<br> — You cannot use the combinations “static abstract”, “final abstract”, or “private abstract”. <br> — Static methods belong to the class rather than instances, while abstract methods are meant to be implemented by subclasses, creating a contradiction.<br> — Final methods cannot be overridden, which conflicts with the purpose of an abstract method, and private abstract methods can’t be accessed in subclasses.</p><p>2. Method Availability:<br> — When calling a method on a superclass reference that points to a subclass object, the method signature must be defined in the superclass. <br> — If the method is not present in the superclass, you will receive an error when trying to call it.</p><p>3. Constructors in Abstract Classes:<br> — You cannot instantiate an abstract class directly, which means you can’t create objects of that class.<br> — However, when you create an object of a subclass that extends the abstract class, the constructor of the abstract class is still invoked.<br> — If the subclass does not define a constructor, the Java compiler automatically inserts a default constructor and a call to the superclass constructor (using super()).<br> — This ensures that any initialization logic in the abstract class’s constructor is executed when creating the subclass object.</p><p>Thus,</p><p>- Abstract Class: Cannot be instantiated directly, but its constructor is called when a subclass object is created.<br>- Method Signature Requirement: Any method called through a superclass reference must exist in the superclass.<br>- Constructor Behavior: Subclass constructors implicitly call the superclass constructor unless specified otherwise, ensuring proper initialization of inherited properties.</p><p><strong>Conclusion</strong></p><p>Abstract classes in Java allow for partial abstraction, meaning we can have both abstract and concrete methods within the same class, which leads to 0 to 100% abstraction. To achieve 100% abstraction, where all methods are abstract, interfaces should be used instead of abstract classes.</p><h4>Interface in Java</h4><p>An interface in Java is a blueprint of a class that can contain static constants and abstract methods. It is a way to define a contract for what methods a class must implement, without specifying the implementation itself. Let’s discuss its features, characteristics, and how it is used in Java.</p><p>Key Characteristics of Interfaces</p><p>1. Declaration: Interfaces are declared using the interface keyword.</p><pre>interface I1 { }</pre><p>2. Compilation: Like classes, interfaces get compiled into .class files.</p><p>3. Variables in Interfaces: All variables in an interface are implicitly public, static, and final.</p><p>4. Methods in Interfaces: All methods in an interface are implicitly public and abstract unless explicitly defined as default or static (from Java 8 onwards).</p><p>Example of Variables in Interfaces</p><pre>interface I1 {<br>    int a = 10; // Equivalent to public static final int a = 10;<br>}<br>class JTC {<br>    public static void main(String[] args) {<br>        System.out.println(I1.a); // Accessing the static variable<br>        // I1.a = 1000; // Error: cannot assign a value to a final variable<br>    }<br>}</pre><p>Explanation: The variable a in interface I1 is treated as public static final. Hence, it is a constant, and its value cannot be changed.</p><p>Methods in Interfaces</p><p>All methods in an interface are abstract by default. You cannot provide a body for these methods directly in the interface.</p><pre>interface I1 {<br>  void m2(); // Equivalent to public abstract void m2();<br>}</pre><p>If you try to provide a method body in the interface, it will cause a compilation error because methods in interfaces are abstract by default.</p><p>Implementing an Interface</p><p>To use the methods of an interface, you need to create a class that implements the interface. The implements keyword is used for this purpose.</p><pre>interface I1 {<br>    int m1();<br>    void m2();<br>}<br>abstract class A implements I1 {<br>    public int m1() {<br>        System.out.println(&quot;m1 in A class&quot;);<br>        return 10;<br>    }<br>}<br>class B extends A {<br>    public void m2() {<br>        System.out.println(&quot;m2 in A class&quot;);<br>    }<br>}<br>class JTC {<br>    public static void main(String[] args) {<br>        I1 i1 = new B();<br>        int a = i1.m1();<br>        i1.m2();<br>        System.out.println(&quot;a :- &quot; + a);<br>    }<br>}</pre><p>Output:</p><pre>m1 in A class<br>m2 in A class<br>a :- 10</pre><p>Explanation:</p><p>- Class A implements the I1 interface but does not implement all its methods, so it is declared as abstract.</p><p>- Class B extends A and provides the implementation for the remaining method, making it a concrete class.</p><p>Multiple Inheritance with Interfaces</p><p>Interfaces allow Java to support multiple inheritance. A class can implement multiple interfaces, gaining the ability to inherit behavior from more than one interface.</p><pre>interface I1 {<br>    int a = 10;<br>}<br>interface I2 {<br>    int b = 20;<br>}<br>interface I3 {<br>    int c = 30;<br>}<br>class A implements I1, I2, I3 {<br>    void m1() {<br>        System.out.println(&quot;m1 in A class&quot;);<br>        System.out.println(&quot;a :- &quot; + a);<br>        System.out.println(&quot;b :- &quot; + b);<br>        System.out.println(&quot;c :- &quot; + c);<br>    }<br>}<br>class JTC {<br>    public static void main(String[] args) {<br>        A a1 = new A();<br>        a1.m1();<br>    }<br>}</pre><p>Output:</p><pre>m1 in A class<br>    a :- 10<br>    b :- 20<br>    c :- 30</pre><p>Explanation: Class A implements multiple interfaces, accessing variables from all the interfaces without any ambiguity.</p><p>Handling Ambiguity in Multiple Interfaces</p><p>If multiple interfaces have variables with the same name, you can resolve the ambiguity by specifying the interface name.</p><pre>interface I1 {<br>    int a = 10;<br>}<br>interface I2 {<br>    int a = 20;<br>}<br>interface I3 {<br>    int a = 30;<br>}<br>class A implements I1, I2, I3 {<br>    void m1() {<br>        System.out.println(&quot;m1 in A class&quot;);<br>        System.out.println(&quot;I1.a :- &quot; + I1.a);<br>        System.out.println(&quot;I2.a :- &quot; + I2.a);<br>        System.out.println(&quot;I3.a :- &quot; + I3.a);<br>    }<br>}<br>class JTC {<br>    public static void main(String[] args) {<br>        A a1 = new A();<br>        a1.m1();<br>    }<br>}</pre><p>Explanation: By using the interface names I1.a, I2.a, and I3.a, we can differentiate between the variables with the same name.</p><p><strong>Inheritance of Interfaces</strong></p><p>An interface can inherit other interfaces using the extends keyword.</p><pre>interface I1 {<br>    int a = 10;<br>}<br>interface I2 {<br>    int b = 20;<br>}<br>interface I3 extends I1, I2 {<br>    int c = 30;<br>}<br>class A implements I3 {<br>    void m1() {<br>        System.out.println(&quot;m1 in A class&quot;);<br>        System.out.println(&quot;a :- &quot; + a);<br>        System.out.println(&quot;b :- &quot; + b);<br>        System.out.println(&quot;c :- &quot; + c);<br>    }<br>}<br>class JTC {<br>    public static void main(String[] args) {<br>        A a1 = new A();<br>        a1.m1();<br>    }<br>}</pre><p>Explanation: Interface I3 extends interfaces I1 and I2, so when class A implements I3, it inherits all the members of I1 and I2.</p><h4>Conflict Resolution in Interfaces</h4><p>In Java, if a class implements multiple interfaces that contain methods with the same signature, there could be a conflict. Java handles this through explicit rules that guide how to resolve these conflicts.</p><p><strong>Scenario 1: Multiple Interfaces with the Same Method Signature</strong></p><p>If a class implements multiple interfaces that define the same method, there’s no conflict if the method does not have a default implementation in either interface. The implementing class only needs to provide a single implementation.</p><pre>interface A {<br>    void show();<br>}<br><br>interface B {<br>    void show();<br>}<br><br>class C implements A, B {<br>    public void show() {<br>        System.out.println(&quot;Show method implemented in class C&quot;);<br>    }<br>}</pre><p>In this case, class `C` provides a single implementation for the `show()` method, fulfilling the contract of both interfaces `A` and `B`.</p><p><strong>Scenario 2: Multiple Default Methods with the Same Signature</strong></p><p>If a class implements multiple interfaces with a default method of the same name and parameters, Java will throw a compilation error due to ambiguity. The implementing class must override the method and provide its own implementation to resolve the conflict.</p><pre>interface A {<br>    default void display() {<br>        System.out.println(&quot;Display from A&quot;);<br>    }<br>}<br><br>interface B {<br>    default void display() {<br>        System.out.println(&quot;Display from B&quot;);<br>    }<br>}<br><br>class C implements A, B {<br>    // Resolving conflict by overriding<br>    @Override<br>    public void display() {<br>        System.out.println(&quot;Display resolved in class C&quot;);<br>    }<br>}</pre><p>In this example, class `C` must override the `display()` method to resolve the conflict between `A` and `B`. If it doesn’t, a compilation error will occur.</p><p><strong>Scenario 3: Calling a Specific Interface’s Default Method</strong></p><p>In cases where you want to specifically call a default method from one of the interfaces, you can use the following syntax within the overriding method:</p><pre>class C implements A, B {<br>    @Override<br>    public void display() {<br>        A.super.display();  // Calls display() from interface A<br>    }<br>}</pre><p>Here, `A.super.display()` explicitly calls the `display()` method from interface `A`, providing a way to choose which default method to invoke.</p><p><strong>Conflict Resolution Summary</strong></p><p>1. Same Method Signature: If the interfaces have the same method signature without default implementations, there’s no conflict, and the class must implement the method.</p><p>2. Same Default Methods: If the interfaces have default methods with the same signature, the class must override the method to resolve ambiguity.</p><p>3. Choosing a Specific Interface’s Default Method: Use `InterfaceName.super.methodName()` to invoke a specific interface’s default method within the overriding method.</p><p>These rules help ensure that Java avoids ambiguity while allowing flexibility in using multiple interfaces.</p><p><strong>Default and Static Methods in Interfaces (Java 8+)</strong></p><p>From Java 8 onwards, interfaces can have methods with implementations using the default and static keywords.</p><pre>interface I1 {<br>    default void m1() {<br>        System.out.println(&quot;m1 in I1 interface&quot;);<br>    }<br>    <br>    static int m2() {<br>        System.out.println(&quot;m2 in I1 interface&quot;);<br>        return 10;<br>    }<br>}<br>class A implements I1 { }<br>class JTC {<br>    public static void main(String[] args) {<br>        A a1 = new A();<br>        a1.m1(); // Calls the default method in the interface<br>        int i = I1.m2(); // Calls the static method in the interface<br>        System.out.println(&quot;i :- &quot; + i);<br>    }<br>}</pre><p>Explanation:</p><p>- Default Methods: Allow you to add new methods to interfaces without breaking the existing code.</p><p>- Static Methods: Can be called directly using the interface name and are not inherited by implementing classes.</p><p>Key Points</p><p>- Interface variables are public static final by default.</p><p>- Interface methods are public abstract by default (unless declared as default or static).</p><p>- A class uses the implements keyword to inherit an interface.</p><p>- Interfaces support multiple inheritance.</p><p>- Default and static methods in interfaces were introduced in Java 8.</p><p>Interfaces provide a way to achieve abstraction and multiple inheritance, making them an essential tool for designing flexible and maintainable code in Java.</p><h4><strong>Types of interfaces in Java:</strong></h4><p><strong>1. Marker Interface</strong></p><p>A Marker Interface is an interface without any methods or fields. It acts as a “marker” or “tag” to provide some metadata about the class implementing it. Marker interfaces are used to indicate that a class has a certain property or behavior. Java’s standard library includes a few well-known marker interfaces:</p><p>- Serializable: Marks a class as capable of being serialized, meaning its state can be converted into a byte stream and saved to a file or sent over a network.</p><p>- Cloneable: Marks a class as being capable of cloning, allowing `Object.clone()` to be called on it without throwing a `CloneNotSupportedException`.</p><p>- Remote: Marks a class as capable of being accessed remotely in Java RMI (Remote Method Invocation).</p><p>Example:</p><pre>public interface MarkerInterface {} // No methods or fields</pre><p><strong>2. Functional Interface</strong></p><p>A Functional Interface has exactly one abstract method, making it a target for lambda expressions in Java. This is particularly useful in functional programming paradigms introduced with Java 8. Functional interfaces can have multiple default or static methods, but only one abstract method is allowed.</p><p>The `@FunctionalInterface` annotation is used to indicate that an interface is a functional interface, helping prevent accidental addition of other abstract methods.</p><p>- Runnable: Contains the `run()` method, commonly used in multithreading.</p><p>- Comparable&lt;T&gt;: Contains the `compareTo()` method for sorting objects.</p><p>- Predicate&lt;T&gt;: Contains the `test()` method, often used in streams for filtering elements.</p><p>Example:</p><pre>@FunctionalInterface<br>public interface Calculator {<br>    int calculate(int a, int b);  // Single abstract method<br><br>    default void print(String message) {<br>        System.out.println(message);<br>    }<br>}</pre><p><strong>3. SAM (Single Abstract Method) Interface</strong></p><p>SAM interfaces are another name for Functional Interfaces, meaning they have one single abstract method (SAM). Any interface with one abstract method can be treated as a SAM interface and used as a target for lambda expressions.</p><p>- ActionListener in Swing: Contains a single method, `actionPerformed(ActionEvent e)`.</p><p>Example:</p><pre>@FunctionalInterface<br>interface Operation {<br>    void perform();<br>}</pre><p><strong>4. Tagging or Metadata Interface</strong></p><p>The Tagging Interface is synonymous with the Marker Interface, as it doesn’t contain any methods or fields. Its purpose is to mark or tag a class with a certain property, allowing classes to be handled differently in certain contexts. For example, `Serializable` is both a Marker and Tagging Interface.</p><p><strong>5. Normal Interface</strong></p><p>A Normal Interface (or Pure Interface) is any standard interface in Java that contains multiple abstract methods. These interfaces are designed to define a set of related operations that implementing classes must provide.</p><p>Example:</p><pre>public interface Animal {<br>    void eat();<br>    void sleep();<br>    void makeSound();<br>}</pre><p><strong>6. Abstract Interface</strong></p><p>Technically, Abstract Interface isn’t a formal term in Java, but some developers refer to interfaces that use `default` and `static` methods as “abstract interfaces.” These types of interfaces provide a combination of abstract methods and implementations within default or static methods.</p><p>Example:</p><pre>public interface Vehicle {<br>    void drive();<br><br>    default void startEngine() {<br>        System.out.println(&quot;Engine started&quot;);<br>    }<br><br>    static void honk() {<br>        System.out.println(&quot;Honk honk!&quot;);<br>    }<br>}</pre><p><strong>Summary</strong></p><p>Each type of interface serves a different purpose:</p><p>- Marker/Tagging Interface: No methods, adds metadata to classes.</p><p>- Functional Interface (SAM Interface): Single abstract method, enables lambda expressions.</p><p>- Normal Interface: Multiple abstract methods, for defining complete behaviors.</p><p>- Abstract Interface: Combination of abstract methods and default/static methods, allowing partial implementation.</p><p>This variety helps Java provide flexibility, enabling both object-oriented and functional programming styles.</p><p><strong>Can We Extend a Class and Implement an Interface at the Same Time?</strong><br>Yes, in Java, a class can extend a superclass and implement one or more interfaces at the same time. This allows for a combination of inheritance from a class and adherence to a contract defined by interfaces. However, a class can only extend one superclass due to Java’s single inheritance model.</p><p><strong>Difference Between extends and implements</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/978/1*_7GJuKeHSgZKVTqyimlcXA.png" /></figure><h4>Inner classes in Java</h4><p>Inner classes in Java are classes defined within another class or within a method, which allows for logically grouping code to make it more readable and maintainable. They also provide more control over class visibility and help in creating more sophisticated data structures or objects. Let’s go through the key types of inner classes and their characteristics in detail:</p><p>Types of Inner Classes in Java:</p><p>1. Non-Static Inner Class (Instance Inner Class)</p><p>2. Static Inner Class</p><p>3. Method Local Inner Class</p><p>4. Anonymous Inner Class</p><p>1. Non-Static Inner Class (Instance Inner Class)</p><p>- Definition: An inner class that does not have the static modifier.</p><p>- Characteristics:</p><p>- It is an instance member of the outer class, meaning it needs an instance of the outer class to be created.</p><p>- It can access all the members (both static and non-static) of the outer class.</p><p>- Cannot be accessed directly; requires an object of the outer class.</p><p>Example:</p><pre>class OuterClass {<br>    int outerField = 10;<br>    class InnerClass {<br>        void display() {<br>            System.out.println(&quot;Outer Field: &quot; + outerField);<br>        }<br>    }<br>    public static void main(String[] args) {<br>        OuterClass outer = new OuterClass();<br>        OuterClass.InnerClass inner = outer.new InnerClass();<br>        inner.display();<br>    }<br>}</pre><p>Output:</p><pre>Outer Field: 10</pre><p>2. Static Inner Class</p><p>- Definition: An inner class that has the static modifier.</p><p>- Characteristics:</p><p>- Does not require an instance of the outer class to be instantiated.</p><p>- Can only access static members of the outer class.</p><p>- Acts as a regular top-level class except for being nested within another class.</p><p>Example:</p><pre>class OuterClass {<br>    static int staticOuterField = 20;<br>    static class StaticInnerClass {<br>        void display() {<br>            System.out.println(&quot;Static Outer Field: &quot; + staticOuterField);<br>        }<br>    }<br>    public static void main(String[] args) {<br>        OuterClass.StaticInnerClass staticInner = new OuterClass.StaticInnerClass();<br>        staticInner.display();<br>    }<br>}</pre><p>Output:</p><pre>Static Outer Field: 20</pre><p>3. Method Local Inner Class</p><p>- Definition: A class defined within a method or a block of code.</p><p>- Characteristics:</p><p>- Can only be accessed within the method or block where it is defined.</p><p>- Can access local variables of the enclosing method only if they are declared as final or effectively final.</p><p>- Primarily used for scenarios where you need to perform a specific function that’s local to a method.</p><p>Example:</p><pre>class OuterClass {<br>    void outerMethod() {<br>        int localVariable = 30;<br>        class LocalInnerClass {<br>            void display() {<br>                System.out.println(&quot;Local Variable: &quot; + localVariable);<br>            }<br>        }<br>        LocalInnerClass localInner = new LocalInnerClass();<br>        localInner.display();<br>    }<br>    public static void main(String[] args) {<br>        OuterClass outer = new OuterClass();<br>        outer.outerMethod();<br>    }<br>}</pre><p>Output:</p><pre>Local Variable: 30</pre><p>4. Anonymous Inner Class</p><p>- Definition: An inner class that does not have a name.</p><p>- Characteristics:</p><p>- Declared and instantiated all in one statement.</p><p>- Usually used when extending a class or implementing an interface with only one method.</p><p>- Often used for providing specific implementations to listeners or callbacks.</p><p>Example:</p><pre>abstract class Animal {<br>    abstract void sound();<br>}<br>public class Main {<br>    public static void main(String[] args) {<br>        Animal dog = new Animal() { // Anonymous inner class<br>            void sound() {<br>                System.out.println(&quot;Woof Woof&quot;);<br>            }<br>        };<br>        dog.sound();<br>    }<br>}</pre><p>Output:</p><pre>Woof Woof</pre><p>Benefits of Using Inner Classes</p><p>1. Encapsulation: Inner classes can group related classes together, leading to better data encapsulation.</p><p>2. Code Organization: They help in logically organizing code that is only relevant in the context of the outer class.</p><p>3. Enhanced Readability: By grouping related code, inner classes can improve the readability and maintainability of code.</p><p>When to Use Inner Classes</p><p>- Instance Inner Classes: Use when the inner class requires access to the instance variables or methods of the outer class.</p><p>- Static Inner Classes: Use when the inner class does not need access to the outer class’s instance variables or methods.</p><p>- Method Local Inner Classes: Use for scenarios that require a class only within a single method.</p><p>- Anonymous Inner Classes: Use for implementing interfaces or abstract classes on the fly, especially for callbacks or event handling.</p><p>Inner classes are a powerful tool in Java that help in structuring code more elegantly and ensuring modular design. They can make your code more intuitive by linking closely related classes together.</p><p><strong>Important Points to remember</strong></p><p><strong>1. How many `.class` files will be created if a class contains an inner class?</strong></p><p>When a Java class contains an inner class, each inner class generates its own separate `.class` file upon compilation. For example, if you have an outer class `OuterClass` with an inner class `InnerClass`, the following `.class` files will be created:</p><p>- `OuterClass.class` (for the outer class)</p><p>- `OuterClass$InnerClass.class` (for the inner class)</p><p>This naming convention is used to represent the relationship between the outer class and the inner class.</p><p><strong>2. Can we write an inner class inside another inner class?</strong></p><p>Yes, you can write an inner class inside another inner class. This is known as a nested inner class or multi-level inner class. There is no limit to how deeply you can nest inner classes. Here’s an example:</p><pre>class OuterClass {<br>    class InnerClass1 {<br>        class InnerClass2 {<br>            void display() {<br>                System.out.println(&quot;Inside InnerClass2&quot;);<br>            }<br>        }<br>    }<br>}</pre><p>In this example, `InnerClass2` is nested within `InnerClass1`, which is nested within `OuterClass`.</p><p><strong>3. Can we write a class within any interface?</strong></p><p>Yes, you can declare a class inside an interface in Java. This is completely valid. By default, the class inside an interface is implicitly `public` and `static`. Here’s an example:</p><pre>interface MyInterface {<br>    class InnerClass {<br>        void display() {<br>            System.out.println(&quot;InnerClass inside Interface&quot;);<br>        }<br>    }<br>}</pre><p>You can access this inner class without needing an instance of the interface since it is `static` by default:</p><pre>MyInterface.InnerClass obj = new MyInterface.InnerClass();<br>obj.display();</pre><p><strong>4. Can we declare an inner class as private?</strong></p><p>Yes, you can declare an inner class as `private`. When you do so, it can only be accessed within the outer class in which it is defined. For example:</p><pre>class OuterClass {<br>    private class InnerClass {<br>        void display() {<br>            System.out.println(&quot;This is a private inner class&quot;);<br>        }<br>    }<br><br>    void show() {<br>        InnerClass inner = new InnerClass();<br>        inner.display();<br>    }<br>}</pre><p>In this case, `InnerClass` is private and can only be accessed from within `OuterClass`.</p><p><strong>5. Can we declare an outer class as static?</strong></p><p>No, you cannot declare an outer class as `static` in Java. Only nested (inner) classes can be declared as `static`. Declaring an outer class as static would not make sense because static is related to members and their association with the instance of a class.</p><p><strong>6. Where exactly is memory allocated for instance and static variables of static inner classes?</strong></p><p>- Instance Variables: Memory for instance variables of a static inner class is allocated when you create an object of that static inner class.</p><p>- Static Variables: Memory for static variables of a static inner class is allocated when the outer class is loaded into memory, similar to how static members of regular classes are handled.</p><p><strong>7. Is the `Object` class the superclass of all inner classes too?</strong></p><p>Yes, the `Object` class is the superclass of all classes in Java, including inner classes. Every class in Java (whether it’s an inner class, nested class, or top-level class) implicitly extends the `Object` class unless it explicitly extends another class.</p><p><strong>8. Between an interface and an abstract class, which one should be chosen?</strong></p><p>The choice between using an interface and an abstract class depends on the design requirements:</p><p>- Use an Interface if:</p><p>- You need to define a contract for unrelated classes to implement.</p><p>- Multiple inheritance is required (as a class can implement multiple interfaces).</p><p>- All methods in the contract are abstract by default (with Java 8, you can also have default and static methods in interfaces).</p><p>- Use an Abstract Class if:</p><p>- You want to share code among closely related classes.</p><p>- You have a class hierarchy where you need to define common methods and allow subclasses to provide specific implementations.</p><p>- You need to maintain state (i.e., have instance variables) or use constructors.</p><p><strong>9. What is an Adapter class?</strong></p><p>An Adapter class in Java is a design pattern that provides a default implementation of an interface, allowing you to create subclasses without needing to implement all methods in that interface. It acts as a bridge between an interface and a concrete class, simplifying the process of handling interfaces with many methods.</p><p><strong>Key Features of an Adapter Class</strong></p><p>1. Partial Implementation: An adapter class provides empty or default implementations for all the methods of an interface. You can extend the adapter class and override only the methods you are interested in.</p><p>2. Convenience: It allows you to avoid writing boilerplate code for methods you do not need, making your code cleaner and easier to manage.</p><p>3. Usage with Listener Interfaces: Adapter classes are commonly used with listener interfaces in Java’s event-handling system. Many interfaces, like `MouseListener` or `KeyListener`, have multiple methods, even if you only need one or two of them.</p><p><strong>Example: MouseListener Interface with an Adapter Class</strong></p><p>Suppose you want to handle mouse events in a Java GUI application. The `MouseListener` interface has five methods:</p><p>- `mouseClicked()`</p><p>- `mousePressed()`</p><p>- `mouseReleased()`</p><p>- `mouseEntered()`</p><p>- `mouseExited()`</p><p>If you implement `MouseListener` directly, you must provide implementations for all five methods, even if you only need one of them. This is where an adapter class, `MouseAdapter`, becomes useful.</p><p>Example Without Adapter Class</p><pre>import java.awt.event.MouseEvent;<br>import java.awt.event.MouseListener;<br><br>public class MyMouseListener implements MouseListener {<br>    @Override<br>    public void mouseClicked(MouseEvent e) {<br>        System.out.println(&quot;Mouse clicked&quot;);<br>    }<br><br>    @Override<br>    public void mousePressed(MouseEvent e) {}<br><br>    @Override<br>    public void mouseReleased(MouseEvent e) {}<br><br>    @Override<br>    public void mouseEntered(MouseEvent e) {}<br><br>    @Override<br>    public void mouseExited(MouseEvent e) {}<br>}</pre><p>In this example, you had to provide empty implementations for all the other methods, even if you didn’t need them.</p><p>Example With Adapter Class</p><p>Using the `MouseAdapter` class simplifies the code:</p><pre>import java.awt.event.MouseAdapter;<br>import java.awt.event.MouseEvent;<br><br>public class MyMouseListener extends MouseAdapter {<br>    @Override<br>    public void mouseClicked(MouseEvent e) {<br>        System.out.println(&quot;Mouse clicked&quot;);<br>    }<br>}</pre><p>Explanation: By extending the `MouseAdapter` class, you only need to override the method you’re interested in (`mouseClicked()`), and you don’t have to provide implementations for the other methods.</p><p><strong>Commonly Used Adapter Classes in Java</strong></p><p>Java provides several adapter classes that correspond to specific listener interfaces, such as:</p><p>- `MouseAdapter` for the `MouseListener` and `MouseMotionListener` interfaces</p><p>- `KeyAdapter` for the `KeyListener` interface</p><p>- `WindowAdapter` for the `WindowListener` interface</p><p>- `FocusAdapter` for the `FocusListener` interface</p><p>These adapter classes provide default (empty) implementations of all methods in their respective listener interfaces.</p><p><strong>Advantages of Using Adapter Classes</strong></p><p>1. Code Simplification: You don’t have to implement all the methods of an interface, only those that are relevant to your use case.</p><p>2. Readability: Adapter classes make the code cleaner and more readable by reducing unnecessary code.</p><p>3. Flexibility: It makes it easier to create custom event handling by overriding only the specific methods you need.</p><p><strong>When to Use Adapter Classes</strong></p><p>- Use adapter classes when working with interfaces that have multiple methods, but you only need to implement a few of them.</p><p>- It is especially useful when working with Java’s event-handling framework.</p><p><strong>Important Note</strong></p><p>Adapter classes are primarily used when implementing listener interfaces. If an interface has only one or two methods, using an adapter class might not be necessary. In that case, implementing the interface directly is often more straightforward.</p><p>Example Scenario: Using `WindowAdapter`</p><p>Here’s an example using `WindowAdapter` to handle window closing in a GUI application:</p><pre>import java.awt.event.WindowAdapter;<br>import java.awt.event.WindowEvent;<br>import javax.swing.JFrame;<br><br>public class MyFrame extends JFrame {<br>    public MyFrame() {<br>        setTitle(&quot;Adapter Class Example&quot;);<br>        setSize(300, 200);<br>        addWindowListener(new WindowAdapter() {<br>            @Override<br>            public void windowClosing(WindowEvent e) {<br>                System.out.println(&quot;Window is closing&quot;);<br>                System.exit(0);<br>            }<br>        });<br>    }<br><br>    public static void main(String[] args) {<br>        MyFrame frame = new MyFrame();<br>        frame.setVisible(true);<br>    }<br>}</pre><p>Explanation: Here, we only handle the `windowClosing()` method using the `WindowAdapter` class, ignoring the rest of the methods of the `WindowListener` interface.</p><p>Summary</p><p>- An adapter class provides a default implementation of an interface’s methods, allowing you to extend it and override only the methods you need.</p><p>- It is useful when you only want to handle specific events in Java’s event-handling system without implementing all methods of the interface.</p><p>- Adapter classes reduce boilerplate code, making the code cleaner and more maintainable.Java Packages</p><p>In Java, a package is a mechanism used to group related classes, interfaces, and sub-packages together. It helps organize code, manage large projects, and avoid naming conflicts. Let’s go through the different aspects of packages in Java.</p><p><strong>Key Points About Packages</strong></p><p><strong>1. What is a Package?</strong></p><p>- A package in Java is essentially a folder that organizes a set of related classes, interfaces, or sub-packages.</p><p>- When you compile a Java program, packages are created automatically in the folder structure corresponding to the package’s name.</p><p><strong>2. Purpose of Packages</strong></p><p>- Packages help to avoid naming conflicts by grouping related classes together.</p><p>- They make the code easier to find, use, and maintain.</p><p>- They provide access protection, restricting certain classes to be accessed only within the package.</p><p><strong>3. Default Package</strong></p><p>- If you don’t explicitly define a package in your Java program, all classes will belong to the default package (usually the current working directory).</p><p>- The classes that are part of the default package do not require an explicit import when accessed by other classes in the same directory.</p><p>Example Without a Package</p><p>Here’s an example of Java code that does not use a package:</p><pre>class LMS {<br>    public static void main(String[] args) {<br>        Hello h1 = new Hello();<br>        Hai hai = new Hai();<br>        h1.m1();<br>        hai.show();<br>    }<br>}<br><br>class Hello {<br>    void m1() {<br>        System.out.println(&quot;m1 in Hello&quot;);<br>    }<br>}<br><br>class Hai {<br>    void show() {<br>        System.out.println(&quot;show in Hai&quot;);<br>    }<br>}</pre><p>Output:</p><pre>m1 in Hello<br>show in Hai</pre><p>- After compiling this code, you’ll get three `.class` files: `LMS.class`, `Hello.class`, and `Hai.class`.</p><p>- Since we have not specified any package, these `.class` files will be located in the current working directory.</p><p>Creating Your Own Package</p><p>You can create your own package in Java using the following syntax:</p><pre>package com.P1.P2;</pre><p>The package declaration must be the first line in the source file.</p><p><strong>Compilation with Package</strong></p><p>When using packages, you must compile your Java code with the `-d` flag to specify the directory structure:</p><p>- Example: `javac -d . Test.java`</p><p>- The `-d` flag instructs the compiler to create the necessary directories to match the package structure in the current directory.</p><p>- Example: `javac -d d:\ Test.java`</p><p>- This command creates the directory structure on the specified drive (`D:` in this case).</p><p>Running the Program with Package</p><p>To run a Java program that uses a package, you must specify the fully qualified name of the class:</p><p>- Example: `java com.P1.P2.LMS`</p><p>This ensures that Java can locate the class file in the correct package.</p><p>Example With a Package</p><p>Here’s an example where we create a package named `com.P1.P2`:</p><pre>package com.P1.P2;<br><br>class JTC {<br>    public static void main(String[] args) {<br>        Hello h1 = new Hello();<br>        Hai hai = new Hai();<br>        h1.m1();<br>        hai.show();<br>    }<br>}<br><br>class Hello {<br>    void m1() {<br>        System.out.println(&quot;m1 in Hello&quot;);<br>    }<br>}<br><br>class Hai {<br>    void show() {<br>        System.out.println(&quot;show in Hai&quot;);<br>    }<br>}</pre><p>Output:</p><pre>m1 in Hello<br>show in Hai</pre><p>- After compiling, a directory structure will be created as `com -&gt; P1 -&gt; P2`, where all `.class` files (`LMS.class`, `Hello.class`, and `Hai.class`) will be stored in the `P2` folder.</p><p><strong>Accessing Classes from Another Package</strong></p><p>Java enforces rules to access classes from different packages to ensure encapsulation. If you need to access a class from another package, you must use either the fully qualified name or the import statement.</p><p>Using Fully Qualified Names</p><pre>package com.P2;<br><br>public class JTC {<br>    public static void main(String[] args) {<br>        com.P1.A a1 = new com.P1.A(); // Using the fully qualified name<br>        a1.m1();<br>    }<br>}</pre><p>Using the import Statement</p><pre>package com.P2;<br><br>import com.P1.A; // Importing class A from the com.P1 package<br><br>public class JTC {<br>    public static void main(String[] args) {<br>        A a1 = new A();<br>        a1.m1();<br>    }<br>}</pre><p>This approach is more readable because you don’t have to type the full package name each time.</p><p><strong>Importing an Entire Package</strong></p><p>You can also import all classes in a package using the following syntax:</p><pre>import com.P1.*; // Imports all classes in the com.P1 package</pre><p>This way, you can use all classes (`A`, `B`, `C`, etc.) in the `com.P1` package without explicitly importing each one.</p><p><strong>Static Import in Java</strong></p><p>Static import allows you to import static members of a class directly so you can use them without the class name.</p><p>Example</p><pre>package com.P2;<br><br>import static com.P1.A.a; // Importing static variable &#39;a&#39;<br>import static com.P1.A.m1; // Importing static method &#39;m1&#39;<br><br>public class JTC {<br>    public static void main(String[] args) {<br>        System.out.println(&quot;a :- &quot; + a); // Using static variable &#39;a&#39; directly<br>        m1(); // Calling static method &#39;m1&#39; directly<br>    }<br>}</pre><p>Summary of Key Points</p><p>1. Packages group related classes and help avoid naming conflicts.</p><p>2. Use the `-d` flag during compilation to create the package directory structure.</p><p>3. To access classes from another package, you must use the fully qualified name or the `import` statement.</p><p>4. You can import static members using the `static import` statement.</p><p>5. The package declaration must always be the first statement in a Java source file.</p><p>Packages are crucial for organizing code in Java, especially in large-scale applications, making them more modular and easier to maintain.</p><h3>Access Modifiers in Java</h3><p>Access modifiers in Java are keywords used to define the accessibility or visibility of variables, methods, constructors, and classes. They help manage access control and set the level of access for different parts of a program. In Java, there are four main access modifiers:</p><p>1. Public</p><p>2. Protected</p><p>3. Default (no keyword)</p><p>4. Private</p><p>Let’s go through each in detail.</p><p>1. Public Access Modifier</p><p>- Keyword: `public`</p><p>- Description: When a member (variable, method, or class) is declared as `public`, it is accessible from any other class, whether in the same package or in a different package.</p><p>- Scope:</p><p>- Same class: Yes</p><p>- Different class in the same package: Yes</p><p>- Different class in different package: Yes (through inheritance or directly)</p><p>- Outside the package: Yes</p><p>- Access Privilege: It has the highest access privilege among all modifiers.</p><p>Example:</p><pre>package com.P1;<br><br>public class A {<br>    public int a = 10;<br><br>    public void display() {<br>        System.out.println(&quot;Public member accessed&quot;);<br>    }<br>}</pre><p>2. Protected Access Modifier</p><p>- Keyword: `protected`</p><p>- Description: Members declared with `protected` are accessible in the same package and can also be accessed in subclasses in different packages using inheritance.</p><p>- Scope:</p><p>- Same class: Yes</p><p>- Different class in the same package: Yes</p><p>- Different class in different package: Yes (only through inheritance)</p><p>- Outside the package: No (unless accessed through inheritance)</p><p>- Note: Objects of a class in a different package cannot directly access protected members without inheritance.</p><p>Example:</p><pre>package com.P1;<br><br>public class A {<br>    protected int b = 20;<br><br>    protected void show() {<br>        System.out.println(&quot;Protected member accessed&quot;);<br>    }<br>}</pre><p>3. Default (No Modifier) Access Modifier</p><p>- Keyword: No keyword (`default` is not a keyword)</p><p>- Description: When no access modifier is specified, the member is considered to have default access. It is only accessible within the same package.</p><p>- Scope:</p><p>- Same class: Yes</p><p>- Different class in the same package: Yes</p><p>- Different class in different package: No</p><p>- Outside the package: No</p><p>- Note: You cannot explicitly use the `default` keyword.</p><p>Example:</p><pre>package com.P1;<br><br>class A {<br>    int c = 30; // Default access<br><br>    void print() {<br>        System.out.println(&quot;Default member accessed&quot;);<br>    }<br>}</pre><p>4. Private Access Modifier</p><p>- Keyword: `private`</p><p>- Description: Private members are only accessible within the class in which they are declared. They are not visible to any other class, even subclasses or classes within the same package.</p><p>- Scope:</p><p>- Same class: Yes</p><p>- Different class in the same package: No</p><p>- Different class in different package: No</p><p>- Outside the package: No</p><p>- Access Privilege: It has the lowest access privilege among all modifiers.</p><p>Example:</p><pre>package com.P1;<br><br>public class A {<br>    private int d = 40; // Private access<br><br>    private void secret() {<br>        System.out.println(&quot;Private member accessed&quot;);<br>    }<br>}</pre><p>Example Scenarios</p><p>To better understand how these access modifiers work in practice, let’s explore some scenarios using the classes defined above.</p><p>Example 1: Accessing from the Same Package</p><pre>package com.P1;<br><br>public class B {<br>    public static void main(String[] args) {<br>        A a1 = new A();<br>        System.out.println(a1.a); // Public access<br>        System.out.println(a1.b); // Protected access<br>        System.out.println(a1.c); // Default access<br>        // System.out.println(a1.d); // Error: Private access<br>    }<br>}</pre><p>Output:</p><pre>10<br>20<br>30</pre><p>Example 2: Accessing from a Different Package Using Object</p><pre>package com.P2;<br>import com.P1.A;<br><br>public class C {<br>    public static void main(String[] args) {<br>        A a1 = new A();<br>        System.out.println(a1.a); // Public access<br>        // System.out.println(a1.b); // Error: Protected access<br>        // System.out.println(a1.c); // Error: Default access<br>        // System.out.println(a1.d); // Error: Private access<br>    }<br>}</pre><p>Output:</p><pre>10</pre><p>Example 3: Accessing from a Different Package Using Inheritance</p><pre>package com.P2;<br>import com.P1.A;<br><br>public class D extends A {<br>    public static void main(String[] args) {<br>        D d1 = new D();<br>        System.out.println(d1.a); // Public access<br>        System.out.println(d1.b); // Protected access<br>        // System.out.println(d1.c); // Error: Default access<br>        // System.out.println(d1.d); // Error: Private access<br>    }<br>}</pre><p>Output:</p><pre>10<br>20</pre><p>Summary Table of Access Modifier Visibility</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/889/1*-PJHx7n0rzpUoW9nNRabAA.png" /></figure><p>This table summarizes the visibility of each access modifier for different scenarios, helping you decide which one to use based on your needs.</p><p><strong>Explain early binding and late binding concept ?</strong></p><p>In Java, early binding and late binding are concepts related to method invocation, specifically to when and how the method that should be called is determined by the Java Virtual Machine (JVM). Let’s go into detail about each concept.</p><p><strong>1. Early Binding (Static Binding)</strong></p><p>- Definition: Early binding, also known as static binding, occurs when the method to be called is determined at compile time. In other words, the method invocation is resolved by the compiler, and the address of the method is linked to the method call before the program runs.</p><p>- Use cases: Early binding happens with:</p><p>- Static methods</p><p>- Private methods</p><p>- Final methods</p><p>- Methods in the same class without using inheritance</p><p>These methods are resolved at compile time because they cannot be overridden.</p><p>- Example:</p><pre>class Animal {<br>    static void makeSound() {  // Static method<br>        System.out.println(&quot;Some generic animal sound&quot;);<br>    }<br>}<br><br>class Dog extends Animal {<br>    static void makeSound() {  // Static method, doesn&#39;t override<br>        System.out.println(&quot;Bark&quot;);<br>    }<br>}<br><br>public class Main {<br>    public static void main(String[] args) {<br>        Animal animal = new Dog();<br>        animal.makeSound();  // Early binding occurs here<br>    }<br>}</pre><p>Output:</p><pre>Some generic animal sound</pre><p>Explanation: In this example, even though the object `animal` refers to an instance of `Dog`, the `makeSound()` method from the `Animal` class is called because it’s a static method. The method is resolved at compile time, which is why it’s known as early binding.</p><p>- Advantages: Early binding has a performance advantage because the method to be executed is determined during compilation, reducing the overhead at runtime.</p><p><strong>2. Late Binding (Dynamic Binding)</strong></p><p>- Definition: Late binding, also known as dynamic binding, occurs when the method to be called is determined at runtime based on the object’s type. This happens because the JVM defers the method resolution until the program runs.</p><p>- Use cases: Late binding occurs with:</p><p>- Instance methods that can be overridden (non-static and non-final)</p><p>- Methods that rely on polymorphism</p><p>This enables polymorphic behavior, where the appropriate method for the object type is called at runtime.</p><p>Example:</p><pre>class Animal {<br>    void makeSound() {  // Instance method<br>        System.out.println(&quot;Some generic animal sound&quot;);<br>    }<br>}<br><br>class Dog extends Animal {<br>    @Override<br>    void makeSound() {  // Overridden method<br>        System.out.println(&quot;Bark&quot;);<br>    }<br>}<br><br>public class Main {<br>    public static void main(String[] args) {<br>        Animal animal = new Dog();<br>        animal.makeSound();  // Late binding occurs here<br>    }<br>}</pre><p>- Output:</p><pre>Bark</pre><p>Explanation: In this case, `animal` is a reference of type `Animal` but is actually pointing to an instance of `Dog`. At runtime, the JVM looks at the actual object (`Dog`) and calls the `makeSound()` method of the `Dog` class, which is why we get the output `Bark`.</p><p>- Advantages: Late binding supports polymorphism, allowing code to be more flexible and extensible. It enables overriding methods, where the method called depends on the object’s runtime type.</p><p><strong>Key Differences Between Early Binding and Late Binding</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/885/1*ZKc3UCgcjsDvanMr5pIORw.png" /></figure><p><strong>Why Early and Late Binding Matter in Java</strong></p><p>- Efficiency: Early binding is faster because method calls are resolved at compile time, which makes the code execute more quickly.</p><p>- Flexibility: Late binding provides flexibility and extensibility in the code by allowing polymorphism, where the method that gets called depends on the runtime object.</p><p><strong>Real-World Example Scenario</strong></p><p>Consider an example of a payment system:</p><p>- Early Binding: If you have a `final` method that checks the status of a payment, it cannot be overridden by subclasses. This method is bound at compile time, ensuring that the correct version of the method is always used.</p><p>- Late Binding: If you have different types of payments like `CreditCardPayment` and `PaypalPayment` that inherit from a superclass `Payment`, and they override a method `processPayment()`, the method that gets called depends on the type of payment object created at runtime.</p><p><strong>When to Use Early Binding and Late Binding</strong></p><p>- Use early binding when the method does not need to be overridden, as it improves performance by avoiding runtime method lookups.</p><p>- Use late binding when you need polymorphic behavior, and the method should behave differently based on the actual object type.</p><p>Understanding the differences between early binding and late binding helps in designing efficient and flexible Java programs that leverage both compile-time and runtime capabilities.</p><p><strong>How to create singleton class ?</strong></p><p>Creating a singleton class in Java ensures that a class has only one instance and provides a global point of access to it. Here are a few common methods to implement a singleton in Java:</p><p>1. Lazy Initialization (Thread-Safe)</p><pre>public class Singleton {<br>    private static Singleton instance;<br><br>    private Singleton() {<br>        // private constructor to prevent instantiation<br>    }<br><br>    public static synchronized Singleton getInstance() {<br>        if (instance == null) {<br>            instance = new Singleton();<br>        }<br>        return instance;<br>    }<br>}</pre><p>2. Eager Initialization</p><pre>public class Singleton {<br>    private static final Singleton instance = new Singleton();<br><br>    private Singleton() {<br>        // private constructor to prevent instantiation<br>    }<br><br>    public static Singleton getInstance() {<br>        return instance;<br>    }<br>}</pre><p>3. Thread-Safe Singleton with Double-Checked Locking</p><pre>public class Singleton {<br>    private static volatile Singleton instance;<br><br>    private Singleton() {<br>        // private constructor to prevent instantiation<br>    }<br><br>    public static Singleton getInstance() {<br>        if (instance == null) {<br>            synchronized (Singleton.class) {<br>                if (instance == null) {<br>                    instance = new Singleton();<br>                }<br>            }<br>        }<br>        return instance;<br>    }<br>}</pre><p>4. Enum Singleton</p><p>Using an enum is the simplest way to create a singleton in Java. It is inherently thread-safe and prevents serialization issues.</p><pre>public enum Singleton {<br>    INSTANCE;<br><br>    // Any additional methods can be added here<br>}</pre><p>Summary</p><p>- Lazy Initialization is useful if the instance is resource-intensive and may not be needed immediately.</p><p>- Eager Initialization is simple and safe, but creates the instance at startup.</p><p>- Double-Checked Locking provides a balance of lazy initialization and thread safety.</p><p>- Enum Singleton is the recommended approach for its simplicity and built-in serialization protection.</p><h4>Lang Package</h4><p><a href="https://medium.com/@pratik.941/java-lang-package-in-java-04c77e1d3ca7">Link</a></p><h4>Exception Handling</h4><p><a href="https://medium.com/@pratik.941/understanding-exception-handling-in-java-f1c538a95299?source=your_stories_page-------------------------------------">Link</a></p><h4>Multithreading</h4><p><a href="https://medium.com/@pratik.941/understanding-threads-and-multithreading-in-java-part-1-94c0cfa6a5ed">Link</a></p><h4>Collections</h4><p><a href="https://medium.com/@pratik.941/collection-framework-in-java-revision-f641efc230b3">Link</a></p><h4>Generics</h4><p><a href="https://medium.com/@pratik.941/understanding-generics-in-java-a-comprehensive-guide-afd437f413cf?source=your_stories_page-------------------------------------">Link</a></p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=0308ddc391cd" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>