JAVA:正确访问静态方法

8
我是一名初学JAVA的学生,喜欢尝试理解每个概念。
在JAVA中访问静态方法 "hero.returnHp()" 时,我遇到了以下问题:
 hero Mike = new hero();

 Mike.returnHp();

程序运行良好,但我注意到Eclipse有一个警告:“应以静态方式访问类型英雄的静态方法。”当我接受自动修复时,它将“Mike.returnHp();”更改为“hero.returnHp();”。
所以我有两个问题:
1)这有什么优势?
2)如果我创建了两个相同类型的对象,如何指定在静态方式下访问时返回哪一个?
谢谢!

2
静态方法的意义在于它们不与类的实例绑定。因此,如果您在点号左侧使用实例或类名调用其中一个方法,都没有区别。 - Daniel Fischer
4
问题在于你在变量名首字母使用大写,而在类名首字母使用小写-这与通用标准完全相反。但是,如果我没记错的话,以上两种形式都是技术上合法的,尽管“首选”的形式是在调用静态时使用类名。 - Hot Licks
当我接受自动修复时,它将 Mike.returnHp(); 更改为 hero.returnHp(); 嗯,我想应该是反过来的。 - leonbloy
1
离题:正如@HotLicks所提到的,您使用大写和小写的方式与Java社区使用的相反,这往往会让人感到困惑。我强烈建议您在开始学习时学习常用的方式。http://bitprison.net/java_naming_conventions - madth3
@DanielFischer:哎呀,确实误导了我。+1 给 HotLicks 的评论,我应该仔细阅读它。 - leonbloy
显示剩余2条评论
5个回答

11

首先,我想指出关键字“静态”(static)的含义。

静态变量只存在于类中一次 - 也就是说,如果您创建了一个带有静态变量的类,那么该类的所有实例都将共享该变量。此外,如果它是公共静态变量,则任何人都可以访问该变量,而无需先创建该类的实例 - 他们只需调用Hero.staticVariableName;

静态方法/函数是无状态的。也就是说,它们只处理(1)由传递给方法/函数的参数提供的信息,或者(2)在静态变量中(如上所述),或者(3)硬编码到方法/函数中的信息(例如,您创建了一个静态函数返回“ hello” - 然后“ hello”被硬编码到函数中)。

Eclipse要求您以静态方式访问静态方法的原因是它可以让您和后续的程序员看到您正在访问的方法是静态的(这有助于防止错误)。无论您怎么做,函数都会运行,但正确的方法是以静态方式访问静态函数。请记住,如果您调用静态方法,则无论从哪个实例变量调用它(Tim.returnHp,Jim.returnHp,Mike.returnHp等),您都将从英雄类中调用相同的函数,并且无论您从谁那里调用它,您将看到完全相同的行为。

如果您创建了两个相同类型的对象,则无法指定在以静态方式访问时要返回哪个对象;静态函数/方法将引用整个Hero类。

您能解释一下您试图做什么,以便我们可以提供更具体的反馈吗?很可能returnHp()不应该是静态的。

那是“返回生命值”吗?如果是,那么您不希望它是静态的,因为英雄拥有的生命值数量是英雄状态的一部分,而静态方法是无状态的。(把状态想象成当前状态 - 活着,死亡,受伤,攻击,防御,以上几种状态的某些组合等)我建议进入Hero类并将returnHp更改为非静态方法。

现在... 我知道你没有询问,但我想建议你一些内容:

类名(例如Hero)应大写。实例变量名(例如mike)应小写。这是一种广泛接受的命名约定,它将增加您的代码的可读性。

Jeff


谢谢,这正是我在寻找的Jeff!你说得对,我正在使用它来为基本战斗模拟器中的角色设置生命值。我正在创建不同动作(攻击、逃跑、物品)的方法,但我注意到如果不将它们设为静态并扩展类,就无法在另一个类中访问它们。我试图创建这些方法,以便在需要时调用它们,而不是为每次战斗编写另一个参数块。这是我能想到的最好的方法。 - Hermes Trismegistus
不客气,Hermes。你能否澄清一下——你说“如果不将它们设为静态变量并扩展类,就无法在另一个类中访问它们。” 当你说另一个类时,是指Hero的子类吗?你试图从哪个其他类中访问它们? 此外,你将它们标记为private attack() private run()等,还是标记为public attack() public run()等? - ManEatingCheese
Hi Jeff,抱歉信息不够清晰,我正在努力使信息尽可能清晰。我有三个类:Hero、Monster和Battle(Main)。我正在创建一个名为“Fight”的新类,用于保存与攻击相关的方法。在Battle类中创建了Hero对象。我试图在Battle类中访问与Hero类相关的变量。Hero类中的变量是私有的,并使用setter和getter方法进行访问。 - Hermes Trismegistus
啊,这很有道理!我试图将代码分散到方法中,以便它不会全部在主方法中。 "Fight"类将保存“Attack”方法,每次玩家战斗时都可以调用该方法。现在游戏非常简单,只有两场战斗:你面对一个怪物,打败它后会出现一个Boss。我试图将攻击写成一个方法,这样我就可以在Boss出现时只调用一次它,而不是再次重写代码块。 - Hermes Trismegistus
Hermes,我猜你是想在Hero和Boss类中重复使用attack()和defend()等代码,这就是Fight类的目的吧?如果是这样,那么代码重用是好的,但要将类的行为保持在类内部。如果你的英雄和Boss以相同的方式攻击,那么我建议创建一个名为Combatant的超类,并让Combatants知道如何攻击(),并让Hero和Boss扩展Combatant。如果你的英雄和Boss以不同的方式攻击,那么情况就更加复杂了,你可能需要研究一下接口。 - ManEatingCheese
显示剩余2条评论

3
一个静态方法属于一个类而不是一个对象。在上面的例子中,您创建了一个hero类的对象Mike。方法returnHp()static的,并且属于hero类,而不是hero对象(如Mike)。
当您从对象引用static方法时,您可能会收到IDE或编译器警告,因为它永远不应该与该对象绑定,只能与其类绑定。
根据方法名称,我猜它不应该是static的。
class hero {
    private float hp;
    public float returnHp() { // Should NOT be "public static float ..."
        return hp;
    }
}

关于类成员的JavaDocs文档也简要介绍了static关键字,你可能需要查看。


@DanielFischer 对不起,应该写成“警告”。当事情出错时,我有一个坏习惯,总是写“错误”。 - Cat

1

静态方法完全独立于类的任何实例。

考虑到这一点,它可以正常工作,而不会导致NullPointerException:

 hero Mike = null;

 Mike.returnHp();

顺便提一下,类名应该以大写字母开头,变量名应该小写。

这里有另一个不错的例子:作为静态方法,Thread.sleep总是使当前线程休眠,即使您尝试在另一个线程实例上调用它。

应该通过类名调用静态方法,而不是通过实例调用,否则会非常令人困惑,主要是因为没有动态分派,静态方法不能在子类中被覆盖:

 hero Tim = new superhero(); // superhero extends hero

 Tim.returnHp();  // still calls the method in hero, not in superhero

你现在收到了一个编译器 警告,但很多人认为这是一个设计错误,应该是一个错误


0
  1. 这是JVM规范的一部分。
  2. 你不需要这样做。静态方法在类的实例之间是共享的,你的困惑来自于认为它是一个实例方法。

0

static 意味着一种静态的方式。使用 static 的一个原因是可以直接使用类来访问它。这是它的好处。这就是为什么 main 函数总是静态的原因。入口函数不需要先创建实例。 实际上,如果你在谷歌中搜索 static,并深入了解它,你就会知道何时以及为什么使用 static。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接