This is a piece of code that I have that I'm testing right now, and I noticed that when I change public to private on the getInfo() method in Person, both Student().printPerson() & Person().printPerson() print out "Person". However, when it's public, "Student" is displayed. Can someone explain this? Why is it that the private modifier disallows access to the getInfo method from Student?
new Student().printPerson();
new Person().printPerson();
}
}
class Student extends Person {
public Student(){
System.out.println("student invoked") ;
}
public String getInfo() {
return "Student";
}
}
class Person {
public Person(){
System.out.println("person invoked");
}
private String getInfo() {
return "Person";
}
public void printPerson() {
System.out.println(getInfo());
}
public (or protected) method in Java are always virtual.
This means that if a derived class overrides the method, calls made through the base class will call the derived class (if the object is actually an instance of the derived class).
When your base method is public, this happens, and calling it from printPerson() calls the overriding derived version.
When it's private, it is not virtual, so calls from the base class always call the base version (since it doesn't know about the derived class' method).
Related
I'm writing program that demonstrates the use of inheritance and I have created a variable using the super() keyword. I am now trying to place the value of that variable into a new method that calls it so that I can call that method in my main method to use its value within other classes.
Here is the relevant code:
Food class (super class)
public class Food {
//field that stores the name of the food
public String name;
//constructor that takes the name of the food as an argument
public Food(String name){
this.name = name;
}
public String getName() {
return name;
}
}
Meat class (sub class with super keyword)
public class Meat extends Food
{
public Meat() {
super("Meat");
}
public String getName() {
return //get super() value??;
}
}
Main class
public class Main {
public static void main(String[] args)
{
Wolf wolfExample = new Wolf();
Meat meatExample = new Meat();
System.out.println("************Wolf\"************");
System.out.println("Wolves eat " + meatExample.getName());
}
}
Any help is appreciated, thanks.
You could just do
public String getName() {
return super.getName();
}
Although you don't even need to override the method in the first place, because you declared the field name in super class to be public which means it can be accessed from anywhere.
Don't override public String getName() in Meat class.
The inheritance allows to inherit public and protected methods of Food in all subclasses of Food, therefore in Meat.
So Meat which IS a Food has by definition this behavior :
public String getName() {
return name;
}
which returns the name field stored in the parent class.
Overriding a method in subclass to write exactly the same code than in the parent method is useless and should not be done because it is misleading. A person which reads the code will wonder : why having overrided the method in the child class if it does the same thing than the parent class ?
Edit
Besides, if you want to access a field declared in a super class from a subclass, you should :
provide a public getter in the super class if the field is private. Here :
public String getName() {
return name;
}
use directly the field in the subclass if the field has the protected modifier.
As a general rule, you should avoid declaring instance fields with the modifier public because by default properties of a object should be protected and you should provide methods to modify the field only if needed.
So, declaring your Food class like that seems more suitable :
public class Food {
//field that stores the name of the food
private String name;
//constructor that takes the name of the food as an argument
public Food(String name){
this.name = name;
}
public String getName() {
return name;
}
}
In your Meat class, imagine you would like to add an additional information in the string returned by getName(), you could override it and why not using the field from the super class :
public class Meat extends Food {
public Meat() {
super("Meat");
}
#Override
public String getName() {
return super.getName + "(but don't abuse it)";
}
}
Here overriding the method is helpful because the behavior of the method in the child class differs from which one definedin the super class.
Simply write:
public String getName() {
return name;
}
This is because when searching for a variable named name, Java proceeds in this order:
Local variables (none)
Current class's fields (none)
Superclass's fields (found)
Super-super-class's fields (etc.)
However, you didn't need to override getName() in the subclass in the first place. If you didn't define it, then it would inherit the superclass's implementation, which corresponds exactly to the behavior you wanted. Thus you were doing extra work for no gain.
The other answers showed you how to do what you want.
But you should't do it (in real life projects)!
The most important principle in object oriented programming is encapsulation (aka information hiding). This means that the internal structure of a class should not be visible or accessible to the outside.
Therefore all member variables should be private.
Also you should avoid setter/getter methods since they just redirect the access. (except the class is a DTO without any logic of its own).
Since food class has the method getName declared as public do
public String getName() {
return super.getName();
}
public class Test {
public static void main(String args[]){
Student s = new Student();
s.printPerson();
}
}
class Person{
private String getInfo(){
return "Person";
}
public void printPerson(){
System.out.println(getInfo());
}
}
class Student extends Person{
private String getInfo(){
return "Student";
}
}
The output is Person. I am confused with this result. In the main method, the reference type is Student. So when executing s.printPerson(), it should executes the method of Student. The key point is, in the public method inherited from superclass, which private method is invoked? And why?
I thought in s.printPerson(), it invokes getInfo() of Student. But it turns out not. The IDE tells me
private String getInfo(){
return "Student";
}
is never used.
Can anyone help me with this please?
In Java, private methods are not inherited.
A subclass does not inherit the private members of its parent class. However, if the superclass has public or protected methods for accessing its private fields, these can also be used by the subclass.
You cannot override getInfo by creating another getInfo method because it's not inherited. That's why your IDE gave you the "never used" warning, because nothing in Student uses it. The getInfo from Person is called, because it is available to Person's printPerson method, so Person is printed.
To override a method, it must not be private. You can make getInfo package-private (no access modifier), protected, or public. Then Student will be able to override it.
You use the private modifier. This modifier means that the method is only visible from within the class itself, not other classes, not even its sub- and superclasses. So when you call getInfo() from class Person, the only method visible is the method defined in the Person class. Effectively this means that private methods are not inherited in Java.
Try to change the private modifier to protected. Then the subclasses can see the method from the superclass, and so they can overide the method.
I am new to java and I remember in c++ we did something like CLASSNAME::Fn() to avoid ambiguity in inheritance.
Here's my code and I want to have same display methods in both classes and access them explicitly.
public class Main {
public static void main(String args[]){
Emplo e = new Emplo("samuel",19,"designer",465);
e.display(); // here i want to call both display()
}
}
public class Person {
String name;
int age;
Person(String s, int a){
name = s;
age = a;
}
public void dispaly(){
System.out.println("name: "+name+"\nage: "+age);
}
}
public class Emplo extends Person {
String desg;
double sal;
Emplo(String s,int a,String d, double sa){
super(s,a);
desg=d;
sal=sa;
}
void display(){
System.out.println("desg: "+desg+"\nsal: "+sal);
}
}
In java, you can't not call the specific method implementation of the class of the instance.
That is, you can't "bypass" a sub-class method and call a super-class version of the method; calling the super-class method can only be done from within the subclass using super.someMethod().
You can't even invoke a super-super class's version, ie you can't do something like super.super.someMethod()
First of in here you are use two different method. display() in Emplo and dispaly() in Person. SO there is no point of talking ambiguity or overriding make that correct.
Suppose you are corrected that. Then you can't code keep this way
public void display(){ // method in Person
System.out.println("name: "+name+"\nage: "+age);
}
Then
void display(){ // method in Emplo
System.out.println("desg: "+desg+"\nsal: "+sal);
}
You are using weaker modifier to override, So you can't compile this code. You can make public the method in Emplo.
And answer for your last question. you can't do it. can't call both method.
In the second display method call the super class display method by using super keywod as :
super.display(); (should be the first statement of the method)
and there will be no ambiguity because that display method will be called whose object is being created that means that the display() method of Employee will be called in this case
so if you want to call the display method of Person class then you should create the object of that class and reference by That class type like :
Person p = new Person(your data);
p.display() // here display method of person will be called
and No you cannot call both methods from the same reference
In your Emplo class display() method super.dispaly() indicates display() method of immediate super class i.e Person class.
void display(){ // here in Emplo class you can't give more restrictive modifier(i.e `public` to `default`. since in `Person` class it is `public` so it must be `public`.(overriding rule)
super.dispaly();
System.out.println("desg: "+desg+"\nsal: "+sal);
}
so put public modifier here:
public void display(){
super.dispaly();
System.out.println("desg: "+desg+"\nsal: "+sal);
}
`
Perhaps this answers your question:
public void myMethod()
{ //inherited method
super.myMethod(); //calls base class method
//... add more code to inherited method
}
for details see original source:
In Java, how do I call a base class's method from the overriding method in a derived class?
I'm using Java 7 and got 3 classes:
TestSuper.java
public abstract class TestSuper {
public TestSuper() {
testMethod();
}
protected abstract void testMethod();
}
TestNull.java
public class TestNull extends TestSuper {
private String test = "Test";
public TestNull() {
super();
System.out.println(test);
}
#Override
protected void testMethod() {
System.out.println(test);
}
}
TestMain.java
public class TestMain {
public static void main(String[] args) {
new TestNull();
}
}
Output:
null
Test
Why does this happen and is there a good workaround for it?
When you call new TestNull(); you're calling the constructor of the class TestNull, which it calls the super() constructor: it contains a call to the method implemented in TestNull, where you print the String field, at this time the fields of the sub-class TestNull are not yet initialized, i.e. are null.
After the super constructor call, all the fields will be initialized, and therefore the second print actually show the new value of the (initialized) string.
The key point here is that fields of a sub-class are initialized after the instantiation of the super-classes.
A workaround? It depends on what exact behaviour you desire: maybe it makes sense to NOT call the abstract method in the super constructor (i.e. in the constructor of the TestSuper class).
According to JLS 8.1.1.1 Abstract Class
A subclass of an abstract class that is not itself abstract may be
instantiated, resulting in the execution of a constructor for the
abstract class and, Therefore, the execution of the Field Initializers
for instance variables of that class.
You are calling an overridable instance method (which also calls an instance field, in your case private String test = "Test";) in the constructor. This might cause inconsistencies since the instance is not fully constructed. This is a bad practice, so avoid it:
public TestSuper() {
testMethod();
}
Please read this thread: What's wrong with overridable method calls in constructors?
you can work around this issue by moving the call of testMethod() to a separate function
public abstract class TestSuper {
public TestSuper() { }
public void callTestMethod(){
testMethod();
}
protected abstract void testMethod();
}
then call callTestMethod() on TestNull constructor
public TestNull() {
super.callTestMethod();
System.out.println(test);
}
public abstract class Person {
private String name;
public Person(String name) {
this.name = name;
System.out.println("Person");
}
public String getName() {
return name;
}
abstract public String getDescription();
}
public class Student extends Person {
private String major;
public Student(String name, String major) {
super(name);
this.major = major;
}
public String getMajor() {
return major;
}
#Override
public String getDescription() {
return "student" + super.getName() + " having" + major;
}
}
public class PersonTest {
public static void main(String[] args) {
Person person = new Student("XYZ", "ABC");
System.out.println(person.getDescription());
}
}
Ques: We cannot create objects of abstract classes, then why Person Constructor has been invoked, even its an abstract class?
Because it's still a class and its constructor is invoked as a part of the object instantiation. The fact that it is abstract doesn't have anything to do with this.
Ques: We cannot create objects of
abstract classes, then why Person
Constructor has been invoked, even its
an abstract class?
If a class is declared abstract, no objects of that class can be created. That DOESNOT mean you cannot create objects of its subclasses.
You can have references(of type abstract class) refer to a subclass(non abstract) object.
Person person = new Student("XYZ",
"ABC");
And in order to construct a Student object, you need to have the "person" parts of the student initialized, thats what exactly the constructor of the abstract super class is called for.
What you can't do is to create an instance of an abstract class.
As a Student is 'partly' a Person super(...) initializes the 'Person part' of the student, it does not create a Person.
I hope you understand what I try to say
The constructor is just a method like others. And you are calling it explicitly from your child class' constructor with:
super(name);
The Person constructor is invoked from the Student class. From the Java tutorials
An abstract class is a class that is
declared abstract—it may or may not
include abstract methods. Abstract
classes cannot be instantiated, but
they can be subclassed.
An abstract class can have constructors - they cannot be invoked directly, but only as part of constructing a subclass instance, via a call to super() in the subclass constructor.
One cannot make an instance of an abstract class but subclasses can call super(name);. Even though it is a constructor, it is just another method.
The Abstract class is a part of your overall concrete class. An Abstract class is a class that is allowed to defer many parts to its concrete implementations but it must still initialize itself.
As such it has a constructor and as such the constructor with any parameters it requires to set itself up.
When you call the super(...) method from your Student class you are explicitly calling the constructor in the Person template class. The super() call must be in the first line of the Person constructor so if your person class wishes to override the defaults set up by the Person() constructor, then you have that option. But exactly one person constructor MUST be invoked when you extend a class (Abstract or concrete).