Розуміння статичного ключового слова


16

Я маю певний досвід у розробці Java, Javascript та PHP.

Я читаю Microsoft Visual C # 2010, крок за кроком, і я вважаю, що це дуже гарна книга про ознайомлення з мовою C #.

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

Але яка реальна мета статичного ключового слова? Коли я повинен оголосити статичну змінну та методи?


4
static у C # майже такий самий, як статичний у Java. Якщо ви розумієте це на Java, у вас не повинно виникнути жодних проблем у C #
superM

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

Якщо коротко: використовуйте "статичну", коли вам не потрібна орієнтація на об'єкт, наприклад, лише деякі автономні методи або змінні. Оголошення класу статичним означає розмістити ці не об’єктно-орієнтовані функції та змінну просто в загальному імені (пробілі), імені класу.
Док Браун

Відповіді:


15

Ключове слово "статичне" в C # позначає щось на уроці або в самому класі, яке ділиться між усіма примірниками класу. Наприклад, поле, позначене як статичне, може бути доступне з усіх примірників цього класу через ім'я класу.

public class SomeObject
{
    //Static Field
    static int Foo = 3;

    //instance field
    private int _Foo2 = 4;

    //instance property
    public int Foo2{get{return _Foo2;}set{_Foo2 = value;}}


    //static factory method
    public static SomeObject CreateSomeObject(int fooValue)
    {
        SomeObject retVal = new SomeObject();
        retVal.Foo2 = fooValue;
        return retVal;
    }

    //Parameterless instance constructor
    public SomeObject()
    {
    }

    public static int Add(int x)
    {
        //Static methods can only deal with local variables, or fields that
        //  are also static in the class.  This one adds x to the static member foo
        return x + Foo;

        //Foo2 is not accessable here!
    }

      //Instance method
    public int AddSomething(int x)
    {
        //Add x to the property value of Foo2
        return x + this.Foo2;

        //Note that Foo *is* accessable here as 'SomeObject.Foo'
    }

}

Я можу чесно сказати, що я ніколи не використовував клас, позначений як статичний, за винятком створення методів розширення ( Швидкий підручник з методами розширення ).

У будь-якому випадку існують конкретні схеми проектування для використання статичних методів, таких як заводський візерунок та однотонний візерунок , але важливо пам’ятати, що статичні методи та конструктори не мають жодного конкретного примірника класу (якщо ви не введете його), зазвичай робити обчислення або робити порівняння між об'єктами. Метод "Основний", на який ви посилаєтесь, завжди є статичним, але щоб побачити це з іншої точки зору, дивіться цю статтю .

Щоб продовжити це, ось, як називається різниця між статичними та інстанційними методами, полями та властивостями.

public static void Main(string[] args)
{
    //This is a static method that starts a thread in an application
    // space.  At this point not everything actually has to be static...

    //Here is an instantiation with a parameterless contruction
    SomeObject obj = new SomeObject();

    //Here is an instantiation using a static factory method
    SomeObject obj2 = SomeObject.CreateSomeObject(3);

    //Getting field value from static field
    // Notice that this references the class name, not an instance
    int fooValue1 = SomeObject.Foo;

    //Getting property value from instance
    //  Note that this references an object instance
    int fooValue2 = obj2.Foo2;

    //Instance method must be called through an object
    obj2.AddSomething(4);  //if default constructor, would return 8

    //Static methods must be called through class name
    SomeObject.Add(4); //Returns 7
}

Також перегляньте цю публікацію , щоб глибше вивчити статичні класи.


18

Ось спосіб його пояснення Джошуа Блоха, який мені здається блискучим, як і більшість того, що він каже (так, я фанат Джошуа Блоха :). Це цитується з пам’яті.

Уявіть, що клас - еквівалент синього друку для будинку. Тоді уявіть, що будинок - це блакитний друк, оскільки екземпляр класу - це для класу. Ви можете створити з нього один клас (синій друк) та кілька екземплярів (будинків).

Тепер здоровий глузд диктує, що більшість функцій / поведінки, які може мати / виконувати будинок (екземпляр), навіть якщо вони задекларовані блакитним принтом, не можна використовувати, поки фактичний будинок (екземпляр) не буде зроблений із цього блакитного кольору -друк (клас). Мовляв, ваш синій друк може містити в ньому місце, куди повинно переходити світло і лампочки, але у вас немає ніякого способу змусити їх працювати над синім принтом, вам потрібно побудувати будинок, щоб мати можливість щоб увімкнути та вимкнути перемикач світла та увімкнути та вимкнути певні лампочки.

Однак у вас може виникнути певна поведінка, яка застосовується безпосередньо до синього друку, і ви можете використовувати / отримувати доступ безпосередньо на блакитному відбитку, не потребуючи зробити фактичний будинок із цього синього друку. Уявіть, що на вашому блакитному відбитку є кнопка, яка при натисканні відобразить слід будинку, що міститься в синьому відбитку (обчисливши всі довжини стін тощо). Очевидно, що ви МОЖЕТЕ спочатку побудувати будинок, а потім обміняти його слід, але ви можете зробити це за допомогою синього друку в поодинці, тому було б корисніше, щоб така поведінка була реалізована в блакитному друку. Така вбудована кнопка синього друку, яка обчислює слід будинку, є еквівалентом наявності статичної функції в класі.


Або у вас був би Blueprintклас, який реалізує функціональність креслення, включаючи можливість обчислити слід будинку, виражений кресленням. Потім цей екземпляр плану подається Builder(у свою чергу, швидше за все, екземпляр), який, у свою чергу, робить все необхідне для побудови та виведення потенційно довільної кількості Buildingекземплярів на основі креслення.
CVn

12

Дивлячись на це таким чином, мені допомагає:

  • У кожного типу є статичний екземпляр.
  • Статичний екземпляр створюється під час першого доступу до типу - або через статичний екземпляр, або створюючи інший екземпляр.
  • Ви можете створити скільки завгодно нестатичних екземплярів, але є лише один статичний екземпляр.
  • Все в класі, яке оголошено статичним, належить до статичного екземпляра, і тому не має доступу до жодних інших створених вами екземплярів. Але інші екземпляри DO мають доступ до статичного екземпляра.
  • Якщо клас оголошений статичним, ви не можете створювати інші екземпляри, може існувати лише статичний екземпляр.
  • Ви можете оголосити статичний конструктор для статичного екземпляра так само, як конструктор для звичайного екземпляра (але оголосивши його статичним).

Щодо того, коли використовувати статичне ключове слово:

  • Будь-який метод, який не потребує доступу до локальних властивостей, може і, ймовірно, повинен бути оголошений статичним.
  • Класи помічників, у яких немає будь-якого стану (який у будь-якому разі має бути рідкісним) і який ніколи не буде знущатися, можна оголосити статичним. Чи повинні вони - це інша справа; користуйтеся цією функціональністю економно.
  • Властивості та поля, до яких повинні бути доступні всі екземпляри класу, повинні бути оголошені статичними. Але використовуйте це лише тоді, коли іншого варіанту немає.

+1, для гарного резюме, я не знав, що кожен тип має 1 статичний екземпляр, і мені дивно говорити тобі правду.
NoChance

2
@EmmadKareem Це просто ментальна модель, яку використовує pdr, тому що "Looking at it this way helps"він. Ви вважаєте це дивним, оскільки це не зовсім правда, але ви можете думати про це так, якщо хочете. Ви знаєте модель Бора? Це подання набір правил та ідей, як атоми та електрони взаємодіють один з одним. Модель працює в залежності від того, що ви робите, але це не реальність.
phant0m

@ phant0m, дякую за пояснення, у мене було враження, що це справді не модель, і я здивований через це.
NoChance

Насправді, іноді є причини, через які ви не хочете зробити метод staticнавіть через те, що це не використовувати локальні властивості. Створення речі staticможе додати зв'язок із клієнтами, оскільки вони мають звертатися безпосередньо до класу. Наприклад, це може ускладнити модульне тестування з / глузування.
Аллан

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

4

Найпростіше пояснення --- Статичний => У середовищі існуватиме лише одна копія.

Таким чином, в межах VM або CLR завжди буде лише одна копія статичного класу, і будь-який інший клас, на який він посилається, повинен буде ділитися своїми методами та даними з усіма іншими класами, на які посилається.

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


2

Статичні члени асоціюються з Класом, а не з будь-яким примірником цього Класу.

Оскільки ми говоримо про .Net, розглянемо клас String , зокрема методи Split і Join .

Спліт - це метод екземпляра . Створіть змінну String, надайте їй значення і ви можете зателефонувати Split () на цій змінній / значенні та отримати масив "біт":

String s1 = "abc,def,ghi" ; 
String[] array2 = s1.Split( ',' ) ; 

Так, методи екземпляра, значення проводиться в рамках примірника даного класу питань .

Приєднання - це статичний метод. Гаразд, це дає результат String, коли йому надають роздільник і String-масив для жування, тому це "щось спільне з" String Class, але воно не пов'язане з яким-небудь конкретним значенням у жодному екземплярі String (дійсно, значення екземплярів є не доступні статичним методам).
В інших мовах метод Join може бути "застряг у" класі Array (або, можливо, краще, клас StringArray), але "Наші друзі в Редмонд" вирішили, що він більше "відповідає" класу String, тому вони його помістили .

String[] array3 = { ... } 
s1 = String.Join( array3, "," ) ; 

Інша альтернатива могла б бути , щоб мати екземпляр методу, в якому значення , що утримується в [екземплярі класу] Струнного нас використовується в якості з'єднувального роздільник Join, що - щось на кшталт:

// Maybe one day ... 
String s4 = "," ; 
s1 = s4.Join( array3 ) ; 

2

staticКлючове слово може бути трохи важко для новачків , щоб зрозуміти. Основна його мета - визначити члена класу як не належного до жодного окремого примірника класу, а замість самого класу.

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

Така поведінка була доступна в C і C ++ у вигляді "глобальної" функції або змінної, яка не була інкапсульована в об'єкт. Таким чином, як компроміс, C # і Java підтримують "статичний обсяг", половину шляху між справді глобальним кодом без батьківського об'єкта та членами екземплярів з обмеженою сферою дії.

Будь-який "член коду" (функція, властивість, поле), оголошений як staticпотрапляє в область застосування з першого рядка функції програми main(), і не залишає його, поки main()функція не припиняється. У звичайній англійській мові статичний член існує і його можна використовувати, поки програма працює. Крім того, статичні члени викликаються, викликаючи їх як членів самого типу, а не членів жодного одного екземпляра цього типу:

public class Foo
{
   public int MyInt {get;set;} //this is an "instance member"
   public static int MyStaticInt {get;set;} //this is a "static member"
}

...

var myFoo = new Foo();
myFoo.MyInt = 5; //valid
myFoo.MyStaticInt = 5; //invalid; MyStaticInt doesn't belong to any one Foo

Foo.MyInt = 5; //invalid; MyInt only has meaning in the context of an instance
Foo.MyStaticInt = 2; //valid

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

Щоб відповісти на ваше запитання, головна перевага позначення чого-небудь як статичного полягає в тому, що воно стає видимим там, де відомий сам тип, незалежно від того, чи має спожиючий код або може отримати екземпляр об'єкта, що містить. Також є невеликий користь від продуктивності; оскільки метод знаходиться в статичній області, він може отримати доступ лише до інших статичних членів (того ж класу або інших), і все, що передається в якості параметра. Тому час виконання не повинен вирішувати жодних посилань на поточний екземпляр об'єкта, що міститься, як це зазвичай доводиться застосовувати для методу екземпляра, щоб забезпечити інформацію про стан, що залежить від контексту.

Цілі класи також можуть бути позначені статичними; тим самим ви повідомляєте компілятору, що декларація класу буде складатися виключно з статичних членів, і, таким чином, їх неможливо встановити. Це простий спосіб переконатися, що в пам’яті є одна і лише одна копія об’єкта; зробити клас і все в ньому статичним. Однак дуже рідко це найкраще рішення такої потреби. У ситуації, коли потрібна саме одна копія набору даних, замість цього виступає "синглтон"; це нестатичний клас, який використовує статичний аксесуар та непублічний конструктор для забезпечення доступу до одного екземпляра себе. Теоретично синглтон дає майже однакові переваги повністю статичного класу, але з додатковою можливістю використовувати клас в об'єктно-орієнтованому об'єкті.

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