정적 변수가 악으로 간주되는 이유는 무엇입니까?
저는 자바 프로그래머로 기업계에 처음 와보는 사람입니다.최근에는 그루비와 자바 어플리케이션을 개발했습니다.내가 작성한 코드 내내 꽤 많은 통계자료를 사용했다.나는 상급 기술 부서로부터 통계 사용 횟수를 줄여달라는 요청을 받았다.저도 같은 내용을 검색해봤는데 많은 프로그래머들이 정적 변수 사용에 상당히 반대한다는 것을 알게 되었습니다.
정적 변수를 사용하는 것이 더 편리하다고 생각합니다.그리고, 클래스내의 함수에 10,000 콜을 걸어야 하는 경우는, 그 메서드를 정적으로 해, 간단하게 사용할 수 있기 때문에, 효율적이라고 생각합니다(잘못했을 경우는 정정해 주세요).Class.methodCall()
10,000개의 클래스 인스턴스와 함께 메모리를 어지럽히는 대신, 그 위에 올려놓아야 합니다.
또한 통계학은 코드의 다른 부분에 대한 상호의존성을 감소시킨다.그들은 완벽한 국가 보유자 역할을 할 수 있다.게다가 통계학은 Smalltalk나 Scala와 같은 일부 언어에서 광범위하게 구현되고 있습니다.그렇다면 왜 프로그래머들(특히 자바 세계) 사이에 정리에 대한 반대가 만연해 있는 것일까요?
추신: 만약 제가 통계학에 대해 추측이 틀렸다면 정정해 주세요.
스태틱 변수는 글로벌 상태를 나타냅니다.이는 추론하기 어렵고 테스트하기 어렵습니다.새로운 오브젝트 인스턴스를 작성하면 테스트 내에서 오브젝트의 새로운 상태를 추론할 수 있습니다.정적 변수를 사용하는 코드를 사용하면 어떤 상태에서도 코드를 수정할 수 있습니다.
저는 꽤 오래 갈 수 있지만, 더 큰 개념으로 생각할 수 있는 것은 어떤 것의 범위가 좁을수록 더 쉽게 추론할 수 있다는 것입니다.우리는 작은 것에 대해 잘 생각하지만, 모듈화가 없다면 백만 회선 시스템의 상태를 추론하는 것은 어렵습니다.참고로 이것은 정적 변수뿐만 아니라 모든 것에 적용됩니다.
그다지 객체 지향적이지 않습니다.통계학이 일부 사람들에 의해 "악"으로 여겨질 수 있는 한 가지 이유는 통계학이 객체 지향적 패러다임과 반대되기 때문이다.특히 데이터가 오브젝트에 캡슐화된다는 원칙(확장 가능, 정보 은폐 등)에 위배됩니다.통계학을 사용하는 방법은 기본적으로 통계학을 글로벌 변수로 사용하여 범위와 같은 문제를 처리하지 않도록 하는 것입니다.그러나 글로벌 변수는 절차적 또는 명령적 프로그래밍 패러다임의 정의 특성 중 하나이며 "좋은" 객체 지향 코드의 특성이 아닙니다.절차 패러다임이 나쁘다고는 할 수 없지만, 당신의 상사는 당신이 "좋은 객체 지향 코드"를 작성하기를 바라고 있고, 당신은 "좋은 절차 코드"를 작성하기를 원하는 것 같습니다.
통계학을 사용하기 시작할 때 Java에는 즉시 알 수 없는 많은 문제가 있습니다.예를 들어, 동일한 VM에서 실행 중인 프로그램 복사본이 두 개 있는 경우 정적 변수의 값을 공유하여 서로 상태를 혼란스럽게 합니까?또는 클래스를 확장하면 어떻게 됩니까? 정적 멤버를 덮어쓸 수 있습니까?비정상적으로 많은 수의 스태틱이 있어 필요한 다른 인스턴스 개체에 메모리를 회수할 수 없기 때문에 VM의 메모리가 부족합니까?
개체 수명:또한 스태틱스에는 프로그램의 전체 런타임과 일치하는 수명이 있습니다.즉, 클래스 사용이 끝난 후에도 모든 정적 변수의 메모리는 가비지 수집될 수 없습니다.예를 들어 변수를 non-static으로 하고 main() 함수에서 클래스의 단일 인스턴스를 만든 후 특정 함수를 10,000회 실행하도록 클래스에 요청하면 해당 10,000개의 콜이 수행된 후 단일 인스턴스에 대한 참조를 삭제하면 모든 정적 변수가 가비지 수집될 수 있습니다.재사용되었습니다.
특정 재사용을 방지합니다.또한 스태틱 메서드는 인터페이스를 구현하는 데 사용할 수 없으므로 스태틱 메서드는 특정 객체 지향 기능을 사용할 수 없도록 할 수 있습니다.
기타 옵션:효율이 주된 관심사인 경우, 일반적으로 작성보다 호출이 빠르다는 장점만 고려하는 것보다 속도 문제를 해결하는 다른 더 좋은 방법이 있을 수 있습니다.일시적인 수식어가 필요한지 휘발성 수식어가 필요한지 여부를 고려합니다.인라인 기능을 유지하기 위해 메서드를 static이 아닌 final로 표시할 수 있습니다.메서드 파라미터 및 기타 변수는 이들 변수를 변경할 수 있는 요소에 대한 가정에 따라 특정 컴파일러 최적화를 허용하도록 최종 마킹할 수 있습니다.인스턴스 개체는 매번 새 인스턴스를 생성하는 대신 여러 번 재사용할 수 있습니다.일반적으로 앱에서 켜야 하는 컴파일러 최적화 스위치가 있을 수 있습니다.10,000회 실행 시 멀티 스레드화가 가능하고 멀티 프로세서 코어를 활용할 수 있도록 설계를 설정해야 합니다.휴대성이 문제가 되지 않는 경우는, 표준적인 방법을 사용하면, 스태틱스보다 스피드가 향상됩니다.
어떤 이유로 객체의 여러 복사본(싱글톤 설계 패턴)을 원하지 않는 경우, 스레드 안전성(싱글톤이 잘 코딩되어 있다고 가정함), 느린 초기화를 허용하고 객체가 사용되었을 때 올바르게 초기화되었는지 확인, 하위 분류, 테스트 및 리팩터링의 이점 등 정적 객체에 대한 이점이 있습니다.코드는 말할 것도 없이 오브젝트의 인스턴스 하나만 원한다는 생각이 바뀌면 인스턴스 변수를 사용하기 위해 모든 정적 변수 코드를 리팩터링하는 것보다 중복 인스턴스를 방지하기 위해 코드를 삭제하는 것이 훨씬 쉽습니다.예전에도 그랬어야 했는데 재미없고 수업도 더 많이 편집해야 해서 새로운 버그가 생길 위험이 커져서...단점이 있는 것처럼 보이더라도 처음부터 제대로 셋업하는 것이 훨씬 낫다.앞으로 여러 개의 복사본이 필요할 경우 재작업이 필요한 것은 스태틱스를 가능한 한 자주 사용하지 않는 가장 설득력 있는 이유 중 하나일 것입니다.따라서 저는 통계학이 상호의존성을 감소시킨다는 당신의 진술에 동의하지 않습니다. 직접 접근할 수 있는 통계학이 많으면 그 자체로 "무엇을 하는 방법을 아는" 객체가 아닌 더 많은 코드를 얻게 될 것이라고 생각합니다.
악은 주관적인 용어이다.
당신은 창조와 파괴의 관점에서 통계학을 통제하지 않습니다.그들은 프로그램 하역부의 명령에 따라 생활한다.
스태틱은 1개의 공간에 존재하므로 스태틱을 사용하는 모든 스레드는 사용자가 관리해야 하는 접근컨트롤을 통과해야 합니다.즉, 프로그램이 더 많이 결합되고 이러한 변화는 (J Sket이 말한 것처럼) 예측하고 관리하기 어렵다는 것을 의미합니다.이로 인해 변경 영향을 분리하는 문제가 발생하여 테스트 관리 방법에 영향을 미칩니다.
이 두 가지가 내가 그들과 가지고 있는 주된 문제이다.
아니, 지구촌은 그 자체로 악하지 않아하지만 코드를 보고 제대로 사용했는지 확인해야 합니다.신입생이 모든 언어의 특징을 남용하는 것처럼 세계 각국을 남용할 가능성이 꽤 있다.
지구촌은 절대적인 필요조건이다.우리는 글로벌 상태를 피할 수 없다.글로벌 상태에 대한 추론을 피할 수 없습니다.- 어플리케이션의 의미를 이해하려면.
그것을 위해 세계국가를 없애려고 하는 사람들은 필연적으로 훨씬 더 복잡한 시스템을 갖게 된다. 그리고 세계국가들은 여전히 교묘하게/우둔하게 여러 층의 지시 아래 위장되어 있다; 그리고 우리는 모든 지시들을 푼 후에도 여전히 세계국가에 대해 논해야 한다.
xml로 글로벌 스테이트를 아낌없이 선언하고 어떻게든 우월하다고 생각하는 봄 사람들처럼.
@Jon 스키트if I create a new instance of an object
이제 개체 내 상태와 개체를 호스팅하는 환경 상태라는 두 가지 이유를 제시해야 합니다.
스태틱 변수에는 주로 다음 2가지 문제가 있습니다.
- 스레드 세이프티 - 정적 리소스는 스레드 세이프가 아닙니다.
- 코드 의미 - 정적 변수가 인스턴스화되는 시기와 다른 정적 변수보다 먼저 인스턴스화될지 여부를 알 수 없습니다.
'final' 키워드를 지정하지 않고 static 키워드를 사용하는 경우 이는 설계를 신중하게 검토하기 위한 신호입니다.심지어 '최종'의 존재도 자유이용권이 아니다. 왜냐하면 가변 정적 최종 객체는 그만큼 위험할 수 있기 때문이다.
저는 '최종'이 없는 '스태틱'을 볼 때 대략 85%가 잘못된 것으로 추정합니다. 종종 이러한 문제를 숨기거나 숨길 수 있는 이상한 회피책을 찾게 됩니다.
정적 돌연변이는 생성하지 마십시오.특히 컬렉션.일반적으로 컬렉션은 포함하는 오브젝트가 초기화되었을 때 초기화해야 하며 포함된 오브젝트가 잊혀졌을 때 재설정되거나 잊혀지도록 설계해야 합니다.
스태틱스를 사용하면 매우 미묘한 버그가 발생하여 엔지니어들이 며칠 동안 고생할 수 있습니다.알아, 내가 이 벌레들을 창조하고 사냥했으니까.
상세한 것에 대하여는, 다음의 내용을 읽어 주세요.
Statics를 사용하지 않는 이유
테스트 작성 및 실행을 포함한 정적인 문제 및 즉시 드러나지 않는 미묘한 문제가 많이 있습니다.
정적 객체에 의존하는 코드는 쉽게 유닛 테스트 할 수 없으며, 정적 코드는 쉽게 조롱할 수 없습니다(일반적으로).
statics를 사용하는 경우 상위 수준의 컴포넌트를 테스트하기 위해 클래스 구현을 스왑할 수 없습니다.예를 들어, 정적인 고객을 가정해 보겠습니다.데이터베이스에서 로드하는 고객 객체를 반환하는 DAO.이제 Customer Filter 클래스가 있습니다.이 클래스는 일부 Customer 객체에 액세스해야 합니다.고객님의 경우DAO는 정적입니다. 먼저 데이터베이스를 초기화하고 유용한 정보를 입력하지 않으면 CustomerFilter에 대한 테스트를 작성할 수 없습니다.
또한 데이터베이스 구현 및 초기화에 오랜 시간이 걸립니다.제 경험상 DB 초기화 프레임워크는 시간이 지남에 따라 변화할 것이며, 이는 데이터가 변형되고 테스트가 중단될 수 있음을 의미합니다.예를 들어 고객1은 VIP였는데 DB 초기화 프레임워크가 변경되어 고객1은 VIP가 아닙니다만, 고객1을 로드하기 위해 테스트가 하드 코드화되어 있습니다.
더 나은 방법은 고객 DAO를 인스턴스화하여 구축 시 고객 필터에 전달하는 것입니다.(스프링 또는 다른 제어 반전 프레임워크를 사용하는 것이 더 나은 접근법이 될 수 있습니다.
이렇게 하면 Customer Filter Test에서 대체 DAO를 신속하게 시뮬레이션 또는 제거할 수 있으므로 테스트를 보다 효과적으로 제어할 수 있습니다.
정적 DAO가 없으면 테스트 속도가 빨라지고(DB 초기화 없음) 신뢰성이 향상됩니다(DB 초기화 코드가 변경되어도 실패하지 않기 때문입니다.예를 들어, 이 경우 테스트에 관한 한 고객1이 항상 VIP임을 보증합니다.
테스트 실행
스태틱스는 유닛테스트 스위트를 함께 실행할 때(예를 들어 Continuous Integration 서버와 함께 실행할 때) 현실적인 문제를 일으킵니다.테스트 간에 열려 있는 네트워크 소켓 객체의 정적 맵을 상상해 보십시오.첫 번째 테스트에서는 포트 8080에서 소켓이 열릴 수 있지만 테스트가 종료되었을 때 Map을 클리어하는 것을 잊었습니다.두 번째 테스트가 시작되면 포트가 아직 사용 중이므로 포트 8080용 새 소켓을 작성하려고 하면 크래시가 발생할 수 있습니다.또한 스태틱 컬렉션의 소켓 참조가 삭제되지 않고 (WeakHashMap을 제외하고) 가비지 수집이 불가능하여 메모리 누수가 발생한다고 가정합니다.
이것은 지나치게 일반적인 예이지만, 대규모 시스템에서는 항상 발생하는 문제입니다.사람들은 같은 JVM에서 소프트웨어를 반복적으로 기동하고 정지하는 것을 생각하지 않습니다.그러나 이것은 소프트웨어 설계의 좋은 테스트이며 고가용성에 대한 열망을 가지고 있다면 주의해야 합니다.
이러한 문제는 DB 액세스, 캐싱, 메시징 및 로깅 계층과 같은 프레임워크 개체에서 자주 발생합니다.Java EE 또는 업계 최고 수준의 프레임워크를 사용하는 경우 이 프레임워크의 대부분을 관리하지만 기존 시스템을 사용하는 경우 이러한 계층에 액세스하기 위한 많은 사용자 지정 프레임워크를 사용할 수 있습니다.
이러한 프레임워크 컴포넌트에 적용되는 시스템 구성이 유닛 테스트 간에 변경되어 유닛 테스트 프레임워크가 컴포넌트를 분해 및 재구축하지 않으면 이러한 변경은 적용되지 않으며 테스트가 이러한 변경에 의존할 경우 실패합니다.
이 문제는 프레임워크 이외의 컴포넌트에서도 발생합니다.Open Orders라고 불리는 정적 지도를 상상해 보십시오.몇 개의 미해결 주문을 생성하고 모두 올바른 상태인지 확인하는 검정을 한 번 작성하면 테스트가 종료됩니다.또 다른 개발자는 필요한 주문을 Open Orders 맵에 넣고 주문 수가 정확하다고 주장하는 두 번째 테스트를 작성합니다.개별적으로 실행할 경우 이들 테스트는 모두 합격하지만 스위트 내에서 함께 실행할 경우 불합격합니다.
더 나쁜 것은 테스트가 실행된 순서에 따라 실패가 발생할 수 있다는 것입니다.
이 경우 정적인 작업을 방지함으로써 테스트 인스턴스 간에 데이터가 유지되는 위험을 방지하여 테스트 신뢰성을 높일 수 있습니다.
미묘한 버그
하이 어베이러빌리티 환경 또는 스레드가 시작 및 정지될 가능성이 있는 장소에서 작업하는 경우 위에서 설명한 유닛테스트 스위트에서도 같은 문제가 발생할 수 있습니다.
스레드를 처리할 때는 데이터를 저장하는 데 정적 개체를 사용하는 대신 스레드의 시작 단계에서 초기화된 개체를 사용하는 것이 좋습니다.이렇게 하면 스레드가 시작될 때마다 오브젝트의 새 인스턴스(잠재적으로 새로운 구성 포함)가 생성되므로 스레드의 한 인스턴스에서 다음 인스턴스로 데이터가 블리딩되는 것을 방지할 수 있습니다.
스레드가 정지해도 정적 개체가 재설정되거나 가비지가 수집되지 않습니다."EmailCustomers(이메일 사용자)"라는 스레드가 있다고 가정하고 시작할 때 정적 문자열 컬렉션에 이메일 주소 목록을 채운 다음 각 주소를 이메일로 보내기 시작합니다.스레드가 중단되거나 취소되어 하이 어베이러빌리티 프레임워크가 스레드를 재시작한다고 가정합니다.그런 다음 스레드가 시작되면 고객 목록이 새로고침됩니다.그러나 컬렉션은 정적이므로 이전 컬렉션의 전자 메일 주소 목록을 유지할 수 있습니다.일부 고객은 중복된 이메일을 받을 수 있습니다.
어사이드:스태틱 파이널
"static final"의 사용은 기술적인 구현에 차이가 있지만 사실상 C #define과 동등한 Java입니다.C/C++ #define은 컴파일 전에 프리프로세서에 의해 코드로부터 스왑 아웃됩니다.Java의 "static final"은 스택에 메모리가 상주하게 됩니다.이 방법에서는 #define보다 C++의 static const 변수에 더 가깝습니다.
요약
나는 이것이 통계학이 왜 문제가 되는지 몇 가지 기본적인 이유를 설명하는데 도움이 되기를 바란다.Java EE나 Spring 등의 최신 Java 프레임워크를 사용하는 경우 이러한 상황이 많이 발생하지 않을 수 있지만 많은 레거시 코드를 사용하는 경우 더 자주 발생할 수 있습니다.
Java에서 정적 방법을 사용할 경우의 기본적인 장점과 단점을 정리합니다.
장점:
- 특정 오브젝트 인스턴스와 연계되지 않고 글로벌하게 접근 가능.
- JVM당 1개의 인스턴스
- 클래스 이름을 사용하여 액세스할 수 있습니다(개체 불필요).
- 모든 인스턴스에 적용할 수 있는 단일 값이 포함됩니다.
- JVM 시작 시 로드되며 JVM이 종료되면 정지됩니다.
- 오브젝트 상태는 수정되지 않습니다.
단점:
- 스태틱 멤버는 사용 여부에 관계없이 항상 메모리의 일부입니다.
- 정적 변수의 생성 및 파괴는 제어할 수 없습니다.프로그램 로드 시 생성되고 프로그램 언로드 시(또는 JVM 종료 시) 파기됩니다.
- 동기화를 사용하여 통계 스레드를 안전하게 만들 수 있지만 약간의 추가 노력이 필요합니다.
- 하나의 스레드가 다른 스레드의 기능을 잃을 수 있는 정적 변수의 값을 변경하는 경우.
- 사용하기 전에 "static"을 알아야 합니다.
- 정적 메서드는 재정의할 수 없습니다.
- 연재가 잘 되지 않습니다.
- 런타임 다형성에는 참여하지 않습니다.
- 다수의 정적 변수/방식이 사용되는 경우 메모리 문제가 발생합니다(어느 정도 있지만 그다지 많지 않은 것 같습니다).프로그램이 종료될 때까지 가비지 수집이 되지 않기 때문입니다.
- 정적 방법도 테스트하기 어렵습니다.
정적 변수는 글로벌 상태를 나타내기 때문에 일반적으로 좋지 않은 것으로 간주되며 따라서 추론하기가 훨씬 어렵습니다.특히 객체 지향 프로그래밍의 가정을 깨는 것입니다.객체 지향 프로그래밍에서는 각 객체는 인스턴스(비정적) 변수로 표현되는 자체 상태를 가집니다.정적 변수는 인스턴스 전체의 상태를 나타내며, 단위 테스트가 훨씬 더 어려울 수 있습니다.이는 주로 정적 변수에 대한 변경을 단일 테스트로 분리하는 것이 더 어렵기 때문입니다.
즉, 정규 정적 변수(일반적으로 나쁘다고 간주)와 최종 정적 변수(AKA 상수, 그리 나쁘지는 않음)를 구별하는 것이 중요합니다.
아무도 이에 대해 언급하지 않았기 때문에: 동시성.정적 변수를 읽고 쓰는 스레드가 여러 개 있는 경우 정적 변수를 사용하면 깜짝 놀랄 수 있습니다.이는 웹 애플리케이션(ASP 등)에서 흔히 볼 수 있습니다.NET)에 의해, 다소 짜증나는 버그가 발생할 가능성이 있습니다.예를 들어, 페이지에 의해 갱신되는 정적 변수가 있고 두 사람이 "거의 동시에" 페이지를 요청하면, 한 사용자가 다른 사용자가 예상한 결과를 얻거나 그 이상의 결과를 얻을 수 있습니다.
statics는 코드의 다른 부분에 대한 상호의존성을 줄입니다.그들은 완벽한 주 소유자로서 행동할 수 있다.
잠금장치를 사용하고 경합에 대처할 준비가 되어있기를 바랍니다.
*사실 프리엣상하가 얘기했어요.
클래스 내의 함수에 10,000 콜을 걸어야 한다면 메서드를 스태틱하게 하여 스트레이트 클래스를 사용하는 것이 좋습니다.methodCall()을 사용하여 메모리를 클래스의 10,000개의 인스턴스로 혼란시키는 대신 사용할 수 있습니다.
데이터를 상태를 가진 객체에 캡슐화할 필요성과 일부 데이터에 대한 함수의 결과를 단순하게 계산할 필요성의 균형을 맞춰야 합니다.
또한 통계학은 코드의 다른 부분에 대한 상호의존성을 감소시킨다.
캡슐화도 마찬가지입니다.대규모 어플리케이션에서 스태틱스는 스파게티 코드를 생성하는 경향이 있으며 리팩터링이나 테스트를 쉽게 허용하지 않습니다.
다른 답변들도 과도한 통계학 사용에 대한 타당한 이유를 제공한다.
제 생각에 이건 성능에 관한 것이 아니라 디자인에 관한 것입니다.스태틱 변수의 사용과 마찬가지로 스태틱 메서드의 사용이 잘못되었다고는 생각하지 않습니다(그러나 실제로는 메서드 호출에 대해 이야기하고 있는 것 같습니다).
단순히 논리를 분리하여 좋은 장소를 제공하는 방법에 대한 것입니다.경우에 따라서는, 이 경우, 스태틱한 방법을 사용하는 것이 정당화될 수 있습니다.java.lang.Math
좋은 예입니다.내 생각에 네가 대부분의 수업의 이름을 말할 때XxxUtil
또는Xxxhelper
디자인을 재고해 보는 게 좋을 거야
저는 방금 답변의 몇 가지 요점을 요약했습니다.잘못된 점이 발견되면 언제든지 수정해 주세요.
스케일링:JVM마다 정확히 하나의 정적 변수 인스턴스가 있습니다.도서관 관리 시스템을 개발하고 있으며, 도서 이름이 책 한 권당 하나이므로 정적 변수를 넣기로 결정했다고 가정합니다.그러나 시스템이 확장되어 여러 JVM을 사용하는 경우 어떤 책을 취급하고 있는지 알 수 없습니다.
스레드 안전성:다중 스레드 환경에서 사용할 경우 인스턴스 변수와 정적 변수를 모두 제어해야 합니다.그러나 인스턴스 변수의 경우 스레드 간에 명시적으로 공유되지 않는 한 보호가 필요하지 않지만 정적 변수의 경우 프로세스 내의 모든 스레드에 의해 항상 공유됩니다.
테스트:테스트 가능한 디자인은 좋은 디자인과 동일하지는 않지만 테스트 불가능한 좋은 디자인은 거의 관찰하지 못할 것입니다.정적 변수는 글로벌 상태를 나타내므로 테스트하기가 매우 어렵습니다.
상태에 대한 추론:클래스의 새 인스턴스를 만들면 이 인스턴스의 상태를 추론할 수 있지만 정적 변수가 있는 경우에는 어떤 상태일 수도 있습니다. 왜일까요?static 변수가 인스턴스 간에 공유되기 때문에 static 변수가 다른 인스턴스에 의해 변경되었을 가능성이 있기 때문입니다.
시리얼화:또, 시리얼화도 잘 되지 않습니다.
생성 및 파괴:정적 변수의 생성 및 파괴는 제어할 수 없습니다.일반적으로 프로그램 로드 및 언로드 시 생성 및 파기됩니다.즉, 메모리 관리에 좋지 않고, 기동시의 초기화 시간도 합산됩니다.
하지만 정말 필요한 거라면요?
하지만 가끔은 정말 필요한 경우도 있습니다.애플리케이션 전체에서 공유되는 많은 정적 변수의 필요성을 느끼는 경우, 하나의 옵션은 이러한 모든 변수를 포함하는 싱글톤 설계 패턴을 사용하는 것입니다.또는 이러한 정적 변수를 사용하여 전달할 수 있는 개체를 만들 수도 있습니다.
또한 정적 변수가 final로 표시되어 있으면 상수가 되고 한 번 할당된 값은 변경할 수 없습니다.그것은 그것이 그것의 불변성 때문에 우리가 직면하는 모든 문제들로부터 우리를 구할 수 있다는 것을 의미한다.
정적 변수에 대해 질문하는 것처럼 보이지만 예제에서 정적 방법을 지적합니다.
정적 변수는 나쁜 것이 아닙니다.대부분의 경우 최종 수식어와 조합된 상수와 같은 글로벌 변수로 채택되지만, 지나치게 사용하지 마십시오.
유틸리티 방식이라고도 불리는 정적 방식.일반적으로 사용하는 것이 나쁜 방법은 아니지만, 주요 우려 사항은 테스트에 방해가 될 수 있다는 것입니다.
많은 스태틱스를 사용하여 올바른 방법으로 수행하는 훌륭한 Java 프로젝트의 예로서 Play! 프레임워크를 참조하십시오.SO에서도 논의되고 있습니다.
static 변수/메서드와 static import를 조합한 메서드는 java에서 선언형 프로그래밍을 용이하게 하는 라이브러리에서도 널리 사용됩니다.많은 정적 변수와 방법이 없었다면 불가능했을 것이다.
정적 변수(및 방법)는 좋지만 현명하게 사용하십시오!
정적 변수는 데이터 보안에 가장 중요한 문제를 일으킨다(언제 변경해도 누구나 변경 가능, 객체 없이 직접 액세스 가능 등).
상세한 것에 대하여는, 이쪽을 봐 주세요.
스태틱 변수를 사용하는 대부분의 경우 싱글톤 패턴을 사용하는 것이 좋습니다.
The problem with global states is that sometimes what makes sense as global in a simpler context, needs to be a bit more flexible in a practical context, and this is where the singleton pattern becomes useful.
Yet another reason: fragility.
If you have a class, most people expect to be able to create it and use it at will.
You can document it's not the case, or protect against it (singleton/factory pattern) - but that's extra work, and therefore an additional cost. Even then, in a big company, chances are someone will try at some point to use your class without fully paying attention to all the nice comments or the factory.
If you're using static variables a lot, that will break. Bugs are expensive.
Between a .0001% performance improvement and robustness to change by potentially clueless developers, in a lot of cases robustness is the good choice.
I find static variables more convenient to use. And I presume that they are efficient too (Please correct me if I am wrong) because if I had to make 10,000 calls to a function within a class, I would be glad to make the method static and use a straightforward class.methodCall() on it instead of cluttering the memory with 10,000 instances of the class, Right?
I see what you think, but a simple Singleton pattern will do the same without having to instantiate 10 000 objects.
static methods can be used, but only for functions that are related to the object domain and do not need or use internal properties of the object.
ex:
public class WaterContainer {
private int size;
private int brand;
...etc
public static int convertToGallon(int liters)...
public static int convertToLiters(int gallon)...
}
The issue of 'Statics being evil' is more of an issue about global state. The appropriate time for a variable to be static, is if it does not ever have more than one state; IE tools that should be accessible by the entire framework and always return the same results for the same method calls are never 'evil' as statics. As to your comment:
I find static variables more convenient to use. And I presume that they are efficient too
Statics are the ideal and efficient choice for variables/classes that do not ever change.
The problem with global state is the inherent inconsistency that it can create. Documentation about unit tests often address this issue, since any time there is a global state that can be accessed by more than multiple unrelated objects, your unit tests will be incomplete, and not 'unit' grained. As mentioned in this article about global state and singletons, if object A and B are unrelated (as in one is not expressly given reference to another), then A should not be able to affect the state of B.
clock 등 정상적인 코드에서의 글로벌 상태 금지에는 몇 가지 예외가 있습니다.시간은 글로벌하며, 어떤 의미에서는 코드화된 관계를 갖지 않고도 객체의 상태를 변화시킵니다.
제 $.02는 이 답변들 중 몇 가지는 "통계학이 나쁘다"고 말하는 것보다 문제를 혼란스럽게 한다는 것입니다. 범위 지정과 인스턴스에 대해 이야기하는 것이 더 낫다고 생각합니다.
즉, 스태틱은 "클래스" 변수이며 해당 클래스의 모든 인스턴스에서 공유되는 값을 나타냅니다.일반적으로는 이러한 방법으로 범위도 지정해야 합니다(보호 또는 개인 클래스 및 해당 인스턴스).
클래스 레벨의 동작을 설정하고, 그것을 다른 코드에 공개할 예정이라면, 싱글톤이 장래의 변경을 서포트하기 위한 보다 좋은 솔루션이 될 가능성이 있습니다(@Jessica의 제안).이는 인스턴스/싱글톤레벨의 인터페이스를 클래스레벨에서는 사용할 수 없는 방법(특히 상속)으로 사용할 수 있기 때문입니다.
왜 다른 답변의 일부 측면이 질문의 핵심이 아니라고 생각하는지에 대한 몇 가지 생각이 있습니다.
통계학은 '글로벌'이 아닙니다.Java에서는 스코핑이 정적/인스턴스와 별도로 제어됩니다.
동시성은 인스턴스 메서드 못지않게 스태틱스에도 위험합니다.여전히 지켜져야 할 상태입니다.인스턴스 변수가 1000개이고 스태틱 변수가 1개밖에 없는 인스턴스가 있는 것은 확실합니다만, 어느 쪽인가에 액세스 하는 코드가 스레드 세이프한 방법으로 써지지 않는 경우는, 실현에 조금 시간이 걸릴 수 있습니다.
라이프 사이클을 관리하는 것은 흥미로운 주장이지만, 저는 그것이 덜 중요하다고 생각합니다.init()/clear()와 같은 클래스 메서드 쌍을 관리하는 것이 싱글톤 인스턴스를 만들고 파기하는 것보다 더 어려운 이유를 알 수 없습니다.사실 어떤 사람들은 싱글톤이 GC 때문에 조금 더 복잡하다고 말할지도 모른다.
PS, Smalltalk에서는 많은 방언에 클래스 변수가 있지만 Smalltalk 클래스는 실제로 메타클래스의 인스턴스이기 때문에 메타클래스 인스턴스의 변수입니다.그래도 나는 같은 경험칙을 적용할 것이다.여러 인스턴스에서 공유 상태로 사용되는 경우 정상입니다.만약 그들이 공공 기능을 지원하고 있다면, 당신은 싱글톤을 살펴봐야 합니다.하아, 정말 스몰톡이 그리운데...
There are two main questions in your post.
First, about static variables. Static variables are completelly unnecesary and it's use can be avoided easily. In OOP languajes in general, and in Java particularlly, function parameters are pased by reference, this is to say, if you pass an object to a funciont, you are passing a pointer to the object, so you dont need to define static variables since you can pass a pointer to the object to any scope that needs this information. Even if this implies that yo will fill your memory with pointers, this will not necesary represent a poor performance because actual memory pagging systems are optimized to handle with this, and they will maintain in memory the pages referenced by the pointers you passed to the new scope; usage of static variables may cause the system to load the memory page where they are stored when they need to be accessed (this will happen if the page has not been accesed in a long time). A good practice is to put all that static stuf together in some little "configuration clases", this will ensure the system puts it all in the same memory page.
Second, about static methods. Static methods are not so bad, but they can quickly reduce performance. For example, think about a method that compares two objects of a class and returns a value indicating which of the objects is bigger (tipical comparison method) this method can be static or not, but when invoking it the non static form will be more eficient since it will have to solve only two references (one for each object) face to the three references that will have to solve the static version of the same method (one for the class plus two, one for each object). But as I say, this is not so bad, if we take a look at the Math class, we can find a lot of math functions defined as static methods. This is really more eficient than putting all these methods in the class defining the numbers, because most of them are rarelly used and including all of them in the number class will cause the class to be very complex and consume a lot of resources unnecesarilly.
In concluson: Avoid the use of static variables and find the correct performance equilibrium when dealing with static or non static methods.
PS: Sorry for my english.
There's nothing wrong with static variables per se. It's just the Java syntax that's broken. Each Java class actually defines two structures- a singleton object which encapsulates static variables, and an instance. Defining both in the same source block is pure evil, and results in a code that's hard to read. Scala did that right.
Static variables are not good nor evil. They represent attributes that describe the whole class and not a particular instance. If you need to have a counter for all the instances of a certain class, a static variable would be the right place to hold the value.
Problems appear when you try to use static variables for holding instance related values.
a) Reason about programs.
If you have a small- to midsize-program, where the static variable Global.foo is accessed, the call to it normally comes from nowhere - there is no path, and therefore no timeline, how the variable comes to the place, where it is used. Now how do I know who set it to its actual value? How do I know, what happens, if I modify it right now? I have grep over the whole source, to collect all accesses, to know, what is going on.
If you know how you use it, because you just wrote the code, the problem is invisible, but if you try to understand foreign code, you will understand.
b) Do you really only need one?
Static variables often prevent multiple programs of the same kind running in the same JVM with different values. You often don't foresee usages, where more than one instance of your program is useful, but if it evolves, or if it is useful for others, they might experience situations, where they would like to start more than one instance of your program.
Only more or less useless code which will not be used by many people over a longer time in an intensive way might go well with static variables.
everything (can:) have its purpose, if you have bunch of threads that needs to share/cache data and also all accessible memory (so you dont split into contexts within one JVM) the static is best choice
-> of course you can force just one instance, but why?
i find some of the comments in this thread evil, not the statics ;)
All the answers above show why statics are bad. The reason they are evil is because it gives the false impression that you are writing object oriented code, when in fact you are not. That is just plain evil.
There are plenty of good answers here, adding to it,
Memory: Static variables are live as long as the class loader lives[in general till VM dies], but this is only in-case of bulk objects/references stored as static.
Modularization: consider concepts like IOC, dependencyInjection, proxy etc.. All are completely against tightly coupling/static implementations.
Other Con's: Thread Safety, Testability
I've played with statics a lot and may I give you a slightly different answer--or maybe a slightly different way to look at it?
When I've used statics in a class (Members and methods both) I eventually started to notice that my class is actually two classes sharing responsibility--there is the "Static" part which acts a lot like a singleton and there is the non-static part (a normal class). As far as I know you can always separate those two classes completely by just selecting all the statics for one class and non-statics for the other.
This used to happen a lot when I had a static collection inside a class holding instances of the class and some static methods to manage the collection. Once you think about it, it's obvious that your class is not doing "Just one thing", it's being a collection and the doing something completely different.
Now, let's refactor the problem a little: If you split your class up into one class where everything is static and another which is just a "Normal Class" and forget about the "Normal Class" then your question becomes purely Static class vs Singleton which is addressed in length here (and probably a dozen other questions).
Static fields are de facto GC roots (see the How Garbage Collection Works section earlier in this chapter), which means they are never garbage-collected! For convenience alone, static fields and collections are often used to hold caches or share state across threads. Mutable static fields need to be cleaned up explicitly. If the developer does not consider every possibility (a near certainty), the cleanup will not take place, resulting in a memory leak. This sort of careless programming means that static fields and collections have become the most common cause of memory leaks!
In short, never use mutable static fields—use only constants. If you think you need mutable static fields, think about it again, and then again! There's always a more appropriate technique.
I think excessive uses of global variables with static keyword will also leads to memory leakage at some point of instance in the applica
From my point of view static
variable should be only read only data or variables created by convention.
For example we have a ui of some project, and we have a list of countries, languages, user roles, etc. And we have class to organize this data. we absolutely sure that app will not work without this lists. so the first that we do on app init is checking this list for updates and getting this list from api (if needed). So we agree that this data is "always" present in app. It is practically read only data so we don't need to take care of it's state - thinking about this case we really don't want to have a lot of instances of those data - this case looks a perfect candidate to be static.
ReferenceURL : https://stackoverflow.com/questions/7026507/why-are-static-variables-considered-evil
'programing' 카테고리의 다른 글
Java - 정수를 문자열로 변환 (0) | 2022.07.17 |
---|---|
계산된 속성 내의 Vue JS if/else 통계 (0) | 2022.07.17 |
정상적으로 기능하려면 0을 반환해야 합니까, 아니면1을 반환해야 합니까? (0) | 2022.07.17 |
실행 파일을 매시간 실행하도록 cron 작업을 설정하려면 어떻게 해야 합니까? (0) | 2022.07.17 |
왜 MongoDB Java 드라이버는 조건부 난수 생성기를 사용하는가? (0) | 2022.07.17 |