2

Here I just create two simple class Dad and Son, Son is a subclass of Dad.

public class Dad {
 }

public class Son extends Dad {
}

Then I create a Function in other class to test

public class Test {
    public static void main(String[] args) {
        Function<? extends Dad, String> fun = son -> son.toString();
        fun.apply(new Son());
}

But I came across a compiler error on fun.apply(new Son()), it says 'apply (captrue in Funtion cannot be appiled to (Son))'. I am confused, the fun need a param of class which extends Dad, I give the subclass but is not right at all.

What's more! I try new Dad() as the param for the fun, but also got the error message 'apply (captrue in Funtion cannot be appiled to (Dad))'

Finally, I don't know which param can be used when the Function with generic version.

Help~~~ Thanks! (⊙o⊙)

7
  • Could you explain what you are trying to do? If you know that the argument to your function extends Dad then why can't you just use Function<Dad,String> instead of Function<? extends Dad, String>? Commented Apr 12, 2016 at 2:30
  • Ok, at first I have a enum which element's name are SON1 and SON2, and here are tow classes Son1 and Son2, both of them extend Dad. Now from the outside I got the enum's name as param, like SON1 or SON2, I want to query the Son1 or Son2 from database by the enum's name, and return the attribute name of Son1 or nickName of Son2, both attribute is String, But I don't want to use the if block to judge the current enum, I only want to get the enum by name and query the database by enum, and get the attribute I want from the enum Commented Apr 12, 2016 at 3:19
  • So I create a attribute Function<? extends Dad, String> in enum, SON1(Son1 son1 -> son1.getName()). SON2(Son2 son2 -> son2.getNickName()). But when I apply it, I got the compiler error just like I show. Could you please help me? or I could only use the if block : ( Commented Apr 12, 2016 at 3:19
  • Could you add the code with the enum? I'm not sure I'm picturing how your classes are structured from your description. Commented Apr 12, 2016 at 3:52
  • Yes, thanks for your patience, the enum code is just like this below: public enum EnumTest { SON1((Son1 son1) -> son1.getName()), SON2((Son2 son2) -> son2.getNickName()); private Function<? extends Dad, String> fun; EnumTest(Function<? extends Dad, String> fun) { this.fun = fun; } public Function<? extends Dad, String> getFun() { return fun; } } Commented Apr 12, 2016 at 6:04

1 Answer 1

2

Consider the following:

class Daughter extends Dad {}

Function<Daughter, String> funcForDaughter = ...;
Function<? extends Dad, String> fun = funcForDaughter;  // ok

fun.apply(new Son()); 

If compiler let you do this, you could be passing a Son to a method that only accepts Daughter. The same reason also prohibits you from calling fun.apply(new Dad()).

Function<? extends Dad, String> fun doesn't mean that fun works on any subtype of Dad. It means that fun works on some specific subtype of Dad that's not known at this point.

By declaring fun this way, you make it unsafe to call fun.apply on anything but null and so the compiler won't let you do it.

Sign up to request clarification or add additional context in comments.

6 Comments

Thanks : ), as what you said, I can't declaring the Function like this way Function<? extends Dad, String> fun, maybe I should think about other way for my code.
@Tony: you are trying to solve a problem which doesn’t exist, complicating matters with Generics. Just use Function<Dad, String>. A function which can accept instances of Dad is already capable of accepting instance of subclasses, including Son, if Son is a subclass of Dad (quite a weird thing). It’s not Generics but basic OOP that you can always pass an instance of a subclass of the required type.
@Holger: Thanks for your reply, it's true when I use Function<Dad, String> fun, it can accept the subclass of Dad as param, but I can't initialize the function with subclass, why I want to use the generics version because there are two subclass of Dad, Son1 and Son2, when come a instance of Son1, I want to get the value attribute 'name' of Son1, like Son1::getName, when come a instance of Son2, I want to get the value attribute 'nickName' of Son2, like Son2::getNickName, (refer to my next reply)
@Holger: So I define a function like Function<? extends Dad, String>, one initialization pattern is (Son1 son1)->son1.getName(), another pattern is (Son2 son2)->son2.getNickName(), when I got a instance, maybe is Son1's or Son2's, applying the funtion and got the compiler error...
A declaration like Function<? extends Dad, String> x = (Son1 son1) -> son1.getName() makes no sense. The function (Son1 son1) -> son1.getName() requires the input to be Son1, so declare it as Function<Son1, String> . In your question you wrote Function<? extends Dad, String> fun = son -> son.toString(); which happens to work because son gets the inferred type Dad which has a toString() method, so you could also write Function<Dad, String> fun = son -> son.toString();. Adding ? extends to an input type of a function just makes the function unusable.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.