1

Trying to pass only the parent class data from the extended class in a function.

public class ParentClass {
 String pageNo;
}

public class ExtendClass extends ParentClass {
 String lineNo;
}

In another class i'm trying to

dosomething(...){

 savePage((ParentClass)extendClass);
}

 savePage(ParentClass pclass){
.....
}

But when i look into the function savePage arguments i can still see lineNo which i don't want to see.

UPDATE

I have added debug pic of the issue i was facing. Even after downcasting to PageApi, i still see "elements" which exist in BoardPage class enter image description here

user1595858
  • 3,700
  • 15
  • 66
  • 109
  • 2
    I don't understand. Casting doesn't modify an object. – Sotirios Delimanolis Nov 20 '15 at 23:56
  • 1
    What is the method signature for savePage? – JRD Nov 20 '15 at 23:57
  • 1
    Let say if I'm trying to convert to String or JSON in savePage method, which still has "lineNo" which i want to avoid. – user1595858 Nov 20 '15 at 23:59
  • 3
    Please post a [MCVE](http://stackoverflow.com/help/mcve). I did some testing on my own and cannot reproduce your problem. For me, the attribute `lineNo` is not visible within `savePage(ParentClass)`. – Turing85 Nov 21 '15 at 00:07
  • You must distinguish between runtime and compile-/development-time. Of course, even if you upcast an object from `ChildClass` to `ParentClass`, the attributes defined in the `ChildClass` are still there (at runtime). But if you reference a `ChildClass`-object with an `ParentClass`-reference, you will not be able to access `ChildClass`es unique methods or attributes (at compile-/development-time). – Turing85 Nov 21 '15 at 00:28
  • Casting will NOT remove member variables from an object at runtime. The only clean way you could do this would be a copy constructor in ParentClass that accepts any of its extending classes, but only copies its own fields. This way you have to duplicate data, but all the additional infos from the children are lost. – JayC667 Nov 21 '15 at 00:57
  • @JayC667 can you show me an example? – user1595858 Nov 21 '15 at 01:13

2 Answers2

2

It seems to me that what you are trying to achieve is impossible.

If you create an instance of ExtendClass, then that instance always has a lineNo field.

When you explicitly cast or implicitly convert the type ExtendedClass to ParentClass, you don't change the actual instance in any way. At runtime, the instance has that lineNo field ... in all cases. Now the compiler won't let code within the body of the savePage method see or refer to that field (unless the code first casts the reference back to the type ExtendedClass), but the field will be there nonetheless.

You are examining the instances using a debugger. A debugger doesn't follow the rules able what fields should be visible. It sees everything, and it shows you everything. And, it clearly shows you the reality ... that the field is really there.

So ... is there a way to make the field go away entirely? Or hide it from the debugger?

Answers: No, and No.


(Warning: this is tangential to the original question, and probably beyond the OP's understanding.)

Should there be a way to make the field go away? From a language design perspective?

Answer: No.

Consider this code as a "thought experiment":

ExtendedClass ec = new ExtendedClass();
ec.lineNo = 42;
ParentClass pc = (ParentClass) ec;  // Actually the cast is redundant
ExtendedClass ec2 = (ExtendedClass) pc;
System.err.println("The old line no is " + ec.lineNo);
System.err.println("The new line no is " + ec2.lineNo);

If (hypothetically) casting from ExtendedClass to ParentClass actually removed a field, then when you cast back to ExtendedClass the field value would no longer be there. But what should ec2.lineNo actually contain? And how could it be different to ec.lineNo ... unless we had actually created a completely new object when we did the type cast(s)?

Thinking it through, if an explicit or implicit type cast created a new object, then you couldn't effectively do polymorphism. Polymorphism depends on being able to operate on a given object from the viewpoints of either its true type or one of its supertypes. If creating that view actually creates a new object ... it simply doesn't work ... unless Java was a pure functional language; i.e. no mutation.

In short, while it might possibly be an attractive idea for a small number of use-cases, this idea would fundamentally break Java as an OO language.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • FYI: In C++ a cast to a more general type actually can remove fields, and then casting back to the more specific type is undefined behavior. This is called [object slicing](http://stackoverflow.com/questions/274626/what-is-object-slicing), and really only matters if you pass objects by value (as opposed to passing references or pointers to them). Personally I think it's a horrible misfeature of C++. Languages with the notion of "reference types" like Java avoid this problem entirely. – Daniel Pryden Nov 21 '15 at 01:46
  • Agreed: passing objects by value is tantamount to creating new objects. – Stephen C Nov 21 '15 at 01:47
  • Right. In C++ it can also happen with a local cast to an object with automatic storage, since that's also "creating a new object" in C++. – Daniel Pryden Nov 21 '15 at 01:56
0

This is my example for the short answer I gave above


import java.lang.reflect.Field;

public class Parenting {

static public class ParentClass { String pageNo; public ParentClass() {} public ParentClass(final ParentClass pOriginal) { // copy CTOR pageNo = pOriginal.pageNo; } } static public class ExtendClass extends ParentClass { String lineNo; } public static void main(final String[] args) throws IllegalArgumentException, IllegalAccessException { final ParentClass pc = new ParentClass(); pc.pageNo = "page #7"; final ExtendClass ec = new ExtendClass(); ec.pageNo = "page#24"; ec.lineNo = "line #25"; analyze("Pure Parent", pc); analyze("Cast Parent", ec); analyze("Copy Parent", new ParentClass(ec)); } static private void analyze(final String pTitle, final ParentClass pAnalyzeObject) throws IllegalArgumentException, IllegalAccessException { System.out.println("Analyzing " + pTitle + ":"); Class<?> p = pAnalyzeObject.getClass(); while (p != Object.class) { for (final Field f : p.getDeclaredFields()) { System.out.println("\t" + p.getName() + "\t" + f.getName() + "\t\"" + f.get(pAnalyzeObject) + "\""); } p = p.getSuperclass(); } }

}

JayC667
  • 2,418
  • 2
  • 17
  • 31