简体   繁体   中英

Java: Is casting to generic type in parent class safe when generic is <T extends Parent>?

I have a parent class for all of my custom exceptions, ParentException. I want all child exceptions to have a method that adds a message to the exception. To do this I created a generic method that returns an object of generic type after adding the message to it. I use this in the parent class method to add the message then return this but since the method returns the generic type I casted it to the generic type T. This seems to work, but gives a warning. My code is as follows:

public class ParentException extends RuntimeException{

    private String message;

    public ParentException() {
        message = "";
    }

    public void addToMessage(String msg) {
        message += msg;
    }

    public void printMessage() {
        System.out.println(message);
    }

    public <T extends ParentException> T withMessage(String msg) {
        this.addToMessage(msg);
        return (T) this; // This line gives the warning
    }
}

The warning given by that line is Unchecked cast from ParentException to T . The method does seem to work as expected, so I'm not worried but I'd like a better understanding of why this gives a warning in the first place.

Will this cast always be safe? Otherwise what case would cause a runtime error?

The following code will compile, but will fail at runtime:

class ChildException extends ParentException { }

ParentException p = new ParentException();
ChildException c = p.withMessage("Connection failed");

I realize it wouldn't make much sense to write that, but the point is that the compiler warning about an unsafe cast can prevent this landmine in the first place.

Consider this case:

class SubException extends ParentException {...}

ParentException ex = new ParentException();
SubException sub = ex.withMessage("blah");

The last line will throw a class cast exception, because ParentException can not be cast to SubException .


You could create a static helper method:

class ParentException extends RuntimeException{
    ...
    protected static <T extends ParentException> T withMessage(T instance, String msg) {
        instance.addToMessage(msg);
        return instance;
    }

    public ParentException withMessage(String msg) {
        return withMessage(this, msg);
    }
}

And use covariant return types to override this method:

class SubException extends ParentException {
    @Override
    public SubException withMessage(String msg) {
        return withMessage(this, msg);
    }   
}

Then, if you have a SubException variable, the call to withMessage will return a SubException too.

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