Я программист на Java, новичок в корпоративном мире. Недавно я разработал приложение с использованием Groovy и Java. Весь код, который я написал, использовал довольно много статики. Старшая техническая партия попросила меня сократить количество используемой статики. Я примерно так же гуглил и обнаружил, что многие программисты против использования статических переменных.
Я считаю, статические переменные более удобны в использовании. И я предполагаю, что они тоже эффективны (пожалуйста, исправьте меня, если я ошибаюсь), потому что, если бы мне пришлось сделать 10000 вызовов функции внутри класса, я был бы рад сделать метод статичным и использовать прямолинейный метод Class.methodCall()
вместо него. захламляя память 10 000 экземплярами класса, верно?
Более того, статика уменьшает взаимозависимости в других частях кода. Они могут выступать в качестве идеальных государственных держателей. В дополнение к этому я обнаружил, что статика широко применяется в некоторых языках, таких как Smalltalk и Scala . Так почему же это угнетение статики распространено среди программистов (особенно в мире Java)?
PS: пожалуйста, поправьте меня, если мои предположения о статике неверны.
Ответы:
Статические переменные представляют глобальное состояние. Трудно рассуждать и проверять: если я создаю новый экземпляр объекта, я могу рассуждать о его новом состоянии в тестах. Если я использую код, который использует статические переменные, он может находиться в любом состоянии - и все может изменить его.
Я мог бы продолжать в течение некоторого времени, но большая идея, о которой стоит подумать, заключается в том, что чем теснее рамки чего-либо, тем легче рассуждать. Мы хорошо разбираемся в мелочах, но трудно рассуждать о состоянии системы с миллионами линий, если нет модульности. Кстати, это относится ко всем видам вещей, а не только к статическим переменным.
источник
Он не очень объектно-ориентирован: одна из причин, по которой статика может считаться "злой" некоторыми людьми, заключается в том, что они противоречат объектно-ориентированной парадигме . В частности, это нарушает принцип, согласно которому данные заключаются в объекты (которые могут быть расширены, информация скрыта и т. Д.). Статика, как вы описываете, используя их, по сути, должна использовать их как глобальную переменную, чтобы избежать решения таких проблем, как область действия. Однако глобальные переменные являются одной из определяющих характеристик парадигмы процедурного или императивного программирования, а не характеристикой «хорошего» объектно-ориентированного кода. Это не значит, что процедурная парадигма плохая, но у меня сложилось впечатление, что ваш супервайзер ожидает, что вы пишете «хороший объектно-ориентированный код», и вы действительно хотите писать »
Когда вы начинаете использовать статику, в Java есть много уловок, которые не всегда очевидны. Например, если у вас есть две копии вашей программы, работающие на одной и той же виртуальной машине, будут ли они хранить значение статической переменной и взаимодействовать с состоянием друг друга? Или что происходит, когда вы расширяете класс, можете ли вы переопределить статический член? Ваша виртуальная машина исчерпала память, потому что у вас есть безумные числа статики, и эта память не может быть восстановлена для других необходимых объектов экземпляра?
Время жизни объекта. Кроме того, у статики есть время жизни, которое соответствует всему времени выполнения программы. Это означает, что даже когда вы закончили использовать свой класс, память от всех этих статических переменных не может быть собрана сборщиком мусора. Если, например, вместо этого вы сделали свои переменные нестатическими, а в своей функции main () вы сделали один экземпляр вашего класса, а затем попросили ваш класс выполнить определенную функцию 10000 раз после выполнения этих 10000 вызовов и вы удаляете ссылки на один экземпляр, все ваши статические переменные могут быть собраны и использованы повторно.
Предотвращает определенное повторное использование. Кроме того, статические методы не могут использоваться для реализации интерфейса, поэтому статические методы могут препятствовать использованию определенных объектно-ориентированных функций.
Другие опции: Если ваша главная задача - эффективность, то могут быть и другие более эффективные способы решения проблемы скорости, чем рассмотрение только преимущества вызова, заключающегося в большей скорости, чем создание. Подумайте, нужны ли где-нибудь временные или переменные модификаторы. Чтобы сохранить возможность встраивания, метод может быть помечен как final, а не static. Параметры метода и другие переменные могут быть помечены как окончательные, чтобы разрешить определенные оптимизации компилятора на основе предположений о том, что может изменить эти переменные. Объект экземпляра можно использовать повторно несколько раз, вместо того, чтобы каждый раз создавать новый экземпляр. Там могут быть переключатели оптимизации компилятора, которые должны быть включены для приложения в целом. Возможно, дизайн должен быть настроен так, чтобы 10000 прогонов могли быть многопоточными и использовать преимущества многопроцессорных ядер. Если портативности нет
Если по какой-либо причине вам не нужны несколько копий объекта, шаблон проектирования синглтонаимеет преимущества перед статическими объектами, такие как безопасность потоков (при условии, что ваш синглтон хорошо закодирован), возможность ленивой инициализации, гарантия правильной инициализации объекта при его использовании, подклассификация, преимущества в тестировании и рефакторинге вашего кода, не говоря уже о том, что если в какой-то момент вы передумали о том, что вам нужен только один экземпляр объекта, гораздо проще удалить код, чтобы предотвратить дублирование экземпляров, чем реорганизовать весь код статической переменной для использования переменных экземпляра. Я должен был сделать это раньше, это не весело, и вам в конечном итоге придется редактировать намного больше классов, что увеличивает риск появления новых ошибок ... намного лучше, чтобы все было "правильно" в первый раз, даже если кажется, что у него есть свои недостатки. Для меня, Необходимая переделка, если вы решите, что в будущем вам понадобится несколько копий чего-либо, является, вероятно, одной из наиболее веских причин для использования статики как можно реже. И поэтому я также не согласен с вашим утверждением о том, что статика уменьшает взаимозависимости, я думаю, что в итоге вы получите код, который будет более связанным, если у вас много статик, к которым можно получить прямой доступ, а не объект, который «знает, как делать» что-то "на себя".
источник
synchronized
методов), это не означает, что в вызывающем коде нет условий гонки по отношению к синглтонному состоянию.Object Lifetime
, это один очень важный момент, который упоминал @jessica.Зло это субъективный термин.
Вы не контролируете статику с точки зрения создания и разрушения. Они живут по указанию программы загрузки и выгрузки.
Поскольку статика находится в одном пространстве, все потоки, желающие их использовать, должны пройти контроль доступа, которым вы должны управлять. Это означает, что программы являются более связанными, и это изменение труднее предвидеть и управлять (как говорит Дж. Скит). Это приводит к проблемам изоляции воздействия изменений и, следовательно, влияет на управление тестированием.
Вот две основные проблемы, которые у меня есть с ними.
источник
Нет. Глобальные государства не являются злом как таковым. Но мы должны увидеть ваш код, чтобы увидеть, правильно ли вы его использовали. Вполне возможно, что новичок злоупотребляет глобальными государствами; так же, как он злоупотребляет каждой языковой особенностью.
Глобальные состояния абсолютно необходимы. Мы не можем избежать глобальных государств. Мы не можем избежать рассуждений о глобальных государствах. - Если мы хотим понять семантику нашего приложения.
Люди, которые пытаются избавиться от глобальных государств ради этого, неизбежно заканчиваются гораздо более сложной системой - и глобальные государства все еще там, хитро / идиотски замаскированы под многими слоями косвенных указаний; и мы все еще должны рассуждать о глобальных государствах, развернув все косвенности.
Как и люди Spring, которые щедро объявляют глобальные состояния в XML и считают, что это лучше.
@Jon Skeet
if I create a new instance of an object
Теперь у вас есть две причины для размышления - состояние внутри объекта и состояние среды, в которой размещается объект.источник
Есть 2 основных проблемы со статическими переменными:
источник
Если вы используете ключевое слово «static» без ключевого слова «final», это должно быть сигналом к тщательному рассмотрению вашего дизайна. Даже наличие 'final' не является свободным проходом, поскольку изменяемый статический конечный объект может быть столь же опасным.
Я бы оценил где-то в 85% случаев, когда вижу «статичный» без «финала», это НЕПРАВИЛЬНО. Часто я нахожу странные обходные пути, чтобы замаскировать или скрыть эти проблемы.
Пожалуйста, не создавайте статические изменяемые файлы. Особенно Коллекции. В общем, Коллекции должны быть инициализированы, когда инициализируется их содержащий объект, и должны быть спроектированы таким образом, чтобы они были сброшены или забыты, когда их содержащий объект забыт.
Использование статики может создать очень тонкие ошибки, которые причинят инженерам мучительные дни боли. Я знаю, потому что я и создал и охотился на этих ошибок.
Если вы хотите получить более подробную информацию, пожалуйста, читайте дальше ...
Почему бы не использовать статику?
Есть много проблем со статикой, включая написание и выполнение тестов, а также тонкие ошибки, которые не сразу очевидны.
Код, основанный на статических объектах, не может быть легко протестирован модулем, а статика не может быть легко смоделирована (обычно).
Если вы используете статику, невозможно поменять реализацию класса, чтобы протестировать компоненты более высокого уровня. Например, представьте статический CustomerDAO, который возвращает объекты Customer, которые он загружает из базы данных. Теперь у меня есть класс CustomerFilter, которому требуется доступ к некоторым объектам Customer. Если CustomerDAO статический, я не могу написать тест для CustomerFilter без предварительной инициализации моей базы данных и заполнения полезной информации.
А заполнение и инициализация базы данных занимает много времени. По моему опыту, ваша структура инициализации БД со временем будет меняться, а это значит, что данные будут изменяться, и тесты могут прерваться. IE, представьте, что Customer 1 раньше был VIP, но структура инициализации БД изменилась, и теперь Customer 1 больше не VIP, но ваш тест был жестко запрограммирован для загрузки Customer 1…
Лучшим подходом является создание экземпляра CustomerDAO и передача его в CustomerFilter при его создании. (Еще лучший подход - использовать Spring или другую платформу Inversion of Control.
Как только вы это сделаете, вы можете быстро смоделировать или заглушить альтернативный DAO в вашем CustomerFilterTest, что позволит вам иметь больше контроля над тестом,
Без статического DAO тест будет более быстрым (без инициализации db) и более надежным (потому что он не потерпит неудачу при изменении кода инициализации db). Например, в этом случае обеспечение того, чтобы Клиент 1 был и всегда будет VIP, насколько это касается теста.
Выполнение тестов
Статика вызывает реальную проблему при совместном запуске комплектов модульных тестов (например, на сервере Continuous Integration). Представьте себе статическую карту сетевых объектов Socket, которая остается открытой от одного теста к другому. Первый тест может открыть Socket на порту 8080, но вы забыли очистить карту, когда тест будет сорван. Теперь, когда запускается второй тест, он может потерпеть крах, когда попытается создать новый сокет для порта 8080, поскольку порт все еще занят. Представьте также, что ссылки на сокеты в вашей статической коллекции не удаляются и (за исключением WeakHashMap) никогда не могут быть подвергнуты сборке мусора, что приводит к утечке памяти.
Это слишком обобщенный пример, но в больших системах эта проблема возникает ВСЕ ВРЕМЯ. Люди не думают о модульных тестах, запускающих и останавливающих свое программное обеспечение повторно в одной и той же JVM, но это хороший тест вашего программного обеспечения, и если у вас есть стремление к высокой доступности, это то, о чем вы должны знать.
Эти проблемы часто возникают с объектами инфраструктуры, например, с уровнями доступа к БД, уровнями кэширования, обмена сообщениями и ведения журнала. Если вы используете Java EE или некоторые из лучших в своем роде фреймворков, они, вероятно, справятся с этим для вас, но если вы, как и я, имеете дело с устаревшей системой, у вас может быть много пользовательских фреймворков для доступа к этим уровням.
Если конфигурация системы, которая применяется к этим компонентам инфраструктуры, изменяется между модульными тестами, а среда модульного тестирования не разрушает и не перестраивает компоненты, эти изменения не вступают в силу, и когда тест полагается на эти изменения, они завершатся неудачно. ,
Даже не-каркасные компоненты подвержены этой проблеме. Представьте себе статическую карту под названием OpenOrders. Вы пишете один тест, который создает несколько открытых ордеров, и проверяет, чтобы убедиться, что все они находятся в правильном состоянии, затем тест завершается. Другой разработчик пишет второй тест, который помещает необходимые ему заказы в карту OpenOrders, а затем утверждает, что количество заказов является точным. Выполненные по отдельности, эти тесты оба пройдут, но при запуске вместе в комплекте они не пройдут.
Хуже того, сбой может быть основан на порядке, в котором выполнялись тесты.
В этом случае, избегая статики, вы избегаете риска сохранения данных в разных тестовых экземплярах, обеспечивая лучшую надежность теста.
Тонкие ошибки
Если вы работаете в среде высокой доступности или в любом месте, где потоки могут запускаться и останавливаться, то же самое упомянутое выше замечание с комплектами модульных тестов может применяться, когда ваш код также работает в рабочей среде.
При работе с потоками вместо статического объекта для хранения данных лучше использовать объект, инициализированный на этапе запуска потока. Таким образом, каждый раз, когда поток запускается, создается новый экземпляр объекта (с потенциально новой конфигурацией), и вы избегаете передачи данных от одного экземпляра потока до следующего экземпляра.
Когда поток умирает, статический объект не получает сброс или сборку мусора. Представьте, что у вас есть поток с именем «EmailCustomers», и когда он запускается, он заполняет статическую коллекцию строк списком адресов электронной почты, а затем начинает отправлять электронные письма на каждый из адресов. Допустим, поток каким-то образом прерван или отменен, поэтому среда высокой доступности перезапускает поток. Затем, когда поток запускается, он перезагружает список клиентов. Но поскольку коллекция является статической, она может сохранить список адресов электронной почты из предыдущей коллекции. Теперь некоторые клиенты могут получить дубликаты писем.
В сторону: статический финал
Использование «static final» фактически является Java-эквивалентом C #define, хотя существуют технические различия в реализации. AC / C ++ #define выгружается из кода препроцессором перед компиляцией. Java «статический финал» в конечном итоге останется в стеке. Таким образом, она больше похожа на переменную «static const» в C ++, чем на #define.
Резюме
Я надеюсь, что это поможет объяснить несколько основных причин, по которым статика вызывает проблемы. Если вы используете современную среду Java, такую как Java EE или Spring и т. Д., Вы можете не сталкиваться со многими из этих ситуаций, но если вы работаете с большим объемом устаревшего кода, они могут стать гораздо более частыми.
источник
Поскольку никто не упомянул это: параллелизм. Статические переменные могут вас удивить, если у вас есть несколько потоков, читающих и записывающих в статическую переменную. Это часто встречается в веб-приложениях (например, ASP.NET) и может вызывать довольно сумасшедшие ошибки. Например, если у вас есть статическая переменная, которая обновляется страницей, и страница запрашивается двумя людьми «почти в одно и то же время», один пользователь может получить результат, ожидаемый другим пользователем, или хуже.
Я надеюсь, что вы готовы использовать замки и бороться с раздорами.
* На самом деле, Прит Сангха упомянул об этом.
источник
Обобщая некоторые основные преимущества и недостатки использования статических методов в Java:
Преимущества:
Недостатки:
источник
Вы должны сбалансировать необходимость инкапсуляции данных в объект с состоянием, а не просто вычисление результата функции для некоторых данных.
Как и инкапсуляция. В больших приложениях статика, как правило, создает код спагетти и не позволяет легко проводить рефакторинг или тестирование.
Другие ответы также дают веские основания против чрезмерного использования статики.
источник
Статические переменные, как правило, считаются плохими, потому что они представляют глобальное состояние и поэтому гораздо труднее рассуждать. В частности, они нарушают предпосылки объектно-ориентированного программирования. В объектно-ориентированном программировании каждый объект имеет свое собственное состояние, представленное экземплярами (нестатическими) переменными. Статические переменные представляют состояние между экземплярами, что может быть гораздо сложнее для модульного тестирования. Это происходит главным образом потому, что сложнее изолировать изменения статических переменных в одном тесте.
При этом важно различать обычные статические переменные (обычно считается плохими) и конечные статические переменные (константы АКА; не так уж плохо).
источник
На мой взгляд, это почти никогда не связано с производительностью, а с дизайном. Я не считаю использование статических методов неправильным, как применение статических переменных (но я полагаю, что вы на самом деле говорите о вызовах методов).
Это просто о том, как изолировать логику и дать ей хорошее место. Иногда это оправдывает использование статических методов, что
java.lang.Math
является хорошим примером. Я думаю, когда вы называете большинство своих классовXxxUtil
илиXxxhelper
вам лучше пересмотреть свой дизайн.источник
Я только что подытожил некоторые моменты, высказанные в ответах. Если вы нашли что-то не так, пожалуйста, исправьте это.
Масштабирование. У нас есть ровно один экземпляр статической переменной для каждой виртуальной машины Java. Предположим, что мы разрабатываем систему управления библиотекой, и мы решили присвоить названию книги статическую переменную, поскольку в каждой книге только одна переменная. Но если система развивается и мы используем несколько JVM, то у нас нет способа выяснить, с какой книгой мы имеем дело?
Потоковая безопасность: Как переменная экземпляра и статическая потребность переменная контролируется при использовании многопоточных окружающей среды. Но в случае переменной экземпляра она не нуждается в защите, если она явно не разделена между потоками, но в случае статической переменной она всегда используется всеми потоками в процессе.
Тестирование: хотя тестируемый дизайн не равен хорошему дизайну, но мы редко наблюдаем хороший дизайн, который не подлежит тестированию. Поскольку статические переменные представляют глобальное состояние, их очень сложно протестировать.
Рассуждение о состоянии: если я создаю новый экземпляр класса, мы можем рассуждать о состоянии этого экземпляра, но если он имеет статические переменные, он может находиться в любом состоянии. Почему? Поскольку возможно, что статическая переменная была изменена некоторым другим экземпляром, поскольку статическая переменная является общей для всех экземпляров.
Сериализация: Сериализация также не работает с ними.
Создание и уничтожение: создание и уничтожение статических переменных невозможно контролировать. Обычно они создаются и уничтожаются во время загрузки и выгрузки программы. Это означает, что они плохо подходят для управления памятью, а также добавляют время инициализации при запуске.
Но что, если они нам действительно нужны?
Но иногда мы можем нуждаться в них. Если мы действительно чувствуем потребность во многих статических переменных, которые совместно используются приложением, тогда одним из вариантов является использование шаблона Singleton Design, который будет иметь все эти переменные. Или мы можем создать некоторый объект, который будет иметь эти статические переменные и может быть передан.
Также, если статическая переменная помечена как финальная, она становится константой, и значение, присвоенное ей один раз, не может быть изменено. Это означает, что он избавит нас от всех проблем, с которыми мы сталкиваемся из-за своей изменчивости.
источник
Мне кажется, что вы спрашиваете о статических переменных, но вы также указываете статические методы в своих примерах.
Статические переменные не являются злыми - они используются в качестве глобальных переменных, таких как константы, в большинстве случаев в сочетании с модификатором final, но, как говорится, не злоупотребляйте ими.
Статические методы ака полезный метод. Как правило, их использование не является плохой практикой, но основная проблема заключается в том, что они могут препятствовать тестированию.
В качестве примера отличного Java-проекта, который использует много статики и делает это правильно, пожалуйста, посмотрите на Play! рамки . Также есть обсуждение в SO.
Статические переменные / методы в сочетании со статическим импортом также широко используются в библиотеках, которые облегчают декларативное программирование в Java, например: облегчают или Hamcrest . Это было бы невозможно без большого количества статических переменных и методов.
Так что статические переменные (и методы) хороши, но используйте их с умом!
источник
Статические переменные, что наиболее важно, создают проблему с безопасностью данных (при любом изменении, любой может измениться, прямой доступ без объекта и т. Д.)
Для получения дополнительной информации прочитайте это Спасибо.
источник
Можно предположить, что в большинстве случаев, когда вы используете статическую переменную, вы действительно хотите использовать шаблон синглтона .
Проблема с глобальными состояниями заключается в том, что иногда то, что имеет смысл быть глобальным в более простом контексте, должно быть немного более гибким в практическом контексте, и именно здесь шаблон синглтона становится полезным.
источник
Еще одна причина: хрупкость.
Если у вас есть класс, большинство людей ожидают, что смогут его создать и использовать по желанию.
Вы можете задокументировать, что это не так, или защитить от этого (синглтон / фабричный шаблон) - но это дополнительная работа и, следовательно, дополнительные расходы. Даже тогда, в большой компании, есть вероятность, что кто-то попытается в какой-то момент использовать ваш класс, не обращая должного внимания на все приятные комментарии или фабрику.
Если вы часто используете статические переменные, это сломается. Ошибки стоят дорого.
Между улучшением производительности на 0,0001% и устойчивостью к изменениям со стороны потенциально невежественных разработчиков, во многих случаях надежность является хорошим выбором.
источник
Я считаю, статические переменные более удобны в использовании. И я предполагаю, что они тоже эффективны (пожалуйста, исправьте меня, если я ошибаюсь), потому что, если бы мне пришлось сделать 10000 вызовов функции внутри класса, я был бы рад сделать метод статическим и использовать простой class.methodCall () на нем вместо того, чтобы загромождать память 10 000 экземплярами класса, верно?
Я понимаю, что вы думаете, но простой шаблон Singleton будет делать то же самое без необходимости создания экземпляров 10 000 объектов.
Статические методы могут использоваться, но только для функций, которые связаны с предметной областью и не нуждаются или не используют внутренние свойства объекта.
например:
источник
Class.Instance
) чуть лучше, чем статическая переменная. Это немного более тестируемо, но все же намного хуже, чем проекты, в которых вы просто создаете один экземпляр, а не строите свой код, исходя из предположения, что есть только один.Class.Instance
), который несет изменяемое состояние, является плохим дизайном IMO. В этом случае я настоятельно предпочитаю проект, в котором я получаю синглтоны, которые мне нужно использовать, передаваемые в качестве параметра в класс, который их использует (обычно с помощью DI). Логически неизменные классические синглтоны - это хорошо, IMO.Проблема «статики быть злым» - это скорее проблема глобального состояния. Подходящее время для того, чтобы переменная была статической, - это если у нее никогда не было более одного состояния; Инструменты IE, которые должны быть доступны для всей среды и всегда возвращать одинаковые результаты для одних и тех же вызовов методов, никогда не являются «злыми», как статические. Что касается вашего комментария:
Статика - идеальный и эффективный выбор для переменных / классов, которые никогда не меняются .
Проблема с глобальным состоянием - это внутреннее несоответствие, которое оно может создать. Документация о модульных тестах часто решает эту проблему, так как в любое время, когда существует глобальное состояние, к которому могут обращаться более чем несколько несвязанных объектов, ваши модульные тесты будут неполными, а не «модульными». Как упоминалось в этой статье о глобальном состоянии и синглетонах , если объект A и B не связаны (так как в одном явно не указана ссылка на другой), то A не должен иметь возможности влиять на состояние B.
Есть несколько исключений для запрета глобального состояния в хорошем коде, например, часы. Время является глобальным и, в некотором смысле, оно изменяет состояние объектов, не имея закодированных отношений.
источник
Мои $ .02 в том, что некоторые из этих ответов сбивают с толку проблему, вместо того, чтобы сказать «статика плохая», я думаю, что лучше поговорить о масштабах и случаях.
Я бы сказал, что статические переменные - это «классовые» переменные - они представляют значение, которое используется всеми экземплярами этого класса. Как правило, он должен быть ограничен таким же образом (защищенным или закрытым для класса и его экземпляров).
Если вы планируете использовать поведение на уровне класса и предоставлять его другому коду, то единственное приложение может быть лучшим решением для поддержки изменений в будущем (как предложила @Jessica). Это потому, что вы можете использовать интерфейсы на уровне экземпляра / синглтона способами, которые вы не можете использовать на уровне класса - в частности наследование.
Некоторые мысли о том, почему я думаю, что некоторые аспекты других ответов не являются ключевыми для вопроса ...
Статика не "глобальная". В Java область видимости контролируется отдельно от static / instance.
Параллельность не менее опасна для статики, чем методы экземпляра. Это все еще государство, которое должно быть защищено. Конечно, у вас может быть 1000 экземпляров с переменной экземпляра каждая и только одна статическая переменная, но если код, к которому осуществляется доступ, не написан потокобезопасным способом, вы все еще ввернуты - вам может потребоваться немного больше времени, чтобы понять это ,
Управление жизненным циклом - интересный аргумент, но я думаю, что он менее важен. Я не понимаю, почему так сложно управлять парой методов класса, таких как init () / clear (), чем создание и уничтожение экземпляра синглтона. На самом деле, некоторые могут сказать, что синглтон немного сложнее из-за GC.
PS С точки зрения Smalltalk, многие из его диалектов имеют переменные класса, но в Smalltalk классы на самом деле являются экземплярами Metaclass, поэтому они действительно являются переменными в экземпляре Metaclass. Тем не менее, я бы применил то же правило. Если они используются для общего состояния между экземплярами, тогда хорошо. Если они поддерживают публичную функциональность, вам стоит взглянуть на Singleton. Вздох, я действительно скучаю по Smalltalk ....
источник
В вашем посте есть два основных вопроса.
Сначала о статических переменных. Статические переменные совершенно не нужны, и их легко избежать. В языке ООП в целом, и в частности в Java, параметры функции передаются по ссылке, то есть, если вы передаете объект в функцию, вы передаете указатель на объект, поэтому вам не нужно определять статические переменные, так как Вы можете передать указатель на объект в любую область, которая нуждается в этой информации. Даже если это подразумевает, что yo будет заполнять вашу память указателями, это не обязательно будет означать низкую производительность, поскольку реальные системы разбивки памяти оптимизированы для работы с этим, и они будут сохранять в памяти страницы, на которые ссылаются указатели, которые вы передали новому. объем; использование статических переменных может привести к тому, что система загрузит страницу памяти, где они хранятся, когда к ним необходимо получить доступ (это произойдет, если страница не была принята в течение длительного времени). Хорошей практикой является объединение всех этих статических компонентов в несколько маленьких «пунктов конфигурации», это гарантирует, что система поместит все это на одну и ту же страницу памяти.
Во-вторых, о статических методах. Статические методы не так уж и плохи, но они могут быстро снизить производительность. Например, подумайте о методе, который сравнивает два объекта класса и возвращает значение, указывающее, какой из объектов больше (типичный метод сравнения), этот метод может быть статическим или нет, но при вызове его нестатическая форма будет более эффективной. поскольку он должен будет решить только две ссылки (по одной для каждого объекта) лицом к трем ссылкам, которые должны будут решить статическую версию одного и того же метода (одна для класса плюс две, одна для каждого объекта). Но, как я уже сказал, это не так уж и плохо, если мы посмотрим на класс Math, мы сможем найти множество математических функций, определенных как статические методы. Это действительно более эффективно, чем помещать все эти методы в класс, определяющий числа,
В заключение: избегайте использования статических переменных и находите правильное равновесие производительности при работе со статическими или нестатическими методами.
PS: извините за мой английский.
источник
Нет ничего плохого в статических переменных как таковых. Это просто синтаксис Java, который нарушен. Каждый класс Java фактически определяет две структуры - одноэлементный объект, который инкапсулирует статические переменные, и экземпляр. Определение обоих в одном и том же исходном блоке - чистое зло, и в результате получается код, который трудно прочитать. Скала сделала это правильно.
источник
а) Причина о программах.
Если у вас есть программа для малого и среднего размера, в которой доступна статическая переменная Global.foo, то вызов к ней обычно происходит из ниоткуда - нет пути и, следовательно, нет временной шкалы, как переменная попадает в то место, где она используется. Теперь, как я узнаю, кто установил его действительное значение? Как я узнаю, что произойдет, если я изменю это прямо сейчас? У меня есть grep для всего источника, чтобы собрать все доступы, чтобы узнать, что происходит.
Если вы знаете, как вы его используете, потому что вы только что написали код, проблема невидима, но если вы попытаетесь понять иностранный код, вы поймете.
б) Вам действительно нужен только один?
Статические переменные часто не позволяют нескольким программам одного типа работать в одной и той же JVM с разными значениями. Вы часто не предвидите использования, когда более чем один экземпляр вашей программы полезен, но если он развивается или если это полезно для других, они могут столкнуться с ситуациями, когда они хотели бы запустить более одного экземпляра вашей программы ,
Только более или менее бесполезный код, который не будет интенсивно использоваться многими людьми в течение более длительного времени, может хорошо сочетаться со статическими переменными.
источник
все (может :) имеет свое предназначение, если у вас есть куча потоков, которые должны обмениваться / кэшировать данные, а также вся доступная память (так что вы не разбиваетесь на контексты внутри одной JVM), статический вариант
- лучший выбор -> конечно, вы можете форсировать только один экземпляр, но почему?
я нахожу некоторые комментарии в этой теме злыми, а не статиками;)
источник
Статические переменные не являются ни добром, ни злом. Они представляют атрибуты, которые описывают весь класс, а не конкретный экземпляр. Если вам нужен счетчик для всех экземпляров определенного класса, статическая переменная будет правильным местом для хранения значения.
Проблемы возникают, когда вы пытаетесь использовать статические переменные для хранения значений, связанных с экземпляром.
источник
Все ответы выше показывают, почему статика плохая. Причина, по которой они являются злыми, заключается в том, что создается ложное впечатление, будто вы пишете объектно-ориентированный код, а на самом деле это не так. Это просто зло.
источник
Здесь есть много хороших ответов, добавляя к этому,
Память: Статические переменные живут до тех пор, пока загрузчик классов живет [в общем, до тех пор, пока не умрет VM], но это только в случае массовых объектов / ссылок, хранящихся как статические.
Модуляризация: рассмотрите такие понятия, как IOC, dependencyInjection, прокси и т. Д. Все они полностью против тесно связанных / статических реализаций.
Другие доводы "против": безопасность потоков, тестируемость
источник
Подумайте, что если у вас есть приложение с большим количеством пользователей и вы определили статическую форму, то каждый пользователь будет изменять все другие формы других пользователей.
источник
Я думаю, что чрезмерное использование глобальных переменных со статическим ключевым словом также приведет к утечке памяти в какой-то момент в приложении
источник
С моей точки зрения
static
переменная должна быть только для чтения только данных или переменных, созданных по соглашению .Например, у нас есть пользовательский интерфейс какого-либо проекта, у нас есть список стран, языков, ролей пользователей и т. Д. И у нас есть класс для организации этих данных. мы абсолютно уверены, что приложение не будет работать без этих списков. поэтому первое, что мы делаем в приложении init, это проверка этого списка на наличие обновлений и получение этого списка из API (при необходимости). Поэтому мы согласны с тем, что эти данные «всегда» присутствуют в приложении. Это практически данные только для чтения, поэтому нам не нужно заботиться о их состоянии - думая об этом случае, мы действительно не хотим иметь много экземпляров этих данных - этот случай выглядит идеальным кандидатом на статичность .
источник
Я много играл со статикой, и могу ли я дать вам немного другой ответ - или, возможно, немного другой взгляд на это?
Когда я использовал статику в классе (члены и методы оба), я в конце концов начал замечать, что мой класс на самом деле состоит из двух классов, разделяющих ответственность - есть «Статическая» часть, которая во многом похожа на одиночную, и -статическая часть (нормальный класс). Насколько я знаю, вы всегда можете полностью разделить эти два класса, просто выбрав все статические значения для одного класса и нестатические для другого.
Это часто случалось, когда внутри класса была статическая коллекция, содержащая экземпляры класса и некоторые статические методы для управления коллекцией. Когда вы думаете об этом, становится очевидным, что ваш класс не делает «только одну вещь», он представляет собой коллекцию, а делает что-то совершенно другое.
Теперь давайте немного реорганизуем проблему: если вы разделите свой класс на один класс, где все статично, а другой - просто «нормальный класс» и забудете о «нормальном классе», тогда ваш вопрос станет чисто статическим классом против синглтона, который подробно рассматривается здесь (и, вероятно, дюжина других вопросов).
источник