2011-06-28 32 views
2

我有一个包含类名称的字符串数组。是否可以使用字符串数组中的'类的名称'来调用实际类的静态方法。有没有办法使用具有类名称的字符串来调用类的静态方法?

public class SortCompare { 

    // There are classes called 'Insertion', 'Selection' and 'Shell' which have a 
    // method called 'sort' 
    private static String[] algorithm = { "Insertion", "Selection", "Shell"}; 

    public static double timeTheRun(String alg, Comparable[] a) { 

     for (int i = 0; i < algorithm.length; i++) 
      if (alg.equalsIgnoreCase(algorithm[i])) { 
       Stopwatch timer = new Stopwatch(); 

       // I want to invoke one of Insertion.sort(), Selection.sort() 
       // or Shell.sort() depending on the value of 'alg' here 

       break; 
      } 
       return timer.elapsedTime(); 
     } 

我可以忘记字符串数组,并简单地使用if-else块来调用它们。

  if (alg.equals("Insertion")) 
      Insertion.sort(a); 
     else if (alg.equals("Selection")) 
      Selection.sort(a); 
     else if (alg.equals("Shell")) 
      Shell.sort(a); 

但我会继续实施其他类型和未来的每一次他们的变化,我将不得不在多个地方(以上的if-else循环,我的程序的帮助信息)的变化。如果前一种方法是可行的,那么我只需要每次向数组插入一个额外的字符串。

+2

使用[的Class.forName](http://download.oracle.com/javase/1,5.0/docs/api/java/lang/Class.html#forName(java.lang.String中)) –

+0

[如何在函数参数中传递类名](http:// stackoverflow。com/questions/6490810/how-to-pass-class-name-in-function-arguments) – flolo

回答

6

来实现,这将是创建一个通用的接口为您的排序算法更好的方法:

interface SortingAlgorithm { 
    public void sort(Comparable[] a); 
}; 

然后把所有的算法实现该接口:

class InsertionSort implements SortingAlgorithm { 
    public void sort(Comparable[] a) { 
     // sort here using insertion-sort 
    } 
}; 

,使参数你的方法需要实现接口:

public static double timeTheRun(SortingAlgorithm alg, Comparable[] a) { 
    // all the setup 
    alg.sort(a); 
    // all the post-processing 
} 

你然后会调用这样的方法:

timeTheRun(new InsertionSort(), data); 

这有一个缺点,即不能使排序例程成为静态方法。

替代如果你坚持静态方法,使您的日常需要一个类对象作为参数:

public static double timeTheRun(Class algClass, Comparable[] a) { 
    // all the setup 
    algClass.getMethod("sort", Comparable[].class).invoke(null, a); 
    // all the post-processing 
}  

注意,你将不得不增加一个try-catch块或抛出声明针对反射方法可能抛出的各种异常。那么你可以这样称呼它:

timeTheRun(InsertSort.class, data); 
+1

我不同意最后看到的缺点 - 从概念上讲,仍然存在一种静态方法访问,因为你称之为构造函数(一种特殊类型的静态方法),然后通过'.sort(x)'来实现。对于任何需要静态性的情况,这仍然提供了静态可访问性 - 例如,你没有*有*预先配置了'SortingAlgorithm'的实例。但这也意味着如果你愿意,你可以做*(这是问题的基本愿望,提问者是否意识到)。 –

+0

@Andrzej:我添加了另一个使用反射和静态方法的提议,但比OPs方法(IMHO)更优雅。 –

+1

如果由于某种原因严格需要静态方法(例如,来自IoC容器的有限接线等),那么这是一个很好的选择。可惜的是,静态方法不能在接口中引用,因为你真正想要的第一个参数是一个'Class <?扩展SortingAlgorithm>',以便在运行时获得编译时安全性,而不是'NoSuchMethodException'。勒叹。 –

4

是的,这是可以通过反射。

Method method = Class.forName(alg).getMethod("sort", Comparable[].class); 
method.invoke(null, a); 

但是,使用反射并不是一个很干净的方法。你应该考虑改变你的代码,让你的排序算法实现一个包含这种排序方法的接口。这样你可以直接调用sort方法。

+0

'getMethod'的第二个参数应该是'Comparable [] .class'。 –

+0

@ Space_C0wb0y的确,错过了。编辑答案。 – wjans

0

是的,你需要的是​​。

在排序算法之间建立共享的接口。然后创建一个工厂对象,根据输入返回正确的算法。无论你喜欢什么,你都可以输入enum,string,.class

public interface Sort { 
    void sort(Comparable[] a) 
} 

public class SortFactory { 
    public static sort getSorter(SortType type) { 
     if (type == SortType.INSERTION) 
      return new InsertionSort(); 
     if (type == SortType.SELECTION) 
      return new SelectionSort(); 
     if (type == SortType.SHELL) 
      return new ShellSort(); 
    } 
} 


public enum SortType { 
    INSERTION, 
    SELECTION, 
    SHELL 
} 
相关问题