简体   繁体   中英

Casting analysis

I am a Java newbie and recently I got into some thinking on the following Android sample code:

TextView txt = (TextView) findViewById(R.id.activity_display_message);

TextView is a child of View class. And findViewById returns a View object.

I wanted to understand how and why we need to explicitly cast the returned View to TextView when the returned object MUST be actually a TextView , otherwise the casting will throw a cast exception.

So, this is my attempt to simulate what is going on behind the scenes with this mockup code:

class View{}
class TextView extends View{} 

public class A{

    // simple hard coded check of the ID
    public static View findViewById(int id){

        if (id == 1){
            return new View();
        }
        else{
            return new TextView();
            //return ((View)new TextView()); // This also works
        }

    }


    public static void main(String[] args){

        TextView txt =  (TextView)findViewById(2); // Works fine
        //TextView txt2 =  findViewById(2); INCOMPATIBLE TYPES ERROR because the returned type is View
        View v = findViewById(2); // Works fine

        View view = new View();
        //TextView test = (TextView) view; // cast error

        View view2 = new TextView();
        TextView test2 = (TextView) view2; // Works OK


    }
}

Conclusion:

It turns out that findViewById actually casts to View any returned element. I guess it is because the defined return value of the method is View and Java automatically casts the result to View .

Please tell me if I am getting it right.

As you describe in the question, findViewById(R.id.activity_display_message); returns a View Object, in this case, you the programmer know that this particular View is actually a TextView Object, but findViewById only promises to return a View , or an instance of any class that descends from View , as any class that descends from View is still a View , it just might have more specific details available.

All that findViewById is guaranteed to return is something that is or extends View . If you want to treat the returned object as though it is a specific subclass of View , you need to cast the object returned by findViewById to that subclass.

From your example, View view = new View(); // This is a View, it is NOT a TextView View textView = new TextView(); // TextView is a View, but it also has TextView stuff going on... //TextView test = (TextView) view; // cast error View view = new View(); // This is a View, it is NOT a TextView View textView = new TextView(); // TextView is a View, but it also has TextView stuff going on... //TextView test = (TextView) view; // cast error

Reason for exception in case 1 is bcz your View class is not aware of any subclass called TextView... where as in case 2 TextView is aware that it belongs to the family of View class.

upcast – Casting a subtype object into a supertype and this is called upcast. In Java, we need not add an explicit cast and you can assign the object directly. Compiler will understand and cast the value to supertype. By doing this, we are lifting an object to a generic level. If we prefer, we can add an explicit cast and no issues.

downcast – Casting a supertype to a subtype is called downcast. This is the mostly done cast. By doing this we are telling the compiler that the value stored in the base object is of a super type. Then we are asking the runtime to assign the value. Because of downcast we get access to methods of the subtype on that object.

ClassCastExcpetion – We get ClassCastException in a downcast. In principle, we guarantee the compiler that the instance value of is subtype and ask it to cast. But during runtime, because of unforeseen circumstances, the value is not of expected subtype. In such cases, we get ClassCastException.

Even though the method returns a View , since TextView is a subclass of View it can be safely returned by the method.

Take for example the following legal assignment:

View view = new TextView(); // Legal, no compiler errors. TextView is a subclass of View, so it can be safely 'downgraded'

And the following illegal assignment:

TextView textView = new View(); // Illegal, compatibility error

It's the exact same way with returning, the TextView is downgraded to a View . As for your question on whether or not you can figure out if it is a TextView that is being returned, you can make use of the instanceof operator.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM