Java:何时使方法成为静态的v。实例

Java:何时使方法成为静态的v。实例,java,oop,static,Java,Oop,Static,我有一个Gene类来跟踪基因Gene有一种计算两个基因之间距离的方法。有什么理由让它静止吗 哪个更好 public static int genedance(基因g0,基因g1) 或 public int-genedance(基因其他) 支持/反对将其设置为静态的论点?我理解会员保持静止意味着什么,我只是对其对最大清洁度/效率等的影响感兴趣 对于返回两个基因的修剪版本、查找基因之间的匹配、查找动物之间的匹配(包含基因集合)等,我重复相同的模式。如果将方法设置为静态,则意味着可以在没有类实例的情况

我有一个
Gene
类来跟踪基因
Gene
有一种计算两个基因之间距离的方法。有什么理由让它静止吗

哪个更好


public static int genedance(基因g0,基因g1)

public int-genedance(基因其他)

支持/反对将其设置为静态的论点?我理解会员保持静止意味着什么,我只是对其对最大清洁度/效率等的影响感兴趣


对于返回两个基因的修剪版本、查找基因之间的匹配、查找动物之间的匹配(包含基因集合)等,我重复相同的模式。

如果将方法设置为静态,则意味着可以在没有类实例的情况下调用该方法。这还意味着,除非向该方法传递对对象的引用,否则该方法无法访问实例变量

有时,将方法设为静态是有意义的,因为该方法与类关联,而不是与类的特定实例关联。例如,所有parseX方法,例如
Integer.parseInt(字符串s
)。这将
字符串
转换为
int
,但与
整数
对象的特定实例无关


另一方面,如果一个方法必须返回某个对象的特定实例所特有的数据(像大多数getter和setter方法一样),那么它就不能是静态的。

IMO没有绝对的“更好”,但是
public int-genedance(Gene-other)
在风格上更类似于Java中的其他方法(例如Object.equals,Comparable.compareTo),所以我会这样做。

这里有一个元答案,还有一个有趣的练习:调查一组Java SDK的库类,看看是否可以对不同类中的静态方法之间的共性进行分类。

实例,而不是静态的
对于这种情况,我认为第二种选择显然更好。如果你考虑一下,任何方法都可以实现为静态的,如果你愿意将对象传递给它,这只是一种特殊情况,因为另一个参数也是一个实例

因此,我们对对称性和抽象性的搜索由于必须在点运算符的两个实例对象之间进行选择而受到了轻微的冒犯。但是,如果您将
.method
视为
then运算符,这并不是一个真正的问题


另外,进行功能样式链接的唯一方法是使用属性,即实例方法。您可能希望
thing.up.down.parent.next.distance(x)
起作用。

我更喜欢第二种形式,即实例方法,原因如下:

  • 静态方法使测试变得困难,因为它们无法被替换
  • 静态方法更面向过程(因此更少面向对象)

  • 在我看来,对于实用程序类(比如StringUtils),静态方法是可以的但是我不想滥用它们。

    我会选择第二种方法。我认为静态方法没有好处。因为方法在Gene类中,静态方法只会增加一个额外的参数,没有额外的增益。如果你需要一个util类,那就完全不同了。但在我看来,如果您可以将该方法添加到相关的类。

    公共静态int-genedance(Gene g0,Gene g1)
    将是一个单独的实用程序类的一部分,如Java中的
    集合
    数组
    ,而
    公共int-genedance(Gene-other)
    将是
    基因
    类的一部分。考虑到您还有其他操作,如“修剪两个基因的版本、查找基因之间的匹配、查找动物之间的匹配(包含基因集合)等”我将为它们创建一个单独的静态实用程序类,因为这些操作在语义上对
    基因
    没有意义


    如果“基因距离”的语义可以包装到你的
    equals(Object o)
    方法中,那么你可以在那里使用它,或者将它包含在你的静态实用程序中。

    在这种特殊情况下,我将把它作为一个intance方法。但是如果你在g0为null时有一个逻辑答案,那么就使用这两个方法(这种情况比你想象的更频繁)

    例如,
    aString.startsWith()
    ,如果aString为null,您可能认为返回null是合乎逻辑的(如果您认为函数可以允许null)。这允许我稍微简化我的程序,因为客户端代码中不需要aString检查null

    
    final Stirng         aPrefix = "-";
    final Vector aStrings = new Vector();
    for(final String aString : aStrings) {
        if (MyString.startsWith(aString, aPrefix))
            aStrings.aStringadd();
    }
    
    而不是

    
    final Stirng         aPrefix = "-";
    final Vector aStrings = new Vector();
    for(final String aString : aStrings) {
        if ((aString != null) && aString.startsWith(aPrefix))
            aStrings.aStringadd();
    }
    
    注意:这是一个过于简化的示例


    只是一个想法。

    我认为问题域应该提供超出一般风格和/或面向对象考虑的答案


    例如,我猜想在遗传分析领域,“基因”和“距离”的概念相当具体,不需要通过遗传进行专门化。如果不是这样,人们可以很好地选择实例方法。

    我会将其作为实例方法。但这可能是由于事实上我对基因一无所知;)


    实例方法可以被子类覆盖,这大大降低了代码的复杂性(不需要if语句)。在静态方法的例子中,如果你得到一种特定类型的基因,其距离的计算会有所不同,那么会发生什么呢?另一种静态方法?如果你要处理一个基因多态列表,你必须查看一个基因类型,以选择正确的距离方法。。。这增加了耦合和复杂性。

    选择实例方法的主要原因是多态性。静态方法不能被子类重写,这意味着您不能基于实例类型自定义实现。这可能不适用于您的情况,但值得一提

    如果基因距离是完全独立的
    import junit.framework.Assert;
    
    import org.junit.Test;
    
    public class GeneTest
    {
        public static abstract class Gene
        {
            public abstract int geneDistance(Gene other);
        }
    
        public static class GeneUtils
        {
            public static int geneDistance(Gene g0, Gene g1)
            {
                if( g0.equals(polymorphicGene) )
                    return g0.geneDistance(g1);
                else if( g0.equals(oneDistanceGene) )
                    return 1;
                else if( g0.equals(dummyGene) )
                    return -1;
                else
                    return 0;            
            }
        }
    
    
        private static Gene polymorphicGene = new Gene()
                                        {
    
                                            @Override
                                            public int geneDistance(Gene other) {
                                            return other.geneDistance(other);
                                            }
                                        };
    
        private static Gene zeroDistanceGene = new Gene() 
                                        {                                        
                                            @Override
                                            public int geneDistance(Gene other) {
                                            return 0;
                                            }
                                        };
    
        private static Gene oneDistanceGene = new Gene() 
                                        {                                        
                                            @Override
                                            public int geneDistance(Gene other) {
                                            return 1;
                                            }
                                        };
    
        private static Gene hardToTestOnIsolationGene = new Gene()
                                        {
    
                                            @Override
                                            public int geneDistance(Gene other) {
                                            return GeneUtils.geneDistance(this, other);
                                            }
                                        };
    
        private static Gene dummyGene = new Gene()
                                        {
    
                                            @Override
                                            public int geneDistance(Gene other) {
                                            return -1;
                                            }
                                        };                                    
        @Test
        public void testPolymorphism()
        {
            Assert.assertEquals(0, polymorphicGene.geneDistance(zeroDistanceGene));
            Assert.assertEquals(1, polymorphicGene.geneDistance(oneDistanceGene));
            Assert.assertEquals(-1, polymorphicGene.geneDistance(dummyGene));
        }
    
        @Test
        public void testTestability()
        {
    
            Assert.assertEquals(0, hardToTestOnIsolationGene.geneDistance(dummyGene));
            Assert.assertEquals(-1, polymorphicGene.geneDistance(dummyGene));
        }    
    
        @Test
        public void testOpenForExtensionClosedForModification()
        {
    
            Assert.assertEquals(0, GeneUtils.geneDistance(polymorphicGene, zeroDistanceGene));
            Assert.assertEquals(1, GeneUtils.geneDistance(oneDistanceGene, null));
            Assert.assertEquals(-1, GeneUtils.geneDistance(dummyGene, null));
        }    
    }
    
        public interface GeneDistance{
            public int get();
        }
    
        public class GeneDistanceImpl implements GeneDistance{
            public int get(){ ... }
        }
    
        public class GeneUtils{
            public static int geneDistance(Gene g0, Gene g1){
                return new GeneDistanceImpl(g0, g1).get();
            }
        }
    
    class Gene{
        // ... Gene implementation ...
    
        public int distanceTo(Gene other){
            return distance.get(this, GeneUtils.getDefaultDistanceImpl());
        }
    
        public int distanceTo(Gene other, GeneDistance distance){
            return distance.get(this, other);
        }
    }
    
    public static int geneDistance(Gene g0, Gene g1)
    {
      int d0=g0.getOneWayDistance(g1);
      int d1=g1.getOneWayDistance(g0);
      if (d0 < d1) return d0; else return d1;
    }