Почему статические переменные считаются злом?

Я программист Java, который новичок в корпоративном мире. Недавно я разработал приложение, используя в Groovy и Java. На протяжении всего кода, который я написал, использовалось довольно много статики. Старшая техническая партия попросила меня сократить количество используемых статиков. Я прогуглил примерно то же самое, и я обнаружил, что многие программисты справедливо против использования статических переменных.

Я нахожу статические переменные более удобными в использовании. И я предполагаю, что они эффективный (пожалуйста, поправьте меня, если я ошибаюсь), потому что, если бы мне пришлось сделать 10 000 вызовов функции в классе, я был бы рад сделать метод статическим и использовать простой Class.methodCall() на нем вместо того, чтобы загромождать память 10,000 экземплярами класса, верно?

кроме того, статика уменьшает взаимные зависимости от других частей кода. Они могут быть идеальными государственными держателями. Добавляя к этому, я нахожу, что статика широко реализована на некоторых языках, таких как Smalltalk и Scala. Так почему же это угнетение статики распространено среди программистов (особенно в мире Java)?

PS: пожалуйста, исправьте меня, если мои предположения о статике неверны.

28 ответов


статические переменные представляют собой глобальное состояние. Это трудно рассуждать и трудно проверить: если я создаю новый экземпляр объекта, я могу рассуждать о его новом состоянии в тестах. Если я использую код, который использует статические переменные, он может быть в любом состоянии - и что угодно может его изменять.

Я мог бы продолжать довольно долго, но большая концепция, о которой нужно думать, заключается в том, что чем плотнее область чего-то, тем легче рассуждать. Мы хорошо думаем о малом. вещи, но трудно рассуждать о состоянии миллионной линейной системы, если нет модульности. Кстати, это относится ко всем вещам, а не только к статическим переменным.


его не очень объектно-ориентированным: Одна из причин, по которой статика может считаться "злой" некоторыми людьми, заключается в том, что они противоречат объектно-ориентированная парадигма. В частности, это нарушает принцип инкапсуляции данных в объекты (которые могут быть расширены, скрытие информации и т. д.). Статика, как вы описываете их использование, по существу должна использовать их как глобальную переменную, чтобы избежать решения таких проблем, как область. Однако глобальные переменные являются одним из определение характеристик процедурной или императивной парадигмы программирования, а не характеристики "хорошего" объектно-ориентированного кода. Это не значит, что процедурная парадигма плоха, но у меня создается впечатление, что ваш руководитель ожидает, что вы напишете "хороший объектно-ориентированный код", и вы действительно хотите написать "хороший процедурный код".

есть много gotchyas в Java, когда вы начинаете использовать статику, которая не всегда сразу очевидна. Например, если у вас есть две копии программа, работающая в одной виртуальной машине, будет ли они shre значение статической переменной и беспорядок с состоянием друг друга? Или что происходит, когда вы расширяете класс, можете ли вы переопределить статический член? У вашей виртуальной машины заканчивается память, потому что у вас есть безумные числа статики, и эта память не может быть восстановлена для других необходимых объектов экземпляра?

Время Жизни Объекта: Кроме того, статика имеет время жизни, которое соответствует всему времени выполнения программы. Это значит, даже один раз вы закончили использовать свой класс, память от всех этих статических переменных не может быть собрана в мусор. Если, например, вместо этого вы сделали свои переменные нестатическими, а в своей функции main() вы сделали один экземпляр своего класса, а затем попросили свой класс выполнить определенную функцию 10 000 раз, как только эти 10 000 вызовов были сделаны, и вы удалите свои ссылки на один экземпляр, все ваши статические переменные могут быть собраны и повторно использованы.

предотвращает определенное повторное использование: Кроме того, статические методы нельзя использовать для реализации интерфейса, поэтому статические методы могут препятствовать использованию определенных объектно-ориентированных объектов.

Другие Варианты: Если эффективность-ваша главная забота, могут быть другие лучшие способы решить проблему скорости, чем рассмотрение только преимущества вызова обычно быстрее, чем создание. Рассмотрим, нужны ли переходные или летучие модификаторы в любом месте. Для сохранения возможность быть встроенным, метод может быть помечен как окончательный, а не статический. Параметры метода и другие переменные могут быть помечены как final, чтобы разрешить определенные оптимизации компилятора, основанные на предположениях о том, что может изменить эти переменные. Объект экземпляра можно использовать повторно несколько раз, а не создавать новый экземпляр каждый раз. Там могут быть параметры оптимизации compliler, которые должны быть включены для приложения в целом. Возможно, дизайн должен быть настроен так, что 10 000 может быть многопоточный и воспользоваться преимуществами многопроцессорных ядер. Если переносимость не является проблемой, возможно, родной метод даст вам лучшую скорость, чем ваша статика.

Если по какой-то причине вы не хотите несколько копий объекта,одноэлементный шаблон проектирования, имеет преимущества перед статическими объектами, такими как потокобезопасность (при условии, что ваш синглтон хорошо закодирован), позволяя ленивую инициализацию, гарантируя, что объект был правильно инициализирован при его использовании, преимущества при тестировании и рефакторинге вашего кода, не говоря уже о том, что если в какой-то момент Вы передумаете хотеть только один экземпляр объекта, гораздо проще удалить код для предотвращения дублирования экземпляров, чем рефакторировать весь код статической переменной для использования переменных экземпляра. Я должен был сделать это раньше, это не весело, и вам в конечном итоге придется редактировать намного больше классов, что увеличивает риск введения новых ошибок...намного лучше настроить "правильно" первый раз, даже если кажется, что у него есть свои недостатки. Для меня повторная работа, необходимая, если вы решите, что вам нужно несколько копий чего-то, вероятно, является одной из самых убедительных причин использовать статику как можно реже. И поэтому я также не согласен с вашим утверждением, что статика уменьшает взаимозависимости, я думаю, что вы получите код, который более связан, если у вас есть много статики, к которой можно получить прямой доступ, а не объект ,который " знает, как это сделать что-то" на себе".


зло-это субъективное понятие.

вы не контролируете статику с точки зрения создания и разрушения. Они живут по воле программы загрузки и разгрузки.

поскольку статика живет в одном пространстве, все потоки, желающие использовать их, должны пройти контроль доступа, которым вы должны управлять. Это означает, что программы более взаимосвязаны, и это изменение сложнее предусмотреть и управлять (как говорит Джей скит). Это приводит к проблемам изоляции влияния изменений и, таким образом, влияет на управление тестированием.

Это две основные проблемы у меня с ними.


нет. Глобальные государства сами по себе не являются злом. Но мы должны увидеть код код, чтобы узнать, правильно ли вы его использовали. Вполне возможно, что Новичок злоупотребляет глобальными государствами; точно так же, как он злоупотребляет каждой языковой особенностью.

глобальные состояния являются абсолютной необходимостью. Мы не можем избегать глобальных государств. Мы не можем избежать рассуждений о глобальных государств. - Если мы хотим понять нашу семантику приложения.

люди, которые пытаются избавиться от глобальных государств ради это неизбежно приводит к гораздо более сложной системе - и глобальные государства все еще там, умно/идиотски замаскированные под многими слоями косвенных ответов; и мы все еще должны рассуждать о глобальных государствах, развернув все косвенные ответы.

как весенние люди, которые щедро объявляют глобальные состояния в xml и думают, что как-то это превосходит.

@Jon Skeet if I create a new instance of an object теперь у вас есть две вещи, о которых нужно рассуждать - состояние внутри объекта и состояние среда размещения объекта.


есть 2 основные проблемы со статическими переменными:

  • безопасность потоков-статические ресурсы по определению не являются потокобезопасными
  • Имплицитность кода-Вы не знаете, когда создается экземпляр статических переменных и будет ли он создан перед другой статической переменной

Если вы используете ключевое слово "static" без ключевого слова "final", это должно быть сигналом для тщательного рассмотрения вашего дизайна. Даже наличие "финала" не является свободным проходом, поскольку изменяемый статический конечный объект может быть столь же опасным.

Я бы оценил где-то около 85% времени, когда я вижу "статический" без "окончательного", это неправильно. Часто я нахожу странные обходные пути, чтобы замаскировать или скрыть эти проблемы.

пожалуйста, не создавайте статические mutables. Особенно Коллекции. В общем случае коллекции должны инициализироваться при инициализации содержащего их объекта и должны быть сконструированы таким образом, чтобы они сбрасывались или забывались, когда их содержащий объект забывается.

использование статики может создать очень тонкие ошибки,которые вызовут у инженеров дни боли. Я знаю, потому что я создал и охотился на этих жуков.

Если вы хотите получить более подробную информацию, пожалуйста, прочитайте...

Почему Бы Не Использовать Статика?

есть много проблем с статикой, включая написание и выполнение тестов, а также тонкие ошибки, которые не сразу очевидны.

код, который полагается на статические объекты, не может быть легко протестирован, а статика не может быть легко высмеяна (обычно).

Если вы используете статику, невозможно поменять реализацию класса для тестирования компонентов более высокого уровня. Например, представьте статический CustomerDAO, который возвращает Объекты клиента загружаются из базы данных. Теперь у меня есть класс CustomerFilter, который должен получить доступ к некоторым объектам Customer. Если CustomerDAO статичен, я не могу написать тест для CustomerFilter без предварительной инициализации базы данных и заполнения полезной информации.

а заполнение и инициализация базы данных занимает много времени. И по моему опыту, ваша структура инициализации БД будет меняться со временем, то есть данные будут трансформироваться, и тесты могут сломаться. Т. е. Представьте себе клиента 1 используется для будьте VIP, но структура инициализации БД изменилась, и теперь клиент 1 больше не VIP, но ваш тест был жестко закодирован для загрузки клиента 1...

лучший подход-создать экземпляр CustomerDAO и передать его в CustomerFilter при его создании. (Еще лучшим подходом было бы использование Spring или другой инверсии структуры управления.

Как только вы это сделаете, вы можете быстро издеваться или тушить альтернативный DAO в своем CustomerFilterTest, позволяя вам иметь больше контроль над тестом,

без статического DAO тест будет быстрее (без инициализации БД) и надежнее (потому что он не потерпит неудачу при изменении кода инициализации БД). Например, в этом случае обеспечение клиента 1 является и всегда будет VIP, насколько это касается теста.

Тесты-Исполнителя

статика вызывает реальную проблему при совместном выполнении наборов модульных тестов (например, с вашим сервером непрерывной интеграции). Представьте себе статическую карту объектов сетевых сокетов, которая остается открытой от одного теста к другому. Первый тест может открыть сокет на порту 8080, но вы забыли очистить карту, когда тест будет сорван. Теперь, когда запускается второй тест, он, скорее всего, сбой при попытке создать новый сокет для порта 8080, так как порт все еще занят. Представьте также, что ссылки на сокеты в вашей статической коллекции не удаляются и (за исключением WeakHashMap) никогда не могут быть мусор собирается, вызывая утечку памяти.

это чрезмерно обобщенный пример, но в больших системах эта проблема происходит все время. Люди не думают о модульных тестах, запускающих и останавливающих их программное обеспечение неоднократно в одной и той же JVM, но это хороший тест вашего программного обеспечения, и если у вас есть стремление к высокой доступности, это то, что вам нужно знать.

эти проблемы часто возникают с объектами framework, например, ваш доступ к БД, слои кэширования, обмена сообщениями и ведения журнала. Если вы используете Java EE или некоторые лучшие фреймворки породы, они, вероятно, управляют многим из этого для вас, но если вы, как и я, имеете дело с устаревшей системой, у вас может быть много пользовательских фреймворков для доступа к этим слоям.

если конфигурация системы, которая применяется к этим компонентам фреймворка, изменяется между модульными тестами, и фреймворк модульного теста не разрушает и не перестраивает компоненты, эти изменения не могут вступить в силу, и когда тест полагается на эти изменения, они провалятся.

даже компоненты вне рамок подвержены этой проблеме. Представьте себе статическую карту под названием OpenOrders. Вы пишете один тест, который создает несколько открытых ордеров и проверяет, все ли они находятся в правильном состоянии, затем тест заканчивается. Другой разработчик пишет второй тест, который помещает необходимые ему заказы в карту OpenOrders, а затем утверждает, что количество заказов является точным. Запуск по отдельности эти тесты будут проходить, но при запуске вместе в номере они потерпят неудачу.

хуже того, сбой может быть основан на порядке выполнения тестов.

в этом случае, избегая статики, вы избегаете риска сохранения данных в тестовых экземплярах, обеспечивая лучшую надежность теста.

Тонкие Ошибки

Если вы работаете в среде высокой доступности или в любом месте, где потоки могут быть запущены и остановлены, та же проблема, упомянутая выше, с комплектами модульных тестов может применяются, когда ваш код также работает на производстве.

при работе с потоками вместо использования статического объекта для хранения данных лучше использовать объект, инициализированный на этапе запуска потока. Таким образом, каждый раз при запуске потока создается новый экземпляр объекта (с потенциально новой конфигурацией), и вы избегаете передачи данных из одного экземпляра потока в следующий экземпляр.

когда поток умирает, статический объект не получить сброс или сбор мусора. Представьте, что у вас есть поток под названием "EmailCustomers", и когда он запускается, он заполняет статическую коллекцию строк списком адресов электронной почты, а затем начинает отправлять по электронной почте каждый из адресов. Допустим, поток прерван или отменен каким-то образом, поэтому ваша платформа высокой доступности перезапускает поток. Затем, когда поток запускается, он загружает список клиентов. Но поскольку коллекция статична, она может сохранить список адресов электронной почты из предыдущего коллекция. Теперь некоторые клиенты могут получать дубликаты писем.

В Сторону: Статический Финал

использование "static final" фактически является эквивалентом Java C #define, хотя существуют технические различия в реализации. Определение C / C++ #заменяется из кода предварительным процессором перед компиляцией. "Статический финал" Java будет в конечном итоге резидентом памяти в стеке. Таким образом, он больше похож на переменную "static const" в C++, чем на a #define.

резюме

Я надеюсь, что это поможет объяснить несколько основных причин, почему статика проблематична. Если вы используете современную структуру Java, такую как Java EE или Spring и т. д., Вы можете не столкнуться со многими из этих ситуаций, но если вы работаете с большим объемом устаревшего кода, они могут стать намного более частыми.


Так как никто не* говорил об этом: параллелизм. статические переменные могут удивить вас, если у вас есть несколько потоков чтения и записи в статическую переменную. Это распространено в веб-приложениях (например, ASP.NET) и это может вызвать некоторые довольно сводящие с ума ошибки. Например, если у вас есть статическая переменная, которая обновляется страницей, и страница запрашивается двумя людьми "почти одновременно", один пользователь может получить результат, ожидаемый другим пользователем, или хуже.

статика уменьшает взаимные зависимости от других частей кода. Они могут выступать в качестве идеальных государственных держателей

Я надеюсь, что вы готовы использовать замки и бороться с разногласиями.

*на самом деле, Прит Санга упоминал об этом.


если бы мне пришлось сделать 10 000 вызовов функции в классе, я был бы рад сделать метод статичным и использовать простой класс.methodCall() на нем вместо загромождения памяти 10,000 экземпляры класса, верно?

вы должны сбалансировать необходимость инкапсуляции данных в объект с состоянием и необходимость простого вычисления результата функции на некоторых данных.

кроме того статика уменьшает взаимозависимости от других частей кода.

то же самое делает инкапсуляция. В больших применениях, статика клонит произвести код спагетти и легко не позволяет рефакторинг или испытание.

другие ответы также дают веские основания против чрезмерного использования статики.


статические переменные обычно считаются плохими, потому что они представляют глобальное состояние и поэтому гораздо сложнее рассуждать. В частности, они нарушают допущения объектно-ориентированного программирования. В объектно-ориентированном программировании каждый объект имеет свое собственное состояние, представленное переменными экземпляра (нестатическими). Статические переменные представляют состояние между экземплярами, которое может быть намного сложнее для модульного тестирования. Это главным образом потому, что труднее изолировать изменения в статические переменные для одного теста.

при этом важно провести различие между регулярными статическими переменными (обычно считающимися плохими) и конечными статическими переменными (ака константы; не так уж плохо).


суммируя несколько основных преимуществ и недостатков использования статических методов в Java:

плюсы:

  1. глобально доступный, т. е. не связанный с каким-либо конкретным экземпляром объекта.
  2. один экземпляр на JVM.
  3. можно получить с помощью имени класса (не требуется объект).
  4. содержит одно значение, применимое ко всем экземплярам.
  5. загрузка при запуске JVM и умирает, когда JVM выключается.
  6. они не изменяют состояние объекта.

недостатки:

  1. статические члены всегда являются частью погоды памяти, которую они используют или нет.
  2. вы не можете контролировать создание и уничтожение статической переменной. С пользой они были созданы при загрузке программы и уничтожены при выгрузке программы (или при выключении JVM).
  3. вы можете сделать статику потокобезопасной с помощью синхронизируйте, но вам нужны дополнительные усилия.
  4. если один поток изменяет значение статической переменной, которая может нарушить функциональность других потоков.
  5. вы должны знать "статический" перед его использованием.
  6. вы не можете переопределить статические методы.
  7. сериализация с ними не работает.
  8. они не участвуют во время выполнения полиморфизм.
  9. есть проблема с памятью (в некоторой степени, но не так много, я думаю), если большой используется количество статических переменных / методов. Потому что они не будут GC до окончания программы.
  10. статические методы также трудно проверить.

на мой взгляд, это вряд ли когда-либо о производительности, это про дизайн. Я не считаю использование статических методов неправильным, поскольку они связаны с использованием статических переменных (но я думаю, что вы на самом деле говорите о вызовах методов).

Это просто о том, как изолировать логику и дать ему хорошее место. Иногда это оправдывает использование статических методов, из которых java.lang.Math хороший пример. Я думаю, когда вы называете большинство ваших классов XxxUtil или Xxxhelper вам лучше пересмотреть свое дизайн.


можно предположить, что в большинстве случаев, когда вы используете статическую переменную, вы действительно хотите быть с помощью синглтон шаблон.

проблема с глобальными состояниями заключается в том, что иногда то, что имеет смысл как глобальное в более простом контексте, должно быть немного более гибким в практическом контексте, и именно здесь синглтонный шаблон становится полезным.


еще одна причина: хрупкость.

Если у вас есть класс, большинство людей ожидают, что смогут его создать и использовать по своему желанию.

вы можете документировать это не так ,или защитить от него (одноэлементный/заводской шаблон) - но это дополнительная работа, и, следовательно, дополнительная стоимость. Даже тогда, в большой компании, есть вероятность, что кто-то попытается в какой-то момент использовать ваш класс, не полностью обращая внимание на все приятные комментарии или фабрику.

Если вы используете статических переменных много, что сломается. Ошибки стоят дорого.

между a .0001% повышение производительности и надежности для изменения потенциально невежественными разработчиками, во многих случаях надежность-хороший выбор.


Я только что резюмировал некоторые моменты, сделанные в ответах. Если вы нашли что-то не так, пожалуйста, не стесняйтесь, чтобы исправить это.

масштабирование: у нас есть только один экземпляр статической переменной на JVM. Предположим, мы разрабатываем систему управления библиотекой и решили поместить имя книги в статическую переменную, так как на книгу приходится только одна переменная. Но если система растет, и мы используем несколько JVMs, то у нас нет способа выяснить, с какой книгой мы имеем дело с?

Потокобезопасность: и переменная экземпляра и статическая переменная нужно контролировать при использовании в multi продетой нитку окружающей среде. Но в случае переменной экземпляра он не нуждается в защите, если он явно не разделен между потоками, но в случае статической переменной он всегда разделяется всеми потоками в процессе.

тестирование: хотя тестируемый дизайн не равен хорошему дизайну, но мы редко будем наблюдать хороший дизайн это невозможно проверить. Поскольку статические переменные представляют глобальное состояние, их очень сложно проверить.

рассуждения о государстве: если я создаю новый экземпляр класса, мы можем рассуждать о состоянии этого экземпляра, но если у него есть статические переменные, то он может быть в любом состоянии. Почему? Потому что возможно, что статическая переменная была изменена каким-то другим экземпляром, поскольку статическая переменная является общей для всех экземпляров.

сериализация: сериализация также не работает хорошо с ними.

создание и разрушение: создание и уничтожение статических переменных невозможно контролировать. Обычно они создаются и уничтожаются во время загрузки и выгрузки программы. Это означает, что они плохи для управления памятью, а также складывают время инициализации при запуске.

но что, если они нам действительно нужны?

но иногда у нас могут быть подлинная потребность в них. Если мы действительно чувствуем потребность во многих статических переменных, которые совместно используются в приложении, то один из вариантов-использовать одноэлементный шаблон дизайна, который будет иметь все эти переменные. Или мы можем создать некоторый объект, который будет иметь эти статические переменные и может быть передан.

также, если статическая переменная отмечена final, она становится константой, и значение, присвоенное ей один раз, не может быть изменено. Это означает, что это спасет нас от всех проблем, с которыми мы сталкиваемся из-за его изменчивость.


статические переменные самое главное создает проблему с безопасностью данных (любое измененное время,любое может изменить,прямой доступ без объекта, etc.)

для получения дополнительной информации прочитайте этой Спасибо.


Я нахожу статические переменные более удобными в использовании. И я предполагаю, что они также эффективны (пожалуйста, поправьте меня, если я ошибаюсь), потому что, если бы мне пришлось сделать 10 000 вызовов функции в классе, я был бы рад сделать метод статическим и использовать простой класс.methodCall () на нем вместо того, чтобы загромождать память 10,000 экземплярами класса, верно?

Я вижу, что вы думаете, но простой паттерн Singleton будет делать то же самое без необходимости создать 10 000 объектов.

статические методы могут использоваться, но только для функций, связанных с доменом объекта и не нуждающихся во внутренних свойствах объекта.

ex:

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

    public static int convertToGallon(int liters)...

    public static int convertToLiters(int gallon)...

}

вопрос о том, что "статика является злом", больше относится к глобальному государству. Подходящее время для того, чтобы переменная была статической, если она никогда не имеет более одного состояния; т. е. инструменты, которые должны быть доступны всей структуре и всегда возвращать одни и те же результаты для одних и тех же вызовов методов, никогда не являются "злыми", как статика. Что касается вашего комментария:

Я нахожу статические переменные более удобными в использовании. И я предполагаю, что они эффективны слишком!--1-->

статика-идеальный и эффективный выбор для переменных / классов, которые никогда не меняются.

проблема с глобальным состоянием-это неотъемлемая непоследовательность, которую он может создать. Документация о модульных тестах часто решает эту проблему, поскольку в любое время существует глобальное состояние, к которому может получить доступ более чем несколько несвязанных объектов, ваши модульные тесты будут неполными, а не "единичными". Как упоминалось в этой статье о глобальное состояние и синглтоны, если объект A и B не связаны (как в одном явно не дается ссылка на другой), то A не должен быть в состоянии повлиять на состояние B.

есть некоторые исключения из глобального состояния запрета в хорошем коде, например часы. Время глобально, и-в некотором смысле-оно изменяет состояние объектов, не имея закодированных отношений.


Мне кажется, что вы спрашиваете о статических переменных, но вы также указываете статические методы в своих примерах.

статические переменные не являются злом - они имеют свое принятие в качестве глобальных переменных, таких как константы в большинстве случаев в сочетании с окончательным модификатором, но, как он сказал, Не злоупотребляйте ими.

статические методы aka utility method. Обычно это не плохая практика использовать их, но основная проблема заключается в том, что они могут загораживать тестирование.

Как a пример большого проекта java, который использует много статики и делает это правильно, пожалуйста, посмотрите на играть! рамки. Существует также обсуждение об этом в SO.

статические переменные / методы в сочетании со статическим импортом также широко используются в библиотеках, которые облегчают декларативное программирование на java, например:легко или Hamcrest. Это было бы невозможно без большого количества статических переменных и методов.

таким образом, статический переменные (и методы) хороши, но используйте их с умом!


мои $.02 заключается в том, что некоторые из этих ответов запутывают проблему, а не говорят "статика плоха", я думаю, что лучше говорить о области и примерах.

Я бы сказал, что статика-это переменные "класса" - она представляет значение, которое совместно используется во всех экземплярах этого класса. Обычно он также должен быть ограничен таким образом (защищен или закрыт для класса и его экземпляров).

Если вы планируете поместить поведение на уровне класса вокруг него и выставить его для другого кода синглтон может быть лучшим решением для поддержки изменений в будущем (как предложила @Jessica). Это происходит потому, что вы можете использовать интерфейсы на уровне экземпляра/синглтона способами, которые вы не можете использовать на уровне класса - в частности наследование.

некоторые мысли о том, почему я думаю, что некоторые аспекты в других ответах не являются ядром вопроса...

статика не "глобальной". В Java область видимости управляется отдельно от static / instance.

параллелизм не менее опасен для статики, чем методы экземпляра. Это все еще государство, которое нуждается в защите. Конечно, у вас может быть 1000 экземпляров с переменной экземпляра каждый и только одна статическая переменная, но если код доступа либо не написан потокобезопасным способом, вы все еще ввернуты-это может занять немного больше времени, чтобы вы это поняли.

Управление жизненным циклом-интересный аргумент, но я думаю, что это менее важный. Я не понимаю, почему это сложнее управлять парой методов класса, таких как init()/clear (), чем создание и уничтожение одноэлементного экземпляра. На самом деле, некоторые могут сказать, что синглтон немного сложнее из-за GC.

PS, с точки зрения Smalltalk, многие из его диалектов имеют переменные класса, но в классах Smalltalk фактически являются экземплярами Metaclass, поэтому они действительно являются переменными в экземпляре Metaclass. Тем не менее, я бы применил то же самое эмпирическое правило. Если они используются для общего состояния в разных экземплярах затем ok. Если они поддерживают общедоступную функциональность, вы должны посмотреть на Синглтон. Вздох, я действительно скучаю по светской беседе....


нет ничего плохого в статических переменных как таковых. Это просто синтаксис Java, который сломался. Каждый класс Java фактически определяет две структуры-одноэлементный объект, который инкапсулирует статические переменные, и экземпляр. Определение обоих в одном исходном блоке является чистым злом и приводит к коду, который трудно прочитать. Скала все сделала правильно.


a) причина о программах.

Если у вас есть программа малого и среднего размера, где статическая переменная глобальная.доступ к foo осуществляется, вызов к нему обычно приходит из ниоткуда - нет пути, и поэтому нет временной шкалы, как переменная доходит до места, где она используется. Теперь, как я узнаю, кто установил его фактическое значение? Откуда мне знать, что произойдет, если я изменю ее прямо сейчас? У меня есть grep над всем источником, чтобы собрать все доступы, чтобы знать, что происходит.

Если вы знаете, как вы его используете, потому что вы только что написали код, проблема невидима, но если вы попытаетесь понять иностранный код, вы поймете.

b) вам действительно нужен только один?

статические переменные часто предотвращают запуск нескольких программ одного и того же типа в одной JVM с разными значениями. Вы часто не предвидите использования, когда более одного экземпляра вашей программы полезно, но если она развивается или если она полезна для других, они могут опыт ситуациях, где они хотели бы запустить более одного экземпляра программы.

только более или менее бесполезный код, который не будет использоваться многими людьми в течение длительного времени на интенсивный путь и статические переменные.


в вашем посте есть два основных вопроса.

во-первых, о статических переменных. Статические переменные совершенно излишни, и их использования можно легко избежать. В языках ООП в целом, и в Java в частности, параметры функции передаются по ссылке, это означает, что если вы передаете объект в funciont, вы передаете указатель на объект, поэтому вам не нужно определять статические переменные, так как вы можете передать указатель на объект в любую область, которая нуждается в этом информация. Даже если это означает, что yo заполнит вашу память указателями, это не обязательно будет представлять собой низкую производительность, потому что фактические системы разбиения на страницы памяти оптимизированы для обработки этого, и они будут поддерживать в памяти страницы, на которые ссылаются указатели, которые вы передали в новую область; использование статических переменных может привести к загрузке страницы памяти, где они хранятся, когда к ним нужно получить доступ (это произойдет, если страница не была доступна в течение длительного времени). Ля хорошей практикой является объединение всего этого статического stuf в некоторые небольшие "конфигурационные классы", это гарантирует, что система поместит все это на одну страницу памяти.

во-вторых, о статических методах. Статические методы не так уж плохи, но они могут быстро снизить производительность. Например, подумать о метод, который сравнивает два объекта класса и возвращает значение, указывающее, какой из объектов больше (типичный сравнение-метод) этот метод может быть статическим или нет, но при вызове его нестатическая форма будет более эффективной, поскольку ей придется решать только две ссылки (по одной для каждого объекта) на три ссылки, которые должны будут решить статическую версию того же метода (один для класса плюс два, один для каждого объекта). Но, как я уже сказал, это не так плохо, если мы посмотрим на математический класс, мы можем найти много математических функций, определенных как статические методы. Это действительно более эффективно, чем поместить все эти методы в класс, определяющий числа, потому что большинство они редко используются, и включение всех их в класс number приведет к тому, что класс будет очень сложным и потребляет много ресурсов без необходимости.

в concluson: избегайте использования статических переменных и найдите правильное равновесие производительности при работе со статическими или нестатическими методами.

PS: извините за мой английский.


все (can:) имеет свою цель, если у вас есть куча потоков, которые должны поделиться/кэш данные, а также все работает (поэтому вы не разделяетесь на контексты в пределах одной JVM) статика-лучший выбор

-> конечно, вы можете заставить только один экземпляр, но почему?
я нахожу некоторые комментарии в этой теме злыми, а не статиками;)


все ответы выше показывают, почему статика плоха. Причина, по которой они зло потому что это создает ложное впечатление, что вы пишете объектно-ориентированный код, когда на самом деле это не так. Это просто зло.


статические переменные не являются ни добром, ни злом. Они представляют атрибуты, описывающие весь класс, а не конкретный экземпляр. Если вам нужно иметь счетчик для всех экземпляров определенного класса, статическая переменная будет правильным местом для хранения значения.

проблемы появляются при попытке использовать статические переменные для хранения значений, связанных с экземпляром.


есть много хороших ответов здесь, добавив к нему,

память: Статические переменные живут до тех пор, пока загрузчик классов живет[в общем, пока VM не умрет], но это только в случае массовых объектов/ссылок, хранящихся как статические.

модуляризации: рассмотрим такие понятия, как IOC, dependencyInjection, proxy и т. д.. Все совершенно против плотно соединять / статических реализаций.

другие мошенники: безопасность резьбы, тестируемость


подумайте, что если у вас есть приложение со многими пользователями и вы определяете статическую форму, то каждый пользователь будет изменять все другие формы других пользователей.


Я думаю, что чрезмерное использование глобальных переменных со статическим ключевым словом также приведет к утечке памяти в какой-то момент в приложении