【问题标题】:Can i call a static java method when all i have is an object?当我只有一个对象时,我可以调用静态 java 方法吗?
【发布时间】:2016-06-20 00:41:41
【问题描述】:

我有一个类库,不是我写的,它定义了几个类和子类,它们有静态方法。一个非常精简的例子:

public class Vehicle {
    static String getName() { return "unknown"; }
}

public class Car extends Vehicle {
    static String getName() { return "car"; }
}

public class Train extends Vehicle {
    static String getName() { return "train"; }
}

现在,我有一个对象,它是车辆,可能是汽车或火车,并且想调用它的 getName() 函数。再次,非常精简:

public class SMCTest {
    public static void main(String[] args) {
        Vehicle vehicle=new Car();
        System.out.println(vehicle.getName());
    }
}

这会打印“unknown”,而不是“car”,因为 JVM 不需要或不使用对象来调用静态方法,它只使用类。

如果那是我的代码,我会重写车辆库以使用单例和非静态方法,但由于它不是我的代码,我宁愿不碰它。

有什么方法可以调用对象的“真实”类的静态方法,最好不使用反射?如果有帮助,我可以将上面示例中的 vehicle 更改为 Class <? extends Vehicle> 变量并使用它,但我看不出这如何帮助我避免反射。

【问题讨论】:

  • 是的,有。您可以简单地向下转换对象vehicle,因为您已经知道它的具体类:Car vehicle = new Car();。然后vehicle.getName() 将返回car。然而,这样做会导致警告,因为您不应该通过实例访问静态方法。
  • 您似乎希望静态方法以多态方式运行。这是不可能的。使用对象调用静态方法显示了一个应该解决的设计问题。静态方法应该是实例方法。
  • @aribeiro:在这个精简的示例中,我知道对象实际上是一辆汽车。在我想在现实世界中做的事情中,我得到了一个从其他地方传递过来的对象,我不知道它到底是什么。所以我不能只使用 Car 类。我想让示例尽可能简短/简单。
  • @JBNizet:我知道存在设计问题。但是由于“Vehicle”类库不是我的,我宁愿绕过它,也不愿花几周时间与该库的创建者争夺一个固定版本,或者花几天时间自己修复它并创建一个我不能的分支得到更新。
  • 是的,反思似乎是唯一的方法。 @Joe 给出了如何做的答案。

标签: java


【解决方案1】:

最好不使用反射?

放弃该要求,并且:

vehicle.getClass().getMethod("getName").invoke(null);

会按要求解决问题。

(但是,您应该修复代码。)

【讨论】:

    【解决方案2】:

    如果您了解所涉及的所有类,则无需反思。使用 java 8(为较低的 java 版本创建必要的接口和(匿名)类):

    public class VehicleUtil {
    
        private static final Map<Class<? extends Vehicle>, Supplier<String>> map = createMap();
    
        private static Map<Class<? extends Vehicle>, Supplier<String>> createMap() {
            Map<Class<? extends Vehicle>, Supplier<String>> result = new HashMap<>();
            result.put(Vehicle.class, Vehicle::getName);
            result.put(Car.class, Car::getName);
            result.put(Train.class, Train::getName);
            return result;
        }
    
        public static String getName(Vehicle vehicle) {
            return map.get(vehicle.getClass()).get();
        }
    
        public static void main(String[] args) {
            System.out.println(VehicleUtil.getName(new Vehicle()));
            System.out.println(VehicleUtil.getName(new Car()));
            System.out.println(VehicleUtil.getName(new Train()));
        }
    }
    

    以上只是一种更优雅的方式,例如:

    public static String getName(Vehicle vehicle) {
        return Vehicle.class.equals(vehicle.getClass()) ? Vehicle.getName()
                : Car.class.equals(vehicle.getClass()) ? Car.getName()
                : Train.class.equals(vehicle.getClass()) ? Train.getName()
                : null;
    }
    

    【讨论】:

    • 那还在用反射。
    • @chrylis 你是什么意思?
    • getClass() 是一个反射调用。
    • @chrylis 是Object 类中的一个方法。我没有在返回的 Class 实例上调用任何方法。
    • 所以?根据“反射”的一般含义和官方文档,它仍然是反射 API 的一部分。
    猜你喜欢
    • 2010-11-28
    • 2015-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-05
    • 2016-06-28
    相关资源
    最近更新 更多