问题
Java8 lets me use a method declaration as implementation of any of my interfaces, as long as it only contains one method.
However once it is defined, the type cannot be changed.
My code:
import java.util.function.IntConsumer;
public class A {
interface MyConsumer {
void doSomething(int i);
}
public static void main(String[] args) {
IntConsumer i = A::consume;
MyConsumer i2 = A::consume;
IntConsumer i3 = (IntConsumer) i2; // ClassCastException
MyConsumer i4 = (MyConsumer) i; // ClassCastException
IntConsumer i5 = i2; // does not compile
MyConsumer i6 = i; // does not compile
IntConsumer i7 = i2::doSomething; // workaround, as suggested by @Eran http://stackoverflow.com/a/35846001/476791
MyConsumer i8 = i::accept;
Object i9 = A::consume; // does not compile
Object i10 = (IntConsumer) A::consume; // works
Object i11 = (MyConsumer) A::consume; // works
Object i12 = (MyConsumer) (IntConsumer) A::consume; // does not work
}
static void consume(int i) {
System.out.println(i);
}
}
Note: if you inline some of the variables, then some of the non-working examples suddenly start to work.
My thoughts in detail:
- if
IntConsumer i = A::consumeis valid, thenA::consumehas toimplement IntConsumer - if
MyConsumer i2 = A::consumeis valid, thenA::consumehas toimplement MyConsumer - if
A::consumeimplements both,IntConsumerandMyConsumer, then casting should be possible
Is there another way to "cast" or "change" the type of the consumer afterwards?
回答1:
A::consume has no inherent type. When it appears in a context in which it is being used or assigned to a functional interface type, the compiler will create an object of that type implemented using A::consume.
Once you have that, you have an object of that specific functional interface type. It's not a method; it's a perfectly normal object. Java objects can't pretend to be other types their real type doesn't implement or extend.
So once you have an IntConsumer, you can't cast it to a MyConsumer. You can use it to get a method reference that can then become a new MyConsumer, but that one object will always be just an IntConsumer, nothing more.
回答2:
Is there another way to "cast" or "change" the type of the consumer afterwards?
You can't change the actual type of an object(1). You can cast a primitive, and you can cast a reference to another type suitable for the object referenced.
What you can do is wrap the instance with the type you want.
MyConsumer mc = ((IntConsumer) A::consume)::accept;
(1) you can hack the class pointer in the object header, but this is highly unlikely to be a good idea.
来源:https://stackoverflow.com/questions/35866449/how-to-change-the-type-of-a-function-reference