什么是"非静态方法"错误以及"this"如何工作?

Bri*_*ian 7 java oop compiler-errors instance-variables class-members

我有一些非常基本的Java问题,我想一劳永逸地理解这些问题.我有以下简短的代码:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

当我编译时,我得到了可怕的"非静态方法swapMe(int,int)无法从静态上下文引用"错误.另外,我得到"a已在swapMe(int,int)中定义","b已经在swapMe(int,int)中定义"

我需要最终通过我的厚厚的头骨,是"非静态方法"错误,它是如何(为什么)引起的,以及如何避免它.

此外,我假设你可以做我试图用'swapMe'方法中的'a'和'b'变量做的事情.我以为我可以传入'a'和'b',但也创建新变量'a'和'b',并用"this"关键字引用它们.

我知道这是非常基本的,但这两个"问题"是我使用Java的两个主要问题,并且出于某种原因,似乎无法正确学习.

谢谢大家,花时间阅读本文.祝你有美好的一天.

Ósc*_*pez 11

这意味着该方法swapMe()是一个实例方法,您需要一个VeryBasicJava类的实例来调用它,如下所示:

VeryBasicJava instance = new VeryBasicJava();
int x = 3; int y = 4;
instance.swapMe(x, y);
Run Code Online (Sandbox Code Playgroud)

或者,您可以声明swapMe()static,这样您就不需要先创建实例:

private static void swapMe(int a, int b)
Run Code Online (Sandbox Code Playgroud)

  • Java中的@Brian(以及大多数面向对象语言)我们对类中的方法进行了区分:_instance_方法,它们可以访问类的_instance_和_class_成员,并且需要在_instance_上调用类.和_class_方法,只能访问类的_class_成员,并且不需要调用_instance_ (2认同)
  • @Brian的混乱是可以理解的,因为你来自程序背景.你需要回到基本知识,才能真正神交面向对象编程 - 就目前而言,我建议你阅读[这](http://docs.oracle.com/javase/tutorial/java/javaOO/classvars. html),来自Java教程. (2认同)
  • @Brian,其中一部分是_static_方法(包括例如`Math.sqrt`)完全按照你期望的方式工作,但是当你的类有自己的字段和含义时,实例方法可以让你做一些你无法做到的事情静态方法. (2认同)

Jon*_*rdy 5

你只有一些小问题.您在评论中提到您对C有一些经验,因此我将尝试绘制一些基本的类比.阿static法(如main)用作普通的C函数.static但是,非方法采用隐藏参数:this,该参数指的是该方法要在其上运行的对象.当你编写这样的方法时:

private void swapMe(int a, int b) {
    // ...
Run Code Online (Sandbox Code Playgroud)

它真的意味着这样的事情:

private void swapMe(VeryBasicJava this, int a, int b){
    //              ^^^^^^^^^^^^^^^^^^^^
    // ...
Run Code Online (Sandbox Code Playgroud)

因为this参数是专门处理的,所以static在对象上调用非方法有一种特殊的语法:

    myInstance.swapMe(someA, someB);
//  ^^^^^^^^^^        ^^^^^  ^^^^^
//     this             a      b
Run Code Online (Sandbox Code Playgroud)

并且因为swapMe没有声明static,它预计会被调用如上所述.

mainVeryBasicJava类中声明的事实并不意味着您自动拥有一个VeryBasicJava 对象.再次,因为mainstatic,它就像一个普通的C函数:

void VeryBasicJava_main(...) {
    // ...
Run Code Online (Sandbox Code Playgroud)

创建对象的实例,请使用new:

VeryBasicJava vbj = new VeryBasicJava();
Run Code Online (Sandbox Code Playgroud)

这类似于mallocC:

VeryBasicJava *vbj = malloc(sizeof(VeryBasicJava));
VeryBasicJava_construct(vbj);
Run Code Online (Sandbox Code Playgroud)

使用实例,您可以调用方法:

vbj.swapMe(spam, eggs);
Run Code Online (Sandbox Code Playgroud)

您的另一个问题有两个:范围成员之一.适用范围,如你所知,是指其中一个变量存在.采取这个功能:

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: }
Run Code Online (Sandbox Code Playgroud)

调用此方法时,会发生以下情况:

  1. a并且b在给定调用中指定的值的情况下创建swapMe.

  2. 使用默认值a在本地创建一个new .这会隐藏参数,并且无法区分它们.swapMe0a a

  3. b创建一个新的,也严格地是本地的.它也具有默认0值,并隐藏参数b.

  4. tmp已创建,其值设置为新声明的值a,因此也是如此0.

  5. [ 见下文 ]

  6. [ 见下文 ]

  7. 本地人a并且b不再存在,参数ab.

在第5行和第6行中,您尝试使用语法this.a来引用本地a而不是参数.虽然这种语法存在于Java中,但它并不是你的意思.参数与局部变量的处理方式相同,因此不区分这两个类别,而是this.a区分本地和成员.现在,会员是什么?好吧,说你的类声明包含变量声明:

class VeryBasicJava {

    private int a;
    private int b;

    // ...

}
Run Code Online (Sandbox Code Playgroud)

这就像C中的成员声明struct:

struct VeryBasicJava {
    int a;
    int b;
};
Run Code Online (Sandbox Code Playgroud)

这意味着当您创建以下实例时VeryBasicJava:

VeryBasicJava vbj = new VeryBasicJava();
Run Code Online (Sandbox Code Playgroud)

该实例有它自己的变量ab,它可以在任何非使用static方法:

public void print() {
    System.out.println("a is " + a);
    System.out.println("b is " + b);
}
Run Code Online (Sandbox Code Playgroud)

如果您有一个与成员同名的局部变量,那么您必须使用this明确声明您要引用该成员.这个完整的程序说明了如何声明,使用和区分成员和本地人.

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

}
Run Code Online (Sandbox Code Playgroud)

它会产生这个输出:

a is 1
b is 2
c is 5
this.a is 3
this.b is 4
this.c is 5
Run Code Online (Sandbox Code Playgroud)

我希望这些例子和解释都有帮助.