Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Weird contradictory behavior when casting classes in a interface

I encountered some weird behavior in a project I was working on and made this example:

class Main implements ClassGetter{
    public static void main(String[] args) {
        Main m = new Main();
        m.test();
    }

    public void test(){
        consumeClazz(this.getClass()); // error in editor
        consumeClazz((Class<? extends Clazz>) this.getClass()); // error in editor
        consumeClazz(getCastedClass()); // compiles and runs successfully
    }

    public void consumeClazz(Class<? extends Clazz> clazz){
        System.out.println(clazz.getSimpleName());
    }
}

interface ClassGetter{
    default Class<? extends Clazz> getCastedClass(){
        return (Class<? extends Clazz>) this.getClass(); // warning in editor
    }
}

class Clazz{}

The focus is the test() method in the Main class and the getCastedClass() method of the ClassGetter interface. The first two lines in the test() method give errors in the editor that explain how Class<capture of ? extends Main> cannot be converted to Class<? extends Clazz>. However, the last line in test() will compile and run successfully, printing out "Main". Interestingly, I get the warning Unchecked cast: 'Class<capture<? extends ClassGetter>>' to 'Class<? extends Clazz>' on the line in the getCastedClass() method, which made me expect the last example wouldn’t work at all like the first two.

Why does the last example work while the first two never compile?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

Why is this illegal in Main?

consumeClazz((Class<? extends Clazz>) this.getClass());

An instance of Main cannot possibly be an instance of Clazz because they are unrelated classes, and Java does not support multiple inheritance.


Why is this legal in ClassGetter?

return (Class<? extends Clazz>) this.getClass();

An instance of ClassGetter might be an instance of Clazz, if there is a subclass of Clazz that implements ClassGetter. Because it’s possible, this is legal but not safe.


Why is this legal in Main?

consumeClazz(getCastedClass())

getCastedClass() is declared to return Class<? extends Clazz>, which is compatible with the parameter type for consumeClazz.


Why does it run successfully?

At runtime, the generics are erased, and your Class<...> references are just Class objects. On that basis, getting the class and printing its name is all legitimate.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading