[java] 개인 헬퍼 메소드가 정적 일 수있는 경우 정적이어야 함

인스턴스화하도록 설계된 클래스가 있다고 가정 해 봅시다. 클래스 내부에 클래스 멤버 중 하나에 액세스 할 필요가없는 몇 가지 개인 “도우미”메서드가 있으며 인수에 대해서만 작동하여 결과를 반환합니다.

public class Example {
   private Something member;

   public double compute() {
       double total = 0;
       total += computeOne(member);
       total += computeMore(member);
       return total;
   }

   private double computeOne(Something arg) { ... }
   private double computeMore(Something arg) {... }
} 

지정하는 특별한 이유가 computeOnecomputeMore여부에 대한 특별한 이유 – 정적 방법으로는?

문제를 일으키지 않고 정적 일 수는 있지만 비 정적 상태로 두는 것이 가장 쉽습니다.



답변

그런 도우미 방법을 선호합니다 private static. 그러면 독자는 객체의 상태를 수정하지 않을 것입니다. 내 IDE는 정적 방법에 대한 호출을 기울임 꼴로 표시하므로 서명을 보지 않고 정적 인 방법을 알 수 있습니다.


답변

정적 메소드는에 액세스 할 수 없으므로 바이트 코드가 약간 작아 질 수 있습니다 this. 속도에 차이가 있다고 생각하지 않습니다 (그렇다면 전체적으로 차이를 만들기에는 너무 작을 것입니다).

나는 일반적으로 가능하다면 그렇게하기 때문에 나는 그것들을 정적으로 만들 것이다. 그러나 그것은 단지 나입니다.


편집 : 이 답변은 바이트 코드 크기에 대한 확실한 주장으로 인해 하향 조정되고 있습니다. 실제로 테스트를 진행하겠습니다.

class TestBytecodeSize {
    private void doSomething(int arg) { }
    private static void doSomethingStatic(int arg) { }
    public static void main(String[] args) {
        // do it twice both ways
        doSomethingStatic(0);
        doSomethingStatic(0);
        TestBytecodeSize t = new TestBytecodeSize();
        t.doSomething(0);
        t.doSomething(0);
    }
}

바이트 코드 (로 검색 javap -c -private TestBytecodeSize) :

Compiled from "TestBytecodeSize.java"
class TestBytecodeSize extends java.lang.Object{
TestBytecodeSize();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

private void doSomething(int);
  Code:
   0:   return

private static void doSomethingStatic(int);
  Code:
   0:   return

public static void main(java.lang.String[]);
  Code:
   0:   iconst_0
   1:   invokestatic    #2; //Method doSomethingStatic:(I)V
   4:   iconst_0
   5:   invokestatic    #2; //Method doSomethingStatic:(I)V
   8:   new     #3; //class TestBytecodeSize
   11:  dup
   12:  invokespecial   #4; //Method "<init>":()V
   15:  astore_1
   16:  aload_1
   17:  iconst_0
   18:  invokespecial   #5; //Method doSomething:(I)V
   21:  aload_1
   22:  iconst_0
   23:  invokespecial   #5; //Method doSomething:(I)V
   26:  return

}

정적 메소드를 호출하려면 두 개의 바이트 코드 (바이트)가 iconst_0필요합니다 (인수의 경우) 및 invokestatic.
비 정적 메소드를 호출하려면 aload_1( TestBytecodeSize객체의 경우), iconst_0(인수의 경우) 및 invokespecial. (이러한 개인 방법 없었다면, 그것은 참고했을 것으로 invokevirtual대신에 invokespecial, 참조 JLS §7.7 모드 실행 방법을 .)

내가 말했듯이 invokestatic바이트 코드가 하나 더 적게 필요한 것 외에는이 두 가지 성능에 큰 차이가 없을 것으로 예상 됩니다. invokestatic그리고 invokespecial모두 약간보다 더 빨리해야 invokevirtual하나가 다른 하나보다 더 빠르게 경우들이 있기 때문에 모두를 사용하는 대신 동적 바인딩 정적,하지만 난 아무 생각이 없다. 좋은 참고 자료도 찾을 수 없습니다. 내가 찾을 수있는 가장 가까운 것은 이 1997 JavaWorld 기사 이며, 기본적으로 방금 말한 내용을 다시 표시합니다.

이러한 명령어로 호출 된 메서드는 정적으로 바인딩되므로 가장 빠른 명령어는 invokespecialand invokestatic일 가능성이 높습니다 . JVM이 이러한 명령어에 대한 기호 참조를 해결하고이를 직접 참조로 바꾸면 해당 직접 참조에 실제 바이트 코드에 대한 포인터가 포함됩니다.

그러나 1997 년 이후 많은 것들이 바뀌 었습니다.

결론적으로 … 나는 여전히 이전에 말한 것을 고수하고있는 것 같습니다. 속도는 최고의 미세 최적화이기 때문에 다른 것을 선택 해야하는 이유가 아닙니다.


답변

개인적으로 선호하는 것은 무국적자라는 명백한 깃발이므로 정적으로 선언하는 것입니다.


답변

대답은 … 그것은 달려 있습니다.

member가 다루고있는 객체에 특정한 인스턴스 변수 인 경우 왜이를 매개 변수로 전달합니까?

예를 들어 :

public class Example {
   private Something member;

   public double compute() {
       double total = 0;
       total += computeOne();
       total += computeMore();
       return total;
   }

   private double computeOne() { /* Process member here */ }
   private double computeMore() { /* Process member here */ }
}


답변

당신이 “전에”클래스 생성자를 호출해야하는 경우가 정적 도우미 메서드를 선언 할 수 있습니다 이유 중 하나는 thissuper. 예를 들면 다음과 같습니다.

public class MyClass extends SomeOtherClass {
    public MyClass(String arg) {
       super(recoverInt(arg));
    }

    private static int recoverInt(String arg) {
       return Integer.parseInt(arg.substring(arg.length() - 1));
    }
}

이것은 약간의 고안된 예이지만 분명히이 recoverInt경우 인스턴스 방법이 될 수는 없습니다.


답변

나는 개인 정적 메소드에 대한 분명한 장점을 생각할 수 없습니다. 즉, 정적이 아닌 것으로 만들면 특별한 이점이 없습니다. 주로 프레젠테이션의 문제입니다. 객체를 변경하지 않는다는 사실을 명확하게 강조하기 위해 정적으로 만들 수 있습니다.

다른 접근 권한을 가진 메소드의 경우 두 가지 주요 주장이 있다고 생각합니다.

  • 객체의 인스턴스를 만들지 않고 정적 메서드를 호출 할 수 있습니다.
  • 정적 메소드는 상속 될 수 없으며, 다형성이 필요한 경우 문제가 될 수 있습니다 (그러나 개인 메소드와는 관련이 없음).

게다가, 그 차이는 꽤 작으며,이 포인터가 인스턴스 메소드에 전달 한 여분의 차이가 크게 다르다는 것을 의심합니다.


답변

정답은 다음과 같습니다.

필드에서 정보를 가져 오지 않고 필드에 정보를 넣지 않는 메소드는 인스턴스 메소드 일 필요는 없습니다. 클래스 나 객체에서 필드를 사용하거나 변경하지 않는 메소드는 정적 메소드 일 수도 있습니다.