Primitive Types vs Reference Types

Answers:

a) Both person1 and person2 are references to objects of type Person.

b) Yes, person1 and person3 point to the same value in memory. When you assign person1 to person3 (Person person3 = person1;), you’re not creating a new object, but rather making person3 refer to the same object as person1.

c) The integer “number” is stored in the stack. Primitive types like integers are typically stored in the stack memory.

d) The value that “person1” points to (an instance of the Person class) is stored in the heap. Objects in Java are stored in the heap memory. So, person1 stores a reference to the actual object in the heap where the data for that person is stored.

(a) Primitive Types vs Reference Types in Java:

  • Primitive Types: These are basic data types provided by Java, which are used to store simple values. Primitive types are not objects and are predefined by the language. They include int, double, boolean, char, etc. Examples:
int num = 10;
double price = 20.5;
boolean isValid = true;
char grade = 'A';
  • Reference Types: Reference types refer to objects in Java. They store references (memory addresses) to objects rather than the actual objects themselves. Examples of reference types include classes, interfaces, arrays, etc. Examples:
String name = "John Doe";
Customer customer = new Customer();
ArrayList<Integer> numbers = new ArrayList<>();

(b) Differences between Primitive Types and Reference Types:

  • Memory Allocation:
    • Primitive Types: Primitive types are allocated memory on the stack. The actual value is stored directly in memory.
    • Reference Types: Reference types are allocated memory on the heap. The reference variable itself is stored on the stack, while the actual object is stored in the heap.
  • Usage:
    • Primitive Types: Primitive types hold the actual value. Operations performed on primitive types directly manipulate their values.
    • Reference Types: Reference types hold references to objects. Operations performed on reference types often involve accessing and modifying the object’s properties or calling its methods indirectly through the reference.

(c) Method Signature and Implementation:

public class InterestCalculator {

    
    // Takes a primitive double representing balance
    // and a reference type Account representing account information
    public double computeInterest(double balance, Account account) {
        // Example implementation: calculate interest based on account type
        double interestRate;
        if (account.getType() == AccountType.SAVINGS) {
            interestRate = 0.03;
        } else {
            interestRate = 0.06; 
        }
        return balance * interestRate;
    }

    // Account class for reference type example, cant be instantiated without requiring an instance of an outer class
    static class Account {
        private String accountNumber;
        private AccountType type;

        // Constructor
        public Account(String accountNumber, AccountType type) {
            this.accountNumber = accountNumber;
            this.type = type;
        }

        // Getter for account type
        public AccountType getType() {
            return type;
        }
    }

    // Enum for account type
    enum AccountType {
        SAVINGS,
        INVESTMENT
    }

    // Example usage
    public static void main(String[] args) {
        InterestCalculator calculator = new InterestCalculator();
        Account account1 = new Account("123456789", AccountType.SAVINGS);
        double balance = 5000.0;
        double interest = calculator.computeInterest(balance, account1);
        System.out.println("Interest for Account " + account1.getAccountNumber() + ": $" + interest);
    }
}

Output:

Interest for Account 123456789: $150.0

Interest Calculation Method:

  • The InterestCalculator class contains a method computeInterest that calculates the interest based on a given balance and an Account object.
  • It takes in a primitive double representing the balance and a reference type Account representing the account information.

Account Class:

  • The Account class is a nested static class within InterestCalculator.
  • It has private fields accountNumber (a String) and type (an AccountType enum).
  • The constructor initializes these fields with provided values.

AccountType Enum:

  • The AccountType enum defines two constants: SAVINGS and INVESTMENT.
  • These represent the types of accounts that can be used in the program.

Interest Rate Calculation:

  • Inside computeInterest, the interest rate is determined based on the Account type.
  • If the account type is SAVINGS, the interest rate is set to 0.03 (3%).
  • For INVESTMENT accounts, the rate is 0.06 (6%).

Example Usage:

  • In the main method, an instance of InterestCalculator is created.
  • An Account object account1 is instantiated with an account number and SAVINGS type.
  • A balance of $5000.0 is used, and computeInterest is called with these values.
  • The calculated interest is then printed to the console for the specified account number.

Reflection: Used a nested static class with a constructor, used enum for constants.

2D Array

(a) Iterating over a 2D array in Java involves using nested loops, typically one loop for the rows and another loop for the columns. This allows you to access each element of the array systematically.

A scenario where iterating over a 2D array is useful could be in a game where you need to keep track of player scores on different levels and attempts. You might represent this information using a 2D array, where each row represents a level and each column represents an attempt. Iterating over this array could help you calculate total scores, find maximum scores, or perform other operations on the scores data.

(b)

public class ScoreCalculator {

    // Method to calculate total score from a 2D array
    public static int calculateTotalScore(int[][] scores) {
        
        int totalScore = 0;
        
        // Nested loops to iterate over each element in the 2D array
        for (int row = 0; row < scores.length; row++) {
            for (int col = 0; col < scores[row].length; col++) {
                // Add the score at current position to total score
                totalScore += scores[row][col];
            }
        }
        
        // Return the total score
        return totalScore;
    }

    // Example usage
    public static void main(String[] args) {
        int[][] playerScores = {
            {10, 20, 30},
            {15, 25, 35},
            {5, 10, 15}
        };

        // Calculate total score
        int totalScore = calculateTotalScore(playerScores);

        // Print the total score
        System.out.println("Total score: " + totalScore);
    }
}

Output:

165

This method calculateTotalScore takes a 2D array scores of integers representing player scores. It iterates over each element of the array using nested loops, adding each score to a totalScore variable. Finally, it returns the total score.

In the main method, an example usage of this method is shown with a sample 2D array playerScores, and the total score is printed out.

Math Class

double number = -10.5;
double absValue = Math.abs(number); // absValue will be 10.5
double base = 2.0;
double exponent = 3.0;
double result = Math.pow(base, exponent); // result will be 8.0 (2^3)
/**
 * Calculates the square root of a given double number using the Math class.
 *
 * @param number The input number whose square root needs to be calculated.
 * @return The square root of the input number.
 */
public static double calculateSquareRoot(double number) {
    // Using Math.sqrt() to calculate the square root
    double squareRoot = Math.sqrt(number);
    return squareRoot;
}