有一个不使用实例变量的非静态方法是否有意义?

时间:2015-08-04 16:10:52

标签: java methods static instance non-static

编译器不允许静态方法调用非静态方法。我理解这样做是因为非静态方法通常最终使用实例变量。

但是有一个不使用实例变量的非静态方法是否有意义。如果我们的行为不影响或不受实例状态的影响,则不应将此类方法标记为静态。

7 个答案:

答案 0 :(得分:30)

确定!我们假设您已进入interface IMyCollection。它有一个方法boolean isMutable()

现在您有两个类class MyMutableListclass MyImmutableList,它们都实现了IMyCollection。他们每个人都会覆盖实例方法isMutable()MyMutableList只返回trueMyImmutableList返回false

两个类中的

isMutable()是一个实例方法,(1)不使用实例变量,(2)不影响实例状态。但是,由于语言的限制(无法覆盖静态方法),这种设计是唯一实用的设计。

另外,我想澄清一个误解(正如@manouti所做的那样):非静态方法不是实例,因为它们使用任何实例变量或影响实例状态;它们是实例方法,因为它们是以这种方式定义的(没有static关键字),因此具有隐式this参数(在Python这样的语言中,实际上是显式的!)。 / p>

答案 1 :(得分:25)

经常,没有。如果方法没有触及任何实例状态,则没有理由将其绑定到实例。

当然,静态方法不能被继承或覆盖,因此,您可能希望拥有一个不使用实例状态的实例方法。 strategy pattern就是一个典型的例子。

另一种情况是,无论如何,您可以将它绑定到实例,如果这是一个公共API,并且您可能想要将该方法绑定到将来的实例状态。在这种情况下,使用API​​的人员的向后兼容性问题可能会使(或不可能)将静态方法转换为实例方法。

答案 2 :(得分:7)

由于无法覆盖静态方法,许多关注代码可测试性的开发人员试图完全避免使用Java中的静态方法。

如果依赖项可以替换为mock对象,则代码更易于测试。 Mockito和EasyMock是最常用的帮助它的工具,它们依靠继承创建子类,允许您轻松覆盖您 想要测试的(通常是复杂的)方法...以便您的测试专注于您想要测试的内容。

我没有尝试使用零静态方法,但是当我承认要包含它们时,我常常后悔,出于测试原因。

所有这一切都非常令人沮丧,因为它与静态vs实例方法的设计考虑无关。这使我希望那些允许你拥有与班级无关的功能的语言......

答案 3 :(得分:7)

如果有人正在编写方法目的的人类可读描述,是否会提及 对象?如果是这样,请使用实例方法。如果不是,请使用静态方法。请注意,某些方法可能以任何一种方式描述,在这种情况下,应该使用判断哪个方法更好。

例如,考虑"获取应该邮寄Freedonian所得税表格的地址" vs"获取Freedonian所得税表格应邮寄的地址"?第一个问题应该通过实例方法来回答;第二种是静态方法。可能是Freedonia目前要求将所有税表发送到同一地址(在这种情况下,前一种方法可能会忽略所有实例字段),但将来可能会为不同地区的人员设置不同的办公室(在这种情况下,前一种方法)可能会查看纳税人ID并根据该地址选择邮寄地址,而后一种方法则必须将表格指向办公室,办公室可以接受任何人的表格并根据需要重定向。)

答案 4 :(得分:3)

  

我理解这样做是因为非静态方法通常最终使用实例变量。

即使实例方法不使用实例变量,它仍然绑定到类的实例。实际上,它在方法参数中隐含地引用了this

换句话说,在以下方法中:

public void foo() {

}
隐式传递

this作为方法中的第一个局部变量。

修改

重新阅读这个问题,这个问题更多地取决于具体情况。通常,如果该方法不需要实例(并且您确定它不会),那么只需将其设为static

答案 5 :(得分:2)

一个很好的例子是布尔值的面向对象编码。大多数语言,甚至像Java这样的面向对象的语言,都选择面向抽象数据类型的布尔值编码,但是Smalltalk使用OO编码,几乎所有方法都不使用任何实例状态。看起来有点像这样:

import java.util.function.Supplier;
@FunctionalInterface interface Block { void call(); }

interface Bool {
  Bool not();
  Bool and(Bool other);
  Bool or(Bool other);
  <T> T ifThenElse(Supplier<T> thenBranch, Supplier<T> elseBranch);
  void ifThenElse(Block thenBranch, Block elseBranch);

  static final Bool T = new TrueClass();
  static final Bool F = new FalseClass();

  class TrueClass implements Bool {
    public Bool not() { return F; }
    public Bool and(Bool other) { return other; }
    public Bool or(Bool other) { return this; }
    public <T> T ifThenElse(Supplier<T> thenBranch, Supplier<T> elseBranch) {
      return thenBranch.get();
    }
    public void ifThenElse(Block thenBranch, Block elseBranch) {
      thenBranch.call();
    }
  }

  class FalseClass implements Bool {
    public Bool not() { return T; }
    public Bool and(Bool other) { return this; }
    public Bool or(Bool other) { return other; }
    public <T> T ifThenElse(Supplier<T> thenBranch, Supplier<T> elseBranch) {
      return elseBranch.get();
    }
    public void ifThenElse(Block thenBranch, Block elseBranch) {
      elseBranch.call();
    }
  }
}

public class Main {
  public static void main(String... args) {
    Bool.F.ifThenElse(() -> System.out.println("True"), () -> System.out.println("False"));
    // False
  }
}

事实上,如果你遵循对OO的认真承诺,使用大量的引用透明方法,并且优先于条件的多态性,你通常会在很多子类中得到方法,其中一个类中的每个实现都返回一个恒定的值。

答案 6 :(得分:2)

我认为有时它是肯定的,因为非静态方法可以覆盖为不同的类执行不同的任务,但任务可能不涉及实例变量,例如:

Fruit.java

public class Fruit{
    public void printInfo(){
        System.out.println("This is fruit");
    }
}

Orange.java

public class Orange extends Fruit{
    public void printInfo(){
        System.out.println("This is orange");
    }
}

Grape.java

public class Grape extends Fruit{
    public void printInfo(){
        System.out.println("This is grape");
    }
}

打印对象信息:

Fruit f=new Grape();
f.printInfo();