Popular Posts

July 15, 2024

Find Longest Substring Without Repeating Characters Java Program

 
Program: 

Find longest substring without repeating characters?

Description:
Given a string, find the longest substrings without repeating characters. Iterate through the given string, find the longest maximum substrings.

Code:

package com.java2novice.algos;

import java.util.HashSet;
import java.util.Set;

public class MyLongestSubstr {

    private Set<String> subStrList = new HashSet<String>();
    private int finalSubStrSize = 0;
    
    public Set<String> getLongestSubstr(String input){
        //reset instance variables
        subStrList.clear();
        finalSubStrSize = 0;
        // have a boolean flag on each character ascii value
        boolean[] flag = new boolean[256];
        int j = 0;
        char[] inputCharArr = input.toCharArray();
        for (int i = 0; i < inputCharArr.length; i++) {
            char c = inputCharArr[i];
            if (flag[c]) {
                extractSubString(inputCharArr,j,i);
                for (int k = j; k < i; k++) {
                    if (inputCharArr[k] == c) {
                        j = k + 1;
                        break;
                    }
                    flag[inputCharArr[k]] = false;
                }  
            } else {
                flag[c] = true;
            }
        }
        extractSubString(inputCharArr,j,inputCharArr.length);
        return subStrList;
    }
    
    private String extractSubString(char[] inputArr, int start, int end){
        
        StringBuilder sb = new StringBuilder();
        for(int i=start;i<end;i++){
            sb.append(inputArr[i]);
        }
        String subStr = sb.toString();
        if(subStr.length() > finalSubStrSize){
            finalSubStrSize = subStr.length();
            subStrList.clear();
            subStrList.add(subStr);
        } else if(subStr.length() == finalSubStrSize){
            subStrList.add(subStr);
        }
        
        return sb.toString();
    }

    public static void main(String a[]){
        MyLongestSubstr mls = new MyLongestSubstr();
        System.out.println(mls.getLongestSubstr("java2novice"));
        System.out.println(mls.getLongestSubstr("java_language_is_sweet"));
        System.out.println(mls.getLongestSubstr("java_java_java_java"));
        System.out.println(mls.getLongestSubstr("abcabcbb"));
    }
}

Output:

[a2novice]
[uage_is]
[_jav, va_j]
[cab, abc, bca]

To find the longest substring without repeating characters in Java, you can use a sliding window approach with a HashMap to keep track of the characters and their positions. Here's a Java program that demonstrates this approach:

import java.util.HashMap;
import java.util.Map;

public class LongestSubstringWithoutRepeating {
    public static void main(String[] args) {
        String input = "abcabcbb";
        System.out.println("The longest substring without repeating characters in '" + input + "' is: " + 
                            findLongestSubstring(input));
    }

    public static String findLongestSubstring(String s) {
        int n = s.length();
        int maxLength = 0;
        int start = 0;
        int startOfLongest = 0;
        
        Map<Character, Integer> map = new HashMap<>();

        for (int end = 0; end < n; end++) {
            char currentChar = s.charAt(end);

            if (map.containsKey(currentChar)) {
                start = Math.max(start, map.get(currentChar) + 1);
            }

            map.put(currentChar, end);

            if (end - start + 1 > maxLength) {
                maxLength = end - start + 1;
                startOfLongest = start;
            }
        }

        return s.substring(startOfLongest, startOfLongest + maxLength);
    }
}

Explanation:

  1. Variables:

    • n: Length of the input string.
    • maxLength: The length of the longest substring found.
    • start: The start index of the current window (substring being considered).
    • startOfLongest: The start index of the longest substring found.
  2. HashMap: Used to store the last occurrence of each character.

  3. Sliding Window:

    • Iterate through the string using end as the end index of the window.
    • For each character at end, check if it is already in the map (which means it has occurred before within the current window).
    • If it is, update the start position to be one more than the last occurrence of the character to avoid repeating characters within the window.
    • Update the position of the current character in the map.
    • Update maxLength and startOfLongest if the current window is longer than the previously found longest substring.
  4. Result: Return the longest substring using the substring method with startOfLongest and maxLength.

This program will output the longest substring without repeating characters for a given input string. For example, given the input "abcabcbb", the output will be "abc".

Difference between == and .equals() method in Java

 

In Java, == and the .equals() method are used to compare objects, but they serve different purposes and work in different ways. Here's a detailed explanation of their differences:

== Operator

Purpose:

  • The == operator is used to compare primitive data types and object references.

Usage:

  • Primitive Data Types: For primitive data types (e.g., int, float, char), == compares the actual values.
  • Object References: For object references, == checks if the two references point to the same memory location (i.e., it checks for reference equality).

Example:

// Comparing primitive data types

int a = 10;

int b = 10;

System.out.println(a == b); // Output: true


// Comparing object references

String str1 = new String("hello");

String str2 = new String("hello");

System.out.println(str1 == str2); // Output: false (different objects in memory)


String str3 = str1;

System.out.println(str1 == str3); // Output: true (same object in memory)


.equals() Method

Purpose:

  • The .equals() method is used to compare the contents (or state) of two objects for logical equality.

Usage:

  • Default Behavior: The default implementation of .equals() in the Object class checks for reference equality (like ==).
  • Overridden Behavior: Many classes, such as String, Integer, and user-defined classes, override .equals() to compare the values contained within the objects rather than their memory addresses.

Example:

// Comparing object contents

String str1 = new String("hello");

String str2 = new String("hello");

System.out.println(str1.equals(str2)); // Output: true (same content)


Integer num1 = new Integer(100);

Integer num2 = new Integer(100);

System.out.println(num1.equals(num2)); // Output: true (same value)


// Custom class example

class Person {

    String name;

    

    Person(String name) {

        this.name = name;

    }

    

    @Override

    public boolean equals(Object obj) {

        if (this == obj) {

            return true;

        }

        if (obj == null || getClass() != obj.getClass()) {

            return false;

        }

        Person person = (Person) obj;

        return name.equals(person.name);

    }

}


Person p1 = new Person("John");

Person p2 = new Person("John");

System.out.println(p1.equals(p2)); // Output: true (same name content)


Key Differences

  1. Comparison Basis:

    • ==: Compares memory addresses (reference equality) for objects and actual values for primitive types.
    • .equals(): Compares logical equality (the contents of objects) when properly overridden.
  2. Default Behavior:

    • ==: Always checks reference equality for objects.
    • .equals(): By default, checks reference equality, but can be overridden to check logical equality.
  3. Common Use Cases:

    • ==: Best suited for comparing primitive data types and checking if two references point to the same object.
    • .equals(): Best suited for comparing the contents of objects, such as strings, numbers, or custom objects.
  4. Overriding:

    • ==: Cannot be overridden as it is an operator.
    • .equals(): Can and often should be overridden in user-defined classes to provide meaningful equality checks.

Practical Example

public class ComparisonExample {
    public static void main(String[] args) {
        String s1 = new String("example");
        String s2 = new String("example");

        // Comparing references
        System.out.println(s1 == s2); // Output: false

        // Comparing contents
        System.out.println(s1.equals(s2)); // Output: true
    }
}

In this example, s1 == s2 is false because s1 and s2 are different objects in memory, whereas s1.equals(s2) is true because the content of the strings is the same.

Understanding the difference between == and .equals() is crucial for correctly comparing objects and values in Java.


July 14, 2024

What is Class and how to declare the class in Java

 

In Java, a class is a blueprint or template for creating objects. It defines a type by bundling data and methods that work on the data into a single unit. A class can contain fields (variables), methods, constructors, blocks, and nested classes and interfaces.

Declaring a Class in Java

To declare a class in Java, you use the class keyword followed by the class name. The body of the class is enclosed in curly braces {}. Here’s a basic structure of a class declaration:

public class ClassName {

    // Fields (variables)

    int field1;

    String field2;


    // Constructor

    public ClassName(int field1, String field2) {

        this.field1 = field1;

        this.field2 = field2;

    }


    // Methods

    public void displayInfo() {

        System.out.println("Field1: " + field1 + ", Field2: " + field2);

    }


    // Other methods, blocks, nested classes/interfaces can be added here

}


Components of a Class

  1. Fields: Variables that store the state or data of an object.
  2. Constructor: A special method used to initialize objects. It has the same name as the class and no return type.
  3. Methods: Functions defined inside a class that describe the behaviors or actions an object can perform.
  4. Blocks: Code blocks, like static blocks or instance initializer blocks.
  5. Nested Classes/Interfaces: Classes or interfaces defined within another class.

Example: Declaring a Class in Java

Here’s an example of a class Car that includes fields, a constructor, and methods:

public class Car {

    // Fields (variables)

    private String color;

    private String model;


    // Constructor

    public Car(String color, String model) {

        this.color = color;

        this.model = model;

    }


    // Methods

    public void displayInfo() {

        System.out.println("Car model: " + model + ", Color: " + color);

    }


    // Getter and Setter methods

    public String getColor() {

        return color;

    }


    public void setColor(String color) {

        this.color = color;

    }


    public String getModel() {

        return model;

    }


    public void setModel(String model) {

        this.model = model;

    }

}


Creating Objects from a Class

To use the class, you create objects (instances) of the class. Here’s how you can create objects and call methods on them:

public class Main {

    public static void main(String[] args) {

        // Creating an object of the Car class

        Car myCar = new Car("Red", "Toyota");


        // Calling methods on the object

        myCar.displayInfo(); // Output: Car model: Toyota, Color: Red


        // Using getter and setter methods

        myCar.setColor("Blue");

        System.out.println("Updated Color: " + myCar.getColor()); // Output: Updated Color: Blue

    }

}


Access Modifiers

Classes and their members (fields, methods, etc.) can have access modifiers to define their visibility:

  • public: The class or member is accessible from any other class.
  • private: The member is accessible only within the class it is declared.
  • protected: The member is accessible within the same package and subclasses.
  • Default (no modifier): The member is accessible within the same package.

Summary

A class in Java is a fundamental building block used to create objects and define their properties and behaviors. By using classes, Java promotes the principles of object-oriented programming, making it easier to manage and organize complex software systems.


July 11, 2024

Difference between Throw and Throws in Java

 

In Java, throw and throws are both related to exception handling, but they serve different purposes:

throw

  • Purpose:

    • throw is used to explicitly throw an exception within a method or block of code.
    • It is used to indicate that a specific exception has occurred programmatically.
  • Syntax:

    throw throwableInstance;

    • Here, throwableInstance is an object of type Throwable or its subclass (typically an Exception or Error).
  • Usage:

    • You can use throw to throw checked exceptions, unchecked exceptions, or errors.
    • It is typically used inside a method to handle exceptional situations where normal execution cannot proceed.
  • Example:

    public void withdraw(int amount) throws InsufficientFundsException {

        if (amount > balance) {

            throw new InsufficientFundsException("Not enough balance to withdraw");

        }

        // Withdraw logic

    }

throws

  • Purpose:

    • throws is used in method signatures to declare that the method may throw one or more exceptions.
    • It specifies the exceptions that a method can throw, allowing the caller to handle them appropriately.
  • Syntax:

    returnType methodName(parameters) throws exceptionType1, exceptionType2, ... {

        // Method body

    }

    • Here, throws exceptionType1, exceptionType2, ... declares that the method can throw exceptions of types specified.
  • Usage:

    • Use throws to declare checked exceptions that a method might throw but doesn't handle itself.
    • It does not handle exceptions; it simply declares that the method might throw certain exceptions, which the caller must handle or propagate further.
  • Example:

    public void readFile(String fileName) throws FileNotFoundException {

        // Code to read a file

    }

Key Differences

  • throw:

    • Used to throw an exception explicitly within a method or block.
    • Specifies the actual instance of Throwable (exception or error) being thrown.
    • Used inside method bodies to handle exceptional conditions.
  • throws:

    • Used in method declarations to specify the exceptions that a method may throw.
    • Lists the types of exceptions that the method might throw, allowing the caller to handle them.
    • Does not throw exceptions itself but indicates the potential for exceptions to be thrown.

Summary

  • throw is used to throw an exception programmatically within a method or block.
  • throws is used in method declarations to specify the types of exceptions that a method may throw.
  • Both are essential for proper exception handling in Java, where throw initiates exception handling and throws declares potential exceptions that need handling in caller methods.

Difference between Stack and Heap Memory in Java

 

In Java, memory management revolves around two main areas: the stack and the heap. These two areas serve different purposes and manage memory differently:

Stack Memory

  1. Purpose:

    • The stack is used for static memory allocation.
    • It stores primitive values (e.g., int, char, boolean), references to objects, and method invocation frames.
  2. Allocation:

    • Memory allocation and deallocation in the stack follows a Last In, First Out (LIFO) model.
    • Local variables, method parameters, and method calls are stored in the stack.
  3. Size:

    • Stack memory is typically smaller in size compared to heap memory.
    • The size of the stack is fixed and set at the start of the program.
  4. Access:

    • Access to stack memory is fast and efficient.
    • Memory allocation and deallocation are handled automatically by the compiler.
  5. Lifetime:

    • The lifetime of variables in stack memory is short-lived. They exist as long as the method is executing.
    • When a method ends, the variables in the stack are popped off, and the memory is freed.

Heap Memory

  1. Purpose:

    • The heap is used for dynamic memory allocation.
    • It stores objects (instances of classes) and arrays.
  2. Allocation:

    • Memory allocation and deallocation in the heap are not as organized as in the stack.
    • Objects are allocated in the heap as needed and may exist longer than the method that created them.
  3. Size:

    • Heap memory is larger compared to stack memory.
    • The size of the heap is dynamic and can grow or shrink during the program's execution.
  4. Access:

    • Access to heap memory is comparatively slower than stack memory.
    • Garbage collection is performed in the heap to reclaim memory occupied by objects that are no longer referenced.
  5. Lifetime:

    • Objects in heap memory may have a longer lifetime than stack-based variables.
    • They are accessible as long as they are referenced by some part of the program.

Example of Stack vs. Heap


public class MemoryExample {
    public static void main(String[] args) {
        // Stack variables
        int a = 10;
        String name = "Java";

        // Heap objects
        Object obj = new Object();  // Object created in heap
        int[] array = new int[5];   // Array created in heap
    }
}

  • In the above example:
    • a and name are stored in stack memory.
    • obj and array are objects stored in heap memory.

Summary

  • Stack is used for static memory allocation, faster access, and manages method execution flow.
  • Heap is used for dynamic memory allocation, larger storage, and manages objects and arrays.

Understanding the differences between stack and heap memory helps in optimizing memory usage and designing efficient Java programs.


Types of Access specifier or modifiers in Java

 

In Java, access specifiers (also known as access modifiers) are keywords used to specify the accessibility or visibility of classes, methods, variables, and constructors. These modifiers control how classes and their members can be accessed by other classes and packages. There are four types of access specifiers in Java:

1. public

  • Most Accessible: The public modifier allows access from any other class or package.
  • Classes, methods, variables, and constructors declared as public can be accessed by any other class.

Example:


public class PublicClass {
    // Class definition
}

public void publicMethod() {
    // Method definition
}

2. protected

  • Package and Subclass Access: The protected modifier allows access within the same package and by subclasses (even if they are in different packages).
  • It is not applicable to top-level classes.

Example:

protected class ProtectedClass {
    // Class definition
}

protected void protectedMethod() {
    // Method definition
}

3. default (no modifier)

  • Package-Private Access: When no access specifier is specified, it is called "default" (package-private).
  • Classes, methods, variables, and constructors with default access can only be accessed by classes in the same package.

Example:

class DefaultClass {
    // Class definition
}

void defaultMethod() {
    // Method definition
}

4. private

  • Most Restrictive: The private modifier restricts access to only within the same class.
  • private members are not accessible from subclasses or from other classes in the same package.

Example:

private class PrivateClass {
    // Class definition
}

private void privateMethod() {
    // Method definition
}

Comparison of Access Modifiers

  • public: Most accessible. Can be accessed from any class or package.
  • protected: Accessible within the same package and by subclasses (even in different packages).
  • default: Accessible only within the same package.
  • private: Most restrictive. Accessible only within the same class.

Best Practices

  • Encapsulation: Use access modifiers to enforce encapsulation and control access to your classes and members.
  • Choose Wisely: Select the appropriate access level for each class member to ensure proper encapsulation and security of your code.

Understanding and correctly applying these access modifiers is crucial for designing Java programs that are both secure and maintainable.



By default class follows which access modifier in Java

 

In Java, if no access modifier is explicitly specified before the class keyword, the class has default (package-private) access. This means the class is accessible only within its own package. Here’s what you need to know about default access for classes in Java:

Default (Package-Private) Access Modifier

  • No Modifier: If you declare a class without any access modifier, it is accessible only within its own package.

    class MyClass {

        // Class definition

    }

  • Visibility: Classes with default access are visible only to other classes within the same package.

  • Example:

    // File: MyClass.java

    package com.example;


    class MyClass {

        // Class definition

    }

// File: AnotherClass.java
package com.example;

public class AnotherClass {
    public static void main(String[] args) {
        // MyClass can be accessed here because it's in the same package
        MyClass myObject = new MyClass();
    }
}

Access Modifiers in Java Classes

Java provides several access modifiers for classes:

  • public: Accessible from any other class.

    public class PublicClass {

        // Class definition

    }

  • protected: Accessible within the same package and by subclasses (even if they are in different packages).

    protected class ProtectedClass {
        // Class definition
    }
  • private: Accessible only within the same class.

    private class PrivateClass {

        // Class definition

    }

  • Default (Package-Private): Accessible only within the same package.

    class PackagePrivateClass {

        // Class definition

    }

Choosing an Access Modifier

  • Encapsulation: Use the most restrictive access level that makes sense for the class. This helps in encapsulating and protecting your class members appropriately.

  • Default Access: Use default access when you want the class to be accessible only within its own package and not from outside.

Summary

By default, in Java, if no access modifier is specified before the class keyword, the class has default (package-private) access. This means it is accessible only within its own package. Understanding and correctly using access modifiers is crucial for designing well-structured and maintainable Java applications.

Can we use special character to create the class in Java

 

In Java, class names can include special characters in specific contexts, but generally, it is recommended to adhere to standard naming conventions for classes to maintain code clarity and compatibility. Here are the rules and considerations regarding the use of special characters in Java class names:

Rules for Class Names in Java

  1. Allowed Characters:

    • Class names can include letters (A-Z, a-z), digits (0-9), dollar signs ($), and underscores (_).
    • The dollar sign ($) and underscore (_) are commonly used, but their use should be limited to specific scenarios, such as naming conventions or inner classes.
  2. Special Characters:

    • Special characters like !, @, #, %, ^, &, *, (, ), -, +, =, [, ], {, }, ,, ., ;, /, \, |, <, >, ?, and : are not allowed in class names.
    • Using such characters will result in a compilation error.
  3. Naming Conventions:

    • Follow CamelCase convention for class names (e.g., MyClass, CarModel).
    • Start class names with an uppercase letter.
    • Use meaningful names that convey the purpose of the class.

Example of Valid and Invalid Class Names

  • Valid Class Names:

    public class MyClass {

        // Class definition

    }


    public class UserAccount {

        // Class definition

    }


    public class Car_Model {

        // Class definition (using underscore convention)

    }

  • Invalid Class Names:

    public class @Test {

        // Invalid: Cannot use @ symbol

    }


    public class 123Class {

        // Invalid: Cannot start with a digit

    }


    public class My_Class! {

        // Invalid: Cannot use special characters like !

    }


Use of $ and _ in Class Names

  • $ (Dollar Sign):

    • While technically allowed, it is primarily used in autogenerated code (e.g., by compilers or tools).
    • It is not recommended for general use in manually written class names.
  • _ (Underscore):

    • Often used to separate words in class names (e.g., Car_Model).
    • Avoid using _ at the beginning or end of class names unless there's a specific convention or requirement.

Best Practices

  • Clarity and Readability: Use clear and meaningful names that accurately describe the class's purpose.
  • Consistency: Follow consistent naming conventions across your codebase.
  • Avoid Ambiguity: Ensure that class names are unambiguous and do not cause confusion.

Summary

While Java allows flexibility in naming classes with certain characters ($ and _), it is advisable to adhere to standard naming conventions to maintain code readability and compatibility. Avoid using special characters that are not allowed by Java syntax rules, as they will result in compilation errors.


Can we create class name with numbers in Java

 

No, in Java, class names cannot start with a number. According to Java naming conventions and syntax rules:

  • Class names must begin with a letter (A to Z or a to z), currency character ($), or underscore (_).
  • After the first character, class names can include digits (0 to 9), currency characters ($), and underscores (_), in addition to letters (A to Z or a to z).

Valid Class Name Examples

  • Car
  • Account
  • MyClass
  • _Test
  • $ClassName
  • Car123
  • Student_Info

Invalid Class Name Examples

Class names starting with numbers are not allowed:

  • 123Class (Invalid)
  • 5Cars (Invalid)
  • 007Agent (Invalid)

Java Identifier Rules

Java identifiers (which include class names) must adhere to the following rules:

  1. Start Character: Can start with a letter (A-Z or a-z), $, or _.
  2. Subsequent Characters: After the first character, identifiers can include letters (A-Z or a-z), digits (0-9), $, or _.
  3. Keywords: Java keywords (like int, class, public, etc.) cannot be used as identifiers.
  4. Case Sensitivity: Java identifiers are case-sensitive (MyClass is different from myClass).

Example

public class MyClass {
    // Class definition
}

Summary

While Java allows flexibility in naming classes and other identifiers, it strictly enforces rules regarding the starting character of class names. By adhering to these naming conventions, developers ensure that their Java code is both syntactically correct and easy to understand for other programmers.


What are naming convention for class in Java

 

In Java, naming conventions for classes are important for readability, maintainability, and adherence to coding standards. These conventions are widely followed in the Java community to ensure consistency across different projects and to make code more understandable. Here are the main naming conventions for classes in Java:

1. Class Names

  • CamelCase: Class names should be in CamelCase.
    • Start with an uppercase letter.
    • Capitalize the first letter of each subsequent concatenated word.
    • Avoid underscores (_) or hyphens (-) between words.

Examples of Correct Class Names

  • Car
  • CustomerAccount
  • HttpRequest

2. Package Names

  • Lowercase: Package names should be in lowercase.
    • Use only lowercase letters.
    • Avoid underscores (_) or hyphens (-).

Example

  • com.example.project

3. Constants

  • Uppercase: Constants (final variables) should be in uppercase.
    • Use uppercase letters.
    • Separate words with underscores (_).

Example

public static final int MAX_LENGTH = 100;

4. Naming Patterns to Avoid

  • Underscores: Avoid using underscores (_) in class names. Use CamelCase instead.
  • Hyphens: Avoid using hyphens (-) in class names. Use CamelCase instead.

Best Practices

  • Meaningful Names: Choose names that are descriptive and convey the purpose or meaning of the class.
  • Consistency: Maintain consistent naming conventions throughout your codebase.
  • Abbreviations: Avoid overly cryptic abbreviations. Use abbreviations only if they are widely understood (e.g., URL).

Example of Class Naming Convention

public class ShoppingCart {
    // Class definition
}

Summary

Following naming conventions in Java, especially for classes, improves code readability and maintainability. By adhering to these conventions, developers can ensure that their code is consistent and easily understandable by others. This consistency becomes particularly important in larger projects and teams where multiple developers are working together.


What is object and how to declare the Object in Java

 

In Java, an object is an instance of a class. It is a concrete realization of a class, containing actual values instead of variables. Objects in Java are created using the new keyword followed by the class constructor.

Declaring and Creating an Object in Java

To declare and create an object in Java, you follow these steps:

  1. Declaration: Define a variable of the class type.
  2. Instantiation: Use the new keyword to create the object.
  3. Initialization: Call the class constructor to initialize the object.

Here's the syntax:

ClassName objectName = new ClassName(parameters);

Example

Let's use the Car class from the previous example to create an object:

Step 1: Define the Car Class

public class Car {
    // Fields (variables)
    private String color;
    private String model;

    // Constructor
    public Car(String color, String model) {
        this.color = color;
        this.model = model;
    }

    // Methods
    public void displayInfo() {
        System.out.println("Car model: " + model + ", Color: " + color);
    }

    // Getter and Setter methods
    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public String getModel() {
        return model;
    }

    public void setModel(String model) {
        this.model = model;
    }
}

Step 2: Create and Initialize an Object


public class Main {
    public static void main(String[] args) {
        // Creating an object of the Car class
        Car myCar = new Car("Red", "Toyota");

        // Calling methods on the object
        myCar.displayInfo(); // Output: Car model: Toyota, Color: Red

        // Using getter and setter methods
        myCar.setColor("Blue");
        System.out.println("Updated Color: " + myCar.getColor()); // Output: Updated Color: Blue
    }
}

Breakdown

  1. Declaration: Car myCar;

    • This declares a variable myCar of type Car.
  2. Instantiation: new Car("Red", "Toyota");

    • The new keyword creates a new instance of the Car class.
  3. Initialization: Car("Red", "Toyota");

    • The Car constructor is called to initialize the new object with the specified values.

Object Methods

Once an object is created, you can use its methods to interact with the object's data. Methods can include:

  • Getters and Setters: To access and modify private fields.
  • Other Methods: To perform operations related to the object's behavior.

Example with Multiple Objects

You can create multiple objects from the same class:

public class Main {

    public static void main(String[] args) {

        // Creating multiple objects of the Car class

        Car car1 = new Car("Red", "Toyota");

        Car car2 = new Car("Blue", "Honda");


        // Calling methods on the objects

        car1.displayInfo(); // Output: Car model: Toyota, Color: Red

        car2.displayInfo(); // Output: Car model: Honda, Color: Blue

    }

}

Summary

  • Object: An instance of a class containing actual data.
  • Declaration: Define a variable of the class type.
  • Instantiation: Use the new keyword to create an object.
  • Initialization: Call the class constructor to set initial values.

Objects are the core concept of object-oriented programming in Java, allowing developers to model real-world entities and their interactions within a program.


What is Object Oriented Programming System OOPS in Java

 

Object-Oriented Programming System (OOPS) in Java is a programming paradigm that uses "objects" to design applications and computer programs. It leverages several fundamental principles to organize software design and development. The main concepts of OOPS in Java include:

  1. Class and Object
  2. Inheritance
  3. Polymorphism
  4. Encapsulation
  5. Abstraction

1. Class and Object

  • Class: A blueprint or template for creating objects. It defines a type by bundling data and methods that work on the data into a single unit.

    public class Car {

        // Fields (variables)

        private String color;

        private String model;

        

        // Constructor

        public Car(String color, String model) {

            this.color = color;

            this.model = model;

        }

        

        // Methods

        public void displayInfo() {

            System.out.println("Car model: " + model + ", Color: " + color);

        }

    }

  • Object: An instance of a class. When a class is defined, no memory is allocated until an object of that class is created.

    public class Main {
        public static void main(String[] args) {
            // Creating an object of the Car class
            Car myCar = new Car("Red", "Toyota");
            myCar.displayInfo(); // Output: Car model: Toyota, Color: Red
        }
    }

2. Inheritance

Inheritance is a mechanism where one class (subclass/child class) inherits the fields and methods of another class (superclass/parent class). It promotes code reusability and establishes a relationship between different classes.

// Superclass

public class Vehicle {

    public void start() {

        System.out.println("Vehicle started");

    }

}


// Subclass

public class Bike extends Vehicle {

    public void ride() {

        System.out.println("Bike is being ridden");

    }

}


public class Main {

    public static void main(String[] args) {

        Bike myBike = new Bike();

        myBike.start(); // Inherited method

        myBike.ride();  // Subclass-specific method

    }

}


3. Polymorphism

Polymorphism allows objects to be treated as instances of their parent class rather than their actual class. The two types of polymorphism in Java are compile-time (method overloading) and runtime (method overriding).

  • Method Overloading: Multiple methods with the same name but different parameters.

    public class MathUtils {

        // Method overloading

        public int add(int a, int b) {

            return a + b;

        }

        

        public double add(double a, double b) {

            return a + b;

        }

    }

  • Method Overriding: A subclass provides a specific implementation of a method that is already defined in its superclass.

    class Animal {
        public void sound() {
            System.out.println("Animal makes a sound");
        }
    }

    class Dog extends Animal {
        @Override
        public void sound() {
            System.out.println("Dog barks");
        }
    }

    public class Main {
        public static void main(String[] args) {
            Animal myDog = new Dog();
            myDog.sound(); // Output: Dog barks (runtime polymorphism)
        }
    }

4. Encapsulation

Encapsulation is the technique of wrapping the data (variables) and code (methods) together as a single unit. It restricts direct access to some of an object's components, which can prevent the accidental modification of data.

public class Account {

    // Private data member

    private double balance;


    // Public getter method

    public double getBalance() {

        return balance;

    }


    // Public setter method

    public void setBalance(double balance) {

        if (balance >= 0) {

            this.balance = balance;

        }

    }

}


public class Main {

    public static void main(String[] args) {

        Account myAccount = new Account();

        myAccount.setBalance(1000.0);

        System.out.println("Account balance: " + myAccount.getBalance()); // Output: Account balance: 1000.0

    }

}


5. Abstraction

Abstraction is the concept of hiding the complex implementation details and showing only the necessary features of an object. It can be achieved using abstract classes and interfaces.

  • Abstract Class: Cannot be instantiated and may contain abstract methods (without implementation).

    abstract class Shape {

        // Abstract method

        abstract void draw();

        

        // Regular method

        public void display() {

            System.out.println("Displaying shape");

        }

    }


    class Circle extends Shape {

        @Override

        void draw() {

            System.out.println("Drawing circle");

        }

    }


    public class Main {

        public static void main(String[] args) {

            Shape myShape = new Circle();

            myShape.draw();    // Output: Drawing circle

            myShape.display(); // Output: Displaying shape

        }

    }

  • Interface: A reference type in Java, it is similar to a class and is a collection of abstract methods. A class implements an interface, thereby inheriting the abstract methods of the interface.

    interface Animal {
        void eat();
        void sleep();
    }

    class Cat implements Animal {
        @Override
        public void eat() {
            System.out.println("Cat eats");
        }
        
        @Override
        public void sleep() {
            System.out.println("Cat sleeps");
        }
    }

    public class Main {
        public static void main(String[] args) {
            Animal myCat = new Cat();
            myCat.eat();   // Output: Cat eats
            myCat.sleep(); // Output: Cat sleeps
        }
    }

Summary

OOPS in Java provides a framework for creating modular, reusable, and maintainable code. By leveraging classes and objects, inheritance, polymorphism, encapsulation, and abstraction, Java enables developers to design applications that are both efficient and easy to understand.



Differences between JDK JRE and JVM

 

Java Development Kit (JDK), Java Runtime Environment (JRE), and Java Virtual Machine (JVM) are key components of the Java platform. Each serves a specific purpose in the process of developing and running Java applications. Here's a detailed comparison of their differences:

Java Development Kit (JDK)

Overview:

  • The JDK is a software development kit used to develop Java applications.
  • It includes the JRE and development tools like the compiler (javac), debugger, and various other tools necessary for Java development.

Components:

  • JRE: Provides the libraries, Java Virtual Machine, and other components to run applications written in Java.
  • Development Tools: Includes tools such as the Java compiler, JavaDoc, Java debugger, etc.

Usage:

  • Used by developers to write, compile, and debug Java programs.
  • Necessary for developing Java applications and applets.

Example:

  • When you write Java code and compile it using javac, you are using the JDK.

Java Runtime Environment (JRE)

Overview:

  • The JRE is a part of the JDK that includes the JVM and a set of libraries and other files that JVM uses at runtime.
  • It provides the libraries, Java Virtual Machine, and other components to run applications written in Java.

Components:

  • JVM: The core part that executes Java bytecode.
  • Libraries: Essential libraries that Java programs need to run.
  • Other Components: Including configuration files, properties files, and other resources.

Usage:

  • Used to run Java applications on a user's machine.
  • Not used for developing Java applications, only for running them.

Example:

  • When you run a Java application using the java command, you are using the JRE.

Java Virtual Machine (JVM)

Overview:

  • The JVM is an abstract computing machine that enables a computer to run a Java program.
  • It is a part of both the JDK and JRE, and it performs all the tasks required to run the compiled Java program.

Components:

  • Class Loader: Loads class files into the JVM.
  • Bytecode Verifier: Checks the bytecode to ensure it does not violate Java security constraints.
  • Interpreter: Interprets the bytecode into machine code.
  • JIT Compiler: Just-In-Time compiler that improves performance by compiling bytecode into native machine code at runtime.
  • Garbage Collector: Manages memory by reclaiming memory used by objects that are no longer in use.

Usage:

  • Responsible for converting bytecode into machine-specific code and executing it.
  • Provides the environment in which Java bytecode is executed.

Example:

  • When you run a Java application, the JVM interprets the compiled bytecode and executes it on the host machine.

Summary of Differences

  1. Purpose:

    • JDK: Development environment for building Java applications.
    • JRE: Runtime environment for executing Java applications.
    • JVM: Executes Java bytecode, making Java applications platform-independent.
  2. Components:

    • JDK: Includes JRE + development tools (compiler, debugger, etc.).
    • JRE: Includes JVM + libraries + other components needed to run Java applications.
    • JVM: Part of both JDK and JRE, includes class loader, bytecode verifier, interpreter, JIT compiler, and garbage collector.
  3. Usage:

    • JDK: Needed for developing Java applications.
    • JRE: Needed for running Java applications.
    • JVM: Core part that actually executes Java bytecode.
  4. Inclusion:

    • JDK: Contains the JRE and other tools for development.
    • JRE: Contains the JVM and libraries necessary to run Java programs.
    • JVM: Integral part of both JDK and JRE, responsible for execution.

Example Workflow

  1. Development:

    • You write Java source code (.java files).
    • Use the JDK to compile the source code (javac MyProgram.java), which produces bytecode (.class files).
  2. Execution:

    • Use the JRE to run the compiled bytecode (java MyProgram).
    • The JVM, which is part of the JRE, loads, verifies, and executes the bytecode.

Understanding these components helps in effectively developing and running Java applications, ensuring that the correct environment is used for each phase of the software lifecycle.


Difference between Primitive and Object Data Types in Java

 

In Java, data types are categorized into two main types: primitive data types and object (reference) data types. Understanding the differences between these two categories is fundamental for Java programming. Here's a detailed comparison:

Primitive Data Types

Overview:

  • Primitive data types are the most basic data types in Java.
  • They are predefined by the language and named by a reserved keyword.
  • They hold their values directly in memory.
  • There are eight primitive data types in Java.

Primitive Data Types:

  1. byte: 8-bit signed integer. (byte b = 100;)
  2. short: 16-bit signed integer. (short s = 10000;)
  3. int: 32-bit signed integer. (int i = 100000;)
  4. long: 64-bit signed integer. (long l = 100000L;)
  5. float: Single-precision 32-bit IEEE 754 floating point. (float f = 234.5f;)
  6. double: Double-precision 64-bit IEEE 754 floating point. (double d = 123.4;)
  7. char: Single 16-bit Unicode character. (char c = 'A';)
  8. boolean: Has only two possible values: true and false. (boolean b = true;)

Characteristics:

  • Memory Allocation: Memory for primitive types is allocated on the stack.
  • Performance: Faster access and manipulation due to direct storage of values.
  • Default Values: Default values are predefined (e.g., 0 for numeric types, false for boolean, '\u0000' for char).
  • No Methods: Primitive types do not have methods or member variables.

Example:

int a = 5;

char c = 'A';

boolean b = true;


Object (Reference) Data Types

Overview:

  • Object data types (also known as reference types) are used to store references to objects.
  • They are instances of classes.
  • They include arrays, classes, and interfaces.

Common Object Data Types:

  • String: A sequence of characters.
  • Arrays: A collection of elements of the same type.
  • Classes: User-defined types that define objects.
  • Interfaces: Abstract types used to specify a behavior that classes must implement.

Characteristics:

  • Memory Allocation: Memory for object types is allocated on the heap.
  • Performance: Generally slower access compared to primitives due to indirect access via references.
  • Default Values: Default value is null.
  • Methods and Members: Objects can have methods and member variables.

Example:

String str = "Hello, World!";

int[] numbers = {1, 2, 3, 4, 5};

Person person = new Person("John", 30);


User-Defined Class Example:

class Person {

    String name;

    int age;


    Person(String name, int age) {

        this.name = name;

        this.age = age;

    }


    void display() {

        System.out.println("Name: " + name + ", Age: " + age);

    }

}


public class Main {

    public static void main(String[] args) {

        Person person = new Person("Alice", 25);

        person.display(); // Output: Name: Alice, Age: 25

    }

}


Key Differences

  1. Memory Allocation:

    • Primitive Types: Stored directly in memory (stack).
    • Object Types: Stored as references pointing to locations in memory (heap).
  2. Performance:

    • Primitive Types: Faster due to direct access.
    • Object Types: Slower due to indirect access via references.
  3. Default Values:

    • Primitive Types: Have predefined default values (e.g., 0, false).
    • Object Types: Default value is null.
  4. Methods and Members:

    • Primitive Types: Cannot have methods or member variables.
    • Object Types: Can have methods and member variables.
  5. Wrapper Classes:

    • Primitive Types: Each primitive type has a corresponding wrapper class (e.g., int -> Integer, char -> Character) that allows them to be used as objects.
    • Object Types: Are inherently classes and can be used directly as objects.

Example with Wrapper Classes:

Integer integerObject = Integer.valueOf(5); // Using Integer wrapper class for int

int intValue = integerObject.intValue(); // Unboxing to primitive int


Understanding the distinction between primitive and object data types is crucial for effective memory management, performance optimization, and correct application design in Java.


Difference between Hashset and Treeset in Java

 

In Java, both HashSet and TreeSet are implementations of the Set interface, which means they are collections that do not allow duplicate elements. However, they have different underlying data structures and characteristics. Here's a detailed comparison:

HashSet

Overview:

  • Implementation: Backed by a hash table.
  • Order: Does not guarantee any order of elements.
  • Performance: Provides constant-time performance for basic operations like add, remove, and contains.

Characteristics:

  • Null Elements: Allows one null element.
  • Performance: Generally faster than TreeSet for most operations (O(1) for add, remove, contains), assuming the hash function disperses elements properly among the buckets.
  • Hashing: Relies on the hashCode() method of the elements to determine where they should be placed.

Example:

import java.util.HashSet;

import java.util.Set;


public class HashSetExample {

    public static void main(String[] args) {

        Set<String> hashSet = new HashSet<>();

        hashSet.add("Apple");

        hashSet.add("Banana");

        hashSet.add("Cherry");


        System.out.println(hashSet);

    }

}


TreeSet

Overview:

  • Implementation: Backed by a red-black tree.
  • Order: Maintains elements in sorted order (natural order or using a specified comparator).

Characteristics:

  • Null Elements: Does not allow null elements (throws NullPointerException if attempted).
  • Performance: Generally slower than HashSet for most operations (O(log n) for add, remove, contains) due to the need to maintain the sorted order.
  • Sorting: Can automatically sort elements in their natural order or using a custom comparator provided at the set creation.

Example:

import java.util.Set;

import java.util.TreeSet;


public class TreeSetExample {

    public static void main(String[] args) {

        Set<String> treeSet = new TreeSet<>();

        treeSet.add("Apple");

        treeSet.add("Banana");

        treeSet.add("Cherry");


        System.out.println(treeSet);

    }

}


Key Differences

  1. Underlying Data Structure:

    • HashSet: Uses a hash table.
    • TreeSet: Uses a red-black tree (a type of self-balancing binary search tree).
  2. Ordering:

    • HashSet: Does not guarantee any specific order of elements.
    • TreeSet: Maintains elements in a sorted order.
  3. Performance:

    • HashSet: O(1) average time complexity for add, remove, and contains.
    • TreeSet: O(log n) time complexity for add, remove, and contains.
  4. Null Handling:

    • HashSet: Allows one null element.
    • TreeSet: Does not allow null elements.
  5. Usage:

    • Use HashSet when you need a fast, unordered collection with no duplicates.
    • Use TreeSet when you need a sorted set with no duplicates.

When to Use Which?

  • HashSet: Choose HashSet if you don't care about the order of elements and need fast performance for basic operations.
  • TreeSet: Choose TreeSet if you need a sorted set and can afford the additional overhead of maintaining order.

Both HashSet and TreeSet are useful in different scenarios, and understanding their differences can help you choose the right one for your specific use case.


Difference between Abstraction and Encapsulation in Java

 

In Java, abstraction and encapsulation are two fundamental object-oriented programming concepts that help in building robust, reusable, and maintainable code. Though they are related, they serve different purposes.

Abstraction

Definition: Abstraction is the concept of hiding the complex implementation details and showing only the essential features of the object. It allows you to focus on what the object does instead of how it does it.

Purpose:

  • To reduce complexity.
  • To increase the efficiency of the design.

How to Achieve:

  • By using abstract classes and interfaces.

Example:

// Abstract Class

abstract class Animal {

    // Abstract method (does not have a body)

    abstract void makeSound();

    

    // Regular method

    void eat() {

        System.out.println("This animal eats food.");

    }

}


// Concrete Class

class Dog extends Animal {

    @Override

    void makeSound() {

        System.out.println("The dog says: Woof Woof");

    }

}


// Interface

interface Vehicle {

    void start();

    void stop();

}


// Implementing the interface

class Car implements Vehicle {

    @Override

    public void start() {

        System.out.println("The car starts.");

    }


    @Override

    public void stop() {

        System.out.println("The car stops.");

    }

}


In this example, Animal is an abstract class with an abstract method makeSound. The Dog class provides the specific implementation of this method. Similarly, the Vehicle interface declares the methods start and stop, and the Car class implements these methods.

Encapsulation

Definition: Encapsulation is the mechanism of wrapping the data (variables) and code (methods) together as a single unit. It also restricts direct access to some of an object's components, which can prevent the accidental modification of data.

Purpose:

  • To protect the internal state of an object.
  • To achieve modularity.
  • To reduce the complexity of the code.

How to Achieve:

  • By declaring the variables of a class as private and providing public getter and setter methods to modify and view the values of the variables.

Example:

public class Person {

    // Private variables

    private String name;

    private int age;


    // Getter method for name

    public String getName() {

        return name;

    }


    // Setter method for name

    public void setName(String name) {

        this.name = name;

    }


    // Getter method for age

    public int getAge() {

        return age;

    }


    // Setter method for age

    public void setAge(int age) {

        if(age > 0) {

            this.age = age;

        } else {

            System.out.println("Age must be positive.");

        }

    }

}


public class Main {

    public static void main(String[] args) {

        // Creating an object of Person class

        Person person = new Person();

        

        // Setting values through setter methods

        person.setName("John");

        person.setAge(25);


        // Accessing values through getter methods

        System.out.println("Name: " + person.getName());

        System.out.println("Age: " + person.getAge());

    }

}


In this example, the Person class encapsulates its data members (name and age) by making them private. The class provides public getter and setter methods to access and modify these variables, ensuring that the internal state of the object is protected and can only be changed in controlled ways.

Summary

  • Abstraction focuses on hiding the complex implementation details and exposing only the necessary parts. It is achieved using abstract classes and interfaces.
  • Encapsulation focuses on bundling the data and methods that operate on the data within one unit and restricting direct access to some of the object's components. It is achieved using access modifiers like private, protected, and public along with getter and setter methods.

Difference between Abstract Class and Interface in Java

 

In Java, both abstract classes and interfaces are used to define abstract types that can be used to specify the behavior that classes must implement. However, they have different features and purposes. Here are the key differences between them:

Abstract Class

  1. Definition: An abstract class is a class that cannot be instantiated on its own and can have abstract methods (methods without a body) as well as concrete methods (methods with a body).
  2. Usage: Abstract classes are used when you want to share code among several closely related classes.
  3. Constructors: An abstract class can have constructors.
  4. Access Modifiers: Methods and fields in an abstract class can have any access modifier (public, protected, private).
  5. Fields: An abstract class can have instance variables (fields).
  6. Inheritance: A class can extend only one abstract class (single inheritance).
  7. Implementation: Abstract classes can provide default implementation for some of the methods.
  8. Static Methods: Abstract classes can have static methods.
  9. State Management: Abstract classes can maintain state (instance variables).

Interface

  1. Definition: An interface is a reference type in Java, similar to a class, that can contain only constants, method signatures, default methods, static methods, and nested types. Method bodies exist only for default methods and static methods.
  2. Usage: Interfaces are used to define a contract that other classes must adhere to. They are suited for declaring methods that one or more classes are expected to implement.
  3. Constructors: Interfaces cannot have constructors.
  4. Access Modifiers: All methods in an interface are implicitly public and abstract (except default and static methods, which are explicitly defined).
  5. Fields: Interfaces can only have static and final fields (constants).
  6. Inheritance: A class can implement multiple interfaces (multiple inheritance).
  7. Implementation: Interfaces cannot provide any method implementations except for default and static methods.
  8. Static Methods: Interfaces can have static methods.
  9. State Management: Interfaces cannot maintain state, as they cannot have instance variables.

Example:

Abstract Class Example

abstract class Animal {
    String name;

    Animal(String name) {
        this.name = name;
    }

    abstract void makeSound();

    void sleep() {
        System.out.println(name + " is sleeping.");
    }
}

class Dog extends Animal {
    Dog(String name) {
        super(name);
    }

    @Override
    void makeSound() {
        System.out.println(name + " says: Woof Woof");
    }
}

Interface Example

interface Animal {
    void makeSound();

    default void sleep() {
        System.out.println("Animal is sleeping.");
    }
}

class Dog implements Animal {
    @Override
    public void makeSound() {
        System.out.println("Dog says: Woof Woof");
    }
}

When to Use What?

  • Abstract Class: Use when you have a base class that should not be instantiated and contains some common code that can be shared among derived classes.
  • Interface: Use when you want to define a contract for what a class can do, without dictating how it should do it. Interfaces are especially useful for defining capabilities that can be added to any class regardless of where it sits in the class hierarchy.

July 08, 2024

Write a Java Program to Implement Hashcode and Equals

 
Program:

Write a Java Program to Implement Hashcode and Equals?

Description:

The hashcode of a Java Object is simply a number, it is 32-bit signed int, that allows an object to be managed by a hash-based data structure. We know that hash code is an unique id number allocated to an object by JVM. But actually speaking, Hash code is not an unique number for an object. If two objects are equals then these two objects should return same hash code. So we have to implement hashcode() method of a class in such way that if two objects are equals, ie compared by equal() method of that class, then those two objects must return same hash code. If you are overriding hashCode you need to override equals method also.

The below example shows how to override equals and hashcode methods. The class Price overrides equals and hashcode. If you notice the hashcode implementation, it always generates unique hashcode for each object based on their state, ie if the object state is same, then you will get same hashcode. A HashMap is used in the example to store Price objects as keys. It shows though we generate different objects, but if state is same, still we can use this as key.

Code:

package com.java2novice.algos;

import java.util.HashMap;

public class MyHashcodeImpl {

    public static void main(String a[]){
        
        HashMap<Price, String> hm = new HashMap<Price, String>();
        hm.put(new Price("Banana", 20), "Banana");
        hm.put(new Price("Apple", 40), "Apple");
        hm.put(new Price("Orange", 30), "Orange");
        //creating new object to use as key to get value
        Price key = new Price("Banana", 20);
        System.out.println("Hashcode of the key: "+key.hashCode());
        System.out.println("Value from map: "+hm.get(key));
    }
}

class Price{
    
    private String item;
    private int price;
    
    public Price(String itm, int pr){
        this.item = itm;
        this.price = pr;
    }
    
    public int hashCode(){
        System.out.println("In hashcode");
        int hashcode = 0;
        hashcode = price*20;
        hashcode += item.hashCode();
        return hashcode;
    }
    
    public boolean equals(Object obj){
        System.out.println("In equals");
        if (obj instanceof Price) {
            Price pp = (Price) obj;
            return (pp.item.equals(this.item) && pp.price == this.price);
        } else {
            return false;
        }
    }
    
    public String getItem() {
        return item;
    }
    public void setItem(String item) {
        this.item = item;
    }
    public int getPrice() {
        return price;
    }
    public void setPrice(int price) {
        this.price = price;
    }
    
    public String toString(){
        return "item: "+item+"  price: "+price;
    }
}

Output:

In hashcode
In hashcode
In hashcode
In hashcode
Hashcode of the key: 1982479637
In hashcode
In equals
Value from map: Banana

In Java, implementing hashCode and equals methods is crucial when you are working with objects in collections like HashSet, HashMap, etc. Below is an example of a Java program that demonstrates how to implement these methods:

Example Class: Person

public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }
        Person person = (Person) obj;
        return age == person.age && name.equals(person.name);
    }

    @Override
    public int hashCode() {
        int result = name.hashCode();
        result = 31 * result + age;
        return result;
    }

    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + "}";
    }

    public static void main(String[] args) {
        Person person1 = new Person("John", 25);
        Person person2 = new Person("John", 25);
        Person person3 = new Person("Jane", 30);

        // Test equals method
        System.out.println("person1 equals person2: " + person1.equals(person2)); // true
        System.out.println("person1 equals person3: " + person1.equals(person3)); // false

        // Test hashCode method
        System.out.println("person1 hashCode: " + person1.hashCode());
        System.out.println("person2 hashCode: " + person2.hashCode());
        System.out.println("person3 hashCode: " + person3.hashCode());

        // Use in HashSet
        Set<Person> set = new HashSet<>();
        set.add(person1);
        set.add(person2);
        set.add(person3);

        System.out.println("HashSet contains: " + set);
    }
}

Explanation:

  1. Person Class Definition: A simple Person class with name and age properties.
  2. Constructor: Initializes the name and age of the Person.
  3. Getter Methods: Methods to access the name and age properties.
  4. equals Method:
    • Checks if the current object is the same as the object passed as an argument.
    • Checks if the object passed is null or not of the same class.
    • Casts the object to Person and compares the name and age properties.
  5. hashCode Method:
    • Generates a hash code using the name's hash code and the age.
    • The 31 multiplier is used to ensure a good distribution of hash codes.
  6. toString Method: Provides a string representation of the Person object.
  7. Main Method:
    • Creates a few Person objects and tests the equals and hashCode methods.
    • Adds Person objects to a HashSet and prints the set to demonstrate that duplicates are not added.

This example demonstrates how equals and hashCode methods should be implemented to ensure that objects behave correctly in collections that rely on these methods, such as HashSet.


Get Distinct Elements From An Array By Avoiding Duplicate Elements Java Program

 
How to get distinct elements from an array by avoiding duplicate elements?

Description:

The below example shows how to avoid duplicate elements from an array and disply only distinct elements. Please use only arrays to process it.

Code:

package com.java2novice.algos;

public class MyDisticntElements {

    public static void printDistinctElements(int[] arr){
        
        for(int i=0;i<arr.length;i++){
            boolean isDistinct = false;
            for(int j=0;j<i;j++){
                if(arr[i] == arr[j]){
                    isDistinct = true;
                    break;
                }
            }
            if(!isDistinct){
                System.out.print(arr[i]+" ");
            }
        }
    }
    
    public static void main(String a[]){
        
        int[] nums = {5,2,7,2,4,7,8,2,3};
        MyDisticntElements.printDistinctElements(nums);
    }
}

Output:

5 2 7 4 8 3

To get distinct elements from an array and avoid duplicates in Java, you can use a HashSet because it does not allow duplicate elements. Here’s a simple program that demonstrates this:

import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;

public class DistinctElements {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.print("Enter the number of elements in the array: ");
        int n = scanner.nextInt();
        int[] array = new int[n];

        System.out.println("Enter the elements of the array:");
        for (int i = 0; i < n; i++) {
            array[i] = scanner.nextInt();
        }
        scanner.close();

        int[] distinctArray = getDistinctElements(array);

        System.out.println("Distinct elements in the array: " + Arrays.toString(distinctArray));
    }

    public static int[] getDistinctElements(int[] array) {
        Set<Integer> set = new HashSet<>();
        for (int element : array) {
            set.add(element);
        }
        
        int[] distinctArray = new int[set.size()];
        int index = 0;
        for (int element : set) {
            distinctArray[index++] = element;
        }
        
        return distinctArray;
    }
}

Explanation:

  1. Import Necessary Classes: The program uses Scanner for input, HashSet for storing unique elements, and Arrays for output formatting.
  2. Get Input: The user is prompted to enter the number of elements in the array and then the elements themselves.
  3. getDistinctElements Method: This method converts the array into a HashSet to remove duplicates:
    • Iterate through the array and add each element to the HashSet.
    • Convert the HashSet back into an array.
  4. Output: The distinct elements are printed.

This program reads an array from the user, removes duplicates using a HashSet, and prints the array of distinct elements.