정적 변수는 왜 악으로 간주됩니까?


635

저는 회사 세계에 새로운 Java 프로그래머입니다. 최근에 Groovy 와 Java를 사용하여 응용 프로그램을 개발했습니다 . 내가 작성한 코드를 통해 꽤 많은 수의 정적을 사용했습니다. 수석 기술 부지에 사용 된 스태틱 수를 줄이라는 요청을 받았습니다. 나는 똑같은 것을 봤다. 많은 프로그래머가 정적 변수를 사용하는 것에 상당히 반대한다는 것을 알았다.

정적 변수를 사용하는 것이 더 편리하다는 것을 알았습니다. 그리고 클래스 내에서 함수를 10,000 번 호출 해야하는 경우 메소드를 정적으로 만들고 Class.methodCall()대신에 직접 사용하는 것이 좋을 것이기 때문에 그것들도 효율적이라고 생각합니다 (잘못되면 나를 정정하십시오) 클래스의 10,000 개의 인스턴스로 메모리를 어지럽히 는가?

또한 정적은 코드의 다른 부분에 대한 상호 종속성을 줄입니다. 그들은 완벽한 주주 역할을 할 수 있습니다. 이것에 덧붙여 스몰 토크스칼라 와 같은 일부 언어에서는 정적이 널리 구현되어 있습니다 . 그렇다면 왜 프로그래머들 사이에서 (특히 Java 세계에서) 정적에 대한 이러한 억압이 발생합니까?

추신 : 정적에 대한 나의 가정이 틀렸다면 저를 정정하십시오.


43
스몰 토크 나 스칼라에는 정적 메소드와 변수가 OOP 원칙에 위배되기 때문에 정적 변수 나 메소드가 없습니다.
Maurício Linhares

87
"정적은 코드의 다른 부분에 대한 상호 의존성을 줄입니다"라는 호기심이 생깁니다. 일반적으로 그들은 의존성을 강화합니다. 호출되는 코드는 호출 된 코드에 매우 밀접하게 바인딩됩니다. 직접적인 의존성 사이에 추상화가 없습니다.
Arne Deutsch

11
좋은 질문 ... 더 많은 프로그래머들 .SE 질문 tho?
WernerCD

26
두 번째 단락은 완전히 다른 주제, 즉 정적 메소드에 관한 것 입니다.
Paul

8
함수형 프로그래밍은 또한 글로벌 상태에 찌그러집니다. 당신이 경우 지금까지 (그리고 당신이 해야 일일 FP에 들어가), 글로벌 국가의 개념을 버려야 할 준비.
new123456

답변:


689

정적 변수는 전역 상태를 나타냅니다. 추론하기 어렵고 테스트하기가 어렵습니다. 객체의 새 인스턴스를 만들면 테스트 내에서 새로운 상태에 대해 추론 할 수 있습니다. 정적 변수를 사용하는 코드를 사용하면 모든 상태에있을 수 있으며 무엇이든 수정할 수 있습니다.

나는 꽤 오랫동안 계속할 수 있지만, 더 큰 개념은 생각의 범위가 좁을수록 추론하기가 쉽다는 것입니다. 우리는 작은 것들에 대해 잘 알고 있지만 모듈성이 없다면 백만 라인 시스템의 상태에 대해 추론하기는 어렵습니다. 이것은 정적 변수뿐만 아니라 모든 종류의 것들에 적용됩니다.


57
요즘 코드 테스트 가능 여부에 관계없이 논쟁의 여지가있는 것 같습니다. 다소 잘못된 추론입니다. 논쟁은 '좋은 디자인'이어야하며 일반적으로 좋은 디자인은 테스트 가능합니다. 그러나 다른 방법은 아닙니다. "나는 그것을 테스트 할 수 없기 때문에 나쁜 디자인이어야합니다." 그래도 오해하지 마십시오. 나는 일반적으로 귀하의 게시물에 동의합니다.
M Platvoet

144
@M Platvoet : 두 개의 동일하게 유효한 디자인 중에서 선택하면 테스트 할 수있는 디자인이 우수하다고 말할 수 있습니다. 테스트 가능한 것은 확실히 잘 설계된 것과 동일하지는 않지만 테스트 할 수없는 좋은 디자인을 거의 사용하지는 않았으며, 테스트 가능성 을 좋은 디자인에 대한 일반적인 목적을 제공하는 지표로 만드는 데 아무런 문제가 없다고 생각하는 경우는 거의 없습니다 .
Jon Skeet

9
@M Platvoet-테스트 가능성은 유지 관리 성과 신뢰성에 영향을 미치며, 디자인 품질의 주요 요소를 고려합니다. 그것들 만이 유일한 요소는 아니지만, 주어진 코드의 IMHO 비용은 머신 사이클, 개발자 사이클 및 사용자 사이클의 조합입니다. 테스트 가능성은이 세 가지 중 두 가지에 해당합니다.
저스틴 모건

5
@M Platvoet-분리 성 클래스는 일반적으로 재사용하기 쉬우므로 테스트 가능성도 재사용성에 영향을주는 경향이 있습니다.
TrueWill

13
M Platvoet-나는 당신의 첫 의견에 동의하지 않습니다. 무언가를 테스트 할 수 없다면 나쁜 디자인이라고 생각합니다. 테스트 할 수 없으면 제대로 작동하는지 알 수 없기 때문입니다. 영업 사원이 "이 모델의 디자인으로 인해 테스트가되지 않아 실제로 작동하는지 모르겠습니다"라고 말하면 자동차를 사겠습니까? 테스트 가능성은 소프트웨어 (차뿐만 아니라)에있어서 매우 중요하며, 디자인이 포함되어야하는 유능한 디자인이 필요합니다.
Dawood ibn Kareem

277

객체 지향적이지 않음 : 일부 사람들이 정적을 "악"으로 간주 할 수있는 한 가지 이유는 객체 지향 패러다임 과 반대되는 것입니다. 입니다. 특히, 데이터가 개체 (캡처, 정보 숨기기 등)에 캡슐화되어 있다는 원칙을 위반합니다. 정적을 사용하여 설명하는 방식은 본질적으로 범위와 같은 문제를 처리하지 않기 위해 전역 변수로 사용하는 것입니다. 그러나 전역 변수는 "좋은"객체 지향 코드의 특성이 아닌 절차 적 또는 명령형 프로그래밍 패러다임의 정의 특성 중 하나입니다. 이것은 절차 적 패러다임이 나쁘다는 것은 아니지만 감독자가 "좋은 객체 지향 코드"를 작성하고 실제로 "

항상 명백하지 않은 정적을 사용하기 시작할 때 Java에는 많은 단점이 있습니다. 예를 들어, 동일한 VM에서 두 개의 프로그램 사본이 실행중인 경우 정적 변수의 값을 잘라 내고 서로의 상태를 망칠 수 있습니까? 또는 클래스를 확장하면 어떻게됩니까? 정적 멤버를 재정의 할 수 있습니까? 많은 수의 스태틱이 있고 필요한 다른 인스턴스 객체에 대해 메모리를 회수 할 수 없기 때문에 VM에 메모리가 부족합니까?

객체 수명 : 또한 정적은 프로그램의 전체 런타임과 일치하는 수명을 갖습니다. 즉, 클래스를 사용한 후에도 모든 정적 변수의 메모리를 가비지 수집 할 수 없습니다. 예를 들어, 대신 변수를 비 정적 상태로 만들고 main () 함수에서 클래스의 단일 인스턴스를 만든 다음 10,000 번의 호출이 완료되면 클래스에 특정 함수를 10,000 번 실행하도록 요청한 경우 단일 인스턴스에 대한 참조를 삭제하면 모든 정적 변수가 가비지 수집되어 재사용 될 수 있습니다.

특정 재사용 방지 : 또한 정적 메소드를 사용하여 인터페이스를 구현할 수 없으므로 정적 메소드를 사용하면 특정 객체 지향 기능을 사용할 수 없습니다.

다른 옵션: 효율성이 주요 관심사 인 경우 일반적으로 작성보다 빠른 호출의 이점 만 고려하는 것보다 속도 문제를 해결하는 다른 더 좋은 방법이있을 수 있습니다. 언제 어디서나 과도 또는 휘발성 수정자가 필요한지 고려하십시오. 인라인 기능을 유지하기 위해 메소드를 정적 대신 최종으로 표시 할 수 있습니다. 메소드 매개 변수 및 기타 변수를 최종으로 표시하여 해당 변수를 변경할 수있는 항목에 대한 가정을 기반으로 특정 컴파일러 최적화를 허용 할 수 있습니다. 매번 새 인스턴스를 작성하는 대신 인스턴스 오브젝트를 여러 번 재사용 할 수 있습니다. 앱에 일반적으로 켜져 있어야하는 컴파일러 최적화 스위치가있을 수 있습니다. 아마도 10,000 번의 실행이 다중 스레드가 가능하고 다중 프로세서 코어를 활용할 수 있도록 설계를 설정해야합니다. 만약 portablity가

어떤 이유로 객체의 여러 복사본을 원하지 않으면 단일 디자인 패턴, 스레드 안전성 (단일 코드가 잘 코딩 된 것으로 가정)과 같은 정적 객체에 비해 이점이 있으며, 지연 초기화가 가능하며, 객체가 사용될 때 객체가 올바르게 초기화되었는지 확인, 서브 클래 싱, 코드 테스트 및 리팩토링의 이점, 말할 것도없이, 어느 시점에서 하나의 객체 인스턴스 만 원한다는 생각이 바뀌면 인스턴스 변수를 사용하기 위해 모든 정적 변수 코드를 리팩토링하는 것보다 중복 인스턴스를 방지하기 위해 코드를 제거하는 것이 훨씬 쉽습니다. 전에는 그렇게하지 않았지만 재미 있지 않았으므로 더 많은 클래스를 편집해야하므로 새로운 버그가 발생할 위험이 높아집니다. 처음에 "올바른"설정을하는 것이 훨씬 좋습니다. 그것이 단점이있는 것처럼 보이더라도. 나를 위해 여러 개의 사본이 필요한 길을 결정할 때 필요한 재 작업은 가능한 한 자주 정적을 사용하는 가장 큰 이유 중 하나 일 것입니다. 따라서 정적 함수가 상호 의존성을 줄인다는 귀하의 진술에 동의하지 않을 것입니다. "어떻게 수행해야하는지 알고있는 객체가 아니라 직접 액세스 할 수있는 정적 요소가 많으면 더 많은 코드가 연결될 것입니다." 그 자체로 "


11
귀하의 답변이 마음에 듭니다. 동시성 및 범위와 같은 빨간 청어보다는 정적 인 요소를 고려하는 것이 타협점에 초점을 맞추고 있다고 생각합니다. 싱글 톤의 경우 +1, 더 좋은 질문은 정적 변수 / 메소드와 싱글 톤을 사용할 때 실제로있을 수 있습니다.
studgeek

2
싱글 톤 자체가 스레드로부터 안전 할 수 있지만 (예 : synchronized메소드 사용 ) 호출 코드에 싱글 톤 상태에 대한 경쟁 조건이없는 것은 아닙니다.
André Caron

8
또한 정적은 OOP 패러다임에 위배되지 않습니다. 많은 OOP 광신자들은 클래스가 객체이고 정적 메소드는 인스턴스가 아니라 클래스 객체의 메소드임을 알려줍니다. 이 현상은 Java에서 덜 존재합니다. Python과 같은 다른 언어를 사용하면 클래스를 변수로 사용하고 해당 객체의 메서드로 정적 메서드에 액세스 할 수 있습니다.
André Caron

4
내가 실수하지 않으면 세 번째 단락의 마지막 줄에 모든 비 정적 변수를 읽어야 합니다 .
Steve

1
Object Lifetime@jessica이 언급 한 매우 중요한 점 중 하나입니다.
Abhidemon

93

악은 주관적인 용어입니다.

생성 및 소멸 측면에서 정적을 제어하지 않습니다. 그들은 프로그램 로딩 및 언 로딩에 따라 움직입니다.

정적은 하나의 공간에 존재하므로이를 사용하려는 모든 스레드는 관리해야하는 액세스 제어를 거쳐야합니다. 이것은 프로그램이 더 결합되어 있으며 이러한 변화는 J Skeet과 같이 계획하고 관리하기가 더 어렵다는 것을 의미합니다. 이로 인해 변경 영향을 분리하는 데 문제가 발생하여 테스트 관리 방법에 영향을줍니다.

이것들은 내가 가진 두 가지 주요 문제입니다.


59

아닙니다. 세계 국가들은 그 자체로 악이 아닙니다. 그러나 우리는 볼 수 있습니다 당신의 당신이 그것을 제대로 사용하면 코드를 볼 수 있습니다. 초보자가 전 세계 국가를 학대 할 가능성이 있습니다. 모든 언어 기능을 남용하는 것처럼 말입니다.

세계 국가는 절대적으로 필요합니다. 우리는 세계 상태를 피할 수 없습니다. 우리는 세계 국가에 대한 추론을 피할 수 없습니다. -응용 프로그램 의미를 이해하려는 경우

이를 위해 세계 국가를 없애려고 노력하는 사람들은 필연적으로 훨씬 더 복잡한 시스템으로 끝납니다. 세계 국가는 여전히 여러 층의 간접적 지시 아래 현명하게 / 아이디 오로 위장되어 있습니다. 우리는 모든 간접 지시를 풀고 난 후에도 여전히 세계 국가에 대해 추론해야합니다.

xml로 멋지게 글로벌 상태를 선언하고 어떻게 든 우수하다고 생각하는 Spring 사람들처럼.

@Jon Skeet은 if I create a new instance of an object이제 객체 내부의 상태와 객체를 호스팅하는 환경의 상태에 대해 두 가지를 고려해야합니다.


10
"추론해야 할 두 가지가 있습니다." 테스트를 객체 상태에만 의존하게 만들지 않습니다. 어느 것이 쉬운 지, 내가 가진 덜 세계적인 상태입니다.
DJClayworth

2
의존성 주입은 전역 상태 또는 전역 가시성과 아무 관련이 없으며 컨테이너 자체도 전역이 아닙니다. "일반"코드와 비교하여 컨테이너 관리 대상 객체가 보이는 유일한 추가 사항은 컨테이너 자체입니다. 실제로 DI는 싱글 톤 패턴을 피하기 위해 매우 일반적으로 사용됩니다.
Floegipoky 2016

31

정적 변수에는 두 가지 주요 문제가 있습니다.

  • 스레드 안전성-정적 리소스는 정의상 스레드 안전성이 아닙니다.
  • 코드 내 재성-정적 변수가 인스턴스화되는시기와 다른 정적 변수보다 먼저 인스턴스화되는지 여부를 알 수 없음

Jon Skeet이 귀하가 게시 한 것과 동일한 의견을 언급 한 것 같습니다.
RG-3

13
나는 스레드 안전 포인트를 얻지 못합니다. 그렇지 않으면 스레드 안전은 없다고 생각합니다. 이것은 정적 인 것과 전혀 관련이없는 것 같습니다. 내가 누락 된 경우 수정하십시오.
Zmaster

1
@Zmaster - 그것은 스레드 안전, 정적 변수에 대한 문제 배타적이지 것은 사실이지만 자신의 정의에 의해 그들은에서 다른 컨텍스트에서 호출 할 수 있기 때문에, 그들에게 더 자두입니다
sternr

2
@sternr "다른 컨텍스트"가 "다른 스레드"와 필연적으로 동일하지 않은 경우 이벤트의 의미를 이해합니다. 그러나 스레드 안전은 종종 정적 리소스와 함께 고려되어야합니다. 문장을 명확히하는 것을 고려해야합니다.
Zmaster

예를 들어 정적 리소스의 유효한 스레드 안전 사용이 있습니다. 개인 정적 최종 로거 LOG = Logger.getLogger (Foo.class); private static final AtomicInteger x = 새로운 AtomicInteger (0); 내가 알기로, 이와 같은 리소스의 정적 할당은 클래스 로더에 의해 스레드 안전을 보장합니다. Logger 인스턴스는 포인터를 할당하는 위치와 독립적으로 스레드로부터 안전하지 않습니다. 정적 상태를 유지하는 것은 좋은 생각이 아니지만 스레드로부터 안전하지 않아야 할 이유는 없습니다.
teknopaul

29

'final'키워드없이 'static'키워드를 사용하는 경우 디자인을 신중하게 고려해야한다는 신호입니다. 변경 가능한 정적 최종 객체가 위험 할 수 있기 때문에 '최종'의 존재조차도 자유 패스가 아닙니다.

나는 '최종'이없는 '정적'을 볼 때의 약 85 % 어딘가에 추정 할 것입니다. 종종 이러한 문제를 숨기거나 숨기는 이상한 해결 방법을 찾을 수 있습니다.

정적 변수를 만들지 마십시오. 특히 컬렉션. 일반적으로 컬렉션은 포함하는 객체가 초기화 될 때 초기화되어야하며 포함하는 객체를 잊었을 때 재설정되거나 잊혀지도록 설계되어야합니다.

스태틱을 사용하면 매우 미묘한 버그가 생겨 엔지니어에게 고통을 줄 수 있습니다. 나는이 버그를 만들고 사냥했기 때문에 알고 있습니다.

자세한 내용은 다음을 참조하십시오.

왜 정적을 사용하지 않습니까?

테스트 작성 및 실행은 물론 눈에 띄지 않는 미묘한 버그를 포함하여 정적 관련 문제가 많이 있습니다.

정적 객체에 의존하는 코드는 쉽게 단위 테스트를 할 수 없으며 정적을 쉽게 조롱 할 수 없습니다 (보통).

정적을 사용하는 경우 더 높은 수준의 구성 요소를 테스트하기 위해 클래스 구현을 교체 할 수 없습니다. 예를 들어 데이터베이스에서로드하는 Customer 객체를 반환하는 정적 CustomerDAO를 상상해보십시오. 이제 CustomerFilter 클래스가 있는데,이 클래스는 일부 Customer 객체에 액세스해야합니다. CustomerDAO가 정적이면 먼저 데이터베이스를 초기화하고 유용한 정보를 채우지 않고 CustomerFilter에 대한 테스트를 작성할 수 없습니다.

데이터베이스 채우기 및 초기화에 시간이 오래 걸립니다. 내 경험상 DB 초기화 프레임 워크는 시간이 지남에 따라 변경되므로 데이터가 변형되고 테스트가 중단 될 수 있습니다. IE는 고객 1이 VIP 였지만 DB 초기화 프레임 워크가 바뀌었고 이제 고객 1은 더 이상 VIP가 아니라고 테스트했지만 고객 1을로드하도록 테스트를 하드 코딩했습니다.

더 좋은 방법은 CustomerDAO를 인스턴스화하여 생성 될 때 CustomerFilter에 전달하는 것입니다. (더 나은 접근 방식은 Spring 또는 다른 Inversion of Control 프레임 워크를 사용하는 것입니다.

이 작업을 수행하면 CustomerFilterTest에서 대체 DAO를 신속하게 조롱하거나 스터브 아웃 할 수 있으므로 테스트를보다 효과적으로 제어 할 수 있습니다.

정적 DAO가 없으면 테스트가 더 빠르며 (db 초기화 없음) 더 안정적입니다 (db 초기화 코드가 변경 될 때 실패하지 않기 때문에). 예를 들어,이 경우 테스트 1과 관련하여 고객 1은 항상 VIP가됩니다.

테스트 실행

정적은 단위 테스트 세트를 함께 실행할 때 (예 : Continuous Integration 서버에서) 실제 문제를 일으 킵니다. 한 테스트에서 다른 테스트로 열려있는 네트워크 소켓 객체의 정적 맵을 상상해보십시오. 첫 번째 테스트는 포트 8080에서 소켓을 열 수 있지만 테스트가 종료 될 때 맵을 지우는 것을 잊었습니다. 이제 두 번째 테스트가 시작되면 포트가 여전히 점유되어 있기 때문에 포트 8080에 대한 새 소켓을 만들려고 할 때 충돌이 발생할 수 있습니다. 정적 컬렉션의 소켓 참조가 제거되지 않고 WeakHashMap을 제외하고는 가비지 수집 대상이되지 않아 메모리 누수가 발생한다고 상상해보십시오.

이것은 지나치게 일반화 된 예이지만 대규모 시스템에서는이 문제가 항상 발생합니다. 사람들은 단위 테스트가 동일한 JVM에서 소프트웨어를 반복적으로 시작하고 중지하는 것을 생각하지 않지만, 소프트웨어 디자인에 대한 좋은 테스트이며, 고 가용성에 대한 열망이있는 경우이를 알아야합니다.

이러한 문제는 종종 DB 액세스, 캐싱, 메시징 및 로깅 계층과 같은 프레임 워크 개체에서 발생합니다. Java EE 또는 최상의 품종 프레임 워크를 사용하는 경우 아마도이를 위해 많은 것을 관리하지만 레거시 시스템을 다루는 경우 이러한 계층에 액세스하기위한 많은 사용자 정의 프레임 워크가있을 수 있습니다.

이러한 프레임 워크 구성 요소에 적용되는 시스템 구성이 단위 테스트간에 변경되고 단위 테스트 프레임 워크가 구성 요소를 분리 및 재 구축하지 않으면 이러한 변경 사항이 적용되지 않으며 테스트가 해당 변경 사항에 의존하면 실패합니다. .

비 프레임 워크 구성 요소도이 문제의 영향을받습니다. OpenOrders라는 정적지도를 상상해보십시오. 하나의 테스트를 작성하여 미결 주문을 작성하고 모두 올바른 상태인지 확인한 다음 테스트를 종료합니다. 다른 개발자는 필요한 주문을 OpenOrders 맵에 넣는 두 번째 테스트를 작성한 다음 주문 수가 정확하다고 주장합니다. 개별적으로 실행하면 이러한 테스트는 모두 통과되지만 스위트에서 함께 실행하면 실패합니다.

더 나쁜 것은 실패는 테스트가 실행 된 순서에 따라 결정될 수 있습니다.

이 경우 정적을 피함으로써 테스트 인스턴스 전체에서 데이터가 지속될 위험을 피하여 테스트 안정성을 향상시킬 수 있습니다.

미묘한 버그

고 가용성 환경에서 작업하거나 스레드가 시작 및 중지 될 수있는 곳에서 작업하는 경우 코드가 프로덕션 환경에서 실행될 때 유닛 테스트 스위트와 동일한 문제가 적용될 수 있습니다.

정적 객체를 사용하여 데이터를 저장하는 대신 스레드를 처리 할 때는 스레드 시작 단계에서 초기화 된 객체를 사용하는 것이 좋습니다. 이렇게하면 스레드가 시작될 때마다 새로운 잠재적 개체 구성을 가진 객체의 새 인스턴스가 만들어지고 스레드의 한 인스턴스에서 다음 인스턴스로 데이터가 번지는 것을 피할 수 있습니다.

스레드가 죽으면 정적 객체는 재설정되거나 가비지 수집되지 않습니다. "EmailCustomers"라는 스레드가 있고 시작시 정적 문자열 콜렉션을 이메일 주소 목록으로 채우고 각 주소로 이메일을 보내기 시작한다고 가정하십시오. 스레드가 어떻게 든 중단되거나 취소되었다고 가정하면 고 가용성 프레임 워크가 스레드를 다시 시작합니다. 그런 다음 스레드가 시작되면 고객 목록을 다시로드합니다. 그러나 모음은 정적이므로 이전 모음의 전자 메일 주소 목록이 유지 될 수 있습니다. 이제 일부 고객은 이메일이 중복 될 수 있습니다.

제쳐두고 : 정적 결승

기술적 인 구현상의 차이가 있지만 "정적 최종"의 사용은 사실상 C #define과 동등한 Java입니다. AC / C ++ #define은 컴파일 전에 프리 프로세서에 의해 코드에서 교체됩니다. Java "정적 최종"은 스택에 상주하는 메모리를 종료합니다. 이런 식으로 C ++의 "정적 const"변수와 #define보다 유사합니다.

요약

이것이 정적이 문제가되는 몇 가지 기본 이유를 설명하는 데 도움이되기를 바랍니다. Java EE 또는 Spring 등과 같은 최신 Java 프레임 워크를 사용하는 경우 이러한 상황이 많이 발생하지 않을 수 있지만 많은 레거시 코드로 작업하는 경우 훨씬 더 빈번해질 수 있습니다.


15

아무도 언급하지 않았으므로 동시성. 정적 변수를 읽고 쓰는 스레드가 여러 개인 경우 정적 변수가 놀라 울 수 있습니다. 이것은 웹 응용 프로그램 (예 : ASP.NET)에서 일반적이며 다소 치명적인 버그를 일으킬 수 있습니다. 예를 들어, 페이지에 의해 업데이트되는 정적 변수가 있고 "거의 거의 동시에"두 사람이 페이지를 요청하면 한 사용자가 다른 사용자가 예상 한 결과를 얻거나 더 나빠질 수 있습니다.

statics는 코드의 다른 부분에 대한 상호 종속성을 줄입니다. 그들은 완벽한 국가 보유자 역할을 할 수 있습니다

잠금을 사용하고 경합을 다룰 준비가 되었기를 바랍니다.

* 사실 Preet Sangha가 언급했습니다.


5
인스턴스 변수는 정적에 비해 스레드 안전성 이점이 없으며 모두 보호되지 않은 변수입니다. 대신, 모든 변수에 액세스하는 코드를 보호하는 방법이 중요합니다.
studgeek

2
나는 그렇게 주장하지는 않았지만 토론을 위해 분리는 보호의 한 형태입니다. 스레드 상태는 분리됩니다. 글로벌 상태는 아닙니다 . 인스턴스 변수는 스레드간에 명시 적으로 공유되지 않는 한 보호 가 필요 하지 않습니다 . 정적 변수는 프로세스의 모든 스레드 가 항상 공유합니다.
Justin M. Keyes

스레드 정적 변수는 모든 래핑 계층을 통해 해당 정보를 전달하지 않고도 래핑 된 서브 루틴 호출에 정보를 안전하게 제공하는 데 매우 유용 할 수 있기 때문에 일류 개념이 되었으면합니다. 예를 들어, 객체에 스레드의 현재 그래픽 컨텍스트로 렌더링하는 메서드가 있고 현재 그래픽 컨텍스트를 저장 / 복원하는 메서드가있는 경우 모든 메서드 호출을 통해 그래픽 컨텍스트를 전달하는 것보다 더 깔끔 할 수 있습니다.
supercat

15

Java에서 정적 메소드 사용의 몇 가지 기본 장점 및 단점을 요약하면 다음과 같습니다.

장점 :

  1. 전역 적으로 액세스 가능합니다. 즉, 특정 객체 인스턴스와 연결되지 않습니다.
  2. JVM 당 하나의 인스턴스.
  3. 클래스 이름을 사용하여 액세스 할 수 있습니다 (객체가 필요 없음).
  4. 모든 인스턴스에 적용 가능한 단일 값을 포함합니다.
  5. JVM 시작시로드되어 JVM 종료시 종료됩니다.
  6. Object의 상태를 수정하지 않습니다.

단점 :

  1. 정적 멤버는 사용 중인지 여부에 관계없이 항상 메모리의 일부입니다.
  2. 정적 변수의 생성 및 소멸을 제어 할 수 없습니다. 프로그램을로드 할 때 작성되어 프로그램을 언로드 할 때 (또는 JVM이 종료 될 때) 소멸되었습니다.
  3. 동기화를 사용하여 정적 스레드를 안전하게 만들 수 있지만 추가 노력이 필요합니다.
  4. 한 스레드가 다른 스레드의 기능을 손상시킬 수있는 정적 변수의 값을 변경하는 경우
  5. 사용하기 전에“정적”을 알아야합니다.
  6. 정적 메소드를 대체 할 수 없습니다.
  7. 직렬화는 제대로 작동하지 않습니다.
  8. 런타임 다형성에 참여하지 않습니다.
  9. 많은 수의 정적 변수 / 메소드가 사용되면 메모리 문제가 있습니다 (어쨌든 나는 추측하지 않습니다). 프로그램이 종료 될 때까지 가비지 수집되지 않기 때문입니다.
  10. 정적 메소드도 테스트하기가 어렵습니다.

단점 6, 7, 8 및 10은 사용 된 언어 / 프레임 워크의 단점이며 일반적으로 정적 변수의 단점은 아닙니다. 단점 1, 4 및 5는 일부 프레임 워크에서 제공하는 일부 단일 패턴과 같은 다른 솔루션에도 존재합니다. (나는 나머지에 동의하기 때문에 답변에 투표하지 않았다. 그리고 그것은 훌륭한 컬렉션이다.)
peterh-Monica Monica Reinstate Monica

13

클래스 내에서 함수를 10,000 번 호출 해야하는 경우 메소드를 정적으로 만들고 클래스의 10,000 인스턴스로 메모리를 어지럽히는 대신 간단한 class.methodCall ()을 사용하는 것이 좋을 것입니다.

상태를 가진 객체로 데이터를 캡슐화 할 필요성과 일부 데이터의 함수 결과를 단순히 계산할 필요성 간의 균형을 맞춰야합니다.

또한 정적은 코드의 다른 부분에 대한 상호 종속성을 줄입니다.

캡슐화도 마찬가지입니다. 대규모 애플리케이션에서 정적은 스파게티 코드를 생성하는 경향이 있으며 리팩토링 또는 테스트를 쉽게 허용하지 않습니다.

다른 답변은 과도한 정적 사용에 대한 합당한 이유를 제공합니다.


13

정적 변수는 일반적으로 전역 상태를 나타내므로 추론하기가 훨씬 어렵 기 때문에 나쁜 것으로 간주됩니다. 특히 객체 지향 프로그래밍의 가정을 어 기고 있습니다. 객체 지향 프로그래밍에서 각 객체는 인스턴스 (비 정적) 변수로 표시되는 자체 상태를 갖습니다. 정적 변수는 인스턴스 테스트에서 훨씬 더 어려울 수있는 인스턴스 전체의 상태를 나타냅니다. 정적 변수에 대한 변경 사항을 단일 테스트로 분리하기가 더 어렵 기 때문입니다.

즉, 일반 정적 변수 (일반적으로 불량으로 간주 됨)와 최종 정적 변수 (AKA 상수, 그렇게 나쁘지 않음)를 구분하는 것이 중요합니다.


4
"정적 변수는 클래스 전체의 상태를 나타냅니다"... "정적 변수는 인스턴스 전체의 상태를 나타냅니다"를 의미한다고 생각하십니까? "최종 정적 AKA 상수, 그렇게 나쁘지 않음"에 대해 +1 가치는 변할 수 없기 때문에, 한 시점에서 그 가치에 의존하는 것은 나중에 그 행동을 암시 적으로 변화시킬 수 없습니다. 가치는 같습니다.
Jared Updike

"정적 변수는 인스턴스 전체의 상태를 나타냅니다."가 훨씬 나은 방법입니다. 내 답변을 편집했습니다.
Jack Edmonds

9

내 생각에 그것은 성능에 관한 것이 아니며 디자인에 관한 것입니다. 정적 변수 사용으로 인해 정적 메소드 사용이 잘못되었다고 생각하지 않습니다 (그러나 실제로 메소드 호출에 대해 이야기하고 있다고 생각합니다).

단순히 논리를 분리하고 좋은 장소를 제공하는 방법에 관한 것입니다. 때로는 정적 메소드를 사용하는 java.lang.Math것이 좋은 예입니다. 수업 대부분의 이름을 정 XxxUtil하거나 Xxxhelper디자인을 더 잘 생각하면 좋을 것 같습니다.


3
순수한 부작용이없는 정적 방법은 완벽하게 훌륭한 IMO입니다. 그러나 글로벌 가변 상태는 거의 없으며 OP를 글로벌 상태에 대해 말하는 것으로 해석합니다.
코드 InChaos

1
@CodeInChaos는 전적으로 동의합니다. 정적 메소드와 vars의 차이점에 대해 OP가 완전히 명확하지 않다는 것을 알았습니다.
M Platvoet

8

나는 대답에서 이루어진 몇 가지 요점을 요약했습니다. 당신이 잘못 발견하면 자유롭게 수정하십시오.

스케일링 : JVM 당 정확히 하나의 정적 변수 인스턴스가 있습니다. 라이브러리 관리 시스템을 개발 중이고 책당 하나만 있기 때문에 책 이름을 정적 변수로 설정하기로 결정했다고 가정하십시오. 그러나 시스템이 커지고 여러 JVM을 사용하고 있다면 어떤 책을 다루고 있는지 알 수있는 방법이 없습니까?

스레드 안전성 : 다중 스레드 환경에서 사용되는 경우 인스턴스 변수와 정적 변수를 모두 제어해야합니다. 그러나 인스턴스 변수의 경우 스레드간에 명시 적으로 공유되지 않는 한 보호가 필요하지 않지만 정적 변수의 경우 프로세스의 모든 스레드가 항상 공유합니다.

테스트 : 테스트 가능한 디자인은 좋은 디자인과 같지 않지만 테스트 할 수없는 좋은 디자인은 거의 관찰되지 않습니다. 정적 변수는 전역 상태를 나타내므로 테스트하기가 매우 어렵습니다.

상태에 대한 추론 : 클래스의 새 인스턴스를 만들면이 인스턴스의 상태에 대해 추론 할 수 있지만 정적 변수가있는 경우 모든 상태에있을 수 있습니다. 왜? 정적 변수가 인스턴스간에 공유되므로 정적 변수가 일부 다른 인스턴스에 의해 수정되었을 수 있습니다.

직렬화 : 직렬화도 제대로 작동하지 않습니다.

창조와 파괴 : 정적 변수의 생성 및 파괴는 제어 할 수 없습니다. 일반적으로 프로그램로드 및 언로드 시간에 작성 및 삭제됩니다. 이는 메모리 관리에 좋지 않으며 시작시 초기화 시간을 추가한다는 의미입니다.

그러나 우리가 정말로 필요하다면?

그러나 때때로 우리는 그것들을 진정으로 필요로 할 수 있습니다. 응용 프로그램에서 공유되는 많은 정적 변수가 필요하다고 생각되면 하나의 옵션은 이러한 모든 변수를 갖는 Singleton Design 패턴을 사용하는 것입니다. 또는 이러한 정적 변수를 가지고 전달 될 수있는 객체를 만들 수 있습니다.

또한 정적 변수가 final로 표시되면 상수가되고 한 번 할당 된 값을 변경할 수 없습니다. 그것은 그것이 우리의 가변성으로 인해 직면 한 모든 문제들로부터 우리를 구원 할 것이라는 것을 의미합니다.


7

정적 변수에 대해 묻고 있지만 예제에서 정적 메서드를 지적하는 것 같습니다.

정적 변수는 사악하지 않습니다. 대부분의 경우 최종 수정 자와 결합 된 상수와 같은 전역 변수로 채택되지만 과용하지는 않습니다.

정적 방법 일명 유틸리티 방법. 그것들을 사용하는 것은 일반적으로 나쁜 습관은 아니지만 주요 관심사는 그들이 방해 할 수 있다는 것입니다 테스트를 입니다.

많은 정적을 사용하고 올바른 방법으로하는 훌륭한 Java 프로젝트의 예로서 Play 를보십시오 ! 프레임 워크 . SO에 대한 토론 도 있습니다 .

정적 가져 오기와 결합 된 정적 변수 / 메소드는 java에서 선언적 프로그래밍을 용이하게하는 라이브러리에서 쉽게 사용됩니다 : make it easy 또는 Hamcrest . 많은 정적 변수와 메소드가 없으면 불가능합니다.

따라서 정적 변수 (및 메소드)는 좋지만 현명하게 사용하십시오!


6

정적 변수는 데이터 보안에 문제를 발생시키는 것이 가장 중요합니다 (언제든지 변경, 누구나 변경 가능, 개체없이 직접 액세스 등).

자세한 내용은 감사를 읽으십시오 .


6

정적 변수를 사용하는 대부분의 경우 실제로 singleton pattern을 사용하고 싶습니다 .

전역 상태의 문제점은 때로는 단순한 컨텍스트에서 전역으로 의미가있는 것이 실제 상황에서 약간 더 유연해야하며 이것이 싱글 톤 패턴이 유용하게되는 것입니다.


5

또 다른 이유 : 취약성.

수업이 있다면 대부분의 사람들은 수업을 만들고 마음대로 사용할 수 있기를 기대합니다.

사례를 문서화하거나 사례로부터 보호 할 수 있지만 (단일 / 공장 패턴) 추가 작업이므로 추가 비용이 발생합니다. 그럼에도 불구하고 대기업에서 누군가는 어떤 좋은 점이나 공장에 완전히주의를 기울이지 않고 어느 시점에서 수업을 사용하려고 시도 할 가능성이 있습니다.

정적 변수를 많이 사용하면 중단됩니다. 버그는 비싸다.

잠재적 인 실마리가없는 개발자가 .0001 %의 성능 향상과 견고성을 변화시키는 경우가 많지만 견고성이 좋은 선택입니다.


4

정적 변수를 사용하는 것이 더 편리하다는 것을 알았습니다. 그리고 클래스 내에서 함수를 10,000 번 호출 해야하는 경우 메소드를 정적으로 만들고 간단한 클래스를 사용하게되어 기쁩니다. 10,000 개의 클래스 인스턴스로 메모리를 어지럽히는 대신에, 그렇지 않습니까?

나는 당신이 어떻게 생각하는지 알지만, 간단한 싱글 톤 패턴은 10,000 개체를 인스턴스화하지 않고도 똑같이 할 것입니다.

정적 메서드는 객체 도메인과 관련이 있고 객체의 내부 속성을 필요로하지 않거나 사용하지 않는 함수에만 사용할 수 있습니다.

전의:

public class WaterContainer {
    private int size;
    private int brand;
    ...etc

    public static int convertToGallon(int liters)...

    public static int convertToLiters(int gallon)...

}

고전적인 싱글 톤 (즉,에 의해 액세스되는 것 Class.Instance)은 정적 변수보다 낫습니다. 테스트가 약간 더 가능하지만 하나만 가정하여 코드를 작성하는 대신 단일 인스턴스를 생성하는 디자인보다 훨씬 나쁩니다.
코드 InChaos

귀하의 의견을 이해하지 못했습니다! 나는 10 000 개의 객체를 인스턴스화하는 것에 대해 그가 이탤릭체로 말한 것에 대해 OP에 응답하고있었습니다. 싱글 톤과 정적 변수를 비교하는 이유를 이해하지 못합니까? 내가 당신이 쓴 것에서 이해하는 것은 Singleton이 나쁜 디자인이라는 것입니다 ...! Spring Framework는 기본적으로 모든 콩을 싱글 톤 ;-)로 만들었 기 때문에 당신을 오해하는 것
같습니다 .-)

Class.Instance변경 가능한 상태를 전달 하는 클래식 싱글 톤 ( )은 잘못된 디자인 IMO입니다. 이 경우 싱글 톤을 얻는 디자인을 선호합니다.이를 사용하는 클래스에 매개 변수로 전달해야합니다 (일반적으로 DI의 도움으로). 논리적으로 불변의 클래식 싱글 톤은 훌륭한 IMO입니다.
코드 InChaos

@ Cygnusx1 클래스 싱글 톤 (클래스가 단일 사본을 보장하는 싱글 톤)이 쉽게 테스트 할 수없는 이유가 확실하지 않은 경우 클래스 존재를 프로그램의 라이프 사이클에 긴밀하게 연결합니다. 이를 테스트하려면 프로그램의 시작 및 종료를 준수해야하며, 이는 종종 클래스 테스트에 중요하지 않은 부작용이 있습니다. 효과적으로 단일 프로그램 (프로그램에 하나의 사본이지만 다른 방식으로 시행되지는 않음) 인 경우 프로그램없이 테스트 시간에 여러 사본을 작성하여 클래스 전체의 동작이 각 테스트 시나리오마다 맞는지 확인할 수 있습니다.
Edwin Buck

4

'정치적 악'이라는 문제는 세계 국가에 대한 문제입니다. 변수가 정적이되는 적절한 시간은 둘 이상의 상태가없는 경우입니다. 전체 프레임 워크에서 액세스 할 수 있어야하고 동일한 메소드 호출에 대해 항상 동일한 결과를 리턴하는 IE 도구는 정적 요소와 '사악'하지 않습니다. 귀하의 의견에 관해서 :

정적 변수를 사용하는 것이 더 편리하다는 것을 알았습니다. 그리고 나는 그들이 또한 효율적이라고 생각합니다

정적은 변하지 않는 변수 / 클래스에 이상적이고 효율적인 선택입니다. .

글로벌 상태의 문제는 그것이 만들 수있는 본질적인 불일치입니다. 여러 관련되지 않은 여러 개체가 액세스 할 수있는 전역 상태가있을 때마다 단위 테스트가 불완전하고 '단위'가 아닌 단위 테스트에 대한 문서가 종종이 문제를 해결합니다. 전역 상태 및 싱글 톤 에 대한이 기사에서 언급 한 것처럼 객체 A와 B가 서로 관련이없는 경우 (하나는 명시 적으로 다른 것을 참조하지 않음) A는 B의 상태에 영향을 줄 수 없습니다.

시계와 같이 양호한 코드로 금지 된 글로벌 상태에는 몇 가지 예외가 있습니다. 시간은 전 세계적이며 어떤 의미에서는 코딩 된 관계없이 객체의 상태를 변경합니다.


"시간은 전 세계적이다"-컴퓨팅 시스템에서 시간을 모델링하는 다른 방법은 그 자체로 변화하는 암시적이고 세계적인 것이어야한다. cf. 이 설문 조사 : "컴퓨팅 모델링 시간 : 란다과 비교 조사"@ arxiv.org/abs/0807.4132
자레드 업다이크

4

내 $ .02는 "정적이 나쁘다"고 말하는 것보다 이러한 답변 중 일부가 문제를 혼란스럽게한다는 것입니다. 범위와 인스턴스에 대해 이야기하는 것이 더 좋습니다.

내가 말할 것은 정적은 "클래스"변수라는 것입니다. 그것은 그 클래스의 모든 인스턴스에서 공유되는 값을 나타냅니다. 일반적으로 범위와 범위를 보호해야합니다 (클래스 및 인스턴스에 대해 보호 또는 비공개).

클래스 수준의 동작을 배치하고 다른 코드에 노출하려는 경우 향후 @Jessica가 제안한대로 싱글 톤이 향후 변경을 지원하는 더 나은 솔루션 일 수 있습니다. 이는 클래스 수준, 특히 상속에서 사용할 수없는 방식으로 인스턴스 / 싱글 톤 수준에서 인터페이스를 사용할 수 있기 때문입니다.

다른 답변의 일부 측면이 질문의 핵심이 아니라고 생각하는 이유에 대한 일부 생각 ...

스태틱은 "글로벌"이 아닙니다. Java 범위 지정은 정적 / 인스턴스와 별도로 제어됩니다.

동시성은 인스턴스 메소드보다 정적에 덜 위험하지 않습니다. 여전히 보호해야 할 상태입니다. 물론 인스턴스 변수가 각각 하나이고 정적 변수가 하나 뿐인 1000 개의 인스턴스가있을 수 있지만 액세스하는 코드가 스레드 안전 방식으로 작성되지 않은 경우 여전히 나사로 고정되어 있습니다. 인식하는 데 조금 더 오래 걸릴 수 있습니다 .

라이프 사이클 관리는 흥미로운 주장이지만 덜 중요하다고 생각합니다. 단일 인스턴스를 생성하고 파괴하는 것보다 init () / clear ()와 같은 클래스 메소드 쌍을 관리하는 것이 왜 더 어려운지 알 수 없습니다. 실제로 일부는 GC로 인해 싱글 톤이 조금 더 복잡하다고 말할 수 있습니다.

추신. 스몰 토크 (Smalltalk) 측면에서 많은 방언에는 클래스 변수가 있지만 스몰 토크 클래스에서는 실제로 메타 클래스의 인스턴스이므로 메타 클래스 인스턴스의 변수입니다. 여전히 동일한 규칙을 적용 할 것입니다. 인스턴스 간 공유 상태에 사용되는 경우 ok입니다. 이들이 공용 기능을 지원하는 경우 싱글 톤을 확인해야합니다. 한숨, 스몰 토크는 그리워 ...


4

게시물에 두 가지 주요 질문이 있습니다.

먼저 정적 변수에 대해 정적 변수는 완전히 불필요하며 사용을 쉽게 피할 수 있습니다. 일반적으로 OOP 언어 및 Java에서는 함수 매개 변수가 참조로 파싱됩니다. 즉, 객체를 함수에 전달하면 포인터가 객체에 전달되므로 정적 변수를 정의 할 필요가 없습니다. 이 정보가 필요한 모든 범위에 객체에 대한 포인터를 전달할 수 있습니다. 이것이 yo가 메모리로 포인터를 채울 것이라는 것을 암시하더라도 실제 메모리 패깅 시스템은이를 처리하도록 최적화되어 있기 때문에 성능이 나쁘지 않을 것입니다. 범위; 정적 변수를 사용하면 시스템이 메모리 페이지에 액세스해야 할 때 저장된 메모리 페이지를로드 할 수 있습니다 (이는 페이지에 오랫동안 액세스하지 않은 경우 발생 함). 좋은 방법은 모든 정적 스텁을 작은 "구성 클래스"로 묶는 것입니다. 이렇게하면 시스템이 모두 동일한 메모리 페이지에이를 배치 할 수 있습니다.

둘째, 정적 메서드에 대해 정적 메서드는 그리 나쁘지는 않지만 성능을 빠르게 저하시킬 수 있습니다. 예를 들어, 클래스의 두 객체를 비교하고 어떤 객체가 더 큰지를 나타내는 값 (팁 비교 방법)을 반환하는 메소드를 생각해보십시오.이 메소드는 정적 일 수도 있고 아닐 수도 있지만, 호출 할 때 비 정적 형식이 더 효율적입니다 왜냐하면 동일한 메소드의 정적 버전 (클래스 하나에 2 개, 각 개체에 1 개)을 해결해야하는 3 개의 참조에 대해 2 개의 참조 (각 오브젝트에 대해 하나씩) 만 해결해야하기 때문입니다. 그러나 내가 말했듯이, 그렇게 나쁘지는 않습니다. Math 클래스를 살펴보면 정적 메서드로 정의 된 많은 수학 함수를 찾을 수 있습니다. 이것은 숫자를 정의하는 클래스에 이러한 모든 방법을 배치하는 것보다 실제로 더 효율적입니다.

결론 : 정적 또는 비 정적 메소드를 다룰 때 정적 변수의 사용을 피하고 올바른 성능 평형을 찾으십시오.

추신 : 영어로 죄송합니다.


4

정적 변수 자체에는 아무런 문제가 없습니다. 깨진 Java 구문 일뿐입니다. 각 Java 클래스는 실제로 정적 변수를 캡슐화하는 단일 객체와 인스턴스라는 두 가지 구조를 정의합니다. 동일한 소스 블록에서 둘 다를 정의하는 것은 순수한 악의적이며 코드를 읽기 어렵습니다. 스칼라는 그렇게 했어요


3

a) 프로그램에 대한 이유.

정적 변수 Global.foo에 액세스하는 중소 규모의 프로그램이있는 경우 일반적으로 어디에서나 호출됩니다. 경로가 없으므로 타임 라인이 없으며 변수가 장소에 어떻게 도달하는지 사용. 이제 누가 실제 값으로 설정했는지 어떻게 알 수 있습니까? 지금 수정하면 어떻게되는지 어떻게 알 수 있습니까? 모든 소스를 수집하고, 모든 액세스 권한을 수집하고, 무슨 일이 일어나고 있는지 알고 싶습니다.

코드를 작성했기 때문에 어떻게 사용하는지 안다면 문제는 보이지 않지만 외국 코드를 ​​이해하려고하면 이해할 것입니다.

b) 정말로 하나만 필요합니까?

정적 변수는 종종 동일한 JVM에서 다른 값을 가진 동일한 종류의 여러 프로그램이 실행되지 못하게합니다. 프로그램의 인스턴스가 두 개 이상 유용 할 경우 사용법을 예측하지 못하는 경우가 많지만, 진화하거나 다른 프로그램에 유용 할 경우 상황이 발생하여 프로그램 인스턴스를 두 개 이상 시작하려는 상황이 발생할 수 있습니다. .

많은 사람들이 오랜 시간 동안 집중적으로 사용하지 않는 쓸모없는 코드 만 정적 변수와 잘 어울릴 수 있습니다.


3

데이터 를 공유 / 캐시 해야하는 스레드가 있고 액세스 가능한 모든 메모리 (하나의 JVM 내에서 컨텍스트로 분할하지 않아야 함)가있는 경우 모든 것이 (수 :) 목적을 가지고 정적은 최선의 선택입니다

-> 물론 강제 할 수 있습니다 하나의 인스턴스이지만 왜?
나는이 스레드에서 주석 중 일부를 발견합니다. 정적은 아닙니다.)


3

정적 변수는 선하거나 악하지 않습니다. 그것들은 특정 인스턴스가 아닌 전체 클래스를 설명하는 속성을 나타냅니다. 특정 클래스의 모든 인스턴스에 대한 카운터가 필요한 경우 정적 변수가 값을 보유하기에 적합한 장소입니다.

인스턴스 관련 값을 보유하기 위해 정적 변수를 사용하려고하면 문제가 나타납니다.


2

위의 모든 답변은 왜 정적이 나쁜지를 보여줍니다. 그들이 악한 이유 는 실제로 객체 지향 코드를 작성하고 있지 않다는 잘못된 인상을주기 때문입니다. 그것은 단지 명백한 악입니다.


1
그러나 임의의 표준 패러다임을 따르는 코드를 엄격하게 고려하면 실제로 코드가 더 나아지거나 작동하는 코드를 작성하는 것을 피하기 위해 불평하고 있습니까?
Zoey

예, 앞으로 더 관리하기 쉽고 이해하기 쉽고 명시 적이기 때문에 더 나아집니다.
blockhead

1
OO 코드를 작성하지 않는 것이 왜 나쁜가요? Bjarne Stroustrup이 왜 귀하와 동의하지 않습니까? 단지 하나의 이름을 ...
후작의 후작

2
나는 OO 코드를 작성하지 않는 것이 악하다고 말하지 않았습니다. 정적 메소드와 속성 뒤에서 전역을 위장 할 때 OO 코드를 작성한다고 생각하는 것은 악하다고 말했습니다. 내가 쓴 것을 다시 읽으십시오.
blockhead

2

여기에 좋은 대답이 많이 있습니다.

메모리 : 정적 변수는 클래스 로더가 수명을 유지하는 한 (일반적으로 VM이 죽을 때까지) 유효하지만 이는 대량 오브젝트 / 참조가 정적으로 저장된 경우에만 해당됩니다.

모듈화 : IOC, dependencyInjection, proxy 등과 같은 개념을 고려하십시오. 모두 밀접하게 결합 / 정적 구현에 반대합니다.

다른 단점 : 스레드 안전성, 테스트 가능성


0

많은 사용자가있는 응용 프로그램이 있고 정적 양식을 정의한 경우 모든 사용자가 다른 모든 사용자의 다른 양식도 수정한다고 생각하십시오.


0

정적 키워드와 함께 전역 변수를 과도하게 사용하면 응용 프로그램의 특정 시점에서 메모리 누수가 발생할 것이라고 생각합니다.


0

내 관점에서 static변수는 컨벤션에 의해 생성 데이터 또는 변수 만 습니다 .

예를 들어 프로젝트의 UI가 있고 국가, 언어, 사용자 역할 등의 목록이 있습니다. 그리고이 데이터를 정리할 클래스가 있습니다. 이 목록이 없으면 앱이 작동하지 않을 것입니다. app init에서 가장 먼저하는 일은이리스트에서 업데이트를 확인하고이리스트를 api에서 가져 오는 것입니다 (필요한 경우). 따라서이 데이터가 앱에 "항상"존재한다는 데 동의합니다. 실제로는 읽기 전용 데이터이므로 상태를 관리 할 필요가 없습니다.이 사례에 대해 생각하면서 실제로 이러한 데이터를 많이 갖고 싶지는 않습니다.이 사례는 정적 일 수있는 완벽한 후보로 보입니다 .


0

나는 정적을 많이 가지고 놀았고 약간 다른 대답을 줄 수 있습니까? 아니면 약간 다르게 볼 수 있습니까?

클래스에서 정적을 사용했을 때 (멤버와 메소드 모두) 결국 내 클래스가 실제로 책임을 공유하는 두 클래스라는 것을 알기 시작했습니다. "정적"부분이 싱글 톤처럼 작동하며 -정적 부분 (정상 클래스). 내가 아는 한, 한 클래스의 모든 정적 요소와 다른 클래스의 비 정적 요소를 선택하여 두 클래스를 완전히 분리 할 수 ​​있습니다.

이것은 클래스의 인스턴스를 보유하는 클래스 내부에 정적 컬렉션과 컬렉션을 관리하는 정적 메서드가있을 때 많이 발생했습니다. 일단 당신이 그것에 대해 생각하면, 당신의 수업이 "한 가지 일"을하고 있지 않다는 것이 명백합니다. 그것은 하나의 컬렉션이고 완전히 다른 것을하고 있습니다.

이제, 문제를 조금 리팩토링 해 봅시다 : 클래스를 모든 것이 정적 인 클래스와 "정상 클래스"인 다른 클래스로 나누고 "정상 클래스"를 잊어 버리면 질문은 정적으로 정적 클래스 대 싱글턴이됩니다. 여기 에 길이가 자세히 설명되어 있습니다 (아마도 다른 질문 12 개).

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.