3

I was looking at this answer, and I don't understand the logic behind why methods would be polymorphic but not fields.

All member functions are polymorphic in Java by default. That means when you call this.toString() Java uses dynamic binding to resolve the call, calling the child version. When you access the member x, you access the member of your current scope (the father) because members are not polymorphic.

When you have some field x in both the super and subclass, and override toString in your subclass, when you call the following in the base class:

System.out.println(this); //calls the subclass's toString implementation
System.out.println(this.x) //prints the base class's x field

The justification for this in the answers listed in the question linked at the beginning is that the base class doesn't "know" about the subclass when it is in its own scope, but with polymorphism, it's the same thing: the superclass doesn't know the subclass exists, yet the subclass method is still called. So what exactly is Java doing that makes the two act differently - one using dynamic binding in the subclass and one keeping the scope of the superclass?

Edit: to clarify, I'm stuck on why this.x will do the same thing as polymorphism, look at the actual type of the object, not just the reference type, and print the x field from the subclass.

Community
  • 1
  • 1
rb612
  • 5,280
  • 3
  • 30
  • 68
  • 1
    By "class members" do you mean "fields"? If so, it would be clearer to say so. Methods are "members" as well... – Jon Skeet Apr 14 '17 at 07:29
  • @JonSkeet, yes thank you. I fixed. – rb612 Apr 14 '17 at 07:30
  • But as the accessors are polymorphic, if you use a getter, you can achieve the behavior you wanted. – Jeremy Grand Apr 14 '17 at 07:31
  • @JeremyGrand this is so strange to me though! Why is this happening? It seems to me the more intuitive approach would be that `this.x` will do the same thing as polymorphism, look at the actual type of the object, not just the reference type, and print the field `x`. – rb612 Apr 14 '17 at 07:32
  • 2
    Fundamentally, each time you declare a new field, you're adding more state. If you override a method, you're not adding a new method, you're replacing the *implementation* of an existing signature. Any time you *want* to use "polymorphism" for fields, there's probably a better design you could use... – Jon Skeet Apr 14 '17 at 07:33
  • 1
    @rb612 I think (but I might be very wrong), that's because x is stored at instance level whereas methods are stored at class level. And a superInstance just doesn't exist. You can call the super class from the child class, but storing a super.x inside your child class Instance is weird. – Jeremy Grand Apr 14 '17 at 07:35
  • 2
    @JonSkeet thank you for your answer, such an honor to get an explanation from you! Now the explanation given in answers to the initial question, that the parent class doesn't "know" about the subclass, doesn't make sense to me. isn't it that when you have `this.x`, Java should immediately see the keyword `this` and realizes that it's actually a child instance, and calls the appropriate method, just like polymorphism? Or is there some different process going on when calling a method on `this` vs. accessing a field? – rb612 Apr 14 '17 at 07:38
  • @rb612: Um, no. `this` just means "the current object", and it's rarely used when you don't need to explicitly differentiate between the use of a parameter and the use of a field with the same name. There's no difference between `foo()` and `this.foo()` for example. I suggest you focus on thinking about what problems you expect would be solved by allowing this... – Jon Skeet Apr 14 '17 at 08:24
  • @JonSkeet I definitely see what you're saying. I think I misphrased what I meant. I guess I don't quite understand why, with a method call, Java looks to see which method (subclass or superclass) should be called, but when accessing a field, Java doesn't utilize dynamic binding (I think that's the term) to resolve which field should be used – rb612 Apr 15 '17 at 01:32
  • And the answer is, "because that wouldn't be useful" as I said before. Again, try to think of a use case where you actually want that behaviour rather than a different design to accomplish the same goal. – Jon Skeet Apr 15 '17 at 06:44

1 Answers1

2

To achieve subtype polymorphism Java needs to keep track of which method to call, it requires additional overhead. You could achieve kind of "polymorphic fields" by keeping fields private and using getters (the former is not required, but sensible to do). You may be interested in checking out

  • invokedynamic
  • invokeinterface
  • invokespecial
  • invokestatic
  • invokevirtual

calls. You may read more about it here: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.invokevirtual

  • Thank you! I'm more curious why methods are polymorphic and not fields. – rb612 Apr 15 '17 at 06:05
  • 1
    I think I should underline *requires additional overhead* :). Let's start by inverting your question: why accessing fields should require polymorphic mechanism? For methods, it could be justified by claiming that subtype polymorphism is one of the basic mechanisms of functionality extension in OOP world. So let's add the functionality of invokevirtual (different from default one: just accessing current object's method) for non-private methods and accept an overhead while calling such methods. Should we accept such overhead for EVERY field resolving, while one could setters/getters when needed? –  Apr 17 '17 at 07:50