5

I'm currently studying a book for the AP CS A exam, specifically the Barron's book for test preparation.

One section of the book refers to two classes, Student and GradStudent, where GradStudent extends Student.

GradStudent has the method getId() while Student does not.

If I were to run the following code:

Student s = new GradStudent()
s.getId()

The book informs me that I would get an error. Why is this? Since I am initializing it as a GradStudent, wouldn't s have access to the method getId()?

Essentially, if I declare a variable as the superclass, and initialize it to the subclass, what happens?

In other words, how do s and g in the following example differ:

Student s = new GradStudent()
GradStudent g = new GradStudent()

EDIT:

I've now understood that s only has access to the methods in the Student class. So what happens if I do the following:

Student s = (new GradStudent().setId(1) )

What happens to the id field? (Assuming it is only present in the GradStudent class) If I casted s to GradStudent again, would it be able to access the same id?

5
  • Yea but the java compiler don't know an method getId() in class Student. To use this method cast s to GradStudent again: GradStudent gs = (GradStudent) s; gs.getId() Commented Apr 19, 2018 at 17:42
  • "Since I am initializing it as a GradStudent, wouldn't s have access to the method getId()?" - No, it would not. You see it as a Student, therefore you can only see what a Student has. The terms you are looking for are most probably "static type" and "dynamic type". Commented Apr 19, 2018 at 17:42
  • @Logan If I initialized the GradStudent variable with some variables present only in the GradStudent class, what would happen if I casted it to a Student? Commented Apr 19, 2018 at 17:44
  • While it may be apparent to us as code readers your intention, the compiler makes no such distinction and only sees a Student s with its available methods. As an aside, imagine if you had Animal a and assigned it, at random, either Bird, Dog, or Cat. You would not be able to safely call a.fly() or a.bark() in this case, because you only know you have an Animal, and not what type it is, without inferring and casting to it. Commented Apr 19, 2018 at 17:45
  • What does setId return? With your latest update, I'm guessing that code would not even compile, unless setId returns this. Commented Apr 19, 2018 at 19:32

4 Answers 4

10

You get an error because s is declared to be type Student. It doesn't matter that it was instantiated as a new GradStudent(), the compiler only knows what type s was declared as. So basically you can only use s as if it were a Student (you can only use methods defined by the Student class).

If you really need to use .getId(), you have two options. You can declare s as a GradStudent:

GradStudent s = new GradStudent();
System.out.println(s.getId());

Or, you can cast s to GradStudent:

Student s = new GradStudent();
System.out.println(((GradStudent) s).getId());
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks! Please look at my edit, because I'm still not entirely sure what's going on.
The id field doesn't get "thrown away", it's still there in s (which is actually a GradStudent). The compiler just won't allow immediate access, because s looks like a Student. So yes, if you cast s to a GradStudent, you will be able to retrieve the id.
4

The variable

Student s

is declared as a Student, not a GradStudent. You assigned a GradStudent instance to the Student variable - this does not change the type of said variable.

You could do the following to address the compile time error :

Student s = new GradStudent()
((GradStudent)s).getId()

but this is considered a code smell.

Comments

3

I hope you have got your answer given by above folks. Just wanted to add some points.

Calling method s.getId() would end up giving you an error because s is a type of Student and at the compile time compiler checks if getId() method exists in Student and if it doesn't find it, will give you an error.

But s is pointing to an object of subtype which is GradStudent and it would be resolved at run time and compiler is unaware of it. So to satisfy compiler you have to downcast s like this

((GradStudent)s).getId()

Comments

2

Exactly because the GradStudent has the method getId() while Student does not.

Your GradStudent inherits the Student methods but Student class only has their OWN methods.

It will work if GradStudent implements a Student getId()

3 Comments

If Student has a getId(), will that be called? Or will the GradStudent implementation of getId() be called?
Yes, you will get the result of GradStudent getId() (that overrides the Student getId()) because of the Inheritance.
@populationzero In java ,methods always will be resolved based on the type of object , not type of the reference variables. Unlike C++ where methods resolved basis on the type of the reference variables or you have to make the method virtual. In case of java ,methods are by default virtual

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.