Edit # 1 add at the bottom of the question.
I got the ClassCastException in an Android project, but the problem seemed to be in the domain of Java, so I wrote the following SSCCE. In this SSCCE, I get the following exception on PVC parentViewHolder = (PVC) holder;
:
Exception in thread "main" Overridden onBindViewHolder in my ExpandableRecyclerAdapter called.
java.lang.ClassCastException: practice_programs.inheritance.class_cast_to_super.RecyclerView$ViewHolder cannot be cast to practice_programs.inheritance.class_cast_to_super.ParentViewHolder
at practice_programs.inheritance.class_cast_to_super.ExpandableRecyclerAdapter.onBindViewHolder(ExpandableRecyclerAdapter.java:9)
at practice_programs.inheritance.class_cast_to_super.ExpandableRecyclerAdapter.main(ExpandableRecyclerAdapter.java:15)
As you can see in the code given, we are trying to cast a RecyclerView.ViewHolder
to ParentViewHolder
(which is actually a subclass of RecyclerView.ViewHolder
)
Although I do understand that Superclass can not be cast to subclass, but my confusion is the following:
The Android project that I am working on actually uses this ExpandableRecyclerView implementation as a library project. In this project, the same thing happening does not cast any problems. That is see Line # 146 on in this class in which RecyclerView.ViewHolder
is being cast to ParentViewHolder
which, you can see on Line#19 here, extends RecyclerView.ViewHolder
.
SSCCE:
public class ExpandableRecyclerAdapter<PVC extends ParentViewHolder> extends RecyclerView.Adapter{
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
System.out.println("Overridden onBindViewHolder in my ExpandableRecyclerAdapter called.");
PVC parentViewHolder = (PVC) holder;//EXCEPTION***************************************
super.onBindViewHolder(parentViewHolder, position);
}
public static void main (String [] args) {
new ExpandableRecyclerAdapter().onBindViewHolder(new RecyclerView.ViewHolder(), 1);
}
}
ParentViewHolder.java
public class ParentViewHolder extends RecyclerView.ViewHolder {
String string = "XAR!";
}
RecyclerView.java
public class RecyclerView {
public static class ViewHolder {}
public static class Adapter {
public void onBindViewHolder(ViewHolder viewHolder, int position) {
System.out.println("onBindViewHolder of RecyclerView.ViewHolder called.");
System.out.println("The string of the passed viewHolder is " + ((ParentViewHolder) viewHolder).string);
}
}
}
_____________________________________________________________________________
EDIT 1:
Another piece of information that may be important is that according to my needs, I made a tiny change to ExpandableRecyclerAdapter:
Line # 119 and Line # 123 are method calls in the method body of onCreateViewHolder
method which receives an argument int viewType
. I added this viewType
argument to the calls to onCreateParentViewHolder
and onCreateChildViewHolder
on Line#119 and Line#123.
In accordance with ^, I add the int viewType
arguments to the corresponding method declarations on Line#187 and Line#195
I think you have a wrong mental picture of what "casting" is - you seem to imagine that casting changes class of an object. This never happens!
Casting only allows us to reveal the true type of an object that is referenced by a variable of superclass type. This is sometimes necessary, because in Java both references and objects have types, and they do not have to exactly match.
In this example mySuperRef
is a reference of type MySuper
, but it really points to an object of type MySub
. That's why we can cast it to reveal the true type:
MySuper mySuperRef = new MySub();
MySub mySubRef = (MySub)mySuperRef;
In this example, the same cast will give as an error, because the "true type" of an object referenced by mySuperRef
is different:
MySuper mySuperRef = new MySuper();
MySub mySubRef = (MySub)mySuperRef;
To wrap it up: in Java you can only cast an object to a type that the object already has. Casting does not allow us to modify objects in any way, it is only used to assign the object to it's proper reference variable.