2016-06-09 6 views
9

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

Мой вопрос: если класс не имеет каких-либо переменных уровня класса, могу ли я сделать все методы в классе static?

Я полагаю, что проблем с резьбой не будет.

Есть ли последствия? Есть ли какое-либо преимущество в производительности, поскольку мне не нужно создавать экземпляр класса?

Класс образца:

Class A{ 
    public Object findTheCar(String id){  
     Car car= new Car();  
     //do something  
     return car;  
    } 
} 

Я намерен изменить выше статической.

+0

Если вы обнаружите, что хотите писать классы, содержащие много/все статические методы, вы не думаете объектно-ориентированные; вы не делаете дизайн OO. Для получения дополнительной информации обратитесь к учебнику, например http://www.amazon.com/dp/0672330164/?tag=stackoverfl08-20. – BadZen

+0

О, я не знаю, может быть, ваш работодатель, профессор, коллеги, будущий я и Будда? – BadZen

+0

@BadZen некоторые из них кажутся действительными;) –

ответ

17

Одно правило большого пальца: спросите себя «имеет ли смысл называть этот метод, даже если объект Obj еще не построен?» Если это так, это обязательно должно быть статичным.

Так что в классе Car у вас может быть метод double convertMpgToKpl(double mpg), который был бы статическим, потому что можно было бы узнать, к чему преобразуется 35mpg, даже если никто никогда не строил автомобиль. Но void setMileage(double mpg) (который устанавливает эффективность одного конкретного автомобиля) не может быть статичным, поскольку невозможно вызвать метод до того, как какой-либо автомобиль будет построен.

(Btw, обратное не всегда верно: иногда вы можете иметь метод, который включает в себя два объекта Car, и все еще хочет, чтобы он был статичным. Например, Car theMoreEfficientOf(Car c1, Car c2).Хотя это можно было бы преобразовать в нестатистическую версию, некоторые утверждают, что, поскольку нет «привилегированного» выбора того, какой автомобиль более важен, вы не должны заставлять вызывающего абонента выбирать один автомобиль как объект, на который вы будете ссылаться. Эта ситуация объясняет довольно небольшую доля всех статических методов, хотя)

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

  • Производительность: если вы хотите, чтобы какой-то код запускался и не хотите создавать экземпляр дополнительного объекта, сделайте это в статическом методе. JVM также может много оптимизировать статические методы (я думаю, что однажды я прочитал Джеймса Гослинга, заявив, что вам не нужны специальные инструкции в JVM, поскольку статические методы будут такими же быстрыми, но не могут найти источник - таким образом это может быть полностью ложным). Да, это микро-оптимизация и, вероятно, ненужная. И мы, программисты, никогда не делаем ненужных вещей только потому, что они классные, не так ли?

  • Практичность: вместо вызова нового метода Util(). (Arg) вызовите метод Util.method (arg) или метод (arg) со статическим импортом. Легче, короче.

  • методы Добавление: вы действительно хотели класса String, чтобы иметь removeSpecialChars() метод экземпляра, но это не есть (и это не должно, так как специальные символы вашего проекта может отличаться от другого проекта), и вы не можете добавить его (поскольку Java минимально нормальная), поэтому вы создаете класс утилиты и вызываете removeSpecialChars (s) вместо s.removeSpecialChars(). Милая.

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

Вы также должны создать статический метод, если вы хотите сделать одноплодной, но ... нет. Я имею в виду, подумайте дважды.

Теперь, что более важно, почему вы не хотите создавать статический метод? В основном, полиморфизм выходит из окна. Вы не сможете переопределить метод и не объявлять его в интерфейсе. Это требует большой гибкости от вашего дизайна. Кроме того, если вам нужно состояние, вы получите множество ошибок ошибок параллелизма и/или узких мест, если вы не будете осторожны.

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

  1. Если вы пишете вспомогательные классы, и они не должны быть изменены.
  2. Если метод не использует переменную экземпляра.
  3. Если какая-либо операция не зависит от создания экземпляра.
  4. Если есть код, который может быть легко разделен всеми методами экземпляра, извлеките этот код в статический метод.
  5. Если вы уверены, что определение метода никогда не будет изменено или переопределено. Поскольку статические методы нельзя переопределить.

Позволяет также обсудить его более подробно:

Преимущества:

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

Недостатки:

Статические члены являются частью класса и, таким образом, остаются в памяти до Завершает приложения и не может быть когда-либо мусора. Использование избытка статических элементов когда-либо предсказывает, что вы не можете спроектировать свой продукт и пытаетесь использовать статическое/процедурное программирование. Это означает, что объектно-ориентированный дизайн скомпрометирован. Это может привести к переполнению памяти. Также есть некоторые недостатки, если вы ставите какой-либо метод статическим в Java, например, вы не можете переопределить какой-либо статический метод в Java, поэтому он усложняет тестирование, вы не можете заменить этот метод макетом. Поскольку статический метод поддерживает глобальное состояние, он может создавать тонкую ошибку в параллельной среде, которую трудно обнаружить и исправить.

Что нужно помнить:

Статическая переменная будет частью определения класса, а не в куче. Однако статические переменные полезны, когда вы знаете, что будут доступны объекты из нескольких мест. Доступ к статическим ресурсам не является потокобезопасным.Вы можете получить странные/непредсказуемые результаты в поточной среде. Но если ваше единственное чтение статического значения, то использование потоков для него в порядке.

Как Статическая Перерывы инкапсуляция:

техническая реализация которых должна позволить государству поддерживать во всех экземпляров класса. Проблема в том, что это по сути не ООП, поскольку она не учитывает инкапсуляцию. Если переменная может быть изменена любым экземпляром класса, то основной принцип скрытия инкапсуляции/информации полностью теряется: объект больше не полностью контролирует его состояние. Его состояние теперь зависит от переменных, которые по сути являются глобальными. Мы знаем, что это плохо. Даже частные статические переменные сохраняют состояние на глобальном уровне, но просто ограничивают его доступ. Любой экземпляр объекта может изменять статическую переменную, которая вызывает неоднозначность, поскольку отдельные экземпляры объекта больше не имеют контроля над своим собственным состоянием. Изменения состояния могут произвольно происходить без знания объекта, который полагается на это состояние, которое является проблематичным, потому что объект может работать неправильно, когда это происходит. Как часто говорят, что «Наследование прерывает инкапсуляцию», статика делает это гораздо более серьезным образом: не только подвергая внутреннюю реализацию, но и подвергая внутреннее состояние.

В вашем примере Вопрос:

Как упоминалось выше, метод будет использоваться в многопоточном invironment, думать о следующей задаче (модифицированный код):

public Object findTheCar(String id) { 
     Car car = null; //Line 2 
     if (id != null) { 
      car = new Car(); 
     } 
     //Line 6 
     // do something 

     // 
     //Line 10 
     return car; 
    } 

В приведенном выше примере: если это выполнено из двух потоков, а 1-я нить - на линии , а вторая нить находится в строке 2, все еще это w плохой нить безопасный.

Потому что:

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

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

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

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

От: http://tutorials.jenkov.com/java-concurrency/thread-safety.html

+0

Спасибо за ваше драгоценное время и хорошо накрытый ответ. Но моя точка зрения заключается в том, что класс не содержит каких-либо переменных класса, как класс должен иметь состояние для изменения? то же самое с сборкой мусора. А почему классифицировать как класс утилиты? Мой класс здесь будет обрабатывать одновременные запросы. – blathur

+0

@rahulk обновил ответ, чтобы дать вам больше ясности. –

+0

@ shridutt kothari У меня есть сомнения в обновленном ответе: «Оба потока будут обрабатывать метод в их собственном контексте, никогда не перекрываться - не так ли? Другая мудрая эта проблема будет возникать для всех классов утилиты. – blathur

3

Если у вас нет переменных уровня класса, то да, вы можете сделать все методы на классе статическими. И это может быть даже немного более эффективным из-за исключения экземпляров объектов. Но в объектно-ориентированном программировании объекты имеют «состояние» и «поведение». У ваших объектов нет состояния, только поведение.Так вы действительно делаете объектно-ориентированное программирование здесь? Я бы сказал, что вы не (что не обязательно плохо). Но, возможно, вам может быть удобнее на языке программирования, отличном от OO.

+0

Что относительно класса Math https://docs.oracle.com/javase/7/docs/api/java/lang/Math.html? Считаете ли вы, что это пример не ООП в явном ядре? – Pavlo

+0

@Pavlo. Да. Класс Math, безусловно, не является объектно-ориентированным. Это библиотека функций. Он имеет частный конструктор, поэтому объекты не предназначены для создания экземпляров класса Math. – Asaph

+0

@Asaph, если нет переменных класса, существует ли состояние, о котором нужно беспокоиться? – blathur

2

Класс без свойств является потокобезопасным. Таким образом, вы можете работать с экземпляром класса или статическим методом. Оба будут работать нормально. Это вопрос вашей архитектуры приложения. Если это простое приложение Java, я бы использовал статический метод здесь.

+0

Может быть, это не просто java-приложение, но я думаю, что оставляю OOPS в стороне, почему бы не перейти к правилу вроде «если нет переменных уровня класса - идти на статические» :) – blathur

+0

Если вы заинтересованы в безопасности потоков, то путь - непреложные классы. Не статические методы. – GhostCat

1

Вы можете определенно сделать все методы статическими. Почему нет? Если язык позволяет это, и это имеет смысл для вас, сделайте это. Мне редко приходилось делать что-то, что не имело для меня смысла, потому что я не видел этого раньше или потому, что он не следовал какой-то схеме дизайна (например, «OO» - это означает, что многие вещи многим люди и Java, особенно Java 8, на самом деле поддерживают многие парадигмы в дополнение к OO). Я определенно не добавлял бы строки кода, которые не нужны (Obj a = new Obj(); a.do() vs Obj.do()).

С точки зрения предшествующего уровня техники такие классы часто называют «utility classes». Но нет ничего полезного в таком классе. Лично я использую статические методы, когда не вижу необходимости фиксировать значения или ссылки внутри экземпляра класса. Для меня это много раз, и я все это видел в программировании других людей.

+0

Хм, потому что ** статический ** должен ** OO ** нравится «Айк» на «Тина Тернер»? Или, может быть, потому что ** static ** сделает ваш код un-unittestable почти по умолчанию? – GhostCat

+0

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

+1

Уверен, что вы можете тестировать статический метод. Но как вы можете тестировать метод, который вызывает статический метод? – GhostCat

1

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

+0

Статический метод останется в памяти до тех пор, пока программа не будет остановлена ​​- план метода остается в памяти, который можно игнорировать. Я прав? – blathur

2

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

Прежде всего, статическая является аномалия в возражали ориентированного программирования. Если вы посмотрите на это, это просто «процедурное программирование» в маскировке. Это может означать: если ваш код состоит в основном из статических методов, которые каким-то образом обрабатывают определенные данные ... скорее всего: вы не очень хорошо работали в правильном моделировании/дизайне OO. Потому что, когда вы создаете проекты OO, вы смотрите на создание абстракций; и объединение «данных и поведения» с использованием разумной инкапсуляции; и даже более важно, обеспечивая скрытую скрытую информацию.

Тогда (почти как хуже в моих глазах): с помощью статического ставит огромное бремя на контролируемости вашего кода. Итак, есть вероятность: вы либо не выполняете тесты TDD/unit; или вы уже прибегали к байт-кодовым манипуляциям, таким как PowerMock, чтобы протестировать код, который использует статические методы. И оба эти варианта скорее ... не очень хорошие.

Итак, длинный рассказ короткий: ответ от shridutt дает вам хорошую отправную точку для оценки того, что может быть static. Но я всем сердцем рекомендую вам сначала отступить, и, например: покажите часть своего кода опытным дизайнерам/кодировщикам и получите их отзывы о том, «как OO и тестируемый - это материал».

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

+0

Каким образом использование статического кода затрудняет проверку кода? У вас есть функция, она принимает аргументы и возвращает значение. Кажется, очень легко протестировать, предполагая, что у него нет побочных эффектов. –

+0

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

+0

@ dimadima Если вы делаете разумные модульные тесты, вам очень часто приходится ** контролировать ** методы, которые вызывает ваш класс под тестом. Вы не можете управлять статическими методами; только с помощью PowerMock. И как сказано: использование PowerMock - очень плохая идея. – GhostCat

1

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

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

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

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

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

Смежные вопросы