Memahami kata kunci statis

15

Saya memiliki beberapa pengalaman dalam pengembangan dengan Java, Javascript dan PHP.

Saya membaca Microsoft Visual C # 2010 Langkah demi Langkah yang saya rasa merupakan buku yang sangat bagus untuk memperkenalkan Anda ke bahasa C #.

Saya sepertinya mengalami masalah dalam memahami kata kunci statis. Dari apa yang saya pahami sejauh ini jika sebuah kelas dinyatakan statis, semua metode dan variabel harus statis. Metode utama selalu merupakan metode statis sehingga di kelas metode utama ada semua variabel dan metode dinyatakan statis jika Anda harus memanggil mereka dalam metode utama. Juga saya perhatikan bahwa untuk memanggil metode statis dari kelas lain Anda tidak perlu membuat objek yang Anda dapat menggunakan nama kelas.

Tapi apa tujuan sebenarnya dari kata kunci statis? Kapan saya harus mendeklarasikan variabel dan metode statis?

Nistor Alexandru
sumber
4
statis di C # hampir sama dengan statis di Jawa. Jika Anda memahaminya di Jawa, Anda tidak harus memiliki masalah dalam C #
superM
Java adalah bahasa pemrograman pertama saya dan saya juga tidak mengerti konsep ini. Saya hanya menggunakan Java untuk waktu yang singkat
Nistor Alexandru
Singkatnya: gunakan "statis" ketika Anda tidak memerlukan orientasi objek, misalnya, hanya beberapa metode atau variabel yang berdiri sendiri. Mendeklarasikan kelas menjadi statis berarti menempatkan fungsi-fungsi dan variabel yang tidak berorientasi objek hanya dalam nama umum (spasi), nama kelas.
Doc Brown

Jawaban:

14

Kata kunci 'statis' dalam C # mengacu pada sesuatu di kelas, atau kelas itu sendiri, yang dibagikan di antara semua contoh kelas. Misalnya, bidang yang ditandai sebagai statis dapat diakses dari semua instance kelas itu melalui nama kelas.

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

}

Jujur saya bisa mengatakan bahwa saya tidak pernah menggunakan kelas yang ditandai sebagai statis dengan pengecualian membuat metode extention ( Tutorial cepat tentang metode ekstensi ).

Bagaimanapun, ada pola desain khusus untuk menggunakan metode statis, seperti pola pabrik dan pola tunggal , tetapi yang penting untuk diingat adalah bahwa metode dan konstruktor statis tidak berurusan dengan instance kelas tertentu (kecuali Anda memasukkannya), biasanya melakukan perhitungan atau melakukan perbandingan antar objek. Metode "Utama" yang Anda maksud selalu statis, tetapi untuk melihatnya dari sudut pandang yang berbeda, lihat artikel ini .

Untuk menindaklanjutinya, berikut adalah perbedaan metode, bidang, dan properti yang disebut metode statis dan instantiated.

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
}

Juga, periksa posting ini untuk melihat lebih dalam ke kelas statis.

iMortalitySX
sumber
18

Inilah cara Joshua Bloch menjelaskannya, yang menurut saya brilian seperti sebagian besar perkataannya (ya saya adalah penggemar boy Joshua Bloch :)). Ini dikutip dari memori.

Bayangkan sebuah kelas setara dengan cetak biru untuk sebuah rumah. Bayangkan kemudian bahwa sebuah rumah adalah cetak biru sebagai contoh kelas adalah untuk kelas. Anda dapat membuat satu kelas (cetak biru) dan beberapa instance (rumah) dibuat darinya.

Sekarang, akal sehat menentukan bahwa sebagian besar fungsi / perilaku yang dapat dimiliki / dilakukan oleh sebuah rumah (contoh), walaupun dinyatakan dalam cetak biru, tidak dapat digunakan sampai rumah yang sebenarnya (contoh) dibuat dari warna biru itu. -cetak (kelas). Seperti, cetak biru Anda mungkin berisi di dalamnya tempat di mana lampu menyala dan bola lampu harus pergi, tetapi Anda tidak memiliki cara untuk membuat itu bekerja pada cetak biru, Anda harus benar-benar membangun rumah agar dapat untuk menghidupkan dan mematikan sakelar lampu dan mematikan lampu tertentu.

Namun, Anda mungkin memiliki beberapa perilaku yang berlaku untuk cetak biru secara langsung, dan yang dapat Anda gunakan / akses langsung pada cetak biru tanpa perlu membuat rumah yang sebenarnya dari cetak biru itu. Bayangkan cetak biru Anda memiliki tombol yang, setelah menekan, akan menampilkan jejak rumah yang terkandung dalam cetak biru itu (dengan menghitung semua panjang dinding dan semacamnya). Tentunya Anda BISA membangun rumah terlebih dahulu, kemudian berkeliling mengukur jejaknya, tetapi Anda dapat melakukan ini dengan cetak biru sendiri, jadi akan lebih membantu untuk menerapkan perilaku ini dalam cetak biru. Tombol tertanam berwarna biru yang menghitung jejak rumah sama dengan fungsi statis di kelas.

Shivan Dragon
sumber
Atau Anda akan memiliki Blueprintkelas yang mengimplementasikan fungsi cetak biru, termasuk kemampuan untuk menghitung jejak rumah yang dinyatakan oleh cetak biru. Mesin cetak biru ini kemudian diumpankan ke Builder(pada gilirannya itu sendiri kemungkinan merupakan mesin cetak ), yang pada gilirannya melakukan apa yang diperlukan untuk membangun dan menghasilkan sejumlah Buildingcontoh mesin yang berpotensi berubah-ubah berdasarkan cetak biru.
CVn
11

Melihatnya dengan cara ini membantu saya:

  • Setiap tipe memiliki instance statis.
  • Instance statis dibuat pada saat pertama kali Anda mengakses tipe - baik melalui instance statis atau membuat instance lain.
  • Anda dapat membuat sebanyak mungkin instance non-statis, tetapi hanya ada satu instance statis.
  • Apa pun di dalam kelas yang dinyatakan sebagai statis adalah milik instance statis, dan dengan demikian tidak memiliki akses ke instance lain yang Anda buat. Tetapi instance lain memiliki akses ke instance statis.
  • Jika suatu kelas dinyatakan sebagai statis maka Anda tidak dapat membuat instance lain, hanya instance statis yang pernah ada.
  • Anda dapat mendeklarasikan konstruktor statis untuk instance statis seperti konstruktor untuk instance normal (tetapi dengan mendeklarasikannya statis).

Adapun kapan harus menggunakan kata kunci statis:

  • Metode apa pun yang tidak memerlukan akses ke properti lokal dapat dan mungkin harus dinyatakan statis.
  • Kelas pembantu yang tidak memiliki status apa pun (yang seharusnya jarang terjadi) dan yang tidak akan pernah diejek dapat dinyatakan statis. Apakah mereka harusnya adalah masalah lain; gunakan fungsi ini dengan hemat.
  • Properti dan bidang yang harus diakses oleh semua instance kelas harus dinyatakan statis. Tetapi gunakan ini hanya ketika tidak ada pilihan lain.
pdr
sumber
+1, untuk ringkasan yang bagus, saya tidak tahu bahwa setiap tipe memiliki 1 instance statis dan saya merasa aneh untuk mengatakan yang sebenarnya.
NoChance
2
@EmmadKareem Itu hanya model mental yang digunakan pdr, karena "Looking at it this way helps"dia. Anda merasa aneh karena itu tidak sepenuhnya benar, tetapi Anda dapat menganggapnya seperti itu jika Anda mau. Apakah Anda tahu model Bohr? Ini adalah sekumpulan aturan dan gagasan tentang bagaimana atom dan elektron berinteraksi satu sama lain. The Model bekerja tergantung pada apa yang Anda lakukan, tetapi bukan realitas.
phant0m
@ phant0m, terima kasih untuk penjelasannya, saya mendapat kesan bahwa itu nyata bukan model dan saya terkejut karenanya.
NoChance
Sebenarnya, kadang-kadang ada alasan Anda mungkin tidak ingin membuat metode staticmeskipun tidak menggunakan properti lokal. Membuat sesuatu staticdapat menambahkan sambungan ke klien karena mereka harus menangani kelas secara langsung. Misalnya, ini dapat mempersulit pengujian unit dengan mengejek.
Allan
@ Allan: Dapat diperdebatkan, jika Anda memanggil metode publik pada kelas yang tidak memengaruhi keadaan instance kelas itu, itu HARUS statis, untuk menjelaskan kepada pengembang klien. Jika metode itu melakukan begitu banyak sehingga perlu diejek, itu masalah yang berbeda yang dapat dipecahkan dengan beberapa cara yang berbeda.
pdr
3

Penjelasan paling sederhana --- Static => Hanya satu salinan akan ada per lingkungan.

Jadi di dalam VM atau CLR hanya akan ada satu salinan dari kelas statis, dan, setiap kelas lain yang mereferensikan itu harus berbagi metode dan data dengan semua kelas lain yang merujuknya.

Untuk variabel statis, hanya akan ada satu instance dari variabel ini dalam lingkungan run time tidak peduli berapa banyak salinan dari kelas pemilik dibuat ketika mereka mereferensikan variabel statis mereka semua akan referensi sepotong penyimpanan yang sama.

James Anderson
sumber
1

Anggota statis dikaitkan dengan Kelas, bukan dengan instance Kelas apa pun.

Karena kita berbicara tentang. Net, pertimbangkan kelas String , khususnya metode Split dan Join .

Split adalah metode instan . Buat variabel String, berikan nilainya dan Anda dapat memanggil Split () pada variabel / nilai itu dan mendapatkan kembali array "bit":

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

Jadi, untuk metode misalnya, nilai diadakan dalam kelas contoh yang diberikan hal-hal .

Bergabung adalah metode statis . OK, itu menghasilkan sebuah String hasil ketika diberi pembatas dan array String untuk mengunyah, sehingga "ada hubungannya dengan" Kelas String, tapi itu tidak terkait dengan tertentu nilai dalam setiap contoh String (memang, nilai-nilai contoh adalah tidak tersedia untuk metode statis).
Dalam bahasa lain, metode Bergabung mungkin telah "terjebak ke" Kelas Array (atau, mungkin lebih baik, Kelas StringArray) tetapi Teman-teman Kita di Redmond memutuskan bahwa itu lebih "relevan" dengan kelas String, jadi mereka meletakkannya di sana .

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

Alternatif lain mungkin memiliki contoh metode Join, di mana nilai yang disimpan dalam String [class instance] kita digunakan sebagai pembatas join, sesuatu seperti:

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

Kata statickunci bisa sedikit sulit bagi pemula untuk memahami. Tujuan utamanya adalah untuk mengidentifikasi anggota kelas yang tidak termasuk dalam instance kelas apa pun, tetapi sebagai bagian dari kelas itu sendiri.

Tanpa terlalu banyak detail, C # (dan Java) secara kaku menegakkan ideal berorientasi objek bahwa semua kode dan data harus dimiliki oleh suatu objek, dan oleh karena itu terbatas dalam ruang lingkup, visibilitas dan masa pakai. Itu umumnya praktik terbaik di mana pun prinsip dasar suatu objek yang mewakili beberapa hal dunia nyata berlaku. Namun, itu tidak selalu; terkadang yang Anda butuhkan adalah fungsi atau variabel yang bisa Anda dapatkan dari mana saja dalam kode, tanpa anda harus melewati sekitar referensi ke sebuah obyek yang berisi itu, dan dengan jaminan bahwa data yang Anda cari di atau mengubah adalah persis apa yang orang yang lain berurusan dengan, dan bukan salinannya milik contoh objek yang berbeda.

Perilaku seperti itu tersedia dalam C dan C ++ dalam bentuk fungsi atau variabel "global", yang tidak dienkapsulasi dalam suatu objek. Jadi, sebagai kompromi, C # dan Java mendukung "ruang lingkup statis", titik setengah antara kode yang benar-benar global tanpa objek induk dan anggota instance lingkup terbatas.

"Anggota kode" apa pun (fungsi, properti, bidang) dinyatakan sebagai staticruang lingkup pada baris pertama dari fungsi program main(), dan tidak meninggalkannya sampai main()fungsi berakhir. Dalam bahasa Inggris biasa, anggota statis ada dan dapat digunakan selama program sedang berjalan. Selain itu, anggota statis dipanggil dengan memanggil mereka sebagai anggota jenis itu sendiri, bukan anggota dari salah satu contoh dari jenis itu:

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

Hal ini membuat anggota statis dapat dilihat oleh kode apa pun yang memiliki pengetahuan tentang jenisnya, terlepas dari apakah mereka tahu atau tidak tentang satu pun instance itu.

Untuk menjawab pertanyaan Anda, manfaat utama menandai sesuatu sebagai statis adalah bahwa itu menjadi terlihat di mana pun jenisnya diketahui, terlepas dari apakah kode yang dikonsumsi memiliki atau bisa mendapatkan turunan dari objek yang mengandung. Ada juga sedikit manfaat kinerja; karena metode ini dalam lingkup statis, hanya dapat mengakses anggota statis lainnya (dari kelas yang sama atau yang lain), dan apa pun yang dilewatkan sebagai parameter. Oleh karena itu, runtime tidak harus menyelesaikan referensi ke instance saat ini dari objek yang berisi, karena biasanya harus untuk metode instance untuk memberikan informasi keadaan konteks-spesifik.

Seluruh kelas juga dapat ditandai statis; dengan melakukannya, Anda memberi tahu kompiler bahwa deklarasi kelas hanya akan terdiri dari anggota statis, dan karenanya tidak dapat dipakai. Ini adalah cara mudah untuk memastikan ada satu, dan hanya satu, salinan suatu objek di memori; buat kelas dan semua yang ada di dalamnya statis. Namun, sangat jarang bahwa ini adalah solusi terbaik untuk kebutuhan seperti itu. Dalam situasi di mana tepat satu salinan dari set data diperlukan, "singleton" biasanya dianjurkan sebagai gantinya; ini adalah kelas non-statis, yang menggunakan accessor statis dan konstruktor non-publik untuk menyediakan akses ke satu contoh itu sendiri. Secara teoritis, singleton memberikan banyak manfaat yang sama dari kelas yang sepenuhnya statis, tetapi dengan kemampuan tambahan untuk menggunakan kelas dengan cara yang berorientasi pada contoh objek.

KeithS
sumber