Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the "non-static method" error and how does "this" work?

I have a couple of EXTREMELY basic Java questions that I would like to finally understand, once and for all. I have the following short piece of code:

public class VeryBasicJava{
    public static void main(String[] args){
        int x = 3;
        int y = 4;
        swapMe(x, y);
    }
    private void swapMe(int a, int b){
        int a;
        int b;
        int tmp = a;
        this.a = b;
        this.b = a;
    }
}

When I compile, I get the dreaded "non-static method swapMe(int,int) cannot be referenced from a static context" error. Also, I get "a is already defined in swapMe(int,int)" and "b is already defined in swapMe(int,int)"

What I need to finally get through my thick skull, is the "non-static method" error, how (why) it is caused, and how to avoid it.

Further, I was under the assumption that you could do what I am attempting to do with my 'a' and 'b' variables in the "swapMe" method. I thought I could pass in an 'a' and 'b', but also create new variables 'a' and 'b', and reference them with "this" keyword.

I know this is extremely basic, but these two "issues" are two of the main sticking points I have with Java, and for some reason, cannot seem to properly learn.

Thank you all, for taking the time to read this. Have a great day.

like image 684
Brian Avatar asked Mar 19 '12 17:03

Brian


4 Answers

That means that the method swapMe() is an instance method and you need an instance of the VeryBasicJava class to invoke it, like this:

VeryBasicJava instance = new VeryBasicJava();
int x = 3; int y = 4;
instance.swapMe(x, y);

Alternatively, you could declare swapMe() as static, in that way you won't need to create an instance first:

private static void swapMe(int a, int b)
like image 176
Óscar López Avatar answered Sep 27 '22 19:09

Óscar López


You have just a few minor problems. You mentioned in a comment that you have some experience with C, so I’ll try to draw some basic analogies. A static method (such as main) behaves like an ordinary C function. A non-static method, however, takes a hidden parameter: this, which refers to an object on which that method is to operate. When you write a method such as this:

private void swapMe(int a, int b) {
    // ...

It really means something like this:

private void swapMe(VeryBasicJava this, int a, int b){
    //              ^^^^^^^^^^^^^^^^^^^^
    // ...

Because the this parameter is treated specially, there is a special syntax for calling non-static methods on objects:

    myInstance.swapMe(someA, someB);
//  ^^^^^^^^^^        ^^^^^  ^^^^^
//     this             a      b

And because swapMe is not declared static, it expects to be called like the above.

The fact that main is declared inside the VeryBasicJava class does not mean that you automatically have a VeryBasicJava object. Again, because main is static, it is just like an ordinary C function:

void VeryBasicJava_main(...) {
    // ...

In order to create an instance of an object, you use new:

VeryBasicJava vbj = new VeryBasicJava();

This is analogous to malloc in C:

VeryBasicJava *vbj = malloc(sizeof(VeryBasicJava));
VeryBasicJava_construct(vbj);

With an instance, you can invoke a method:

vbj.swapMe(spam, eggs);

Your other issue is twofold: one of scope, and of members. Scope, as you may know, refers to where a variable exists. Take this function:

1: private void swapMe(int a, int b) {
2:     int a;
3:     int b;
4:     int tmp = a;
5:     this.a = b;
6:     this.b = a;
7: }

When this method is called, the following things happen:

  1. a and b are created, given the values specified in the call to swapMe.

  2. A new a is created, local to swapMe, with the default value 0. This a hides the parameter a, and there is no way to differentiate them.

  3. A new b is created, also strictly local. It too has the default 0 value, and hides the parameter b.

  4. tmp is created, and its value is set to that of the newly declared a, so it too is 0.

  5. [see below]

  6. [see below]

  7. The locals a and b cease to exist, as do the parameters a and b.

In lines 5 and 6, you attempt to use the syntax this.a to refer to the local a rather than the parameter. Though this syntax exists in Java, it does not do what you mean. Parameters are treated just the same as local variables, so rather than differentiating between those two categories, this.a differentiates between locals and members. Now, what are members? Well, say your class declaration contains variable declarations:

class VeryBasicJava {

    private int a;
    private int b;

    // ...

}

That’s just like member declarations in a C struct:

struct VeryBasicJava {
    int a;
    int b;
};

What this means is that when you create an instance of VeryBasicJava:

VeryBasicJava vbj = new VeryBasicJava();

That instance has its own variables a and b, which can be used in any non-static method:

public void print() {
    System.out.println("a is " + a);
    System.out.println("b is " + b);
}

If you have a local variable with the same name as a member, then you must use this to explicitly state that you want to refer to the member. This complete program illustrates how to declare, use, and differentiate between members and locals.

class VeryBasicJava {

    private int a;
    private int b;
    private int c;

    public static void main(String[] args) {
        VeryBasicJava vbj = new VeryBasicJava();
        vbj.a = 3;
        vbj.b = 4;
        vbj.c = 5;
        vbj.print(1);
    }

    public void print(int a) {
        int b = 2;
        System.out.println("a is " + a);
        System.out.println("b is " + b);
        System.out.println("c is " + c);
        System.out.println("this.a is " + this.a);
        System.out.println("this.b is " + this.b);
        System.out.println("this.c is " + this.c);
    }

}

It will produce this output:

a is 1
b is 2
c is 5
this.a is 3
this.b is 4
this.c is 5

I hope these examples and explanations are helpful.

like image 33
Jon Purdy Avatar answered Sep 27 '22 19:09

Jon Purdy


Your problems stem from not understanding how the object-orientated paradigm works.

The idea is that you define a class, which is a "type of thing". From that class, you create instances, which are effectively examples of that type of thing.

For example, when you create a class "Wallet", that defines how your system will treat wallets (i.e. what they can do, and what you can do with them). You can now create multiple different instances of wallets, that store different values, but still work the same way. (e.g. "myWallet" and "yourWallet" are both Wallets, so you can take money out and put money in etc, but if I check the money in yourWallet, I get a value of 50, whereas if I check the value in myWallet, I get a value of 20)

Now, "static" methods belong to the class. This means that they can't access members variables specific to the class. For example, if I'm keeping track of every wallet in my system, that value doesn't belong to any particular wallet in the class, but it's still involved with that class, so we make it static.

To use my example, if you have two objects of type "Wallet", and one has its "cash" value set to 30, and the other has its cash value set to "25", a static function can't access both values, so it can't access either. You have to give it a particular wallet to access.

The advantage of this method over C's approach is that it ties related functionality together. For example, if you see a C array of ints, you don't really know what they are intended to represent and may do something unexpected with them. But if I give you a Java array of Wallets, you also get the methods that influence how you interact with them. (This is a really stripped down explanation of encapsulation)

One of the principle issues with Java is that it ties everything to a class. This causes a problem for the main method, which has to start the program, because it has no instances yet, but must still be part of the class. Therefore the main method must always be static. This tends to confuse new programmers, as invariably the first thing you do within the main method is create an instance of the class it's "inside".

In your example, you've got no "specific" data. Everything's inside the methods, which means you're effectively trying to write procedural code in Java. You can do this (just declare everything static), but the language will fight you, and you'll write very bad code.

When I was originally starting out with Java, I effectively treated the main() method of a class as if it wasn't part of the class. Conceptually, it helped, because you stop thinking of the non-static stuff as something that's already there (which is your main issue). But my recommendation to you is try reading through this. But there are some very good transition courses out there for learning object-orientated programming, and you may want to invest in them.

like image 23
deworde Avatar answered Sep 27 '22 19:09

deworde


Classes are a template for OBJECTS. An instance of a class (i.e. and object) has its own version of variables and methods that are non-static.

static methods and fields are not tied to any specific instance of a class.

So it makes no sense to invoke a class instance method from a static method, without the instance on which you want to invoke the method. In your example, this is a reference to an instance, but you have no instance....

like image 41
hvgotcodes Avatar answered Sep 27 '22 19:09

hvgotcodes