Почему статические методы могут использовать только статические данные?

38

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

ДЖАВА
источник
11
Потому что только статические данные существуют с точки зрения статических методов.
Mouviciel
4
Поделиться своими исследованиями помогает всем. Расскажите нам, что вы пробовали и почему это не соответствует вашим потребностям. Это свидетельствует о том, что вы потратили время, чтобы попытаться помочь себе, избавляет нас от повторения очевидных ответов и, прежде всего, помогает получить более конкретный и актуальный ответ. Также см. Как спросить
комнат
19
@gnat в этом случае OP пытается понять причину, лежащую в основе дизайнерского решения. Что вы ожидаете от него попробовать в этом случае?
Компьютерщик
2
@Geek - существование статических методов, статические данные - проблема дизайна языка. Принимая стандартные значения, тот факт, что статические методы не могут получить доступ к данным экземпляра, не является. Ограничение подразумевается определениями и тем, что возможно и имеет смысл, а не слабостями некоторых дизайнеров языка.
Steve314
6
Перефразируя Гертруду Стейн: «Там нет этого ».
танцор бегемота

Ответы:

73

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

Статические методы , напротив, не знают отдельных экземпляров классов. Статический метод похож на свободную функцию в C или C ++. Он не привязан к конкретному экземпляру класса. Вот почему они не могут получить доступ к значениям экземпляра. Там нет экземпляра, чтобы взять значение из!

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

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

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

class Foo {
    // This static value belongs to the class Foo
    public static final string name = "Foo";

    // This non-static value will be unique for every instance
    private int value;

    public Foo(int value) {
         this.value = value;
    }

    public void sayValue() {
        println("Instance Value: " + value);
    }

    public static void sayName() {
        println("Static Value: " + name);
    }
}

Foo foo1 = new Foo(10);
Foo foo2 = new Foo(20);

foo1.sayValue(); // Prints "Instance Value: 10" - called on foo1
foo2.sayValue(); // Prints "Instance Value: 20" - called on foo2

Foo.sayName(); // Prints "Static Value: Foo" - called on Foo (not foo1 or foo2)

Обновить

Как ПРИХОДЯТ ОТ точек в комментариях, статический метод является способным работать с не-статическими данными, но оно должно быть передано в явном виде. Давайте предположим, что у Fooкласса был другой метод:

public static Foo Add(Foo foo1, Foo foo2) {
    return new Foo(foo1.value + foo2.value);
}

Addвсе еще статичен и не имеет собственных valueэкземпляров, но, будучи членом класса Foo, он может получить доступ к закрытым valueполям переданного объекта foo1и foo2экземпляров. В этом случае мы используем его для возврата нового Foo с добавленными значениями обоих переданных значений.

Foo foo3 = Foo.Add(foo1, foo2); // creates a new Foo with a value of 30
KChaloux
источник
30
Расширение «Нет экземпляра для получения значения» - даже если есть экземпляры, статический метод не может знать, из какого экземпляра взять значение.
Steve314
9
Это гораздо проще объяснить на языках, которые не заставляют все быть частью объекта по умолчанию.
Мейсон Уилер
3
@ Мейсон Истинные слова. Такие языки, как Java, навязывают ложное представление о том, что функция - это то, что обязательно принадлежит классу.
KChaloux
5
Это хороший ответ, но он все еще не может сказать всю правду: статические методы могут получить доступ к нестатическим данным. У них просто нет неявного объекта или thisссылки. Я думаю, что это жизненно важно понять.
С
2
@COMEFROM Вы имеете в виду под явной передачей? Я могу сделать это, если я правильно вас понимаю. Я предположил, что подразумевается, что статический метод может получить доступ к явно переданным нестатическим данным, учитывая, что любая функция может работать с данными, явно переданными ему.
KChaloux
22

Давайте объясним это гипотетическим примером.

Представьте себе простой класс:

class User
{
User(string n) { name = n; };
string name;
}

Теперь мы создаем 2 экземпляра этого класса:

User Bones = new User("Bones");
User Jim = new User("Jim");

Теперь подумайте - а что если мы добавим новый статический метод в User, например:

static string GetName();

и ты называешь это:

string x = User::GetName()

что бы х содержал? «Джим», «Кости» или что-то еще?

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

gbjbaanb
источник
3

Он может использовать данные поля; рассмотрим следующий код Java:

class MyBean {
    private String myString;

    static void myStaticMethod() {
        myString = "tada";/*not allowed; if this was possible how would 
                           be different from a field without static?*/

        MyBean myBean = new MyBean();//allowed if associated with an instance
        myBean.myString = "tada";
    }
}
m3th0dman
источник
Хотя технически это может быть статический метод, использующий нестатические данные, он упускает суть. Конечно, вы можете создать новый экземпляр и получить к нему доступ. Но это никак не связано с staticНессом.
Бобсон
2
На самом деле, я думаю, что это очень хорошее дополнение к объяснению сути. В нем подчеркивается, что статическому методу требуется экземпляр класса, прежде чем он сможет получить доступ к нестатическим данным, и в то же время интуитивно понятная причина, почему это так.
Бен Хокинг,
@ Бобсон Вы должны прочитать код и комментарии также.
m3th0dman
@BenHocking «да», даже если я думаю, что было бы хорошо сказать, что «переменная экземпляра всегда связана с объектом»
JAVA
2

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

smp7d
источник
2

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

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

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

Лорен Печтель
источник
Я не согласен. Статический метод не может получить доступ к данным экземпляра, потому что данные экземпляра должны быть доступны через экземпляр объекта, а статический метод не связан ни с одним конкретным экземпляром (но с определением класса).
Филл У.
Вы упускаете мою точку зрения. Если он вызывается из класса, компилятор может передать указатель экземпляра, как это происходит, когда это не статический класс. Проблема возникает, если она вызывается из другого места - это означает, что частные статические методы могут получить доступ к данным экземпляра (хотя внутренне игнорируя статическое).
Лорен Печтел
Да, компилятор / мог / но зачем это? Передача такого указателя существенно сводит его к методу экземпляра. Ваше условие, что это могут делать только частные методы, является спорным - технологии отражений делают / все / методы доступными - приватными или нет - делая это еще более рискованным предложением. Наши Друзья в Редмонде пошли в другом направлении; их языки выдают предупреждение, если вы пытаетесь вызвать статический метод для экземпляра объекта (а не для самого класса).
Фил В.
1

Думайте об этом как о статических методах, живущих в не-объектно-ориентированном измерении.

В «объектно-ориентированном измерении» класс может порождать несколько эго (экземпляров), каждое эго имеет совесть о себе через свое состояние.

В плоском неOO-измерении класс не замечает своего эго, живущего в OO-измерении. Их мир плоский и процедурный, почти как если бы ООП еще не был изобретен, и как будто класс был маленькой процедурной программой, а статические данные были просто глобальными переменными.

Тулаинс Кордова
источник
1

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

// Create three new cars.  Cars have a name attribute.  
Car car1 = new Car("Mazda3");
Car car2 = new Car("FordFocus");
Car car3 = new Car("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.  

Для полноты здесь представлен класс автомобилей:

public class Car{

    public String name;

    public Car(String name){
        this.name = name;
    }

    public static printCarName(){
        print "Not sure what to do here...  Don't know which car you are talking about.";
    }

    public static printCarName(Car c){
        print c.name;
    }

    public /*NOT static*/ printMyName(){
        print this.name;
    }

}
sixtyfootersdude
источник
как это отвечает на заданный вопрос?
Комнат
1
@gnat Обновлено с комментариями для уточнения.
sixtyfootersdude
1

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

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

Это не значит, что они не могут получить доступ к нестатическим данным.

class MyClass {
  public static void foo(MyOtherClass object) {
    System.out.println(object.member);
  }
}
class MyOtherClass { public int member = 10; }

Я знаю, что это всего лишь деталь, но я нашел ваш вопрос странным, когда прочитал его. «Может использовать только статические данные» слишком ограничительно.

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

Педро Энрике А. Оливейра
источник