Почему статические методы могут использовать только статические данные?
38
Я не понимаю, почему статический метод не может использовать нестатические данные. Кто-нибудь может объяснить, в чем проблемы и почему мы не можем это сделать?
Потому что только статические данные существуют с точки зрения статических методов.
Mouviciel
4
Поделиться своими исследованиями помогает всем. Расскажите нам, что вы пробовали и почему это не соответствует вашим потребностям. Это свидетельствует о том, что вы потратили время, чтобы попытаться помочь себе, избавляет нас от повторения очевидных ответов и, прежде всего, помогает получить более конкретный и актуальный ответ. Также см. Как спросить
комнат
19
@gnat в этом случае OP пытается понять причину, лежащую в основе дизайнерского решения. Что вы ожидаете от него попробовать в этом случае?
Компьютерщик
2
@Geek - существование статических методов, статические данные - проблема дизайна языка. Принимая стандартные значения, тот факт, что статические методы не могут получить доступ к данным экземпляра, не является. Ограничение подразумевается определениями и тем, что возможно и имеет смысл, а не слабостями некоторых дизайнеров языка.
Steve314
6
Перефразируя Гертруду Стейн: «Там нет этого ».
танцор бегемота
Ответы:
73
В большинстве ОО-языков, когда вы определяете метод внутри класса, он становится методом экземпляра . Когда вы создаете новый экземпляр этого класса через newключевое слово, вы инициализируете новый набор данных, уникальный только для этого экземпляра. Методы, принадлежащие этому экземпляру, могут затем работать с данными, которые вы определили для него.
Статические методы , напротив, не знают отдельных экземпляров классов. Статический метод похож на свободную функцию в C или C ++. Он не привязан к конкретному экземпляру класса. Вот почему они не могут получить доступ к значениям экземпляра. Там нет экземпляра, чтобы взять значение из!
Статические данные похожи на статический метод. У объявленного значения staticнет связанного экземпляра. Он существует для каждого экземпляра и объявляется только в одном месте в памяти. Если он когда-либо будет изменен, он будет меняться для каждого экземпляра этого класса.
Статический метод может получить доступ к статическим данным , потому что они оба существуют независимо от конкретных экземпляров класса.
Это может помочь посмотреть, как вы вызываете статический метод, по сравнению с методом экземпляра. Допустим, у нас был следующий класс (с использованием Java-подобного псевдокода):
classFoo{// This static value belongs to the class Foopublicstaticfinal string name ="Foo";// This non-static value will be unique for every instanceprivateint value;publicFoo(int value){this.value = value;}publicvoid sayValue(){
println("Instance Value: "+ value);}publicstaticvoid sayName(){
println("Static Value: "+ name);}}Foo foo1 =newFoo(10);Foo foo2 =newFoo(20);
foo1.sayValue();// Prints "Instance Value: 10" - called on foo1
foo2.sayValue();// Prints "Instance Value: 20" - called on foo2Foo.sayName();// Prints "Static Value: Foo" - called on Foo (not foo1 or foo2)
Обновить
Как ПРИХОДЯТ ОТ точек в комментариях, статический метод является способным работать с не-статическими данными, но оно должно быть передано в явном виде. Давайте предположим, что у Fooкласса был другой метод:
Addвсе еще статичен и не имеет собственных valueэкземпляров, но, будучи членом класса Foo, он может получить доступ к закрытым valueполям переданного объекта foo1и foo2экземпляров. В этом случае мы используем его для возврата новогоFoo с добавленными значениями обоих переданных значений.
Foo foo3 =Foo.Add(foo1, foo2);// creates a new Foo with a value of 30
Расширение «Нет экземпляра для получения значения» - даже если есть экземпляры, статический метод не может знать, из какого экземпляра взять значение.
Steve314
9
Это гораздо проще объяснить на языках, которые не заставляют все быть частью объекта по умолчанию.
Мейсон Уилер
3
@ Мейсон Истинные слова. Такие языки, как Java, навязывают ложное представление о том, что функция - это то, что обязательно принадлежит классу.
KChaloux
5
Это хороший ответ, но он все еще не может сказать всю правду: статические методы могут получить доступ к нестатическим данным. У них просто нет неявного объекта или thisссылки. Я думаю, что это жизненно важно понять.
С
2
@COMEFROM Вы имеете в виду под явной передачей? Я могу сделать это, если я правильно вас понимаю. Я предположил, что подразумевается, что статический метод может получить доступ к явно переданным нестатическим данным, учитывая, что любая функция может работать с данными, явно переданными ему.
KChaloux
22
Давайте объясним это гипотетическим примером.
Представьте себе простой класс:
classUser{User(string n){ name = n;};
string name;}
Теперь подумайте - а что если мы добавим новый статический метод в User, например:
static string GetName();
и ты называешь это:
string x =User::GetName()
что бы х содержал? «Джим», «Кости» или что-то еще?
Проблема в том, что статический метод - это отдельный метод, определенный в классе, а не в объектах. В результате вы не знаете, к какому объекту он может быть применен. Вот почему это особенная вещь. Лучше всего рассматривать статические методы как отдельные вещи, например, функции в Си. То, что языки наподобие Java содержат их внутри классов, является в основном проблемой того, что Java не позволяет чему-либо существовать вне класса, поэтому такие функции нужно каким-то образом вызывать внутри класса (немного похоже на то, как main () вынужден быть внутри класса, когда все говорят, что это должна быть отдельная, отдельная функция).
Он может использовать данные поля; рассмотрим следующий код Java:
classMyBean{privateString myString;staticvoid myStaticMethod(){
myString ="tada";/*not allowed; if this was possible how would
be different from a field without static?*/MyBean myBean =newMyBean();//allowed if associated with an instance
myBean.myString ="tada";}}
Хотя технически это может быть статический метод, использующий нестатические данные, он упускает суть. Конечно, вы можете создать новый экземпляр и получить к нему доступ. Но это никак не связано с staticНессом.
Бобсон
2
На самом деле, я думаю, что это очень хорошее дополнение к объяснению сути. В нем подчеркивается, что статическому методу требуется экземпляр класса, прежде чем он сможет получить доступ к нестатическим данным, и в то же время интуитивно понятная причина, почему это так.
Бен Хокинг,
@ Бобсон Вы должны прочитать код и комментарии также.
m3th0dman
@BenHocking «да», даже если я думаю, что было бы хорошо сказать, что «переменная экземпляра всегда связана с объектом»
JAVA
2
Нестатические данные связаны с экземпляром класса. Статические методы (и данные) не связаны с конкретным экземпляром класса. Для использования статических методов в нем не должно быть экземпляра класса. Даже если бы существовали экземпляры, у Java не было бы возможности гарантировать, что вы работаете с ожидаемым экземпляром при вызове статического метода. Следовательно, статические методы не могут иметь доступ к нестатическим данным.
Я думаю, что проблема здесь заключается в понимании.
С технической точки зрения статический метод, вызываемый изнутри объекта, вполне способен видеть поля экземпляра. Я сильно подозреваю, что именно это вызвало вопрос в первую очередь.
Проблема в том, что методы могут быть вызваны извне объекта. На данный момент нет данных экземпляра для их предоставления - и, следовательно, у компилятора нет способа разрешить код. Поскольку разрешение данных экземпляра вызвало противоречие, мы не должны разрешать данные экземпляра.
Я не согласен. Статический метод не может получить доступ к данным экземпляра, потому что данные экземпляра должны быть доступны через экземпляр объекта, а статический метод не связан ни с одним конкретным экземпляром (но с определением класса).
Филл У.
Вы упускаете мою точку зрения. Если он вызывается из класса, компилятор может передать указатель экземпляра, как это происходит, когда это не статический класс. Проблема возникает, если она вызывается из другого места - это означает, что частные статические методы могут получить доступ к данным экземпляра (хотя внутренне игнорируя статическое).
Лорен Печтел
Да, компилятор / мог / но зачем это? Передача такого указателя существенно сводит его к методу экземпляра. Ваше условие, что это могут делать только частные методы, является спорным - технологии отражений делают / все / методы доступными - приватными или нет - делая это еще более рискованным предложением. Наши Друзья в Редмонде пошли в другом направлении; их языки выдают предупреждение, если вы пытаетесь вызвать статический метод для экземпляра объекта (а не для самого класса).
Фил В.
1
Думайте об этом как о статических методах, живущих в не-объектно-ориентированном измерении.
В «объектно-ориентированном измерении» класс может порождать несколько эго (экземпляров), каждое эго имеет совесть о себе через свое состояние.
В плоском неOO-измерении класс не замечает своего эго, живущего в OO-измерении. Их мир плоский и процедурный, почти как если бы ООП еще не был изобретен, и как будто класс был маленькой процедурной программой, а статические данные были просто глобальными переменными.
Я думаю, что самый простой способ объяснить это - взглянуть на некоторый код, а затем подумать, какие результаты мы ожидаем от кода.
// Create three new cars. Cars have a name attribute. Car car1 =newCar("Mazda3");Car car2 =newCar("FordFocus");Car car3 =newCar("HondaFit");// Now we would like to print the names of some cars: // First off why don't we try this: Car.printCarName();// Expected behaviour: // If we think about what we are trying to do here it doesn't// really make sense. What instance of car name should this // print? Should it print Mazda3? FordFoucs?// What is the expected behaviour? If we are going to have a// static call on car call printCarName it should probably do// something like print all car names or a random car name or// throw an error. //Now lets try this instead: Car.printCarName(car1);// Expected Behaviour: // Luckily the expected behaviour is very clear here. This// should print Mazda3. This works as expected. // Finally lets try this:
car1.printMyName();// Expected Behaviour:// Same as previous example, however this is the *right* way// to do it.
Для полноты здесь представлен класс автомобилей:
publicclassCar{publicString name;publicCar(String name){this.name = name;}publicstatic printCarName(){
print "Not sure what to do here... Don't know which car you are talking about.";}publicstatic printCarName(Car c){
print c.name;}public/*NOT static*/ printMyName(){
print this.name;}}
Другие ответы в значительной степени говорят обо всем, однако, я хотел бы добавить некоторые «детали».
Статические методы (скажем, те, что в Java) просто не имеют неявного объекта, связанного с ними (доступного через this), к членам которого вы можете обращаться, как правило, напрямую по имени.
Это не значит, что они не могут получить доступ к нестатическим данным.
classMyClass{publicstaticvoid foo(MyOtherClass object){System.out.println(object.member);}} classMyOtherClass{publicint member =10;}
Я знаю, что это всего лишь деталь, но я нашел ваш вопрос странным, когда прочитал его. «Может использовать только статические данные» слишком ограничительно.
Кстати, я не тестировал код, я просто написал его здесь, чтобы проиллюстрировать то, что я говорил.
Ответы:
В большинстве ОО-языков, когда вы определяете метод внутри класса, он становится методом экземпляра . Когда вы создаете новый экземпляр этого класса через
new
ключевое слово, вы инициализируете новый набор данных, уникальный только для этого экземпляра. Методы, принадлежащие этому экземпляру, могут затем работать с данными, которые вы определили для него.Статические методы , напротив, не знают отдельных экземпляров классов. Статический метод похож на свободную функцию в C или C ++. Он не привязан к конкретному экземпляру класса. Вот почему они не могут получить доступ к значениям экземпляра. Там нет экземпляра, чтобы взять значение из!
Статические данные похожи на статический метод. У объявленного значения
static
нет связанного экземпляра. Он существует для каждого экземпляра и объявляется только в одном месте в памяти. Если он когда-либо будет изменен, он будет меняться для каждого экземпляра этого класса.Статический метод может получить доступ к статическим данным , потому что они оба существуют независимо от конкретных экземпляров класса.
Это может помочь посмотреть, как вы вызываете статический метод, по сравнению с методом экземпляра. Допустим, у нас был следующий класс (с использованием Java-подобного псевдокода):
Обновить
Как ПРИХОДЯТ ОТ точек в комментариях, статический метод является способным работать с не-статическими данными, но оно должно быть передано в явном виде. Давайте предположим, что у
Foo
класса был другой метод:Add
все еще статичен и не имеет собственныхvalue
экземпляров, но, будучи членом класса Foo, он может получить доступ к закрытымvalue
полям переданного объектаfoo1
иfoo2
экземпляров. В этом случае мы используем его для возврата новогоFoo
с добавленными значениями обоих переданных значений.источник
this
ссылки. Я думаю, что это жизненно важно понять.Давайте объясним это гипотетическим примером.
Представьте себе простой класс:
Теперь мы создаем 2 экземпляра этого класса:
Теперь подумайте - а что если мы добавим новый статический метод в User, например:
и ты называешь это:
что бы х содержал? «Джим», «Кости» или что-то еще?
Проблема в том, что статический метод - это отдельный метод, определенный в классе, а не в объектах. В результате вы не знаете, к какому объекту он может быть применен. Вот почему это особенная вещь. Лучше всего рассматривать статические методы как отдельные вещи, например, функции в Си. То, что языки наподобие Java содержат их внутри классов, является в основном проблемой того, что Java не позволяет чему-либо существовать вне класса, поэтому такие функции нужно каким-то образом вызывать внутри класса (немного похоже на то, как main () вынужден быть внутри класса, когда все говорят, что это должна быть отдельная, отдельная функция).
источник
Он может использовать данные поля; рассмотрим следующий код Java:
источник
static
Нессом.Нестатические данные связаны с экземпляром класса. Статические методы (и данные) не связаны с конкретным экземпляром класса. Для использования статических методов в нем не должно быть экземпляра класса. Даже если бы существовали экземпляры, у Java не было бы возможности гарантировать, что вы работаете с ожидаемым экземпляром при вызове статического метода. Следовательно, статические методы не могут иметь доступ к нестатическим данным.
источник
Я думаю, что проблема здесь заключается в понимании.
С технической точки зрения статический метод, вызываемый изнутри объекта, вполне способен видеть поля экземпляра. Я сильно подозреваю, что именно это вызвало вопрос в первую очередь.
Проблема в том, что методы могут быть вызваны извне объекта. На данный момент нет данных экземпляра для их предоставления - и, следовательно, у компилятора нет способа разрешить код. Поскольку разрешение данных экземпляра вызвало противоречие, мы не должны разрешать данные экземпляра.
источник
Думайте об этом как о статических методах, живущих в не-объектно-ориентированном измерении.
В «объектно-ориентированном измерении» класс может порождать несколько эго (экземпляров), каждое эго имеет совесть о себе через свое состояние.
В плоском неOO-измерении класс не замечает своего эго, живущего в OO-измерении. Их мир плоский и процедурный, почти как если бы ООП еще не был изобретен, и как будто класс был маленькой процедурной программой, а статические данные были просто глобальными переменными.
источник
Я думаю, что самый простой способ объяснить это - взглянуть на некоторый код, а затем подумать, какие результаты мы ожидаем от кода.
Для полноты здесь представлен класс автомобилей:
источник
Другие ответы в значительной степени говорят обо всем, однако, я хотел бы добавить некоторые «детали».
Статические методы (скажем, те, что в Java) просто не имеют неявного объекта, связанного с ними (доступного через
this
), к членам которого вы можете обращаться, как правило, напрямую по имени.Это не значит, что они не могут получить доступ к нестатическим данным.
Я знаю, что это всего лишь деталь, но я нашел ваш вопрос странным, когда прочитал его. «Может использовать только статические данные» слишком ограничительно.
Кстати, я не тестировал код, я просто написал его здесь, чтобы проиллюстрировать то, что я говорил.
источник