Я не розумію, чому статичний метод не може використовувати нестатичні дані. Чи може хтось пояснити, що це за проблеми, і чому ми не можемо цього зробити?
Я не розумію, чому статичний метод не може використовувати нестатичні дані. Чи може хтось пояснити, що це за проблеми, і чому ми не можемо цього зробити?
Відповіді:
У більшості мов 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
this
наявного неявного об'єкта або -референції. Я думаю, що це життєво важливо зрозуміти.
Давайте пояснимо це за допомогою гіпотетичного зразка.
Уявіть простий клас:
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 () всередині класу теж, коли всі сенси говорять, що це повинна бути особлива, окрема функція).
Нестатичні дані асоціюються з екземпляром класу. Статичні методи (і дані) не пов'язані з певним екземпляром класу. Для використання статичних методів у ньому не повинно бути примірника класу. Навіть якби були екземпляри, Java не змогла б гарантувати, що ви працюєте над тим екземпляром, який ви очікуєте, коли ви викликаєте статичний метод. Тому статичні методи не можуть мати доступ до нестатичних даних.
Він може використовувати дані на місцях; врахуйте наступний код 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
ness.
Я думаю, що питання тут є одним із розумінь.
З технічної точки зору статичний метод, викликаний всередині об'єкта, цілком здатний побачити поля екземпляра. Я сильно підозрюю, що саме це викликало питання в першу чергу.
Проблема полягає в тому, що методи можуть бути викликані ззовні об'єкта. На той момент немає даних про екземпляри, щоб їх надати - і, отже, компілятор не може вирішити код. Оскільки надання даних про екземпляр викликало суперечність, ми не повинні допускати даних екземплярів.
Розглядайте це як статичні методи, що живуть у не об’єктно-орієнтованому вимірі.
У "об'єктно-орієнтованому вимірі" клас може породжувати кілька его (екземплярів), кожне его має свідомість через свій стан.
У плоскій, не-OO-вимірі, клас не звертає уваги на свої егої, що живуть у розмірі OO. Їх світ є рівним і процедурним, майже так, як ніби OOP ще не був винайдений, і ніби клас був невеликою процедурною програмою, а статичні дані - просто глобальні змінні.
Я думаю, що найпростіший спосіб пояснити це - подивитися якийсь код, а потім розглянути, які результати ми б очікували, що код отримає.
// 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;
}
Я знаю, що це лише деталь, але я знайшов ваше питання дивним, коли я читав його. "Можна використовувати лише статичні дані" занадто сильно обмежує.
До речі, я не перевіряв код, я просто написав його тут, щоб пояснити, що я говорив.