0

I'm trying to implement a simple spreadsheet using Java. It interacts with the user through some menus on the console, and a user can import a given file with some pre-made info about the spreadsheet to be created (lines, columns, and content of cells). I am trying to make a static class which I called Parser, and the goal of this class is to break down each line of the import into little pieces so I can then apply the correct methods to them (read the cell to which content is being added, and what type of content am I trying to add).

I made my Parser static, because I want to use it without the need of instantiating a new object every time I need it (is this correct?). I have a specific method that is giving me trouble though. Whenever I receive input like this: 1;1|=2;3it means that my cell 1;1 references the cell 2;3. I am telling the parser to return a new Reference(getCell(i,j)). This is because my Reference class constructor receives a Cell, but of course the java compiler tells me I cannot use a non-static method, which is the case of the getCell, inside that static class.

So my question is: is there any way to overcome this problem? Any way to use a non-static method in a static class or should I instantiate a new Parser object when I try to read an import file?

Rita Pereira
  • 61
  • 2
  • 10

4 Answers4

2

It might be helpful to see some of your code to determine which method is more appropriate, but as this is a common pitfall in object oriented design, I'll try to answer the question generically.

If you define something as static, that means it has no association with any instances, even though it shares the class name. For instance,

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;
  }
}

The problem arises because the parseInput method is static, and yet it is referencing a specific instance's list of cells! Which one is it referencing? Who knows!

You can solve the issue two ways:

1: Make the parser non-static: public Cell parseInput(String input) {

2: Pass the table to the parser, so it knows what to reference:

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;
}

Now, as you stated, the parser is a class, not just a method. But the general rule still applies. You cannot reference an instance field from a static method, because that static method is not associated with any instance!

Klazen108
  • 690
  • 4
  • 19
1

I made my Parser static, because I want to use it without the need of instantiating a new object every time I need it (is this correct?).

Maybe, but not for the reason you state. Why don't you want to create an instance of your class? If that's your only reason for making it static, then it's not a very relevant one. Indeed, something like the Singleton Pattern essentially achieves the same thing, ensuring that you don't have to keep creating an instance, because there's always exactly one instance to use.

If your object is exactly that... an object, then it should probably be modeled as an instance. I generally tend to think of things which are objects as non-static by nature and things which are concepts about an object are more static by nature.

Let's use the belabored OO example of cars for a moment. If I want to know the price of a car, that's a property of a particular car. I'd have to specify an instance of an Accord for example in order to query it for that property. If, on the other hand, I want to know the average price for a particular model, that's more of a static concept. I'm not talking about any particular instance of Accord, just Accords in general. So where something like getPrice() would be an instance method on Car, something like getAveragePrice() might not.

should I instantiate a new Parser object when I try to read an import file?

Is that such a bad thing?


Now, for the problem at hand, which reference specifically is the compiler complaining about? I guess I'm having trouble picturing it, can you provide a simplified code example so I can see how these static and non-static classes/members relate? Essentially you can reference instance members from a static location, you just need to reference an instance in order to do it. Taking my belabored example above, I can't do this:

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

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

But I can do this (albeit probably ill-advised in this overly-contrived example):

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

    static int getAveragePrice() {
        var someRandomCar = new Car();
        return someRandomCar.getPrice();
    }
}
David
  • 208,112
  • 36
  • 198
  • 279
0

If your static method need access to non-static methods (without instantiating anything or accessing instance directly), then MUST be defined as non-static.

MariuszS
  • 30,646
  • 12
  • 114
  • 155
0
private static Parser INSTANCE = new Parser();

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

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

Editing to make this more clear:

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();
    }
}
Steve Cohen
  • 4,679
  • 9
  • 51
  • 89
  • I think your example is flawed. Why would you need to get the static instance within a non-static method? You'd just use `this` in that case. I think you meant to make the method static... – DaoWen Nov 14 '13 at 20:59
  • No, the signature is still `public void nonStaticMethod()` not `public static void nonStaticMethod()` (and you'd want to rename the method since it's now static). – DaoWen Nov 14 '13 at 21:00
  • 1
    No, you're wrong now. nonStaticMethod is just what it claims to be, a non static method. It retrieves a reference to a static object through a static reference to the Parser class and uses that reference to do what it needs to do. That is perfectly legal. Try it! – Steve Cohen Nov 14 '13 at 21:02
  • I think you missed my point. If you're already in a non-static method, then you have access to `this` (which is an instance of `Parser`), so you can just call `whateverParserMethodYouWant();` (which implicitly uses `this` as the target). That's a lot more straightforward than getting the static instance of `Parser` just to invoke a method which you can already invoke. The point of the question was trying to invoke a non-static method from a static method. Your example would work with a static method too (hence me suggesting to add `static`)—but for some reason you went with non-static...? – DaoWen Nov 15 '13 at 05:06
  • Also, when I said _I think you're example is flawed_, I didn't mean that the code is illegal. I meant it was flawed like writing `if (x == 1) return true; else return false;` is flawed, because it doesn't make sense given that you can just write `return x == 1;` instead. In this case, `Parser.getInstance()` is pointless because you can much more succinctly use `this` to make the method call instead. Now, if `nonStaticMethod()` _were_ a static method, then it would make sense since there's no `this` in scope... – DaoWen Nov 15 '13 at 05:12
  • @DaoWen What you weren't understanding, (and it's partly my fault because I wasn't as clear as I might have been) was that my three dots were supposed to convey that nonStaticMethod() was NOT A MEMBER OF the Parser class but of some other class. In that case, it would have to get an instance of a Parser first. If it were a member of the parser class, then indeed, my example would make no sense at all. – Steve Cohen Nov 15 '13 at 16:33
  • I actually thought of that possibility—but I decided that would make even less sense than everything being in `Parser` because 1) assuming that the `...` was supposed to span two classes (and thus probably two source files) seemed a bit farfetched, 2) because it makes no difference if the client's method is static or non-static (so why ephasise `nonStaticMethod`?), and 3) because the question was specifically asking about making the method call from a _static method within the `Parser` class_. Either way, the example didn't really make sense to me in the context of the question that was asked. – DaoWen Nov 15 '13 at 19:36