1. Primitives, References, Stack and Heap
  2. Objects and Void
  3. Boolean
  4. Iteration
  5. Classes
  6. Arrays
  7. ArrayList
  8. 2D Arrays
  9. Inheritance

⭐ Primitives

Here are the key points about primitive data types in Java and the related concepts:

Primitive Data Types

  • Primitive types store simple data and are not associated with a class.
  • 3 main types for AP CSA:
    • int: Stores whole numbers within the range of -2,147,483,648 to 2,147,483,647.
    • double: Stores decimal values, can hold up to 15 decimal digits.
    • boolean: Stores true or false values.

Variable Naming Conventions

  • Variable names follow camel case (e.g., firstName).
  • Class names follow Pascal case (e.g., BankAccount).

Other Primitive Types

  • byte, short, long: Store different sizes of whole numbers.
  • float: Single-precision decimal.
  • char: Holds a single Unicode character.

Important Terms

  • Constraints: Limitations on the range of values a data type can store.
  • Overflow: When a value exceeds the maximum limit.
  • Underflow: When a value goes below the minimum limit.

Popcorn Hack: Broken Code Fix

  • Corrected variable types:
    • int for whole numbers.
    • double for decimal values.
    • boolean for binary true/false.
    • char for a single character.
    • String (capitalized) for strings of text.

⭐ References

Here are the key points about Reference Types in Java:

Reference Types Overview

  • Reference types store memory addresses (references) to objects, not the objects themselves.
  • Reference types include:
    • Classes: Can contain fields (variables) and methods. They create complex data structures.
    • Arrays: Hold collections of variables of the same type.
    • Interfaces: Define methods that a class can implement.

Classes Example

  • Class declaration:
    class Person {
        String name;
        int age;
    }
    
    • When you create an instance, the reference (e.g., person) is stored in the stack, but the actual object (e.g., Person) is stored in the heap.

Arrays Example

  • Array declaration:
    int[] numbers = new int[5];
    
    • The array reference is stored in the stack, and the array itself is in the heap.

Example Code Explanation

  • myString: A reference to a String object, storing the address of "Hello, World!".
  • myArray: A reference to an array of integers {1, 2, 3, 4, 5}.

Output

  • Prints the string and array contents:
    Hello, World!
    [1, 2, 3, 4, 5]
    

⭐ Stack and Heap

Memory Allocation: Stack and Heap

  • Stack Memory:
    • Stores primitive types and references to objects.
    • Follows LIFO (last-in-first-out) order.
    • Each thread has its own stack.
    • Variables are passed by value (creates a copy).
  • Heap Memory:
    • Stores objects and arrays.
    • Shared by all threads; managed by the garbage collector.
    • Objects live in the heap as long as references exist in the stack.
    • Variables are passed by reference (changes persist).

Pass-by-Value vs Pass-by-Reference

  • Pass-by-value: Changes to primitives inside methods do not affect the original variable.
  • Pass-by-reference: Changes to objects inside methods affect the original object (e.g., IntByReference class).

Literal vs Input

  • Literal: Hard-coded values in the source code (e.g., int age = 17;).
  • Input: Values provided by user input (e.g., using Scanner).

⭐ Objects & Void

Objects:

  • Definition: Objects are instances of a class. They store data (attributes) and can perform actions (methods).
  • Example: In class Dog, myDog = new Dog("Shelby", "Golden Retriever", 5) creates an object myDog with attributes name, breed, and age, and can perform the action bark().

Void Methods:

  • Definition: A void method doesn’t return any value. It performs an action but doesn’t send back a result.
  • Example: void bark() in the Dog class prints “Woof!” but doesn’t return anything.
  • Another Example: void printTitle() in class Movie prints the movie title but doesn’t return anything.

Non-Void Methods:

  • Definition: These methods return a value. For example, public double circumference() in the Circle class returns the calculated circumference.

⭐ Boolean

  • Boolean Type: The boolean type in Java can hold only two values: true or false.

  • Declaration:
     boolean isActive = true;
    
  • Common Usage:
    • Used in conditional statements like if, while, for.
    • Logical operations (&&, ||, !) to combine or negate boolean values.
  • Default Value: If declared but not initialized, a boolean has a default value of false.

  • Example:
     boolean isMember = (age > 18 && income >= 30000);  // Boolean expression
    
  • Methods:
    • Boolean.parseBoolean(String) converts a string to boolean.
    • Boolean.TRUE and Boolean.FALSE constants can be used for clarity.

⭐ Iteration

Brief Notes on Java Iteration

  • For Loop: Used for a known number of iterations. Syntax:
    for (int i = 0; i < limit; i++) {
        // code block
    }
    

    Useful when looping over a range or an array/list with indices.

  • Enhanced For Loop: Simplified version to loop through elements in arrays or collections.
    for (Type element : collection) {
        // code block
    }
    

    Good for when you don’t need the index, just the elements.

  • While Loop: Continues as long as a condition is true. Syntax:
    while (condition) {
        // code block
    }
    

    Used when the number of iterations isn’t known beforehand.

  • Do-While Loop: Executes the code block at least once before checking the condition.
    do {
        // code block
    } while (condition);
    

    Useful when you need to run the loop body before validating the condition.

  • Iterator: Provides a way to traverse collections like ArrayList or HashSet. Prevents ConcurrentModificationException by using iterator.remove() instead of modifying directly during iteration.
    Iterator<Type> it = collection.iterator();
    while (it.hasNext()) {
        Type element = it.next();
        // code block
    }
    
  • Streams (Java 8+): Allows functional-style iteration.
    collection.stream().forEach(element -> {
        // code block
    });
    

    Ideal for working with large datasets or performing transformations on collections.

⭐ Arrays

1. Definition

  • An array in Java is a collection of elements of the same type stored in contiguous memory locations. It can hold multiple values under a single variable name.

2. Declaring and Initializing Arrays

  • Syntax for Declaration:
    dataType[] arrayName;
    
  • Example:
    int[] numbers;
    String[] cities;
    
  • Initialization:
    • With values:
      int[] numbers = {1, 2, 3, 4, 5};
      
    • Without values (defaults to zero or null):
      String[] names = new String[5];  // Creates an array of size 5
      

3. Accessing Elements

  • Indexing:
    • Arrays are zero-indexed. The first element is accessed using arrayName[0].
    • Example:
      String firstCity = cities[0];  // Accesses the first city
      

4. Length of Array

  • Use the .length property to get the size of the array.
    int size = numbers.length;  // Returns the number of elements in the array
    

5. Modifying Elements

  • Elements can be changed using their index.
    numbers[2] = 10;  // Changes the third element to 10
    

6. Iterating Over Arrays

  • For Loop:
    for (int i = 0; i < array.length; i++) {
        System.out.println(array[i]);
    }
    
  • Enhanced For Loop (for-each loop):
    for (dataType element : array) {
        System.out.println(element);
    }
    

7. Common Array Operations

  • Finding the Maximum and Minimum:
    public static void findMaxAndMin(int[] array) {
        int max = array[0];
        int min = array[0];
        for (int i = 1; i < array.length; i++) {
            if (array[i] > max) max = array[i];
            if (array[i] < min) min = array[i];
        }
        System.out.println("Max: " + max + ", Min: " + min);
    }
    
  • Sum of Elements:
    int sum = 0;
    for (int num : array) {
        sum += num;
    }
    
  • Count Occurrences of a Target:
    public static int countOccurrences(int[] arr, int target) {
        int count = 0;
        for (int num : arr) {
            if (num == target) count++;
        }
        return count;
    }
    

8. Multi-Dimensional Arrays

  • Arrays can be multi-dimensional (e.g., 2D arrays).
    int[][] matrix = {
        {1, 2, 3},
        {4, 5, 6}
    };
    
  • Accessing elements:
    int element = matrix[0][1];  // Accesses the element at first row, second column
    

9. Array Utility Methods

  • Java provides utility methods in java.util.Arrays for common operations, such as sorting and searching.
    Arrays.sort(array);  // Sorts the array
    int index = Arrays.binarySearch(array, target);  // Searches for a value
    

10. Important Notes

  • Array Size: Once an array is created, its size cannot be changed. Use ArrayList if dynamic sizing is needed.
  • Type Safety: All elements must be of the same type. Attempting to mix types will lead to a compile-time error.

⭐ ArrayList

Java Arrays vs. ArrayLists

Java Arrays

  • Definition: A fixed-size data structure that holds elements of the same type.
  • Declaration:
    int[] numbers = new int[5]; // Array of integers with size 5
    
  • Accessing Elements: Use index-based access.
    numbers[0] = 10; // Assigning value
    int firstNumber = numbers[0]; // Accessing value
    
  • Size: Fixed after declaration. Cannot change size dynamically.

ArrayLists

  • Definition: A resizable array implementation of the List interface in Java’s Collections Framework.
  • Import Statement:
    import java.util.ArrayList;
    
  • Declaration:
    ArrayList<String> fruits = new ArrayList<String>(); // ArrayList of strings
    
  • Adding Elements:
    fruits.add("Apple");
    fruits.add("Banana");
    
  • Accessing Elements: Use get(index) method.
    String firstFruit = fruits.get(0); // Accessing first element
    
  • Dynamic Size: Automatically resizes as elements are added or removed.
  • Key Methods:
    • add(element): Adds an element to the end of the list.
    • remove(index): Removes the element at the specified index.
    • set(index, element): Replaces the element at the specified index.
    • size(): Returns the number of elements in the list.

Examples

Example 1: Basic ArrayList Usage

import java.util.ArrayList;

public class ArrayListExample {
    public static void main(String[] args) {
        ArrayList<Integer> testGrades = new ArrayList<Integer>();
        
        // Adding grades
        testGrades.add(85);
        testGrades.add(90);
        testGrades.add(78);
        
        // Print grades
        System.out.println("Test Grades: " + testGrades);
    }
}

Example 2: Manipulating an ArrayList

import java.util.ArrayList;

public class ArrayListManipulation {
    public static void main(String[] args) {
        ArrayList<String> hobbies = new ArrayList<>();
        
        // Adding hobbies
        hobbies.add("Reading");
        hobbies.add("Swimming");
        hobbies.add("Coding");
        
        // Removing a hobby
        hobbies.remove("Swimming");
        
        // Replacing a hobby
        hobbies.set(0, "Gardening");
        
        // Output the modified list
        System.out.println("Hobbies: " + hobbies);
    }
}

Key Differences Between Arrays and ArrayLists

Feature Array ArrayList
Size Fixed size Dynamic size
Data Types Can store primitives only Can store objects and primitives
Methods Length property Methods like add(), remove(), and size()
Performance Faster access Slight overhead due to method calls
Flexibility Less flexible More flexible

Summary

  • Use arrays when the number of elements is fixed and known in advance.
  • Use ArrayLists when you need a resizable array that can grow and shrink dynamically, making it more suitable for applications where the size of the dataset may change.

Additional Notes

  • Always specify the type in <> when creating an ArrayList to avoid type errors.
  • For performance-critical applications with a known size, prefer arrays.
  • ArrayLists are often easier to work with due to their built-in methods, making them more suitable for general-purpose programming.

⭐ 2D Arrays

1. Declaration and Initialization:

  • A 2D array is an array of arrays, allowing you to create a table-like structure.
  • Syntax:
    dataType[][] arrayName = new dataType[rows][columns];
    
  • Example:
    int[][] matrix = new int[3][4]; // 3 rows, 4 columns
    
  • You can also initialize a 2D array with values:
    String[][] greetings = {
        {"Hello", "World"},
        {"Java", "Rocks!"}
    };
    

2. Accessing Elements:

  • Elements are accessed using two indices: arrayName[row][column].
  • Example:
    String greeting = greetings[0][1]; // "World"
    

3. Looping Through 2D Arrays:

  • You can use nested loops to iterate over rows and columns.
  • Example:
    for (int i = 0; i < array.length; i++) {
        for (int j = 0; j < array[i].length; j++) {
            System.out.print(array[i][j] + " ");
        }
    }
    

4. Enhanced For Loop:

  • An enhanced for loop can simplify the iteration:
    for (String[] row : grades) {
        for (String student : row) {
            // process student names and grades
        }
    }
    

5. Common Operations:

  • Finding an Element: Search for an element in a 2D array and return its position.
  • Flattening a 2D Array: Convert a 2D array into a 1D array.
    public static int[] flatten2DArray(int[][] array) {
        // Logic to flatten the 2D array
    }
    

6. Searching in 2D Arrays:

  • You can create a method to search for a specific value:
    public static String searchGrade(String[][] grades, String name) {
        for (String[] student : grades) {
            if (student[0].equals(name)) {
                return student[1]; // Return the grade
            }
        }
        return "Student not found"; // If name not found
    }
    

7. Important Notes:

  • Indexing: Remember that indexing starts at 0.
  • Variable Lengths: Each row in a 2D array can have different lengths (ragged array).
    int[][] jaggedArray = {
        {1, 2},
        {3, 4, 5},
        {6}
    };
    

8. Using Arrays Class:

  • The java.util.Arrays class provides utility methods for array manipulation, such as Arrays.deepToString(), which prints 2D arrays in a readable format.

9. Sorting 2D Arrays:

  • To sort a 2D array, flatten it, sort the 1D array, and then reshape it back to 2D.
  • Example:
    Arrays.sort(flattenedArray);
    

10. Conclusion:

  • 2D arrays are useful for representing matrices, grids, and tabular data. Understanding how to declare, initialize, access, and manipulate them is fundamental in Java programming.

⭐ Inheritance

  1. Definition: Inheritance is a fundamental concept in object-oriented programming (OOP) that allows one class (subclass) to inherit fields and methods from another class (superclass).

  2. Syntax:
    • Use the extends keyword to create a subclass.
      class Subclass extends Superclass {
        // Subclass implementation
      }
      
  3. Types of Inheritance:
    • Single Inheritance: A class inherits from one superclass.
    • Multilevel Inheritance: A class is derived from another class, which is also derived from another class.
    • Hierarchical Inheritance: Multiple subclasses inherit from a single superclass.
    • Multiple Inheritance: Not supported directly (i.e., a class cannot inherit from multiple classes) to avoid ambiguity. Can be achieved using interfaces.
  4. Constructors:
    • The constructor of the superclass is called first. Use super() to invoke it in the subclass.
    • If not explicitly called, the default constructor of the superclass is invoked automatically.
  5. Method Overriding:
    • Subclasses can provide specific implementations of methods that are already defined in their superclass.
    • Use the @Override annotation to indicate that a method is being overridden.
      @Override
      public void methodName() {
        // New implementation
      }
      
  6. Access Modifiers:
    • Inherited fields and methods follow the same access control as defined in the superclass:
      • Public: Accessible everywhere.
      • Protected: Accessible within the same package and subclasses.
      • Default (no modifier): Accessible only within the same package.
      • Private: Not accessible outside the class.
  7. Polymorphism:
    • Inheritance supports polymorphism, allowing a superclass reference to refer to a subclass object.
      Shape shape = new Circle();
      
    • The method invoked will depend on the actual object type (dynamic binding).
  8. Abstract Classes and Interfaces:
    • Abstract classes can contain abstract methods (without a body) that must be implemented by subclasses.
    • Interfaces define a contract for classes to implement but do not provide method implementations.
  9. Benefits of Inheritance:
    • Code Reusability: Allows code to be reused in subclasses.
    • Method Overriding: Enables dynamic behavior based on the object type at runtime.
    • Organization: Helps organize code into a hierarchical structure, making it easier to maintain.

Example of Inheritance

class Animal {
    void eat() {
        System.out.println("This animal eats food.");
    }
}

class Dog extends Animal {
    void bark() {
        System.out.println("The dog barks.");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.eat(); // Inherited method
        dog.bark(); // Dog's own method
    }
}