简体   繁体   中英

How to properly use a parameter of type class?

In java, I'd like to do something like this

    public class Tata{ 

        public static void f(){
            //something
        }
        public static void g(){
            //something
        }
    }

    public class Titi{ 

        public static void f(){
            //something
        }
        public static void g(){
            //something
        }
    }

    public class Toto{

        private Class c = Tata.class; //or Titi.class 

        public static void main(String[] args) {
            c.f();
            c.g();
        }
    }

To be precise, I'd like to be able to freely switch between classes Tata and Titi , to use their respective methods f or g .

This doesn't work as intended, as I get the cannot resolve method 'f()' error. Simply replacing cf(); and cg(); with Tata.f(); and Tata.g(); works fine, but defeats the purpose of using a parameter. How to solve this?

Will turn the comment into answer after all.. The correct (Java) way to deal with what you want is the use of interface. So in your demo code the implementation would be the following:

public interface TheFGFunctions {
    void f();
    void g();
}
public class Tata implements TheFGFunctions {
    @Override
    public void f() {
        //something
    }
    @Override
    public void g() {
        //something
    }
}
public class Titi implements TheFGFunctions {
    @Override
    public void f() {
        //something
    }
    @Override
    public void g() {
        //something
    }
}
public class Toto {
    private TheFGFunctions c;
    public Toto(TheFGFunctions c) {
        this.c = c;
    }
    public void notStaticFunction() {
        c.f();
        c.g();
    }
}

This way is totally typesafe with zero exceptions to deal with!

You could use reflections:

private Class c = Tata.class;

public Toto() throws Exception {
    c.getMethod("f").invoke(null);
    c.getMethod("g").invoke(null);
}

Here my Tata class

public class Tata {
    public static void f() {
        System.out.println("ffff");
    }

    public static void g() {
        System.out.println("gggg");
    }
}

Output on new Toto() call:

ffff
gggg

Update (call with parameters):

public Toto() throws Exception {
    c.getMethod("f", String.class).invoke(null, "paramValue1");
    c.getMethod("g", String.class).invoke(null, "paramValue2");
}

public class Tata {
    public static void f(String param1) {
        System.out.println("ffff " + param1);
    }

    public static void g(String param2) {
        System.out.println("gggg " + param2);
    }
}

Output:

ffff paramValue1
gggg paramValue2

You cannot access a static method polymorphically. The Java language doesn't support it.

The reason your current approach fails is that c is an instance of the class Class , and the class Class doesn't define methods f() or g() .

(The methods that it does define are listed in the javadoc for Class . Note that Class is final so you can't create a custom subclass with extra methods.)


The simple alternative is to use reflection; eg

     Class c = 
     Method f = c.getMethod("f");
     f.invoke(null);   // because it is static

But note:

  • This is not statically type-safe. The compiler cannot tell when you make the mistake of trying to use a static f() on a class that doesn't have such a method.

  • There are a few exceptions that you need to deal with; eg missing methods, incorrect signatures, methods that are not static, methods that don't have the correct access.


Other answers have proposed creating an interface and wrapper classes to make certain static methods dispatchable. It will work and it will be compile-time type-safe (!) but there is a lot of boiler plate code to write.


@Michael Michailidis commented:

Thus interfaces!

Yea ... kind of. You can only dispatch polymorphically on instance methods declared on an interface. That implies that you must have an instance of Tata or Titi , and call the methods on it. My reading of the Question is that the author wants to avoid that.

(IMO, the avoidance is the real problem. You are better of not trying to avoid instance methods.)

FWIW, you can declare static methods in an interface (since Java 8), but they would behave the same as if you declared them in a class. You wouldn't be able to dispatch ...

Write a wrapper interface

interface CWrapper {
    void f();
    void g();
}

and wrapper class factory method for each Class containing the methods

class CWrappers {
    CWrapper forTiti(Class<Titi> titiClass) {
        return new CWrapper() {
            void f() { Titi.f(); }
            void g() { Titi.g(); }
        }
    }
    // another factory method for Tata
}

Then you can use that:

public class Toto {
    private CWrapper c = CWrappers.forTata(Tata.class); //or forTiti(Titi.class)

    public static void main(String[] args) {
        c.f();
        c.g();
    }
}

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