2011-02-01 4 views
17

나는 이클립스에서이 findbugs 경고와 함께 약간 혼란 스럽다.인스턴스 메소드의 정적 변수에 쓰는 것은 왜 나쁜 습관입니까?

public class MyClass { 
    public static String myString; 
} 


public class AnotherClass { 
    public void doSomething() { 
     MyClass.myString = "something"; 
    } 
} 

이 나에게, 그러나이 나에게 경고를주지 않는다 "인스턴스 메소드에서 정적 필드에 쓰기"경고 findbugs 제공 : 얼마나

public class MyClass { 
    public static String myString; 
} 


public class AnotherClass { 
    public void doSomething() { 
     doAnotherThing(); 
    } 
    public static doAnotherThing() { 
     MyClass.myString = "something"; 
    } 
} 

을이 어떤 다른?, 왜 쓰고있다 인스턴스 메서드에서 정적 변수에 나쁜 연습?, 나는 그것이 동기화와 관련이 있다고 가정하지만 여전히 나에게 분명하지 않다.

변수가 final이어야하는 것으로 알고 있지만 속성 파일에서 값을로드하고 있습니다.

답변

18

그것의 형태 :

그리고 findbugs는

+1

저는 동기가 아니라 정적 원리인지 여부에 관계없이 문제의 근본적인 근거로서 이해와 명확성에 중점을 두는 것을 좋아합니다. –

+0

@ 스티브 - 감사합니다. –

1

이것은 제 취복식이므로 소금 한 알씩 가져 가십시오. 이 경고의 주요 원인 인 동기화 문제에 대해 언급 한 바 있지만 더 중요한 것은 두 가지 경우가 서로 다른 개념의 "수준"의 데이터에서 근본적으로 작동한다는 것입니다. 인스턴스 메소드는 객체에 의해 "소유"되며 개별 인스턴스를 설명하는 데이터를 수정합니다. 클래스 메서드는 일반 작업이며 클래스와 관련되어 있지만 개별 개체와 관련이 없다고 명시합니다. 따라서 각 인스턴스 내에서 해당 상태를 수정하는 것은 아마도 (반드시 그런 것은 아님) 잘못된 설계 결정 일 수 있습니다.

4

정적 필드를 변경하려는 이유는 많지 않습니다. 이 필드를이 클래스의 모든 인스턴스에 대해이 값이 변경된 새 값으로 설정하면 기억하십시오. 두 개 이상의 스레드가 doSomething()을 호출하는 다중 스레드 환경에서 문제가 발생할 수 있습니다. 적절한 동기화가 필요합니다.

모든 경우의 99 %에서 인스턴스 메서드가 비 정적 필드 만 변경하면 findbugs가 경고하는 이유가됩니다. http://findbugs.sourceforge.net/bugDescriptions.html#ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD

3

이 FindBugs 이것에 대해 말을하는 것입니다 인스턴스 방법은 간접적으로 두 번째 예 :)의 필드 변경에 대해 알아 정도로 영리하지 않다 알리아싱은 반 직관적 일 수 있습니다. 카운터 직관적 인 코드는 유지 보수가 쉽지 않습니다.

논리적으로 인스턴스 메소드가 해당 인스턴스의 데이터에 영향을 주길 기대합니다. 정적 메소드가 정적 데이터에 영향을 줄 것으로 기대합니다. 이 코드의 독자는 즉시 ab의 인스턴스가 실제로 동일한 데이터에 영향을 미치고 있다는 사실을 인식하지 못할 수도있다

... 
a.initialize(); 
... 
b.initialize(); 
... 

:

은의이 doSomething initialize에 이름을 보자. 이것은 동일한 메모리를 두 번 초기화했기 때문에 버그 일 수 있지만 각 인스턴스마다 initialize을 호출해야 할 수도 있으므로 합당한 것처럼 보입니다.

그러나, 코드가 있었다 :이 경우

... 
MyClass.initialize(); 
... 
MyClass.initialize(); 
... 

, 그것보다 직관적 우리가 가능성이 같은 정적 데이터에 영향을주지하고,이 가능성이 버그입니다.

동일한 범위의 두 변수가 동일한 인스턴스를 가리키는 일반적인 버전의 별칭과 비슷합니다. 마지막 예를 들어


,

  • 인스턴스는 정적 메서드

    에 인스턴스 방법은 플래그를 인상 할 것으로 예상되지 않는 정적 메소드를 호출한다는 사실을 호출합니다. 예를 들어 이것은 문제가 될 가능성이있는 부분보다 훨씬 유용합니다.

  • 한 클래스의 정적 메소드가 어떤 의미에서 다른 클래스의 정적 데이터

    영향는 다른, 그러나 유사한 경고를 발생한다 : 하나 개의 클래스가 다른 클래스의 데이터 장난된다. 그러나 정적 변수 public을 암묵적으로 승인하는 방법이므로 이러한 경고는 필요하지 않습니다.

FindBugs는 가능한 모든 문제가 아니라 잠재적 인 문제를 코드에 간단히 표시하려고합니다. 첫 번째 예는 잠재적 인 유지 관리 문제로 실제 문제인지 여부를 조사해야합니다. 두 번째 예제는 문제가 아니거나 이 아닌의 사용 사례와 너무 비슷한 실제 문제 일 수 있습니다.

0

정적 필드를 변경하면 모든 인스턴스에 대해 변경되므로 올바르게 동기화되지 않으면 알려지지 않은 문제가 발생합니다.

공유 필드를 설정하기 위해 속성 파일을 읽는 경우 정적 방법으로 수행하십시오. 또는 필드를 다른 클래스가 읽을 수있는 별도의 싱글 톤 인스턴스로 리팩터링합니다. 하나의 인스턴스 만 가지려는 경우에는 싱글 톤 패턴을 사용하고 필드를 비 정적으로 만듭니다.

정적 메서드는 정적 데이터에만 영향을 주어야하며 인스턴스 메서드는 인스턴스 데이터에만 영향을 주어야합니다.

0

동기화 (여러 답변에서 언급 한 것)와 관련이 없다고 생각합니다. 결국 인스턴스 메서드처럼 쉽게 여러 메서드에서 정적 메서드를 호출 할 수 있습니다.

경고의 이유 (FindBugs 문서에서 잘 설명되지 않은)는 의심스럽고 실수 일 수 있다는 몇 가지 대답으로 암시한다고 생각합니다. Jochen Bedersdorfer와 마찬가지로 다른 인스턴스의 인스턴스 메서드에서 한 클래스의 정적 변수에 할당하려는 사용 사례가 많지 않습니다. 그냥

while (x = y) { 
    // ... 
} 

은 기술적으로 오류가 아닙니다. (사실 x와 y가 부울 인 경우 실제 Java가 아닙니다.) 거의 항상 실수입니다. 마찬가지로, FindBug의 저자는 주제에 관해서도 같은 것을 느꼈습니다.

관련 문제