Java 什么是「;“非静态法”;错误和“怎么做?”;这";工作
我有几个非常基本的Java问题,我想最终一劳永逸地理解它们。我有以下简短的代码:Java 什么是「;“非静态法”;错误和“怎么做?”;这";工作,java,oop,compiler-errors,instance-variables,class-members,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;
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;
}
}
当我编译时,我得到了可怕的“非静态方法swapMe(int,int)不能从静态上下文引用”错误。另外,我得到“a已经在swapMe(int,int)中定义”和“b已经在swapMe(int,int)中定义”
我需要的是“非静态方法”错误,它是如何(为什么)产生的,以及如何避免它
此外,我假设您可以使用“swapMe”方法中的“a”和“b”变量执行我试图执行的操作。我想我可以传入'a'和'b',但也可以创建新的变量'a'和'b',并用“this”关键字引用它们
我知道这是非常基本的,但这两个“问题”是我在Java中遇到的两个主要问题,并且由于某些原因,似乎无法正确地学习
感谢大家花时间阅读本文。祝您度过愉快的一天。这意味着方法
swapMe()
是一个实例方法,您需要VeryBasicJava
类的实例来调用它,如下所示:
VeryBasicJava instance = new VeryBasicJava();
int x = 3; int y = 4;
instance.swapMe(x, y);
int a; //this is the first argument
int b; //this is the second argument
int a; //this is the first line of your function
int b; //this is the second line of your function
private void swapMe(int a, int b){
int tmp = a;
a = b;
b = tmp;
}
private void swapMe(VeryBasicJava this, int a, int b){
// ^^^^^^^^^^^^^^^^^^^^
// ...
或者,您可以将swapMe()
声明为static
,这样您就不需要先创建实例:
private static void swapMe(int a, int b)
类是对象的模板。类的实例(即和对象)有自己的非静态变量和方法版本 静态方法和字段不绑定到类的任何特定实例
因此,如果没有要调用该方法的实例,那么从静态方法调用类实例方法是没有意义的。在您的示例中,
此
是对实例的引用,但您没有实例……对于第二个问题,当您创建函数时,它会为其所有变量创建自己的小堆栈。它的参数包含在该堆栈中-因此,您的堆栈如下所示:
VeryBasicJava instance = new VeryBasicJava();
int x = 3; int y = 4;
instance.swapMe(x, y);
int a; //this is the first argument
int b; //this is the second argument
int a; //this is the first line of your function
int b; //this is the second line of your function
private void swapMe(int a, int b){
int tmp = a;
a = b;
b = tmp;
}
private void swapMe(VeryBasicJava this, int a, int b){
// ^^^^^^^^^^^^^^^^^^^^
// ...
这就是为什么你会遇到问题——你在你的论点之后声明的a和b与你的论点相冲突,而不是“this.a”和“this.b”
您的第一个问题已经得到回答。swapMe需要一个VeryBasicJava实例来调用它。静态不需要 从该对象外部,您可以调用:VeryBasicJava.main(args) 从对象外部,您需要执行(new VeryBasicJava()).swapMe(a,b)来调用该方法 在swapMe中出现错误的原因是因为您定义了两次这些变量。签名行在该命名空间中为您声明了它们。在该方法中,您已经有一个int a。然后在第一行,再次声明int a 您希望在交换中执行的操作如下:
VeryBasicJava instance = new VeryBasicJava();
int x = 3; int y = 4;
instance.swapMe(x, y);
int a; //this is the first argument
int b; //this is the second argument
int a; //this is the first line of your function
int b; //this is the second line of your function
private void swapMe(int a, int b){
int tmp = a;
a = b;
b = tmp;
}
private void swapMe(VeryBasicJava this, int a, int b){
// ^^^^^^^^^^^^^^^^^^^^
// ...
当然,变量a和b只存在于该方法中,因此一旦该方法结束,您的工作就会丢失。如果您想保留它,请将变量设置为类变量,并为它们提供getter和setter。由于提供了修复程序,我想添加: 静态方法只能调用其他静态方法,并且只能直接访问静态变量(在java中)
要调用非静态方法,您必须创建该类的实例,然后调用这些方法。您只有几个小问题。你在评论中提到你对C有一些经验,所以我将尝试做一些基本的类比。
static
方法(例如main
)的行为类似于普通的C函数。但是,非静态
方法采用一个隐藏参数:this
,该参数引用该方法要操作的对象。当您编写这样的方法时:
private void swapMe(int a, int b) {
// ...
它的真正含义是:
VeryBasicJava instance = new VeryBasicJava();
int x = 3; int y = 4;
instance.swapMe(x, y);
int a; //this is the first argument
int b; //this is the second argument
int a; //this is the first line of your function
int b; //this is the second line of your function
private void swapMe(int a, int b){
int tmp = a;
a = b;
b = tmp;
}
private void swapMe(VeryBasicJava this, int a, int b){
// ^^^^^^^^^^^^^^^^^^^^
// ...
因为这个
参数是经过特殊处理的,所以有一种特殊的语法用于在对象上调用非静态
方法:
myInstance.swapMe(someA, someB);
// ^^^^^^^^^^ ^^^^^ ^^^^^
// this a b
而且由于swapMe
未声明为static
,因此希望像上面那样调用它
main
在VeryBasicJava
类中声明这一事实并不意味着您自动拥有一个VeryBasicJava
对象。同样,由于main
是static
,因此它与普通的C函数类似:
void VeryBasicJava_main(...) {
// ...
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: }
要创建对象的实例,请使用new
:
VeryBasicJava vbj = new VeryBasicJava();
这类似于C中的malloc
:
VeryBasicJava *vbj = malloc(sizeof(VeryBasicJava));
VeryBasicJava_construct(vbj);
通过实例,您可以调用一个方法:
vbj.swapMe(spam, eggs);
你的另一个问题有两个:一个是范围问题,另一个是成员问题。您可能知道,作用域是指变量存在的位置。采取以下措施:
void VeryBasicJava_main(...) {
// ...
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: }
调用此方法时,会发生以下情况:
swapMe
中指定的值,将创建a
和b
A
,位于swapMe
本地,默认值为0
。此a
隐藏参数a
,无法区分它们b
,也是严格本地的。它也有默认的0
值,并隐藏参数b
tmp
,其值设置为新声明的a
的值,因此它也是0
a
和b
不复存在,参数a
和b
也不复存在this.a
来引用本地a
,而不是参数。尽管这种语法存在于Java中,但它并不符合您的意思。参数被视为与局部变量完全相同,因此与其区分这两个类别,不如将这两个类别区分开来