Best practice to set variable on subclass constructor - java

Superclass
public class food {
private String name;
public food( String name){
this.name = name;
}
public void foodName() {
System.out.println("This is "+name);
}
}
Subclass
public class Bacon extends food {
private String name;
public Bacon (String name) {
super(name);
this.name=name;
}
public void foodName() {
System.out.println("This is a food named " +name);
}
}
For the variable name of the subclass Bacon to work in the overriden method, is this the best practice or are there better ways to do it?
public Bacon(String name){
super(name);
this.name=name;
}

In class Bacon, the declaration of name hides the declaration of name in Food class, and all references to name in Bacon class refer to the Bacon.name not Food.name.
So please go through the Inheritance chapter again.
There is no need of name declaration again in Bacon class. Remove the declaration, since it is extending Food class, it will have name property.
To access name in the child classes add access specifier to the name property as protected like
protected String name; //inherited classes can have access to this property
Also modify the constructor
public Bacon (String name) {
super(name);
// (removed) this.name=name;
}

In this case more logical will be to mark name variable as protected, it will allow subclasses and package members to access it.
Superclass
public class food {
protected String name;
public food( String name){
this.name = name;
}
public void foodName() {
System.out.println("This is "+name);
}
}
And remove duplicate name variable in subclass and just use constructor if superclass
public class Bacon extends food {
public Bacon (String name) {
super(name);
}
public void foodName() {
System.out.println("This is a food named " +name);
}
}

There is no overriding of variables in Java, and you can't access a private variable from a superclass in a subclass in general; so what you have is two separate variables called name.
If you want your subclass to have access to the variable then make it protected in the superclass:
public class food {
protected String name;
//...
}
If you really want to restrict access, and the subclass only needs to use the variable (not modify it), then you should uses a getter method.
public class food {
private String name;
protected String getName() {
return name;
}
//...
}
You subclass can then call getName() instead of using name.

Related

Java: Issue building a zoo using inheritance

I am new to Java and I'm having an issue with inheritance. I'm working through an activity where I have a parent class (Animal) and child classes (Giraffe in this instance) which inherits the fields of the parent class. I was instructed to have a default constructor and a constructor that accepts parameters in both instances of the parent and child classes.
The issue that I'm encountering is that when I run printInfo() it is returning the default for species in the parent's default constructor ('species') and not the child class ('giraffe'). I had assumed that the Giraffe child class would inherit this parent class method, but it seems that something's not quite right here.
(Note that each of my classes are separate files)
Any assistance or pointers would be greatly appreciated.
// Parent class:
public class Animal {
String name;
String species;
int age;
// default constructor
public Animal() {
name = "name";
species = "species";
age = 0;
}
// constructor w/ parameters
public Animal(String name, String species, int age){
this.name = name;
this.species = species;
this.age = age;
}
// method for printing out animal info
void printInfo() {
System.out.println(name + ", " + species + ", " + age);
}
}
// Child class:
public class Giraffe extends Animal {
String species = "giraffe";
// default giraffe constructor
public Giraffe() {
super();
name = "Errol";
age = 0;
}
// giraffe constructor with parameters
public Giraffe(String name, int age) {
super();
this.name = name;
this.age = age;
}
}
// Main class (calls printInfo method from Animal parent class)
public class ZooBuilder {
public static void main(String[] args) {
Giraffe one = new Giraffe("Mark", 23);
one.printInfo();
}
}
Prints: *Mark, species, 23*
Change the Giraffe constructor to call the full constructor
public Giraffe(String name, int age) {
super(name, "Giraffe", age);
}
Change the default to also be like the above

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.

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.

java default access modifiers

I am a complete beginner in java, so please forgive me if this question is not up to the standard of this website:
class person{
String name;
int age;
}
class teacher extends person{
person s1=new person();
teacher t1=new teacher();
t1.age=56;
}
Here I am trying to access the variable age and name of class to assign them values person, which happens to be the super class of person. But the compiler is giving error. I even tried to make the name variable and age variable as public. But the compiler is still reporting an error. I want to know the reason why I can't access superclass variable in subclass directly and assign values to them.
You are not allowed to write arbitrary code directly within a class body. The closest thing to what you have written is
class teacher extends person{
person s1=new person();
teacher t1=new teacher();
{
t1.age=56;
}
}
This is called the instance initializer block.
In general, it is not a good idea to access variables directly. Consider using something like the code below.
Test driver
package com.example.input;
public class TestPeople {
public static void main(String[] args) {
Person s1 = new Person();
s1.setName("student 1").setAge(19);
Teacher t1 = new Teacher("Dr. Fun",0);
t1.setAge(56);
System.out.println("Student " + s1.getName() + ", " + s1.getAge());
System.out.println("Teacher " + t1.getName() + ", " + t1.getAge());
}
}
Class Person
package com.example.input;
public class Person {
private String name;
private int age;
public Person() {};
public Person(String aName, int anAge) {
setName(aName).setAge(anAge);
}
public String getName() {return name;}
public int getAge() {return age;}
public Person setName(String aName) { name = aName; return this;}
public Person setAge(int anAge) { age = anAge; return this;}
}
Class Teacher
package com.example.input;
public class Teacher extends Person {
public Teacher() {
super();
}
public Teacher(String aName, int anAge) {
super(aName, anAge);
}
}
Actually you are making an assignment of variable of external class in existing class body which is not legal.Make the assignment in a method or constructor or in a anonymous block.
class person{
String name;
int age;
}
class teacher extends person{
person s1=new person();
teacher t1=new teacher();
// t1.age=56; Error here
public teacher()
{
t1.age=56;
}
//or method
public void setAge()
{
t1.age=56;
}
}
do whatever suits your program and you.

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);

Categories

Resources