Simplify java program using inheritance - java

I'm currently learning inheritance in java. I have a superclass called Students with subclasses UndergradStudents & GraduateStudents. Both of them have a method called deansHonourList. In the undergrad deansHonourList method it checks if the GPA is greater than 3.5 to qualify for the deans list and for the graduate subclass the gpa has to be greater than 3.75, I have to remove the methods in the subclasses and create one method in the superclass that determines if the student qualifies for the deans honour list. Here is my code so far.
import java.io.*;
public class Activity6C {
public static void main(String[] args) {
Student[] students = new Student[4];
students[0] = new UndergradStudent(8032, "Casper", 2.78, 2);
students[1] = new GraduateStudent(3044, "Sheena", 3.92, "Natural Language Processing");
students[2] = new UndergradStudent(6170, "Yolanda", 4.26, 3);
students[3] = new GraduateStudent(1755, "Geordi", 3.58, "Human-Computer Interaction");
printStudents(students);
printDeansList(students);
System.out.println("\nEnd of processing.");
}
public static void printStudents(Student[] students) {
System.out.println("\nList of all students:\n");
for (int i = 0; i < students.length; i++) {
System.out.println(i + 1 + ": " + students[i]);
}
}
public static void printDeansList(Student[] students) {
System.out.println("\nDean's honour list:\n");
for (int i = 0; i < students.length; i++) {
if (students[i].deansHonourList()) {
System.out.println(students[i]);
}
}
}
}
class Student {
private int number;
private String name;
private double gpa;
public Student(int number, String name, double gpa) {
this.number = number;
this.name = name;
this.gpa = gpa;
}
public double getGPA() {
return gpa;
}
public boolean deansHonourList() {
//Here is where i make my code to determine honour list students
return false;
}
public String toString() {
return number + " " + name + " (" + gpa + ")";
}
}
class UndergradStudent extends Student {
private int year;
public UndergradStudent(int number, String name, double gpa, int year) {
super(number, name, gpa);
this.year = year;
}
public boolean deansHonourList() {
boolean result = false;
if (getGPA() >= 3.5)
result = true;
return result;
}
public String toString() {
return "Undergraduate: " + super.toString() + " year: " + year;
}
}
class GraduateStudent extends Student {
private String thesis;
public GraduateStudent(int number, String name, double gpa, String thesis) {
super(number, name, gpa);
this.thesis = thesis;
}
public boolean deansHonourList() {
boolean result = false;
if (getGPA() >= 3.75)
result = true;
return result;
}
public String toString() {
return "Graduate: " + super.toString() + " thesis: " + thesis;
}
}
Note: This is an exercise and it's not worth much but I would like a hint in the right direction. Here is what the question also specifies.
I have to make it work without using instanceof or getClass(), and without adding any more if-else statements or instance variables. There should be no deansHonourList() method in either GraduateStudent or UndergraduateStudent, and the getGPA() method can be removed.
The hint i got was to add another instance method to the superclass and override it in the subclasses as necessary; call that method in your deansHonourList() method.
I can't think of a way to do this. I mean what can I put in the new instance method that I would make, and then override it in the subclasses.
Thank you for reading my question or any hints you are able to give me.

You'll need a (possibly abstract) method which returns the minimum GPA score acceptable to be considered for the honours list, maybe something like
abstract class Student {
private int number;
private String name;
private double gpa;
public Student(int number, String name, double gpa) {
this.number = number;
this.name = name;
this.gpa = gpa;
}
public double getGPA() {
return gpa;
}
public abstract double getMinimumHonourListGPA();
public boolean deansHonourList() {
boolean result = false;
if (getGPA() >= getMinimumHonourListGPA()) {
result = true;
}
return result;
}
public String toString() {
return number + " " + name + " (" + gpa + ")";
}
}
Then you could implement doing something like...
class UndergradStudent extends Student {
private int year;
public UndergradStudent(int number, String name, double gpa, int year) {
super(number, name, gpa);
this.year = year;
}
public String toString() {
return "Undergraduate: " + super.toString() + " year: " + year;
}
#Override
public double getMinimumHonourListGPA() {
return 3.5;
}
}
Now, if that's not acceptable, you will need to pass the minimum GPA score via the constructor to the parent class, something like...
class Student {
private int number;
private String name;
private double gpa;
private double minimumHonourListGPA;
public Student(int number, String name, double gpa, double minimumHonourListGPA) {
this.number = number;
this.name = name;
this.gpa = gpa;
this.minimumHonourListGPA;
}
public double getGPA() {
return gpa;
}
public boolean deansHonourList() {
boolean result = false;
if (getGPA() >= minimumHonourListGPA) {
result = true;
}
return result;
}
public String toString() {
return number + " " + name + " (" + gpa + ")";
}
}
class UndergradStudent extends Student {
private int year;
public UndergradStudent(int number, String name, double gpa, int year) {
super(number, name, gpa, 3.5);
this.year = year;
}
public String toString() {
return "Undergraduate: " + super.toString() + " year: " + year;
}
}
for example

Ok, what if you had a method 'requiredGPA()', which returned the GPA required to get on the Deans Honour List?
You would then override this method in the subclasses to return their different requirements, and the superclass's deansHonourList() would use the value returned from this method to decide if the student was on the list?
I could give a code example if needed... let me know if I haven't been clear in this answer?
Edit- looks like MadProgrammer has hit the idea I was going for here.

This is an example of Facade design pattern.
Check here.
This pattern is about providing a simple interface to hide the underlying complexity. Interface is used for the invocation of a single and during the run time JVM will determine which method to call. This method is determined by the implementing class of the object on which method was invoked.
In your case Student is going to work as the interface. As others suggested you can use an abstract class with abstract method deansHonourList or you can use an empty implementation.
Now suppose we have empty constructors in all three classes.
Student student1 = new Student();
Student student2 = new UnderGraduateStudent();
Student student3 = new GraduateStudent();
Since a parent class reference variable can hold instance of the child class we are able to assign objects of UnderGraduateStudent and GraduateStudent to the Student type reference variables.
All these three classes have method deansHonourList.
When we call this method on all the three objects as following
student1.deansHonourList(arguments...)
student2.deansHonourList(arguments...)
student3.deansHonourList(arguments...)
JVM will find the correct class from which it has to invoke the method by checking the type of the student1, student2, student3 instances.
Only one of these methods will be called (unlike constructor where super class constructor is called in subclass constructor).
Even if the deansHonourList is called on parent class reference, the method from the child class is called as the reference holds child class instance.
This is called Method Overriding.
Check this out.
Overriding only works in case of non static methods, in case of static methods, parent class methods are called. Since static members are part of the class not the class instance, instance plays no role in the method resolution.
This is called Method Hiding

Related

why i am getting an error when i try to over ride a method

Hello and good morning guys I'm new to Java, I've encountered some problems while doing my home work. It is related to inheritance.
I need to create a super class named Employee where the variable name and Employee number are kept. And then I need to create a displayInfo() methods to print all the variables.
Then I've been assigned to create a subclass where i calculate the salary and make an overridden method to print the variables from the super class and add the salary to it using the displayInfo() method. But when I try to use it in the subclass, there is an error shown up where it says:
the field employee.number is not visible
Is there any way I can solve this?
Thank you very much for your help! Here is the code I've tried so far
public class Employee {
private String name;
private String number;
private String date;
public Employee()
{
}
public Employee(String name,String number,String date)
{
this.name=name;
this.number=number;
this.date=date;
}
public String getName()
{
return name;
}
public String getNumber()
{
return number;
}
public String getDate()
{
return date;
}
public void displayInfo()
{
System.out.println("Name = "+ name + "Number = "+number+ " Date = " + date);
}
}
\\ my sub class
public class ProductionWorker extends Employee {
private int shift;// 1 = day, 2 = night
private double HoursOfWorking;// day = RM10, night = RM12.50
public ProductionWorker(int shift,int HoursOfWorking)
{
this.shift=shift;
this.HoursOfWorking=HoursOfWorking;
}
public int getShift()
{
return shift;
}
public double getHoursOfWorking()
{
return HoursOfWorking;
}
public double calculateSalary()
{
if(shift==1)
{
return HoursOfWorking * 10 * 20;
}
else
{
return HoursOfWorking * 12.5 * 20;
}
}
public void displayInfo() // this is where the error is encountered
{
System.out.println("Name = "+ name + "Number = "+number+ " Date = " + date + "Sallary = "+ calculateSalary());
}
}
As the below fields are private
private String name;
private String number;
private String date;
you do not have access to them in the subclass, so either make them protected or use the getter methods.
EDIT: I actually take back my answer below. That will only work if the classes are in the same file like this:
class OuterClass
{
public class Employee
{
// ...
}
public class ProductionWorker extends Employee
{
// ...
}
}
You can either change the variables visibility to public/protected or use the getter methods you defined in your Employee class. I'd recommend using the getter methods.
In order to access the values of the Employee class in your subclass ProductionWorker, you have to use the super keyword.
public void displayInfo()
{
System.out.println("Name = " + super.name + "Number = " + super.number + " Date = " + super.date + "Salary = " + calculateSalary());
}
since number is declared as private it is not visible you have to use
your getNumber() method

How to use an attribute in the subclass and not the one from the extended abstract class?

I want you use the method setSalary in this subclass, but I don't know how. It keeps printing out the default value which I initialized in the superclass.
Superclass code:
public abstract class Employee {
private String name;
private String ssn;
protected double salary;
public Employee (String n,String s){
this.name=n;
this.ssn=s;
this.salary=0;
}
public abstract void setSalary(double salary);
#Override
public String toString() {
return "Employee Name: " + name + ", with social security number: " + ssn;
}
}
Subclass code:*
public class HourlyEmployee extends Employee {
private int hours;
private int rate;
public HourlyEmployee(int hours, int rate, String n, String s) {
super(n, s);
this.hours = hours;
this.rate = rate;
}
public void setSalary(double salary) {
this.salary = rate*hours;
}
#Override
public String toString() {
return super.toString()+ "\n"+ "Number of working hours is " +hours+ " and the rate per hour is" + rate + "\n"+" Employee salary is: " +salary +"$";
}
}
The problem is that you are printing the value before calling the setter method. Try to call it first and then make the toString call.
At
public void setSalary(double salary) {
this.salary = rate*hours;
}
You are multiplying the default values which you set in the super class but not using the parameter.
Create the HourlyEmployee object using constructor,
Call the setSalary method on the object,
Now, toString method should return right value
In the first time, the salary property of the super class is initialized by the 0 value in the super constructor which is always called when you create the subclass instance, so you need to call setSalary method just after you created the instance of subclass to rectify the value of salary property and before you use it in the next of your code.

Mutator methods not storing values for the class that I have just made?

Here is the class:
package employee;
public class Employee
{
private String name, department,position;
private int idNumber;
public Employee(String n, int id, String depart,String pos)
{
n= name;
id=idNumber;
depart=department;
pos=position;
}
public Employee(String n, int id)
{
n= name;
id=idNumber;
department="";
position="";
}
public Employee()
{
name="";
idNumber=0;
department="";
position="";
}
public void setName(String n)
{
n=name;
}
public void setDepartment(String depart)
{
depart=department;
}
public void setPosition(String pos)
{
pos=position;
}
public void setId(int id)
{
id=idNumber;
}
public String getName()
{
System.out.println();
return name;
}
public String getDepartment()
{
return department;
}
public String getPosition()
{
return position;
}
public int getId()
{
return idNumber;
}
}
Here is the program:
package employee;
public class RunEmployee
{
public static void main(String[] args)
{
Employee first= new Employee();
first.setName("Susan Myers");
first.setId(47899);
first.setDepartment("Accounting");
first.setPosition("Vice President");
Employee sec= new Employee("Mark Jones",39119,"IT","Programmer");
Employee third= new Employee("Joy Rogers", 81774);
third.setDepartment("Manfacturing");
third.setPosition("Engineer");
/*Printing employee ones information*/
System.out.print("Employee #1- using the no-arg constructor.");
System.out.println("Name: " + first.getName());
System.out.println("Id Number: "+ first.getId());
System.out.println("Department: " + first.getDepartment());
System.out.println("Position: "+ first.getPosition());
/*Printing employee twos information*/
System.out.println("Name: " + sec.getName());
System.out.println("Id Number: "+ sec.getId());
System.out.println("Department: " + sec.getDepartment());
System.out.println("Position: "+ sec.getPosition());
/*Printing employee threes information*/
System.out.print("Employee #3- using a constructor that accepts the name"
+ "and ID number only.");
System.out.println("Name: " + third.getName());
System.out.println("Id Number: "+ third.getId());
System.out.println("Department:" + third.getDepartment());
System.out.println("Position: "+ third.getPosition());
}
}
For this project, I am simply trying to store values into the constructor in different ways. However, my output is showing that my mutator methods are not storing any values. I tried to post my output but I do not have the reputation points. Basically, all the the values for the things I tried to arguments say zero or null.
You've got your assignments backwards!
n = name; puts the value of name to n, not the other way around.
You are assigning the value from the Employee instance to your passed in parameters. To prevent that, it is probably a good idea to use this -
this.name = n; // <-- assign n to the name field of the current instance.
In your example code, this.n would have given you a compile time error.

How can I access the value of a private attribute in an abstract class in a subclass object?

I am taking a class in Java and this question relates to one of the exercises I am to complete. I am trying to print out the contents of an array of objects created from 2 subclasses of an abstract superclass. I am able to create the objects and store them in an array, but when I print out the contents of the array I'm only able to get the last instance of the "age" and "weight" attributes of the superclass. As you can see they are private attributes. Is there a way to access the value of those attributes when the object is created? I've done a fair bit of reading and I'm confused as to whether I can do it and if I can, then how?
My code:
public abstract class Parent {
private static int age;
private static double weight;
public Animal(int age, double weight) {
this.age = age;
this.weight = weight;
}
public static int getAge() {
return age;
}
public static double getWeight() {
return weight;
}
}
public class Child1 extends Parent {
private String name, owner, petInfo;
protected int age;
protected double weight;
public Child1(int age, double weight, String name, String owner) {
super(age, weight);
this.name = name;
this.owner = owner;
}
public String toString() {
petInfo = "Pet's name: " + this.getName() + "\nPet's age: " + getAge() + " years\nPet's weight: " + getWeight() + " kilos\nOwner's name: " + this.getOwner();
return petInfo;
}
}
public class Child2 extends Parent {
public String wildInfo;
public Child2(int age, double weight) {
super(age, weight);
}
public String toString() {
wildInfo = "The wild animal's age: " + getAge() + "\nThe wild animal's weight: " + getWeight();
return wildInfo;
}
}
public class Console {
public static void main(String[] args) {
Parent ref[] = new Parent[5];
for(i = 0; i < 5; i++) {
//user input here
Child1 pet = new Child1(age, weight, name, owner);
ref[i] = pet;
//more user input
Child2 wild = new Child2(age, weight);
ref[i] = wild;
}
//print contents of array
for(Parent item : ref)
System.out.println("\n" +item.toString()+ "\n");
My understanding is that I can only access the attributes of the superclass through the methods. When I use the getAge() and getWeight() methods in the toString() I am not getting the values entered for each object, only the last value the attributes had.
Any help would be greatly appreciated. Cheers.
Don't use static variables for age and weight:
private static int age;
private static double weight;
The values of static variables are the same for all objects of this type since these variables are be class variables, not instance variables. These guys should be instance or non-static fields which will make them unique for each instance of this class (or instances of child classes).
Then in your Child class, get rid of these shadowing variables, since they will shadow the similarly named field in the Parent class:
public class Child1 extends Parent {
private String name, owner, petInfo;
protected int age; // ***** get rid of, since it shadows
protected double weight; // ***** get rid of, since it shadows
Instead, wherever you use these, use the getters and setters in the Child class.
There were errors in the above program.
Corrected the static methods in Parent Class into non-static methods.
Sample Code:
import java.util.Scanner;
abstract class Parent {
private int age;
private double weight;
public Parent(int age, double weight) {
this.age = age;
this.weight = weight;
}
public int getAge() {
return age;
}
public double getWeight() {
return weight;
}
}
class Child1 extends Parent {
private String name, owner, petInfo;
public Child1(int age, double weight, String name, String owner) {
super(age, weight);
this.name = name;
this.owner = owner;
}
public String toString() {
petInfo = "Pet's name: " + this.getName() + "\nPet's age: " + getAge() + " years\nPet's weight: " + getWeight() + " kilos\nOwner's name: " + this.getOwner();
return petInfo;
}
public String getName() {
return name;
}
public String getOwner() {
return owner;
}
}
class Child2 extends Parent {
public String wildInfo;
public Child2(int age, double weight) {
super(age, weight);
}
public String toString() {
wildInfo = "The wild animal's age: " + getAge() + "\nThe wild animal's weight: " + getWeight();
return wildInfo;
}
}
public class Console {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
Parent ref[] = new Parent[2];
//int weight=10;
//int age=5;
//String name="parrot";
//String owner="rajesh";
for(int i = 0; i < 2; i++) {
System.out.println("Enter the name");
String name=in.next();
System.out.println("Enter the age ");
int age=in.nextInt();
System.out.println("Enter the weight");
double weight=in.nextDouble();
System.out.println("Enter the owner");
String owner=in.next();
//user input here
Child1 pet = new Child1(age, weight, name, owner);
ref[i] = pet;
//more user input
if (i==1)
{
break;
}
System.out.println("Enter the name");
name=in.next();
System.out.println("Enter the age ");
age=in.nextInt();
System.out.println("Enter the weight");
weight=in.nextDouble();
System.out.println("Enter the owener");
owner=in.next();
Child2 wild = new Child2(age, weight);
ref[++i] = wild;
}
//print contents of array
for(Parent item : ref)
System.out.println("\n" +item.toString()+ "\n");
}
}

Method for getting value for primitive types

II am having so much trouble getting this method: A method in SmallBank named printBankDetailsthat prints out the details of the stored BankAccounts. This method should work in the case that there is only one BankAccount as well as in the case that there are two BankAccounts. You can check whether there is a value in the account2 instance variable as follows. I have no idea how to get the value of the primitive types I created, account1 and account2 then print that value. Any suggestions?
public class SmallBank
{
private BankAccount account1;
private BankAccount account2;
public SmallBank(String name, int balance)
{
account1 = new BankAccount(name, balance);
account2 = null;
}
public void addSecondAccount(BankAccount newAccount)
{
account2 = newAccount;
}
public void printBlankDetails()
{
account1.getDeclaredFields();
String name = field.getName();
Int balance = field.getBalance();
System.out.println(b);
}
}
An alternate design is to have say printDetails() in the BankAccount class itself. Something like:
public class BankAccount {
String name;
int balance;
...
...
public String printDetails() {
return (name + "/" + balance);
}
}
and then use it in your SmallBank::printBlankDetails() method as follows:
printBlankDetails() {
if(account1 != null) system.out.println(account1.printDetails());
if(account2 != null) system.out.println(account2.printDetails());
}
IMO, this approach provides better encapsulation, hides the details of BankAccount from SmallBank class.
First of all, account1 and account2 are NOT primitive types.
Also, you can access both quite simply as below.
public void printBlankDetails()
{
String name1 = account1.getName();
String name2 = account2.getName();
}
p.s. there are many issues with your printBlankDetails function, so I didnt attempt to replicate it.
You could declare BankAccount as:
class BankAccount {
private int balance;
private String name;
public BankAccount (String name, int balance) {
this.name = name;
this.balance = balance;
}
public String getName () {
return name;
}
public int getBalance () {
return balance;
}
}
Then you call the methods in SmallBank class:
public void printBankDetails () {
System.out.println("Account 1:");
System.out.println("Name: " + account1.getName());
System.out.println("Balance: " + account1.getBalance());
}

Categories