编译器不允许静态方法调用非静态方法。我理解这样做是因为非静态方法通常最终使用实例变量。
但是有一个不使用实例变量的非静态方法是否有意义。如果我们的行为不影响或不受实例状态的影响,则不应将此类方法标记为静态。
答案 0 :(得分:30)
确定!我们假设您已进入interface IMyCollection
。它有一个方法boolean isMutable()
。
现在您有两个类class MyMutableList
和class MyImmutableList
,它们都实现了IMyCollection
。他们每个人都会覆盖实例方法isMutable()
,MyMutableList
只返回true
,MyImmutableList
返回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();