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】);


回答:

在我的认知中,实例方法是不能直接作为参数传递的。所以我很好奇 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方法。

以上是 java 泛型的方法引用相关问题? 的全部内容, 来源链接: utcz.com/p/944994.html

回到顶部