简体   繁体   中英

Java strange class cast exception

Could anyone help me understand why in 1 situation I do not have ClassCastException? At least String::trim is not a MagicFunction.

public class Main {

    @FunctionalInterface
    interface MagicFunction extends Function<String, String> {
    }

    public static void main(String[] args) throws IOException {
        // 1. OK
        final MagicFunction fun1 = String::trim;

        // 2. java.lang.ClassCastException
        Function<String, String> trim = String::trim;
        final MagicFunction fun2 = (MagicFunction) trim;
    }
}

So, method references (like String::trim ) are a bit weird; unlike most expressions in Java, they don't really have a type of their own. Something like this:

System.out.println((String::trim).getClass());

won't even compile, because it doesn't give the compiler enough information about what type String::trim should be.

Instead, the type of every method reference must be inferred from the surrounding context, eg by being the right-hand-side of an assignment statement (using the type of the variable on the left-hand-side) or by being passed directly to a method (using the type of the method parameter). The compiler then generates a class for you that implements the appropriate type using the method in question. Something like this:

final MagicFunction fun1 = String::trim;

is effectively equivalent to this:

final MagicFunction fun1 = new MagicFunction() {
    public String apply(final String s) {
        return s.trim();
    }
};

Note that this only works for specific types, called "functional interface" types. The detailed rules are a bit complicated, but the basic idea is that it has to be an interface type with exactly one abstract method. The method reference supplies the implementation of that method. (And of course, the signature of this method has to be compatible with the signature of the method reference; you can't use String::trim to implement Function<Integer, Integer> .)

"And of course, the signature of this method has to be compatible with the signature of the method reference; you can't use String::trim to implement Function<Integer, Integer>." - yes, you can. Here is an example

String g = "testString";
testMethod(String::trim, g);


public static <T, R> void testMethod(Function<T, R> func, T t) {
    func.apply(t);
}

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