인스턴스화하도록 설계된 클래스가 있다고 가정 해 봅시다. 클래스 내부에 클래스 멤버 중 하나에 액세스 할 필요가없는 몇 가지 개인 “도우미”메서드가 있으며 인수에 대해서만 작동하여 결과를 반환합니다.
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) {... }
}
지정하는 특별한 이유가 computeOne
및 computeMore
여부에 대한 특별한 이유 – 정적 방법으로는?
문제를 일으키지 않고 정적 일 수는 있지만 비 정적 상태로 두는 것이 가장 쉽습니다.
답변
그런 도우미 방법을 선호합니다 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 기사 이며, 기본적으로 방금 말한 내용을 다시 표시합니다.
이러한 명령어로 호출 된 메서드는 정적으로 바인딩되므로 가장 빠른 명령어는
invokespecial
andinvokestatic
일 가능성이 높습니다 . 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 */ }
}
답변
당신이 “전에”클래스 생성자를 호출해야하는 경우가 정적 도우미 메서드를 선언 할 수 있습니다 이유 중 하나는 this
나 super
. 예를 들면 다음과 같습니다.
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
경우 인스턴스 방법이 될 수는 없습니다.
답변
나는 개인 정적 메소드에 대한 분명한 장점을 생각할 수 없습니다. 즉, 정적이 아닌 것으로 만들면 특별한 이점이 없습니다. 주로 프레젠테이션의 문제입니다. 객체를 변경하지 않는다는 사실을 명확하게 강조하기 위해 정적으로 만들 수 있습니다.
다른 접근 권한을 가진 메소드의 경우 두 가지 주요 주장이 있다고 생각합니다.
- 객체의 인스턴스를 만들지 않고 정적 메서드를 호출 할 수 있습니다.
- 정적 메소드는 상속 될 수 없으며, 다형성이 필요한 경우 문제가 될 수 있습니다 (그러나 개인 메소드와는 관련이 없음).
게다가, 그 차이는 꽤 작으며,이 포인터가 인스턴스 메소드에 전달 한 여분의 차이가 크게 다르다는 것을 의심합니다.
답변
정답은 다음과 같습니다.
필드에서 정보를 가져 오지 않고 필드에 정보를 넣지 않는 메소드는 인스턴스 메소드 일 필요는 없습니다. 클래스 나 객체에서 필드를 사용하거나 변경하지 않는 메소드는 정적 메소드 일 수도 있습니다.