Я не понимаю, почему статический метод не может использовать нестатические данные. Кто-нибудь может объяснить, в чем проблемы и почему мы не можем это сделать?
Я не понимаю, почему статический метод не может использовать нестатические данные. Кто-нибудь может объяснить, в чем проблемы и почему мы не можем это сделать?
Ответы:
В большинстве ОО-языков, когда вы определяете метод внутри класса, он становится методом экземпляра . Когда вы создаете новый экземпляр этого класса через 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
this
ссылки. Я думаю, что это жизненно важно понять.
Давайте объясним это гипотетическим примером.
Представьте себе простой класс:
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 () вынужден быть внутри класса, когда все говорят, что это должна быть отдельная, отдельная функция).
Он может использовать данные поля; рассмотрим следующий код 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";
}
}
static
Нессом.
Нестатические данные связаны с экземпляром класса. Статические методы (и данные) не связаны с конкретным экземпляром класса. Для использования статических методов в нем не должно быть экземпляра класса. Даже если бы существовали экземпляры, у Java не было бы возможности гарантировать, что вы работаете с ожидаемым экземпляром при вызове статического метода. Следовательно, статические методы не могут иметь доступ к нестатическим данным.
Я думаю, что проблема здесь заключается в понимании.
С технической точки зрения статический метод, вызываемый изнутри объекта, вполне способен видеть поля экземпляра. Я сильно подозреваю, что именно это вызвало вопрос в первую очередь.
Проблема в том, что методы могут быть вызваны извне объекта. На данный момент нет данных экземпляра для их предоставления - и, следовательно, у компилятора нет способа разрешить код. Поскольку разрешение данных экземпляра вызвало противоречие, мы не должны разрешать данные экземпляра.
Думайте об этом как о статических методах, живущих в не-объектно-ориентированном измерении.
В «объектно-ориентированном измерении» класс может порождать несколько эго (экземпляров), каждое эго имеет совесть о себе через свое состояние.
В плоском неOO-измерении класс не замечает своего эго, живущего в OO-измерении. Их мир плоский и процедурный, почти как если бы ООП еще не был изобретен, и как будто класс был маленькой процедурной программой, а статические данные были просто глобальными переменными.
Я думаю, что самый простой способ объяснить это - взглянуть на некоторый код, а затем подумать, какие результаты мы ожидаем от кода.
// 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;
}
}
Другие ответы в значительной степени говорят обо всем, однако, я хотел бы добавить некоторые «детали».
Статические методы (скажем, те, что в Java) просто не имеют неявного объекта, связанного с ними (доступного через this
), к членам которого вы можете обращаться, как правило, напрямую по имени.
Это не значит, что они не могут получить доступ к нестатическим данным.
class MyClass {
public static void foo(MyOtherClass object) {
System.out.println(object.member);
}
}
class MyOtherClass {
public int member = 10;
}
Я знаю, что это всего лишь деталь, но я нашел ваш вопрос странным, когда прочитал его. «Может использовать только статические данные» слишком ограничительно.
Кстати, я не тестировал код, я просто написал его здесь, чтобы проиллюстрировать то, что я говорил.