Чому статичні методи можуть використовувати лише статичні дані?


38

Я не розумію, чому статичний метод не може використовувати нестатичні дані. Чи може хтось пояснити, що це за проблеми, і чому ми не можемо цього зробити?


11
Тому що лише статичні дані існують з точки зору статичних методів.
mouviciel

4
Обмін дослідженнями допомагає всім. Розкажіть, що ви пробували і чому це не відповідало вашим потребам. Це свідчить про те, що ви знайшли час, щоб спробувати допомогти собі, це позбавляє нас від повторення очевидних відповідей, і найбільше це допомагає вам отримати більш конкретну та релевантну відповідь. Також дивіться Як просити
gnat

19
@gnat в цьому випадку ОП намагається зрозуміти причину дизайнерського рішення. Що ви очікуєте, що він спробує в цій справі?
Geek

2
@Geek - існування статичних методів, статичні дані - це проблема дизайну мови. Якщо припустити стандартні значення, то факт, що статичні методи не можуть отримати доступ до даних екземплярів, не є. Обмеження має на увазі визначення та те, що можливо і має сенс, а не певна частина мовних дизайнерів.
Steve314

6
Перефразовуючи Гертруду Штейн: " Цього там немає".
бегемотист

Відповіді:


73

У більшості мов OO, коли ви визначаєте метод всередині класу, він стає методом Instance . Коли ви створюєте новий екземпляр цього класу за допомогою 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

30
Розширення на "Немає жодного примірника, щоб взяти значення" - навіть якщо є екземпляри, статичний метод не може знати, з якого екземпляра взяти значення.
Steve314

9
Це набагато менш складно пояснити мовами, які не змушують все бути частиною об'єкта за замовчуванням.
Мейсон Уілер

3
@Mason Правдиві слова. Такі мови, як 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");

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

static string GetName();

і ви називаєте це:

string x = User::GetName()

що б містило х? "Джим", "Кістки" чи щось інше?

Проблема полягає в тому, що статичний метод - це єдиний метод, визначений на класі, а не об'єкти. Як результат, ви не знаєте, до якого об’єкта він може застосовуватися. Ось чому його особлива річ. Найкраще статичні методи розглядати як окремі речі, як, наприклад, функції C. Такі мови, як Java, містять їх у класах, в основному є проблемою, коли Java не дозволяє нічого існувати поза класом, тому такі функції, як ця, повинні бути примушені всередині класу певним чином (трохи схоже на те, як змушений бути main () всередині класу теж, коли всі сенси говорять, що це повинна бути особлива, окрема функція).


2

Нестатичні дані асоціюються з екземпляром класу. Статичні методи (і дані) не пов'язані з певним екземпляром класу. Для використання статичних методів у ньому не повинно бути примірника класу. Навіть якби були екземпляри, Java не змогла б гарантувати, що ви працюєте над тим екземпляром, який ви очікуєте, коли ви викликаєте статичний метод. Тому статичні методи не можуть мати доступ до нестатичних даних.


2

Він може використовувати дані на місцях; врахуйте наступний код 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";
    }
}

Хоча це технічно може бути статичним методом, використовуючи нестатичні дані, він не вистачає суті. Звичайно, ви можете створити новий екземпляр і отримати доступ до нього. Але це взагалі не має нічого спільного з staticness.
Бобсон

2
Власне, я думаю, що це дуже гарне доповнення до пояснення суті. Він підкреслює, що статичному методу потрібен екземпляр класу, перш ніж він може отримати доступ до нестатичних даних, надаючи інтуїтивну причину, чому це так.
Бен Хокінг

@Bobson Ви також повинні прочитати код та коментарі.
m3th0dman

@BenHocking "так", навіть я думаю, що добре сказати, що "змінна інстанція завжди пов'язана з об'єктом"
JAVA

2

Я думаю, що питання тут є одним із розумінь.

З технічної точки зору статичний метод, викликаний всередині об'єкта, цілком здатний побачити поля екземпляра. Я сильно підозрюю, що саме це викликало питання в першу чергу.

Проблема полягає в тому, що методи можуть бути викликані ззовні об'єкта. На той момент немає даних про екземпляри, щоб їх надати - і, отже, компілятор не може вирішити код. Оскільки надання даних про екземпляр викликало суперечність, ми не повинні допускати даних екземплярів.


Я не погоджуюсь. Статичний метод не може отримати доступ до даних екземпляра, оскільки дані про екземпляр повинні бути доступні через екземпляр об'єкта, а статичний метод не асоціюється з жодним даним екземпляром (але з визначенням класу).
Phill W.

Ви сумуєте за моєю точкою. Якщо він викликається з класу, компілятор може передавати покажчик екземпляра, як це робиться, коли це не статичний клас. Проблема виникає, якщо її викликають з іншого місця, а це означає, що приватні статичні методи можуть отримати доступ до даних екземплярів (хоча, внутрішньо, в основному, ігноруючи статику.)
Лорен Печтел,

Так, компілятор / міг /, але навіщо це робити? Передача такого покажчика по суті зводить його до методу екземпляра. Ваше твердження про те, що це можуть зробити лише приватні методи, - суперечливі технології роблять / доступні / всі / методи доступними - приватними чи ні - роблячи це ще більш ризикованим. Наші Друзі в Редмонд пішли в інший бік; їх мови викликають попередження, якщо ви намагаєтеся викликати статичний метод проти екземпляра об'єкта (а не самого класу).
Phill W.

1

Розглядайте це як статичні методи, що живуть у не об’єктно-орієнтованому вимірі.

У "об'єктно-орієнтованому вимірі" клас може породжувати кілька его (екземплярів), кожне его має свідомість через свій стан.

У плоскій, не-OO-вимірі, клас не звертає уваги на свої егої, що живуть у розмірі OO. Їх світ є рівним і процедурним, майже так, як ніби OOP ще не був винайдений, і ніби клас був невеликою процедурною програмою, а статичні дані - просто глобальні змінні.


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;
    }

}

як це відповідає на поставлене запитання?
гнат

1
@gnat Оновлено коментарями для уточнення.
шістдесят футів

1

Інші відповіді дуже багато говорять про це, однак, я хотів би додати деякі "деталі".

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

Це не означає, що вони не можуть отримати доступ до нестатичних даних.

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

Я знаю, що це лише деталь, але я знайшов ваше питання дивним, коли я читав його. "Можна використовувати лише статичні дані" занадто сильно обмежує.

До речі, я не перевіряв код, я просто написав його тут, щоб пояснити, що я говорив.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.