Free Response Questions

Question 1 - Pojos and Access Control:

Situation: The school librarian wants to create a program that stores all of the books within the library in a database and is used to manage their inventory of books available to the students. You decided to put your amazing code skills to work and help out the librarian!

a. Describe the key differences between the private and public access controllers and how it affects a POJO

Private Access Modifier:

  • Fields or methods marked as private are only accessible within the same class.
  • They cannot be accessed or modified by any other class, even subclasses.
  • This encapsulation ensures that the internal state of the object is hidden and can only be manipulated through predefined methods provided by the class itself.
  • It provides a higher level of security and abstraction, as the internal implementation details are hidden from other classes.

Public Access Modifier:

  • Fields or methods marked as public are accessible from any other class.
  • They can be accessed and modified freely by any other class, including subclasses and classes in different packages.
  • This allows for greater visibility and flexibility but may also compromise encapsulation and expose the internal state of the object.
  • Public members are typically used for defining the interface of a class, providing access to the external behavior of the object.

b. Identify a scenario when you would use the private vs. public access controllers that isn’t the one given in the scenario above

Suppose you have a Person class representing individuals in a system. Each person has attributes such as name, age, and address. Here’s how you might use private and public access controllers in different scenarios:

Private Access: Let’s say you have a sensitive attribute like Social Security Number (ssn) in the Person class. This information should be strictly private to ensure security and privacy. Therefore, you would declare the ssn field as private to restrict direct access from outside the class. Access to this information should be mediated through controlled methods like getSSN() and setSSN() which can enforce additional validation or security checks.

Public Access: Consider a scenario where you want to provide read-only access to certain attributes of a Person, such as their name and age, to external classes for informational purposes. In this case, you might declare getter methods like getName() and getAge() as public, allowing other classes to retrieve this information but not modify it directly. This maintains the encapsulation of the Person class while still providing access to relevant information.

c. Create a Book class that represents the following attributes about a book: title, author, date published, person holding the book and make sure that the objects are using a POJO, the proper getters and setters and are secure from any other modifications that the program makes later to the objects

import java.util.Date;

public class Book {
    private String title;
    private String author;
    private Date datePublished;
    private String genre;
    private String personHolding;

    // Constructor
    public Book(String title, String author, Date datePublished, String genre) {
        this.title = title;
        this.author = author;
        this.datePublished = datePublished;
        this.genre = genre;
    }

    public String getTitle() {
        return this.title;
    }

    public String getAuthor() {
        return this.author;
    }

    public Date getDatePublished() {
        return this.datePublished;
    }

    public String getPersonHolding() {
        return this.personHolding;
    }

    public String getGenre(){
        return this.genre;
    }

    // Setters
    public void setTitle(String title) {
        this.title = title;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public void setDatePublished(Date datePublished) {
        this.datePublished = datePublished;
    }

    public void setPersonHolding(String personHolding) {
        this.personHolding = personHolding;
    }

    public void setGenre(String genre){
        this.genre = genre;
    }

    @Override
    public String toString() {
        return "Book{" +
                "title='" + title + '\'' +
                ", author='" + author + '\'' +
                ", datePublished=" + datePublished +
                ", genre='" + genre + '\'' +
                ", personHolding='" + personHolding + '\'' +
                '}';
    }

    public static void main(String[] args) {
        // Creating Book objects
        Book book1 = new Book("The Great Gatsby", "F. Scott Fitzgerald", new Date(), "Fiction");
        Book book2 = new Book("To Kill a Mockingbird", "Harper Lee", new Date(), "Fiction");
        Book book3 = new Book("1984", "George Orwell", new Date(), "Science Fiction");
        Book book4 = new Book("The Hobbit", "J.R.R. Tolkien", new Date(), "Fantasy");

        // Printing book details
        System.out.println("Book 1:");
        System.out.println(book1);

        System.out.println("\nBook 2:");
        System.out.println(book2);

        System.out.println("\nBook 3:");
        System.out.println(book3);

        System.out.println("\nBook 4:");
        System.out.println(book4);
    }
}

Book.main(null);
Book 1:
Book{title='The Great Gatsby', author='F. Scott Fitzgerald', datePublished=Wed Mar 27 12:41:50 PDT 2024, genre='Fiction', personHolding='null'}

Book 2:
Book{title='To Kill a Mockingbird', author='Harper Lee', datePublished=Wed Mar 27 12:41:50 PDT 2024, genre='Fiction', personHolding='null'}

Book 3:
Book{title='1984', author='George Orwell', datePublished=Wed Mar 27 12:41:50 PDT 2024, genre='Science Fiction', personHolding='null'}

Book 4:
Book{title='The Hobbit', author='J.R.R. Tolkien', datePublished=Wed Mar 27 12:41:50 PDT 2024, genre='Fantasy', personHolding='null'}
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Book {
    private String title;
    private String author;
    private String genre;

    public Book(String title, String author, String genre) {
        this.title = title;
        this.author = author;
        this.genre = genre;
    }

    public String getTitle() {
        return title;
    }

    public String getAuthor() {
        return author;
    }

    public String getGenre() {
        return genre;
    }

    @Override
    public String toString() {
        return title + " by " + author;
    }
}

public class Library {
    private Map<String, List<Book>> booksByGenre;

    public Library() {
        booksByGenre = new HashMap<>();
    }

    public void addBook(Book book) {
        String genre = book.getGenre();
        List<Book> books = booksByGenre.getOrDefault(genre, new ArrayList<>());
        books.add(book);
        booksByGenre.put(genre, books);
    }

    public void printBooksByGenre(String genre) {
        List<Book> books = booksByGenre.getOrDefault(genre, new ArrayList<>());
        System.out.println("Books in genre '" + genre + "':");
        for (Book book : books) {
            System.out.println(book);
        }
    }
}

Library library = new Library();
library.addBook(new Book("The Great Gatsby", "F. Scott Fitzgerald", "Fiction"));
library.addBook(new Book("To Kill a Mockingbird", "Harper Lee", "Fiction"));
library.addBook(new Book("1984", "George Orwell", "Science Fiction"));
library.addBook(new Book("The Hobbit", "J.R.R. Tolkien", "Fantasy"));

library.printBooksByGenre("Fiction");
library.printBooksByGenre("Science Fiction");
library.printBooksByGenre("Fantasy");
library.printBooksByGenre("Nonexistent Genre");

Books in genre 'Fiction':
The Great Gatsby by F. Scott Fitzgerald
To Kill a Mockingbird by Harper Lee
Books in genre 'Science Fiction':
1984 by George Orwell
Books in genre 'Fantasy':
The Hobbit by J.R.R. Tolkien
Books in genre 'Nonexistent Genre':

Question 2 - Writing Classes:

(a) Describe the different features needed to create a class and what their purpose is.

  • Good nomenclature
    • Classes should have good naming structure in order to ensure that code readability is easy
  • Setters/Getters
    • These are used to access or to change class instance variables, which should remain private in order to ensure encapsulation
  • Instance Variables
    • Instance variables contain values that represent parts of a larger, abstracted class, hence they are required to allow for any change within a class.

(b) Code:

Create a Java class BankAccount to represent a simple bank account. This class should have the following attributes:

  • accountHolder (String): The name of the account holder. balance (double): The current balance in the account. Implement the following mutator (setter) methods for the BankAccount class:
  • setAccountHolder(String name): Sets the name of the account holder.
  • deposit(double amount): Deposits a given amount into the account.
  • withdraw(double amount): Withdraws a given amount from the account, but only if the withdrawal amount is less than or equal to the current balance. Ensure that the balance is never negative.
public class BankAccount {
    private String accountHolder;
    private double balance;

    public BankAccount(String accountHolder, double balance) {
        this.accountHolder = accountHolder;
        if (balance >= 0) {
            this.balance = balance;
        } else {
            System.out.println("Initial balance cannot be negative. Setting balance to 0.");
            this.balance = 0;
        }
    }

    public void setAccountHolder(String name) {
        this.accountHolder = name;
    }

    public void deposit(double amount) {
        if (amount > 0) {
            this.balance += amount;
            System.out.println("Deposit of $" + amount + " successful. New balance: $" + this.balance);
        } else {
            System.out.println("Invalid deposit amount.");
        }
    }

    public void withdraw(double amount) {
        if (amount > 0) {
            if (this.balance >= amount) {
                this.balance -= amount;
                System.out.println("Withdrawal of $" + amount + " successful. New balance: $" + this.balance);
            } else {
                System.out.println("Insufficient funds. Withdrawal failed.");
            }
        } else {
            System.out.println("Invalid withdrawal amount.");
        }
    }

    public double getBalance() {
        return balance;
    }

    public String getAccountHolder() {
        return accountHolder;
    }

    public static void main(String[] args) {
        BankAccount account = new BankAccount("John Doe", 1000.0);

        System.out.println("Initial account details:");
        System.out.println("Account Holder: " + account.getAccountHolder());
        System.out.println("Balance: $" + account.getBalance());

        account.deposit(500.0);

        account.withdraw(200.0);

        account.withdraw(2000.0);

        System.out.println("\nFinal account details:");
        System.out.println("Account Holder: " + account.getAccountHolder());
        System.out.println("Balance: $" + account.getBalance());
    }
}

BankAccount.main(null);
Initial account details:
Account Holder: John Doe
Balance: $1000.0
Deposit of $500.0 successful. New balance: $1500.0
Withdrawal of $200.0 successful. New balance: $1300.0
Insufficient funds. Withdrawal failed.

Final account details:
Account Holder: John Doe
Balance: $1300.0

Question 3 - Instantiation of a Class

(a) Explain how a constructor works, including when it runs and what generally is done within a constructor.

A constructor in Java is a special type of method that is called when an object of a class is created. It has the same name as the class and does not have a return type, not even void. Constructors are primarily responsible for initializing the newly created object. When an object is instantiated using the new keyword, the constructor associated with that class is automatically invoked. Constructors are often used to set initial values for object attributes or perform other setup tasks necessary for the object to function correctly. They can accept parameters, allowing for the initialization of object attributes with specific values. Constructors can also initialize other objects, call methods, or perform any other necessary initialization tasks. Constructors play a crucial role in the object-oriented programming paradigm by ensuring that objects are properly initialized before they are used.

(b) Create an example of an overloaded constructor within a class. You must use at least three variables. Include the correct initialization of variables and correct headers for the constructor. Then, run the constructor at least twice with different variables and demonstrate that these two objects called different constructors.

public class Car {
    private String make;
    private String model;
    private int year;

    public Car() {
        make = "Unknown";
        model = "Unknown";
        year = 0;
    }

    public Car(String make, String model, int year) {
        this.make = make;
        this.model = model;
        this.year = year;
    }

    public void displayDetails() {
        System.out.println("Make: " + make);
        System.out.println("Model: " + model);
        System.out.println("Year: " + year);
    }

    public static void main(String[] args) {
        Car car1 = new Car();
        System.out.println("Car 1 Details:");
        car1.displayDetails();

        Car car2 = new Car("Toyota", "Camry", 2020);
        System.out.println("\nCar 2 Details:");
        car2.displayDetails();
    }
}
Car.main(null);
Car 1 Details:
Make: Unknown
Model: Unknown
Year: 0

Car 2 Details:
Make: Toyota
Model: Camry
Year: 2020

Car’s Overloaded Constructor:

// Overloaded constructor
public Car(String make, String model, int year) {
    this.make = make;
    this.model = model;
    this.year = year;
}

This constructor is overloaded because it has a different parameter list than the default constructor. It accepts three parameters: make, model, and year, which represent the make of the car, its model, and the year it was manufactured, respectively. Inside the constructor, the this keyword is used to refer to the current object being constructed. It initializes the make, model, and year instance variables of the Car object with the values passed as arguments to the constructor.

Question 4 - Wrapper Classes:

(a) Provide a brief summary of what a wrapper class is and provide a small code block showing a basic example of a wrapper class.

A wrapper class in Java is a class that provides an object representation of primitive data types. It allows primitive data types to be used as objects. Wrapper classes also provide utility methods for converting between primitive data types and objects, as well as for performing various operations on the wrapped values. In summary, wrapper classes serve as a bridge between primitive data types and objects, enabling them to be used interchangeably in Java programs.

Code block:

public class WrapperExample {
    public static void main(String[] args) {
        // Creating an Integer object using the Integer wrapper class
        Integer number = new Integer(10);
        
        // Using utility methods of the Integer wrapper class
        int value = number.intValue();
        System.out.println("Value: " + value);
        
        // Performing arithmetic operations using the Integer wrapper class
        Integer sum = number + 5;
        System.out.println("Sum: " + sum);
    }
}

Integer is the wrapper class in this example.

(b) Create a Java wrapper class called Temperature to represent temperatures in Celsius. Your Temperature class should have the following features:

Fields:

A private double field to store the temperature value in Celsius.

Constructor:

A constructor that takes a double value representing the temperature in Celsius and initializes the field.

Methods:

getTemperature(): A method that returns the temperature value in Celsius. setTemperature(double value): A method that sets a new temperature value in Celsius. toFahrenheit(): A method that converts the temperature from Celsius to Fahrenheit and returns the result as a double value.

public class Temperature {
    private double celsius;

    public Temperature(double celsius) {
        this.celsius = celsius;
    }

    public double getTemperature() {
        return celsius;
    }

    public void setTemperature(double celsius) {
        this.celsius = celsius;
    }

    public double toFahrenheit() {
        return (celsius * 9 / 5) + 32;
    }

    public static void main(String[] args) {
        Temperature temp = new Temperature(25.0);
        
        System.out.println("Temperature in Celsius: " + temp.getTemperature());
        
        double fahrenheit = temp.toFahrenheit();
        System.out.println("Temperature in Fahrenheit: " + fahrenheit);
    }
}

Temperature.main(null);
Temperature in Celsius: 25.0
Temperature in Fahrenheit: 77.0

Question 5 - Inheritence:

Situation: You are developing a program to manage a zoo, where various types of animals are kept in different enclosures. To streamline your code, you decide to use inheritance to model the relationships between different types of animals and their behaviors.

(a) Explain the concept of inheritance in Java. Provide an example scenario where inheritance is useful.

Inheritance in Java is a mechanism by which a class (subclass) can acquire properties and behaviors (methods) from another class (superclass). Subclasses inherit attributes and methods from their superclass, allowing for code reuse and the creation of a hierarchy of classes with shared characteristics. For example, in a software application for managing different types of vehicles, a superclass Vehicle can define common properties and behaviors such as speed and accelerate(), while subclasses like Car and Truck can inherit these attributes and methods and add their specific features like numberOfDoors or cargoCapacity.

(b) Code:

You need to implement a Java class hierarchy to represent different types of animals in the zoo. Create a superclass Animal with basic attributes and methods common to all animals, and at least three subclasses representing specific types of animals with additional attributes and methods. Include comments to explain your code, specifically how inheritance is used.

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

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

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

    public void displayInfo() {
        System.out.println("Name: " + name);
        System.out.println("Age: " + age);
    }
}


class Lion extends Animal {
    private int maneLength;

    public Lion(String name, int age, int maneLength) {
        super(name, age); 
        this.maneLength = maneLength;
    }


    @Override
    public void displayInfo() {
        super.displayInfo(); 
        System.out.println("Mane Length: " + maneLength);
    }

    public void roar() {
        System.out.println("Lion roars loudly!");
    }
}

class Elephant extends Animal {
    private double tuskLength;


    public Elephant(String name, int age, double tuskLength) {
        super(name, age); 
        this.tuskLength = tuskLength;
    }

    @Override
    public void displayInfo() {
        super.displayInfo(); // Call superclass method
        System.out.println("Tusk Length: " + tuskLength);
    }

    public void trumpet() {
        System.out.println("Elephant trumpets loudly!");
    }
}

class Penguin extends Animal {
    private boolean canSwim;


    public Penguin(String name, int age, boolean canSwim) {
        super(name, age); 
        this.canSwim = canSwim;
    }


    @Override
    public void displayInfo() {
        super.displayInfo(); 
        System.out.println("Can Swim: " + canSwim);
    }


    public void slide() {
        System.out.println("Penguin slides on its belly!");
    }
}


public class Zoo {
    public static void main(String[] args) {
        Lion lion = new Lion("Simba", 5, 15);
        Elephant elephant = new Elephant("Dumbo", 10, 2.5);
        Penguin penguin = new Penguin("Pingu", 3, true);

    
        System.out.println("Information about Lion:");
        lion.displayInfo();
        lion.roar(); 
        
        System.out.println("\nInformation about Elephant:");
        elephant.displayInfo();
        elephant.trumpet();
        
        System.out.println("\nInformation about Penguin:");
        penguin.displayInfo();
        penguin.slide(); 
    }
}

Zoo.main(null);
Information about Lion:
Name: Simba
Age: 5
Mane Length: 15
Lion roars loudly!

Information about Elephant:
Name: Dumbo
Age: 10
Tusk Length: 2.5
Elephant trumpets loudly!

Information about Penguin:
Name: Pingu
Age: 3
Can Swim: true
Penguin slides on its belly!