简体   繁体   中英

In Java, how do I refer explicitly to a static member of the class of `this`?

In Java, how do I refer explicitly to a static member of the class of this ?

I want to refer explicitly to the static member for readability, but to not use a literal class name to respect subclasses overriding the value.

A contrived example:

class Flying {
   static final String label = "A Flying Superhero";
   String exclamation() {
      return "Look! Up in the sky! It’s a bird! It’s a plane! It’s "+(WHAT GOES HERE?)+"!";
   }
}

class Superman extends Flying {
   static final String label = "Superman";
}
class Howard extends Flying {
   static final String label = "Howard the Duck";
}

Note that I want to avoid using label alone, because its meaning could be ambiguous; I want a reader to know immediately that it's a static member, as they would from Flying.label , but without naming the base class.

(In the case that inspired the question, the static member is also final, but I don't think that affects how you refer to it.)


EDIT : Here's a possibly more compelling case. I want to implement main in the superclass, and have it create and use an instance of the subclass that was invoked.

class Super
   public static void main( String[] args ) {
      Super instance = new (?WHAT GOES HERE?)( /*...*/ );
      instance.use();
   }
}

class Sub extends Super {
   void use() {
      /* ... */
   }
}

When the jvm is started on Sub , I want it to use the same implementation of main, but use an instance of the subclass.

This case is different in that the context is static, and the static member to access is a constructor.

(This is coming up for a homework assignment in a graduate course in modeling & simulation; the superclass is a model, and different scenarios are implemented as subclasses.)

To clairify the question , I think three things are needed:

  • Within an invocation of a static method, get the Class on which the method was invoked (I haven't found anything on this)
  • Given a Class, access a static member of that class (possibly with aClass.getDeclaredField ?)
  • Given a Class, construct a new instance of that class (possibly with aClass.getConstructors ?)

Conclusion

I hadn't realized I was trying to do something so contrary to the Java way until reading the answers. Apparently I've gotten used to more dynamic languages. (It seems wrong to feel like I've been spoiled by JavaScript.)

This architecture was largely motivated by the GUI provided by the framework I'm using, which gives you a class picker and then a UI to interact with an instance of the class you pick. This makes the convenient way to work with different scenarios to have a class for each scenario.

For the original case restricted to accessing static members, for the time being it's good enough to use literal class names.

For the edited case involving instantiation, I'm leaving the instantiation in subclasses and passing instances to a method of the superclass, like this:

class Model {
   public static void run( Model m ) {
      /* ... */
   }
}

class Scenario extends Model {
   public static void main( String[] args ) {
      Model.run( new Scenario( /*...*/ ) );
   }
}

In the future, I'll try to avoid following the lead of some library into territory that conflicts with language features.

You can't override variables, instead, you'll need to provide a method instead, for example...

class Flying {

    private final String label = "A Flying Superhero";

    String exclamation() {
        return "Look! Up in the sky! It’s a bird! It’s a plane! It’s " + getLabel() + "!";
    }

    public String getLabel() {
        return label;
    }
}

class Superman extends Flying {

    private final String label = "Superman";
    @Override
    public String getLabel() {
        return label;
    }

}

class Howard extends Flying {

    private final String label = "Howard the Duck";
    @Override
    public String getLabel() {
        return label;
    }
}

Subclasses do not inherit static members. In your new example, main can be referred to by Sub like Sub.main(args); but it always belongs to Super . You may even check the stack trace which will confirm it is invoked on Super .

  • Within an invocation of a static method, get the Class on which the method was invoked (I haven't found anything on this)

This can't be done.

  • Given a Class, access a static member of that class (possibly with aClass.getDeclaredField ?)

This can be done but it's a totally cumbersome way to approach a problem that's extremely simple if you just use regular inheritance.

  • Given a Class, construct a new instance of that class (possibly with aClass.getConstructors ?)

This can be done and is useful from time to time. It is less useful now with Java 8 Supplier, for example SomeClass::new .

Static is the wrong way to approach this kind of problem in Java. Regular inheritance lets you do these things trivially.

class InterfacesExample {
    public static void main(String[] args) {
        @SuppressWarnings("unchecked") // Arrays#asList
        List<Class<? extends Printer>> classes = Arrays.asList(
            FruitPrinter.class,
            TreePrinter.class
        );

        for(Class<? extends Printer> cls : classes) {
            try {
                Constructor<? extends Printer> ctor = cls.getDeclaredConstructor();
                Printer p = ctor.newInstance();
                p.print();
            } catch(Exception e) {
                System.err.println(e);
            }
        }
    }
}

interface Printer {
    void print();
}

class FruitPrinter implements Printer {
    @Override
    public void print() {
        System.out.println("Apple, Banana, Plum, Pear");
    }
}

class TreePrinter implements Printer {
    @Override
    public void print() {
        System.out.println("Oak, Maple, Elm, Willow");
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM