0

Coming from Python and Objective-C land, I may not fully understand what static methods are in Java, I think of them as "methods that operate on all members of the class" or "class-specific methods that are available when you don't have an instance of that class."

But is there a syntax for saying: "This abstract superclass requires each concrete subclass to implement this static method"? I know that static abstract isn't permitted, but it would conceptually be something like this:

public abstract class Lander {

    @RequireImplmentationInSubclass     // clearly my made-up name...
    static abstract boolean probe(Radio radio);
}

public class MarsLander extends Lander {
    static boolean probe(Radio radio) {
        // ... some MarsLander specific implementation
    }
}

public class LunarLander extends Lander {
    static boolean probe(Radio radio) {
        // ... some LunarLander specific implementation
    }
}

update

... and somewhere else, a factory method does something like:

if (MarsLander.probe(radio)) {
    ... create an instance of MarsLander and work with it
} else if (LunarLander.probe(radio)) {
    ... create an instance of LunarLander and work with it
}

In my application, creating an instance invokes a lot of machinery, so I need to call probe() on a class method before I create an instance of the class.

I looked over Is there a way to make sure classes implementing an Interface implement static methods? and most of the responses were "why would you want to do that?".

I hope this example makes it clear(er). Perhaps there's' a more Java-esque way to remind the developer that a class-visible probe() method is required?

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
fearless_fool
  • 33,645
  • 23
  • 135
  • 217

5 Answers5

1

There is no way to require a static method.

But you can create a factory class with non-static methods:

public abstract class LanderFactory<L extends Lander> {
    public abstract L createLander();
    public abstract boolean probe(Radio radio);
}

You can even have a registry of LanderFactory implementations, so they effectively act as singletons:

public abstract class LanderFactory<L extends Lander> {
    private static final Map<Class<? extends Lander>,
                             LanderFactory<? extends Lander>> registry
        = Map.of(MarsLander.class, new MarsLanderFactory(),
                 LunarLander.class, new LunarLanderFactory());

    public static LanderFactory<? extends Lander> getInstance(
                                                Class<? extends Lander> type) {
        LanderFactory<? extends Lander> factory = registry.get(type);
        if (factory == null) {
            throw new IllegalArgumentException("No factory known for " + type);
        }
        return factory;
    }

    public abstract L createLander();

    public abstract boolean probe(Radio radio);
}

public class MarsLanderFactory extends LanderFactory<MarsLander> {
    @Override
    public MarsLander createLander() {
        return new MarsLander();
    }

    @Override
    public boolean probe(Radio radio) {
        // ...
    }
}

public class LunarLanderFactory extends LanderFactory<LunarLander> {
    @Override
    public LunarLander createLander() {
        return new LunarLander();
    }

    @Override
    public boolean probe(Radio radio) {
        // ...
    }
}
VGR
  • 40,506
  • 4
  • 48
  • 63
0

I tried your code(and other things surrounding this), and I'd like to tell you there's a way but I don't think there is.

I would instead recommend using a utility class that supports this static functionality you're looking for.For example, a LanderUtility class that has static methods in it might solve this in a reasonable way.

Mostly though, I don't think of using static methods in that way in Java. The real power in what is going on with this abstract class is that you can count on(somewhat) a certain type of behavior from a child. Notably, for this to matter, the child needs to be instantiated in the first place and you can use a normal, non-static method and have the child implement that instead.

Dharman
  • 30,962
  • 25
  • 85
  • 135
dskinner
  • 81
  • 3
0
"methods that operate on all members of the class"

This is not right. static methods operate on no members of a class. Use of this is prohibited in static contexts.

I feel your question itself has the answer you are looking for. static abstract doesnt exists because on one hand you want it to behave differently (based on if it is a LunarProbe or a MarsProbe) and on the other hand you want it to be independent of the instance of LunarProbe and MarsProbe. static abstract contradicts itself.

Besides

static boolean probe() {
     // ... some MarsLander specific implementation
     // what goes here? you dont have access to any instance of this class.
}

static abstract violates a tenet of OOP called polymorphism.

Boss Man
  • 587
  • 2
  • 12
  • "static methods operate on no members of a class" -- that's a more accurate way to say what I meant. So yes, I'm familiar with class methods vs instance methods. – fearless_fool Jul 29 '20 at 22:07
0

In Java, static methods is allowed to be invoked directly on class references. It does not matter whether it is a abstract class or a normal class.

Due to this reason, static and abstract modifiers can't be used together. Otherwise, what would be the output of this code if the lander method is not implemented ? That's why it is illegal.

Lander.probe();

But, I think we can throw an exception from our super class static method with some hint in the exception message. We can enforce implementation of the static method.

public abstract class Lander {
  static boolean probe() {
    throw new RuntimeException("Oh oh !!! Why am I here ??");
  }
}

public class MarsLander extends Lander {
  static boolean probe() {
    // ... some MarsLander specific implementation
  }
}

public class LunarLander extends Lander {
  static boolean probe() {
    // ... some LunarLander specific implementation'
  }
}

That way, if there is a Lander implementation which has not implemented a static probe method, the probe method will get inherited but this will throw a run time exception.

SKumar
  • 1,940
  • 1
  • 7
  • 12
  • `static` methods cannot be overridden, so this will not work. – VGR Jul 30 '20 at 12:20
  • @VGR I did not talked about overriding. I said that static methods will get inherited from Super class. That's perfectly legal. The OP is trying to call static methods on Class Reference and not on Object instance. Example, MarsLander.probe(radio), LunarLander.probe(radio). So, if the methods are not declared in sub class, I am saying the super class static method will be invoked. What will not work here ? – SKumar Jul 30 '20 at 13:05
  • The runtime checking you propose is what I'm accustomed to Python, but I'm not sure it's the most appropriate idiom in Java. – fearless_fool Jul 30 '20 at 14:58
  • Did you try to compile your code and run it? – bfrguci Oct 05 '21 at 14:46
  • @bfrguci yes the code works. All it needs is a return statement. – SKumar Oct 05 '21 at 16:57
0

Methods can't be both abstract and static, because abstract methods have to be overridden, and static methods in Java cannot be overridden. Which class implementation of a static method is used is determined at compile time. You can declare a static method with the same signature in a subclass, but it is not considered overriding because there won’t be any run-time polymorphism. The static method of the superclass is 'masked' in the subclass. If a derived class defines a static method with the same signature as a static method in the base class, the method in the derived class hides the method in the base class.

Martin Fall
  • 121
  • 7