Constructor error in my sub class constructor - java

Here is the Assignment:
Design and implement a class representing a Person along with 3 subclasses using the following guidelines:
a.Create a class named Person and its three subclasses named Employee, Student, Retired.
b.The Person has the following data fields: name, year_of_birth, isStudying, and isEmployed. It also has methods for setting and getting the values of each of the fields along with a method to calculate the current age and display the status of a Person. A constructor that sets the isStudying and isEmployed fields to false is also included in the Person class. You are welcome to add additional data fields and methods if you like.
1.Finally, create a Java test class that simulates using your Person class. In your test class you should at a minimum: a) Construct 4 instances of a Person, b) print the names of your instances c) print the status of your instances based on the values of their age, isStudying and isEmployed attributes.
public class Person2 {//begin class
//declare variables
String name;
int year_of_birth;
boolean isStudying;
boolean isEmployed;
int age;
public Person2(String name, int year_of_birth, boolean isEmployed, boolean isStudying, int age){//begin constructor
this.name = name;
this.year_of_birth = year_of_birth;
this.isEmployed = false;
this.isStudying = false;
this.age = age;
}//end constructor
public int getYear(){//get year method
return year_of_birth;
}//end method
public String getName(){//get name method
return name;
}//end method
public boolean getEmployed(){//get employed method
return isEmployed;
}//end method
public boolean getStudying(){//get employed method
return isStudying;
}//end method
public int getAge(){//get year method
age = 2014 - year_of_birth;
return age;
}//end method
public void setName(String name){//set name method
this.name = name;
}//end method
public void setYear (int year){//set year method
this.year_of_birth = year;
}//end method
public void setEmployed(boolean employed){//set employed method
this.isEmployed = employed;
}//end method
public void setAge (int age){//set year method
this.age = age;
}//end method
public static void main(String[] args) {
// TODO code application logic here
}
}
class Student extends Person2 {//begin class
public Student(String name, int year_of_birth, boolean isEmployed, boolean isStudying, int age){//begin constructor
this.name = name;
this.year_of_birth = year_of_birth;
this.isEmployed = isEmployed;
this.isStudying = isStudying;
this.age = age;
}//end constructor)
#Override
public int getYear(){//get year method
return year_of_birth;
}//end method
#Override
public String getName(){//get name method
return name;
}//end method
#Override
public boolean getEmployed(){//get employed method
return isEmployed = false;
}//end method
#Override
public boolean getStudying(){//get employed method
return isStudying = true;
}//end method
#Override
public int getAge(){//get year method
age = 2014 - year_of_birth;
if (age > 30){
System.out.println("Person is not a student");
}
return age;
}//end method
}
This code obviously isn't complete I am getting hung up on this constructor error. It says "actual and formal arguments differ in length".

You problem is that you are not invoking the super constructor Person2. Your constructor in Student is trying to invoke a the default constructor (with no arguments) of Person2, which doesn't exist.
You only have one constructor in Person2, and should call that constructor from the constructor of Student:
public Student(String name, int year_of_birth, boolean isEmployed, boolean isStudying, int age) {
super(name, year_of_birth, isEmployed, isStudying, age);
}
This also means you don't need to repeat all of that initialisation code twice.
You also shouldn't be repeating all the methods in Student that are in Person2. If you take them out, Student will inherit them anyway. That's the whole point in extending the class in the first place. You should only override a method like that if you don't want the inherited behaviour, but want some Student specific behaviour instead.

When extending any functionality you should try to use that functionality...
Your class Student extends Person2 but does it use anything from Person2?
Why do you override all methods and provide identical functionality in your subclass???

Related

Compile time vs Runtime method binding [duplicate]

I have a basic inheritance situation with an overloaded method in the super class.
public class Person {
private String name;
private int dob;
private String gender;
public Person(String theName, int birth, String sex){
name = theName;
dob = birth;
gender = sex;
}
public void work(){
getWorkDetail(this);
}
public void getWorkDetail(Employee e){
System.out.println("This person is an Employee");
}
public void getWorkDetail(Person p){
System.out.println("This person is not an Employee");
}
}
The following Employee class extends the Person class above:
public class Employee extends Person {
String department;
double salary;
public Employee(String theName, int birth, String sex){
super(theName, birth, sex);
department = "Not assigned";
salary = 30000;
}
}
The main method simply creates an Employee object (both static and dynamic type) and calls .work() on it:
public static void main(String[] args){
Employee e1 = new Employee("Manager1", 1976, "Female");
e1.work();
}
This ends up printing
This person is not an Employee
Looking through this I had thought that since both the static and dynamic type of the object e1 is Employee it would call the overloaded method in Person that takes an Employee as a parameter. Since I am clearly wrong about this I opened a debugger assuming the reference to "this" at the line getWorkDetail(this) in the Person class must have morphed to it's super class. However this is not what I found.
Clearly at this point in the code this is an Employee object, however it still chose to execute the overloaded method getWorkDetail(Person p). Can anyone explain this behavior?
Unlike method overrides, method overloads are linked based on the static type. And in this case, getWorkDetail(this) in Person only knows about the Person type.
Method overloading is not designed to provide dynamic runtime behavior.
To take advantage of dynamic binding, you may need to redesign your code to override the methods, instead:
public static void main(String[] args) throws IOException {
new Employee("Manager1", 1976, "Female").getWorkDetail();
new Person("Manager1", 1976, "Female").getWorkDetail();
}
And modify behavior based on implementing classes. Of course, you can overload methods, as long as you take care of overriding the overloaded methods too, if required.
class Person {
private String name;
private int dob;
private String gender;
public Person(String theName, int birth, String sex) {
name = theName;
dob = birth;
gender = sex;
}
public void getWorkDetail() {
System.out.println("This person is not an Employee");
}
}
class Employee extends Person {
String department;
double salary;
public Employee(String theName, int birth, String sex) {
super(theName, birth, sex);
department = "Not assigned";
salary = 30000;
}
public void getWorkDetail() {
System.out.println("This person is an Employee");
}
}
The overload resolution happens during compile time, not at runtime.
So, when you call getWorkDetails(this), this is assumed to be a Person (which is the static type) and hence called the corresponding overload.
Note: Using this inside Employee class would have made it an Employee type. You can verify this by overloading work() in Employee like this.
class Employee extends Person {
...
public void work() {
getWorkDetails(this); // This should print "This person is an Employee"
}
}
Problem specific solution
In some languages parameters are resolved to their dynamic type, but not in java. The compiler already determines at compile time where your getWorkDetail(this); will go. this is of type Person, so getWorkDetail(Person e) is called. In your specific case the solution is quite obvious. As others have already pointed out, you'll need to override getWorkDetail() in the Employee class.
Resolving methods to their dynamic parameter types
To solve the general problem of resolving parameter types at runtime, using the instanceof operator should be avoided, as it usually leads to unclean code.
If you have two different classes, a solution as simple as stated above is no longer possible. In these cases you'll have to use the visitor pattern.
Consider the following classes:
public interface Animal {
default void eat(Food food) {
food.eatenBy(this);
}
void eatMeat(Meat meat);
void eatVegetables(Vegetables vegetables);
}
public class Shark implements Animal {
public void eatMeat (Meat food) {
System.out.println("Tasty meat!");
}
public void eatVegetables (Vegetables food) {
System.out.println("Yuck!");
}
}
public interface Food {
void eatenBy(Animal animal);
}
public class Meat implements Food {
public void eatenBy(Animal animal) {
animal.eatMeat(this);
}
}
public class Vegetables implements Food {
public void eatenBy(Animal animal) {
animal.eatVegetables(this);
}
}
Which you can call like this:
Animal animal = new Shark();
Food someMeat = new Meat();
Food someVegetables= new Vegetables();
animal.eat(someMeat); // prints "Tasty meat!"
animal.eat(someVegetables); // prints "Yuck!"
Following the visitor pattern calling Animal.eat will call Food.eatenBy, which is implemented by both Meat and Vegetables. Those classes will call the more specific eatMeat or eatVegetables method, which uses the correct (dynamic) types.
Call preference
class Foo {
static void test(int arg) { System.out.println("int"); }
static void test(float arg) { System.out.println("float"); }
static void test(Integer arg) { System.out.println("Integer"); }
static void test(int... arg) { System.out.println("int..."); }
public static void main(String[] arg) {
test(6);
}
}
The output will be int printed on console. Now you comment the first test() method and see what is the output coming.
This is the preference hirarchey in primitive data types. Now coming to derived types declare a class FooChild like this
class FooChild extends Foo {
}
and create two new methods in Foo like
static void testChild(Foo foo) { System.out.println("Foo"); }
static void testChild(FooChild fooChild) { System.out.println("FooChild"); }
then in main method try calling testChild like this testChild(new FooChild());.
getWorkDetail(this) does not know what the subclasses are. call getWorkDetail instead.

How to call an abstract method (overridden in subclasses) from the superclass?

I have an abstract method in an abstract class, Student.
The Subclass, JUPASStudent overrides it.
Now I am trying to sort the ArrayList of type Student. It requires to call that abstract method but I am unable to do so.
I am writing here my partial code.
Superclass:
abstract class Student {
protected String name;
public Student (String name) {
this.name = name;
}
public String getName() {
return name;
}
abstract double getResult(); //abstract method
}
Subclass:
public class JUPASStudent extends Student {
private double dseResult;
public JUPASStudent(String n, double d) {
super (n);
this.dseResult = d;
}
public double getResult() {
return dseResult; //abstract method is overridden here
}
public String getName() {
return super.name;
}
public void setResult(double dseResult) {
this.dseResult = dseResult;
}
public void setName(String name) {
super.name = name;
}
}
Now I am writing a Sort function to make an ArrayList (Student class)
public ArrayList <Student> sort(ArrayList<Student> sList){
sList.sort(Comparator.comparingInt(Student::getResult));
return sList;
}
Input:
A 9
B 5
C 8
Expected Output:
B 5
C 8
A 9
Error
-The method comparingInt(ToIntFunction<? super T>) in the type Comparator is not applicable for the arguments (Student::getResult)
-The type Student does not define getResult(T) that is applicable here
If you have override the method in the subclass, it'll use the implementation of the subclass, so don't worry about calling it explicit, at least in your case
getResult() is returning double, try returning Int and i think it would work.
edit:
or use comparingDouble() method

Which Overloaded Method is Called in Java

I have a basic inheritance situation with an overloaded method in the super class.
public class Person {
private String name;
private int dob;
private String gender;
public Person(String theName, int birth, String sex){
name = theName;
dob = birth;
gender = sex;
}
public void work(){
getWorkDetail(this);
}
public void getWorkDetail(Employee e){
System.out.println("This person is an Employee");
}
public void getWorkDetail(Person p){
System.out.println("This person is not an Employee");
}
}
The following Employee class extends the Person class above:
public class Employee extends Person {
String department;
double salary;
public Employee(String theName, int birth, String sex){
super(theName, birth, sex);
department = "Not assigned";
salary = 30000;
}
}
The main method simply creates an Employee object (both static and dynamic type) and calls .work() on it:
public static void main(String[] args){
Employee e1 = new Employee("Manager1", 1976, "Female");
e1.work();
}
This ends up printing
This person is not an Employee
Looking through this I had thought that since both the static and dynamic type of the object e1 is Employee it would call the overloaded method in Person that takes an Employee as a parameter. Since I am clearly wrong about this I opened a debugger assuming the reference to "this" at the line getWorkDetail(this) in the Person class must have morphed to it's super class. However this is not what I found.
Clearly at this point in the code this is an Employee object, however it still chose to execute the overloaded method getWorkDetail(Person p). Can anyone explain this behavior?
Unlike method overrides, method overloads are linked based on the static type. And in this case, getWorkDetail(this) in Person only knows about the Person type.
Method overloading is not designed to provide dynamic runtime behavior.
To take advantage of dynamic binding, you may need to redesign your code to override the methods, instead:
public static void main(String[] args) throws IOException {
new Employee("Manager1", 1976, "Female").getWorkDetail();
new Person("Manager1", 1976, "Female").getWorkDetail();
}
And modify behavior based on implementing classes. Of course, you can overload methods, as long as you take care of overriding the overloaded methods too, if required.
class Person {
private String name;
private int dob;
private String gender;
public Person(String theName, int birth, String sex) {
name = theName;
dob = birth;
gender = sex;
}
public void getWorkDetail() {
System.out.println("This person is not an Employee");
}
}
class Employee extends Person {
String department;
double salary;
public Employee(String theName, int birth, String sex) {
super(theName, birth, sex);
department = "Not assigned";
salary = 30000;
}
public void getWorkDetail() {
System.out.println("This person is an Employee");
}
}
The overload resolution happens during compile time, not at runtime.
So, when you call getWorkDetails(this), this is assumed to be a Person (which is the static type) and hence called the corresponding overload.
Note: Using this inside Employee class would have made it an Employee type. You can verify this by overloading work() in Employee like this.
class Employee extends Person {
...
public void work() {
getWorkDetails(this); // This should print "This person is an Employee"
}
}
Problem specific solution
In some languages parameters are resolved to their dynamic type, but not in java. The compiler already determines at compile time where your getWorkDetail(this); will go. this is of type Person, so getWorkDetail(Person e) is called. In your specific case the solution is quite obvious. As others have already pointed out, you'll need to override getWorkDetail() in the Employee class.
Resolving methods to their dynamic parameter types
To solve the general problem of resolving parameter types at runtime, using the instanceof operator should be avoided, as it usually leads to unclean code.
If you have two different classes, a solution as simple as stated above is no longer possible. In these cases you'll have to use the visitor pattern.
Consider the following classes:
public interface Animal {
default void eat(Food food) {
food.eatenBy(this);
}
void eatMeat(Meat meat);
void eatVegetables(Vegetables vegetables);
}
public class Shark implements Animal {
public void eatMeat (Meat food) {
System.out.println("Tasty meat!");
}
public void eatVegetables (Vegetables food) {
System.out.println("Yuck!");
}
}
public interface Food {
void eatenBy(Animal animal);
}
public class Meat implements Food {
public void eatenBy(Animal animal) {
animal.eatMeat(this);
}
}
public class Vegetables implements Food {
public void eatenBy(Animal animal) {
animal.eatVegetables(this);
}
}
Which you can call like this:
Animal animal = new Shark();
Food someMeat = new Meat();
Food someVegetables= new Vegetables();
animal.eat(someMeat); // prints "Tasty meat!"
animal.eat(someVegetables); // prints "Yuck!"
Following the visitor pattern calling Animal.eat will call Food.eatenBy, which is implemented by both Meat and Vegetables. Those classes will call the more specific eatMeat or eatVegetables method, which uses the correct (dynamic) types.
Call preference
class Foo {
static void test(int arg) { System.out.println("int"); }
static void test(float arg) { System.out.println("float"); }
static void test(Integer arg) { System.out.println("Integer"); }
static void test(int... arg) { System.out.println("int..."); }
public static void main(String[] arg) {
test(6);
}
}
The output will be int printed on console. Now you comment the first test() method and see what is the output coming.
This is the preference hirarchey in primitive data types. Now coming to derived types declare a class FooChild like this
class FooChild extends Foo {
}
and create two new methods in Foo like
static void testChild(Foo foo) { System.out.println("Foo"); }
static void testChild(FooChild fooChild) { System.out.println("FooChild"); }
then in main method try calling testChild like this testChild(new FooChild());.
getWorkDetail(this) does not know what the subclasses are. call getWorkDetail instead.

Calling a super method in Java

Customer.java:17: error: cannot find symbol
super.display();
^
symbol: method display()
1 error
This what is happening when I compile my program. How do I display the objects data in the Customer subclass?
import java.util.Scanner;
public class Person {
private String name;
private String address;
private String number;
//No Argument constructor//
public Person() {
name = "";
address = "";
number = "";
}
//Explicit value constructor//
public Person(String num, String nam, String add) {
number = num;
name = nam;
address = add;
}
//Accessor method//
public String getName() {
return name;
}
//Mutator method//
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getTelephoneNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String toString() {
return name + "\n" + address + "\n" + number;
}
}
The subclass:
public class Customer extends Person {
public Customer(String num, String nam, String add) {
super(num, nam, add);
}
public boolean checkResponse(char response) {
if (response == 'Y') {
return true;
}
return false;
}
public void display() {
super.display();
}
}
In order for super.display() to work, you require a method called display() in your parent class.
Since you have no such method, Java will not allow the code you have to compile.
Since it seems you're trying to show useful information about the object when it's printed, why not override toString() again? The caveat here is that you don't have any more meaningful information to show about it being a Customer over it being a Person (there's no Customer-specific fields, so the inheritance relationship is moot).
You may want to consider adding more info to differentiate a Customer from a Person, then override toString().
The error occurs because there is no display() method in the Person class. So you cant invoke a non existing method using super.display()
So change the display() method in Customer to
public void display() {
System.out.println(super.toString());
}
As the error is trying to tell you, super.display() doesn't exist.
You can simply access the number, name or address directly. Modify the display() method, remove super.display() like below.
public void display()
{
System.out.println("Customer telephone number:" + number);
}
Super keyword in java is related to parent class and Super.display() means you are calling the display method of the parent class.Your parent class is person as you are extending it public class Customer extends Person {
But there is no display() in person hence your are getting compilation error
You don't have display() function defined in parent class(Pesron);

Something weird is happening to the Person

In the following java code
public class Person {
int age = 18;
}
class Student extends Person {
public Student() {
this.age = 22;
}
public static void main(String[] args) {
Student student = new Student();
student.doSomthing();
}
void doSomthing() {
System.out.println(this.age);
System.out.println(super.age);// Here is something weird, at least for me till rightNow()
}
}
Why the super.age value is 22 , the same value as the sub-class's age value, Isn't it supposed to be 18;
Any help is appreciated.
Thanks in advance.
Age is a field in the super class. In the constructor of the subclass, when you say this.age = 22, you are updating the instance variable in the super class.
Try the following ... I dont have a compiler handy but i think it might do what you are expecting.
public class Person {
int age = 18;
}
class Student extends Person {
int age; // Hides the super variable
public Student() {
this.age = 22;
}
public static void main(String[] args) {
Student student = new Student();
student.doSomthing();
}
void doSomthing() {
System.out.println(this.age);
System.out.println(super.age);
}
}
this is behaving as you would expect. You haven't declared an 'age' member of Student, so this.age naturally references 'age' defined in the superclass.
The code below will provide the behaviour you are expecting (although shadowing variables like that is often a very bad idea).
public static class Person {
int age = 18;
}
public static class Student extends Person {
int age = 18;
public Student() {
this.age = 22;
}
void doSomthing() {
System.out.println(this.age);
System.out.println(super.age);
}
}
No, that is correct. In the constructor, you are overriding the super class's age. You could instead do something like this:
public class Person {
public int getAge() {
return 18;
}
}
class Student extends Person {
public Student() {
}
#Override
public int getAge() {
return 22;
}
public static void main(String[] args) {
Student student = new Student();
student.doSomthing();
}
void doSomthing() {
System.out.println(this.getAge()); //22
System.out.println(super.getAge()); //18
}
}
Student inherits age from parent, so there is no difference between age and super.age
No, what is happening is correct. When you create a subclass (Student is a subclass of Person), that subclass inherits all of the fields (variables) from the superclass. However, there is only one set of variables: there is only one value for age, even though it is inherited. In other words, when a class inherits a field, it doesn't create a new copy of it - there is only one copy per student.
In this source, this and super are the same instance variable because you define it in the super class an inherited in the subclass.
When you create your Student you initilize it to 22 and that's it.
Nothing strange, it's behaving correctly. Class Student doesn't have a private variable age, which would overwrite parents variable.
You're setting age in your Student class, but the parent is the one declaring age and they share the same variable - therefore, it makes sense that the value was modified. Overriden methods would be different, however.

Categories

Resources