Question 1: Primitive Types vs Reference Types (Unit 1)

Part 1: MCQ

public class Person {
    String name;
    int age;
    int height;
    String job;

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

public static void main(String[] args) {
    Person person1 = new Person("Carl", 25, 165, "Construction Worker");
    Person person2 = new Person("Adam", 29, 160, "Truck Driver");
    Person person3 = person1;
    int number = 16;
    System.out.println(number);
}
main(null);

(a) What kind of types are person1 and person2?
Answer: They are reference types because they are objects with values stored in the heap, while their place in the heap (references) are stored in the stack to be called.

(b) Do person1 and person3 point to the same value in memory?
Answer: Yes. Because person1 is a reference type Object, when person3 is declared to represent person1, person3 references the same location in the heap containing person1's data.

(c) Is the integer “number” stored in the heap or in the stack?
Answer: Because it's a primitive type integer, its value is stored directly in the stack.

(d) Is the value that “person1” points to stored in the heap or in the stack?
Answer: The value that person1 points to is stored in the heap.

Part 2: FRQ

(a) Define primitive types and reference types in Java. Provide examples of each.

A reference type is a subclass of java.lang.Object that stores its data in the stack and a reference to said data in the heap to be called. Examples include custom-made POJO objects, Strings, and ArrayLists. Primitive types have their exact values directly stored in memory to be called and modified. Some examples include int, double, byte, char, etc.

(b) Explain the differences between primitive types and reference types in terms of memory allocation and usage in Java programs.

Primitive types store their values directly in memory, while reference types store references to values that are stored in the heap. Primitive types have a fixed size in memory depending on their specific type, while reference types can vary more because they aren't stored directly in the stack.

(c) You have a method calculateInterest that takes a primitive double type representing the principal amount and a reference type Customer representing the customer information. Write the method signature and the method implementation. Include comments to explain your code.

// this is the customer class used in the calculateInterest method
public class Customer {
    private String name; // (a) REFERENCE TYPE
    private int creditScore; // (a) PRIMITIVE TYPE

    public Customer(String name, int creditScore) {
        this.name = name;
        this.creditScore = creditScore;
    }

    public String getName() { // this is just used for good formatting, it isn't really necessary
        return this.name;
    }

    public int getCreditScore() { // needed to calculate interest
        return this.creditScore;
    }
}
public class Bank {
    // the method is static so that it can be called within a static context
    public static double calculateInterest(double principalAmount, Customer customer) {
        // this double value is stored in the stack directly
        double baseInterestRate = 0.2; // 20%
        // this double value is stored in the stack directly
        // in the process of calling customer.getCreditScore, the customer's location in the heap is referenced
        // then, once the customer data is accessed, the creditScore primitive data is taken and used here
        double creditScore = customer.getCreditScore(); // we will use this to calculate interest

        // interest rate decreases by 0.005% for each 1 credit score, just for simplicity
        double adjustedInterestRate = baseInterestRate - (creditScore * 0.00005);
        
        // interest is calculated based on the principal amount and the adjustedInterestRate calculated above
        // it would normally be way more complicated than this, but this works for a simple demo
        double interest = principalAmount * adjustedInterestRate;
        
        // the interest (a double primitive value) is returned
        return interest;
    }
    // main method to demonstrate
    public static void main(String[] args) {
        Customer customer = new Customer("John Creditscore", 800);
        // principal amount was set to 1000 for a normal case
        System.out.println(customer.getName() + "'s interest was calculated to be " + calculateInterest(0.1, customer) + ".");
    }
}

Bank.main(null);
John Creditscore's interest was calculated to be 0.016.

Question 2: Iteration over 2D arrays (Unit 4)

Situation: You are developing a game where you need to track player scores on a 2D grid representing levels and attempts.

(a) Explain the concept of iteration over a 2D array in Java. Provide an example scenario where iterating over a 2D array is useful in a programming task.

Iterating over a 2D array in Java typically entails iterating through each row (or whatever is represented by the arrays within the encapsulating array), and then, within each row, iterating through each column. This can be done through various forms of loops, as shown below (using a 2D array of ints as an example):

// using enhanced for loop
for (int[] row : array2D) {
    for (int column : row) {
        // access column data here
    }
}
// using a standard for loop
for (int r = 0; r < array2D.length; r++) {
    for (int c = 0; c < array2D[r].length; c++) {
        // access column data through indexes r (row) and c (column)
    }
}

These methods can be mixed to great effect, but overall, the enhanced for loop method is good for accessing each piece of data sequentially, while the standard for loop method is good for manipulating the accessed indexes in the 2D array.

This is helpful to iterate through 2D arrays if data that is stored is being represented in a 2D model like a table, and all data in the table must be processed or modified in some way.

(b) You need to implement a method calculateTotalScore that takes a 2D array scores of integers representing player scores and returns the sum of all the elements in the array. Write the method signature and the method implementation. Include comments to explain your code.

// this will be part of an overall game method class for use
// that's probably how it should be implemented, since the score is supposed to be taken as an argument
public class GameMethods {
    // static method makes most sense here
    public static int calculateTotalScore(int[][] scores) {
        // initializing the sum at 0 to be added to
        int sum = 0;
        // iterating through each row with an enhanced for loop
        for (int[] row : scores) {
            // iterating through each column of the row
            for (int column : row) {
                // adding each score to the sum
                sum += column;
            }
        }
        // after all iteration is complete, I return the sum
        return sum;
    }
    // main method to show functionality
    public static void main(String[] args) {
        int[][] playerScores = {
            {3, 5, 2, 3, 4},
            {3, 5, 6, 7, 2},
            {12, 4, 5, 8, 1},
            {3, 8, 4, 3, 10}
        };
        // manually calculated sum: 98 points
        System.out.println("The sum of the players' scores is " + calculateTotalScore(playerScores) + ".");
    }
}

GameMethods.main(null);
The sum of the players' scores is 98.

Question 3: ArrayList (Unit 6)

Situation: You are developing a student management system where you need to store and analyze the grades of students in a class.

(a) Define an ArrayList in Java. Explain its significance and usefulness in programming.

ArrayList is an object that acts as a form of Collection object, meaning it can store multiple pieces of data. Unlike a typical array, among other benefits, its length is mutable, meaning that the number of elements stored within it is dynamic. ArrayLists also come with a number of methods that can be used to interact with data, such as the .contains method.

(b) You need to implement a method calculateAverageGrade that takes an array grades of integers representing student grades and returns the average of all the elements in the array. Write the method signature and the method implementation. Include comments to explain your code.

public class GradeCalculator {
    // I had it take an ArrayList of Integer grades rather than just an array to fit the nature of this section
    // it returns a double value because it would provide a more accurate average
    public static double calculateAverageGrade(ArrayList<Integer> grades) {
        // initializing an integer to represent their sum
        int sum = 0;
        // iterating through the grades and finding their sum
        // I used this method to show the use of the .get() and .size() method
        for (int i = 0; i < grades.size(); i++) {
            sum += grades.get(i);
        }
        // dividing the sum by the size of the ArrayList to find the average
        double average = (double) sum / grades.size();
        return average;
    }

    public static void main(String[] args) {
        ArrayList<Integer> testGrades = new ArrayList<Integer>();
        // showing the use of the .add() method
        testGrades.add(98);
        testGrades.add(91);
        testGrades.add(76);
        testGrades.add(83);
        testGrades.add(89);
        // showing how an enhanced for loop can be used for ArrayLists
        System.out.print("Test grades: ");
        for (int grade : testGrades) {
            System.out.print(grade + " ");
        }
        System.out.println("\nThe average of the test grades is " + calculateAverageGrade(testGrades) + "/100.");
    }
}

GradeCalculator.main(null);
Test grades: 98 91 76 83 89 
The average of the test grades is 87.4/100.

Question 4: Math Class (Unit 2)

Situation: You are developing a scientific calculator application where users need to perform various mathematical operations.

(a) Discuss the purpose and utility of the Math class in Java programming. Provide examples of at least three methods provided by the Math class and explain their usage.

The Math class supplies many useful methods that can be utilized for easier access to mathematical functions. Some examples of Math class methods that are very useful include:

  • Math.pow(double base, double exponent) is used to calculate using an exponential value on a base. If you wanted to easily calculate 3 to the power of 5, you could call Math.pow(3, 5)
  • Math.abs(double value) is used to find the absolute value of a number, so 10 would be returned for Math.abs(-10)
  • Math.sin(double radians) and similar trigonometry methods can be used to calculate trig values for given radians. (This works well with the Math.PI value.)

(b) You need to implement a method calculateSquareRoot that takes a double number as input and returns its square root using the Math class. Write the method signature and the method implementation. Include comments to explain your code.

// i tested and i don't need to do this but i will for CB so I'll show this import
import java.lang.Math;
// very redundant but we'll use this class here for the method
public class RootFinder {
    // static method makes most sense again
    public static double calculateSquareRoot(double number) {
        // using the Math square root method from the Math class
        return Math.sqrt(number);
    }
    // main method for showing functionality
    public static void main(String[] args) {
        System.out.println("Square root of 9: " + calculateSquareRoot(9));
        System.out.println("Square root of 64: " + calculateSquareRoot(64));
    }
}

RootFinder.main(null);
Square root of 9: 3.0
Square root of 64: 8.0

Question 5: If, While, Else (Unit 3-4)

Situation: You are developing a simple grading system where you need to determine if a given score is passing or failing.

(a) Explain the roles and usage of the if statement, while loop, and else statement in Java programming. Provide examples illustrating each.

If Statement

The if statement is used, it can cause a certain set of program instructions to be run ONLY under certain circumstances. This allows the use of “conditionals,” where data can be utilized and modified in different ways depending on the nature of the data. An example of its usage is found in the code block below the following section, because an Else statement is also used.

Else Statement

The else statement essentially acts as a blanket process that will occur if the conditions of an if statement (or multiple if statements) are not met. This is useful in cases where, for example, you are looking for specific anomalies in data, and if they aren’t recognized, a more general/neutral response should be provided. An example of this and the previous topic, if statements, are shown below:

// the purpose of this code is to express if an IQ is above of below average
int[] iqs = {80, 100, 120};
public static String calculateIqStatus(int iq) {
    if (iq > 115) { // if statements are used to determine if the IQ is above or below average
        return "Your IQ is above average!";
    } else if (iq < 85) {
        return "Your IQ is below average... :(";
    } else { // this is the case for all IQs not within the previous if statements' ranges
        return "Your IQ is within the average range.";
    }
};
// using a while loop for demonstration
int i = 0;
while (i < iqs.length) {
    System.out.println("For an IQ of " + iqs[i] + ": " + calculateIqStatus(iqs[i]));
    i++;
}
For an IQ of 80: Your IQ is below average... :(
For an IQ of 100: Your IQ is within the average range.
For an IQ of 120: Your IQ is above average!

While Loop

A while loop is a type of loop that runs while a certain condition is met. Where loops like for loops, for example, focus on iterating based on a specific, limited progression (such as the length/indexes of an array), a while loop has the potential to continue forever until a condition is met, such as a response being given properly. This can be used in many ways, but one I often utilize is ensuring that a valid response is provided when using user input:

Scanner scanner = new Scanner(System.in);
String userInput;
boolean validInput = false;
while (!(validInput)) {
    System.out.print("Do you want to continue? (y/n): ");
    userInput = scanner.nextLine();
    if (userInput.equalsIgnoreCase("y")) {
        System.out.println("Continuing...");
        validInput = true; // used to break the loop for a valid input
    } else if (userInput.equalsIgnoreCase("n")) {
        System.out.println("Exiting...");
        validInput = true; // used to break the loop for a valid input
    } else {
        System.out.println("Invalid input. Please enter 'y' or 'n'.");
        // because the loop is not broken, it continues again
    }
}
scanner.close();
Do you want to continue? (y/n): Invalid input. Please enter 'y' or 'n'.
Do you want to continue? (y/n): Exiting...

Alternative

The alternative below uses the same loop, but uses the while(true) statement so that it loops forever until being broken. I think this method is more sensible than the one above, but I wanted to use that to show a conditional being met specifically.

Scanner scanner = new Scanner(System.in);
String userInput;
while (true) {
    System.out.print("Do you want to continue? (y/n): ");
    userInput = scanner.nextLine();
    if (userInput.equalsIgnoreCase("y")) {
        System.out.println("Continuing...");
        break; // used to break the loop for a valid input
    } else if (userInput.equalsIgnoreCase("n")) {
        System.out.println("Exiting...");
        break; // used to break the loop for a valid input
    } else {
        System.out.println("Invalid input. Please enter 'y' or 'n'.");
        // because the loop is not broken, it continues again
    }
}
scanner.close();
Do you want to continue? (y/n): Invalid input. Please enter 'y' or 'n'.
Do you want to continue? (y/n): Continuing...

(I’m aware that doing this code outside of an encapsulating class and method is bad form but I’m only using it for basic demonstration.)

(b) You need to implement a method printGradeStatus that takes an integer score as input and prints “Pass” if the score is greater than or equal to 60, and “Fail” otherwise. Write the method signature and the method implementation. Include comments to explain your code.

// I'll make this part of a greater grade analysis class
public class GradeAnalysis {
    // a static method makes sense here again
    public static void printGradeStatus(int score) {
        // the process following will only occur if the grade is above/equal to 60, so passing
        if (score >= 60) {
            System.out.println("Pass");
        // using else ensures that all grades that are not >=60 are registered as failures
        } else {
            System.out.println("Fail");
        }
    }
    // this main method is used to show functionality
    public static void main(String[] args) {
        System.out.println("Status for a grade of 89:");
        printGradeStatus(89);
        System.out.println("Status for a grade of 55:");
        printGradeStatus(55);
    }
}

GradeAnalysis.main(null);
Status for a grade of 89:
Pass
Status for a grade of 55:
Fail