Java

  • [Knowledge] The difference between static and non-static

    Static variables and methods are shared by all instances of the class. They are initialized only once. Whereas non-static variables and methods are not accessed by other instances.

    // Example of Static variables and methods
    
    public class Counter {
        static int count = 0;  // Static variable shared by all instances of Counter
    
        // Static method that can be called without creating an object
        public static void increment() {
            count++;  // Modifies the static variable
        }
    
        public static void main(String[] args) {
            Counter.increment();  // Calling static method without creating an object
            System.out.println(Counter.count);  // Output: 1
    
            Counter.increment();  // Calling static method again
            System.out.println(Counter.count);  // Output: 2
        }
    }
    
    // Example of non-static variables and methods
    
    public class Car {
        String color;  // Instance variable, each Car object will have its own color
        int speed;     // Instance variable, each Car object will have its own speed
    
        // Instance method, works with instance variables
        public void drive() {
            System.out.println("The car is driving at " + speed + " km/h");
        }
    
        public static void main(String[] args) {
            Car car1 = new Car();  // Create an instance of Car
            car1.color = "Red";     // Set the color of car1
            car1.speed = 120;       // Set the speed of car1
            car1.drive();           // Call the instance method on car1
    
            Car car2 = new Car();  // Create another instance of Car
            car2.color = "Blue";    // Set the color of car2
            car2.speed = 150;       // Set the speed of car2
            car2.drive();           // Call the instance method on car2
        }
    }
    
  • [Knowledge] Final

    final is like constant in python. It prevents you from assigning a variable again

  • [Knowledge] float and double
    • The float and double data types can store fractional numbers. Note that you should end the value with an "f" for floats and "d" for doubles
      float myNum = 5.75f;
      double myNum = 19.99d;
  • [Knowledge] Primitive and non-primitive data types
    • Primitive data types are simple values predefined by the java language. They don’t contain any additional methods or functionality
      int number = 10
      double = price = 99.99;
      char grade = 'A';
    • Non-primitive data types (reference types) are used to represent objects, arrays and other user-defined types. They do not hold the actual value but instead reference or point to the location in memory where the actual data is stored.
      int[] numbers = {1, 2, 3, 4}
      String[] names = {"Mustafa", "Julia", "Charlie"}
      String name = "Hello Mustafa"
    • Differences between primitive and non-primitive values
      FeaturePrimitive TypesNon-Primitive Types
      DataHolds the actual value.Holds a reference to the actual data.
      SizeFixed size (e.g., int is always 4 bytes).Variable size (depends on the object/array).
      Default ValueHas default values (e.g., 0, false).Default value is null.
      MethodsCannot have methods.Can have methods (e.g., String, objects).
      NullabilityCannot be null.Can be null.
      Examplesint, char, boolean, double, byte.String, Arrays, custom classes (Object).
      StorageStored directly in memory.Stored as references to memory locations.
  • [Knowledge] Some strings methods
    String txt = "Hello World";
    System.out.println(txt.toUpperCase());   // Outputs "HELLO WORLD"
    System.out.println(txt.toLowerCase());   // Outputs "hello world"
    
    String txt = "Please locate where 'locate' occurs!";
    System.out.println(txt.indexOf("locate")); // Outputs 7
    
    String txt = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    System.out.println("The length of the txt string is: " + txt.length());
  • [Knowledge] For-each loop

    for-each loop or (enhanced for loop) designed to iterate over collections like arrays, lists, or other iterable objects.

    String[] cars = {"Volvo", "BMW", "Ford", "Mazda"};
    for (String i : cars) {
      System.out.println(i);
    }

    Normally the previous loop would be written like this:

    String[] cars = {"Volvo", "BMW", "Ford", "Mazda"};
    for (int i = 0; i < cars.length; i++) {
      System.out.println(cars[i]);
    }
  • [Knowledge] Multidimensional Arrays
    int[][] myNumbers = { {1, 2, 3, 4}, {5, 6, 7} };
    System.out.println(myNumbers[1][2]); // Outputs 7
  • [Knowledge] String [] args in main

    String[] args (or an equivalent parameter) is required in the main method's signature when writing a standalone Java program because the JVM expects this exact method signature as the entry point. <args> can be any name but String[] is a must when using constructing main.

    public class Main {
        public static void main(String[] args) {
            if (args.length > 0) {
                System.out.println("Command-line input: " + args[0]);
            } else {
                System.out.println("No command-line arguments passed.");
            }
        }
    }
    
  • [Note] Can main be omitted?

    If you want your program to be executed directly from the command line using: java ClassName, then the main method is mandatory. The JVM looks for it as a starting point when running the program. main can be ommited If a class is meant to be used as a utility, library, or part of a larger system.

  • [Note] main method must not return anything

    main method in Java must always return void. This is a strict requirement of the Java Virtual Machine (JVM) specification for standalone Java applications. If the main method has a different return type, the JVM will not recognize it as the entry point, and your program will fail to run.

  • [knowledge] Priority Queues

    A priority queues is a queue where elements are ordered based on their priority rathar than their order of addition into the queue.

    They have few important characteristics:

    • Min-Heap by default: Elements in a priority queue are ordered in ascending order, where the smallest elements have the highest priority.
    • Custom order: The order in a priority queue can be defined by a (comparator).

    Key methods: (assume p is a priority queue)

    • p.add(e) add new elements
    • p.peek() print the head elements (the element that has the highest priority)
    • p.poll() retrieve and remove the head of the queue
  • [ISSUE] Priority queue not having the correct order after using comparator

    After ordering a priority queue and trying to print it using System.out.println() it prints with the previous order.

    The reason System.out.println(pq) doesn't work as expected is that PriorityQueue doesn't provide a custom string representation of its elements. When you call println() on the queue, it uses the default toString() method, which prints a basic representation of the queue (e.g., [element1, element2, element3]) but does not reflect the internal order based on your comparator.

    To print elements in the correct order, you must poll from the queue or iterate over it manually, as you did with pq.poll().

  • [Knowledge] Difference between ArrayList and LinkedList

    1. Data Structure:

    • ArrayList: Backed by a dynamic array (resizable array).
    • LinkedList: Implemented as a doubly linked list (each element points to the next and previous elements).

    2. Access Time (Indexing):

    • ArrayList: Constant time O(1) for accessing an element by index.
    • LinkedList: Linear time O(n) for accessing an element by index because it must traverse the list.

    3. Insertion/Deletion (at any position):

    • ArrayList: Insertion and deletion can be slow, especially in the middle, due to shifting elements, with a time complexity of O(n).
    • LinkedList: Insertion and deletion are faster (O(1)) when the node to be inserted/deleted is known. However, searching for the node takes O(n).

    4. Memory Usage:

    • ArrayList: Memory is contiguous, meaning no extra memory for pointers, just the elements themselves.
    • LinkedList: Each element has additional memory overhead for storing pointers (next and previous nodes), which increases memory consumption.

    5. Use Case:

    • ArrayList: Ideal for applications where fast random access is required, and the size is relatively stable (not requiring frequent insertions/deletions).
    • LinkedList: More suitable for applications where frequent insertions and deletions occur, especially at the start or middle of the list.

    6. Performance in Various Operations:

    • ArrayList:
      • Access: O(1)
      • Add (end): O(1) amortized, but O(n) if resizing is needed.
      • Remove: O(n) for removing an element (due to shifting).
    • LinkedList:
      • Access: O(n)
      • Add (end/start): O(1)
      • Remove: O(1) if node is already found.

    7. Thread Safety:

    • ArrayList: Not synchronized, not thread-safe.
    • LinkedList: Not synchronized, not thread-safe.