有没有办法在静态类中使用非静态方法?

时间:2013-11-14 20:41:22

标签: java static-methods static-class static

我正在尝试使用Java实现一个简单的电子表格。它通过控制台上的某些菜单与用户交互,用户可以导入给定文件,其中包含有关要创建的电子表格的一些预先制作的信息(行,列和单元格内容)。 我正在尝试创建一个我称为Parser的静态类,这个类的目标是将导入的每一行分解成小块,然后我可以将正确的方法应用于它们(读取内容所在的单元格)添加了,我想添加什么类型的内容)。

我将Parser设置为静态,因为我想在不需要每次需要时实例化新对象的情况下使用它(这是正确的吗?)。我有一个特定的方法给我带来了麻烦。每当我收到这样的输入时:1;1|=2;3表示我的单元格1; 1引用单元格2; 3。我告诉解析器返回一个新的Reference(getCell(i,j))。这是因为我的Reference类构造函数接收了一个Cell,但当然java编译器告诉我,我不能在静态类中使用非静态方法,即getCell的情况。

所以我的问题是:有没有办法克服这个问题?在静态类中使用非静态方法的任何方法,还是在尝试读取导入文件时应该实例化一个新的Parser对象?

4 个答案:

答案 0 :(得分:2)

看一些代码来确定哪种方法更合适可能会有所帮助,但由于这是面向对象设计中常见的陷阱,我将尝试回答这个问题。

如果将某些内容定义为静态,则表示它与任何实例都没有关联,即使它共享类名。例如,

public class Table {
  List<Cell> cells;

  public Table() {
    while (someCondition)
      parseInput(nextInput);
  }

  public Cell getCell(int i, int j) {
    ...
  }

  public static Cell parseInput(String input) {
    Cell cellToReturn = new Cell();
    ...
    if (input.references(cell)) cell = getCell(i,j); //Error here!
    ...
    return cellToReturn;
  }
}

问题出现是因为parseInput方法是静态的,但它引用了特定实例的单元格列表!它引用了哪一个?谁知道!

您可以通过两种方式解决问题:

1:使解析器非静态:public Cell parseInput(String input) {

2:将表传递给解析器,因此它知道要引用的内容:

public static Cell parseInput(String input, Table target) {
  Cell cellToReturn = new Cell();
  ...
  if (input.references(cell)) cell = target.getCell(i,j); //No more error!
  ...
  return cellToReturn;
}

现在,正如您所说,解析器是一个类,而不仅仅是一个方法。但一般规则仍然适用。 您无法从静态方法引用实例字段,因为该静态方法与任何实例都没有关联!

答案 1 :(得分:1)

  

我将Parser设为静态,因为我想在不需要每次需要时实例化一个新对象时使用它(这是正确的吗?)。

也许,但不是因为你陈述的原因。你为什么不想创建你的类的实例?如果那是使其成为静态的原因,那么它不是一个非常相关的原因。实际上,像Singleton Pattern这样的东西基本上可以实现相同的目的,确保您不必保持创建实例,因为总有一个实例可以使用。

如果你的对象正是......一个对象,那么它应该被建模为一个实例。我通常倾向于认为对象本质上是非静态的,而关于对象的概念本质上更加静态。

让我们暂时使用汽车的OO示例。如果我想知道汽车的价格,那就是特定汽车的财产。我必须指定一个Accord的实例,以便查询该属性。另一方面,如果我想知道特定模型的平均价格,那更多的是静态概念。我不是在谈论Accord的任何特定实例,只是Accord一般。因此getPrice()之类的内容会Car上的实例方法,getAveragePrice()之类的内容可能不会。

  

当我尝试读取导入文件时,是否应该实例化一个新的Parser对象?

这是件坏事吗?


现在,对于手头的问题,具体是哪个引用编译器抱怨?我想我无法想象它,你能提供一个简化的代码示例,以便我可以看到这些静态和非静态类/成员之间的关系吗?基本上你可以从静态位置引用实例成员,你只需要引用一个实例来实现它。以上是我上面提到的例子,我不能这样做:

class Car {
    int getPrice() {
        return 20000;
    }

    static int getAveragePrice() {
        return Car.getPrice();
    }
}

但是我能做到这一点(尽管在这个过于人为的例子中可能是不明智的):

class Car {
    int getPrice() {
        return 20000;
    }

    static int getAveragePrice() {
        var someRandomCar = new Car();
        return someRandomCar.getPrice();
    }
}

答案 2 :(得分:0)

如果你的静态方法需要访问非静态方法(没有实例化任何东西或直接访问实例),那么必须定义为非静态方法。

答案 3 :(得分:0)

private static Parser INSTANCE = new Parser();

public static Parser getInstance() {
   return INSTANCE;
}
...

public void nonStaticMethod() {
    Parser parser = Parser.getInstance();
    parser.whateverParserMethodYouWant();
}

编辑以使其更清晰:

class Parser {
    private Parser() {}
    private static Parser INSTANCE = new Parser();

    public static Parser getInstance() {
       return INSTANCE;
    }
}
...
class ParserClient {
...    
    public void nonStaticMethod() {
        Parser parser = Parser.getInstance();
        parser.whateverParserMethodYouWant();
    }
}