java 泛型的方法引用相关问题?

各位大神早上好,请看我的问题:

@Data
public class Car{
    private String id;
    private int status;
}

@Data
public class RedCar  extends Car{

}

@Data
public class YellowCar  extends Car{

}

RedCar、YellowCar 是 Car 的子类,正常情况下可以使用如下方法引用:
queryWrapper.lambda().eq(RedCar::getId,1)


下面我创建了一个BaseCarController ,RedCarController、YellowCarController 都继承于它

public class BaseCarController<T extends Car> {
    @Autowired
    CommonService cs;

    public void test(int id) {
        cs.toggle(id, T::getStatus);
    }
}

public class RedCarController extends BaseCarController<RedCar> {

}

public class YellowCarController extends BaseCarController<YellowCar> {

}

原本以为:

调用 RedCarController 的 test 方法,应该执行的是
cs.toggle(id, RedCar::getStatus);

调用 YellowCarController 的 test 方法,应该执行的是
cs.toggle(id, YellowCar::getStatus);

但是发现 BaseCarController.class 文件中 T::getStatus 变成了Car::getStatus 导致 cs.toggle 方法中 mybatis-plus 没有成功更新对应的表。

请问这种情况怎么解决呢,怎么实现我上面的预期效果呢?


另外,如果我只有一个 redCar 对象
RedCar redCar = new RedCar();
有没有什么方法,可以通过 redCar 这个对象达到 RedCar::getStatus 这个效果呢,类似如下:
cs.toggle(id, 【通过redCar获取RedCar::getStatus】);

阅读 1.6k
2 个回答

在我的认知中,实例方法是不能直接作为参数传递的。所以我很好奇 CommonService.toggle 是怎么定义的。假如我的认识无误,那说明 getStatus 是个静态方法。静态方法没有继承关系,在定义 BaseCarController 的时候,就已经决定了它是哪个类的静态方法。另外,从 Java 泛型具有类型擦除特性来说,T 的信息也是不会被保留使用的

测试代码:

public class Controller<T extends Car> {
    public void test() {
        invoke(T::getStatus);
    }

    private void invoke(Supplier<String> supplier) {
        System.out.println(supplier.get());
    }
}

class RedController extends Controller<RedCar> { }
class YellowController extends Controller<YellowCar> { }

生成 .class 之后再反编译出来是这样的

public class Controller<T extends Car> {
    public Controller() {
    }

    public void test() {
        this.invoke(Car::getStatus);
    }

    private void invoke(Supplier<String> supplier) {
        System.out.println((String)supplier.get());
    }
}

class RedController extends Controller<RedCar> {
    RedController() { }
}

class YellowController extends Controller<YellowCar> {
    YellowController() { }
}

可以看到,直接就是传入的 Car::getStatus,在基类定义的时候并不知道会有哪些子类,而子类中也没有重载 test() 定义,所以只能找到 Car::getStatus


如果改成实例 Lambda(需要实例对象)应该可以达到你的要求。示例代码:

public class Car {
    public String getStatus() { return "Car::status"; }
}

class RedCar extends Car {
    @Override
    public String getStatus() { return "RedCar::status"; }
}
public class Controller<T extends Car> {
    public void test(T car) {
        invoke(car::getStatus);  // 注意这里是实例 car 的方法,不是静态方法
    }

    private void invoke(Supplier<String> supplier) {
        System.out.println(supplier.get());
    }
}
    public static void main(String[] args) {
        RedCar car = new RedCar();
        new RedController().test(car);
    }
新手上路,请多包涵

根据题主的描述看,需求应该是根据实例对象redCar调用RedCar类的getStatus,那应该直接利用多态来实现比较好吧。测试代码如下:

public class Car {
    public void getStatus() {
        System.out.println("Car getStatus");
    }
}

public class RedCar extends Car {
    public void getStatus() {
        System.out.println("RedCar getStatus");
    }
}

public class YellowCar extends Car{
    public void getStatus() {
        System.out.println("YellowCar getStatus");
    }
}
public class BaseCarController {
    public void test(Car car) {
        car.getStatus();
    }
}

class RedCarController extends BaseCarController {
    public static void main(String[] args) {
        BaseCarController redCarController = new RedCarController();
        redCarController.test(new RedCar()); // output: RedCar getStatus
    }
}

class YellowCarController extends BaseCarController {
    public static void main(String[] args) {
        BaseCarController yellowCarController = new YellowCarController();
        yellowCarController.test(new YellowCar()); // output: YellowCar getStatus
    }
}

题主的代码中的“T::getStatus”认定了getStatus方法为静态方法,使用泛型会被擦除类型信息,直接编译为Car::getStatus。即使仍然使用静态方法定义getStatus,用Car的实例对象调用静态方法.getStatus(),也会在编译期直接转为Car.getStatus()。

所以我的理解是题主想要通过实例对象redCar调用的getStatus方法,只能是继承的实例方法,并用多态来实现调用对应各个类的getStatus方法。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题