Bir yöntemi statik olarak bildirmenin kazancı nedir


95

Son zamanlarda Eclipse'deki uyarılarıma bakıyordum ve şuna rastladım:

statik uyarı

Yöntem statik olarak bildirilebilirse, bir derleyici uyarısı verecektir.

[değiştir] Eclipse yardımında özel ve nihai vurgu ile kesin alıntı:

Etkinleştirildiğinde, derleyici özel veya nihai olan ve yalnızca statik üyelere başvuran yöntemler için bir hata veya uyarı verir .

Evet, kapatabileceğimi biliyorum ama açmanın nedenini bilmek istiyorum.

Mümkün olan her yöntemi statik ilan etmek neden iyi bir şey olsun?

Bu herhangi bir performans avantajı sağlayacak mı? (mobil bir alanda)

Bir yöntemi statik olarak işaret ederek, sanırım herhangi bir örnek değişkeni kullanmadığınızı gösteriyor, bu nedenle bir utils stil sınıfına taşınabilir?

Günün sonunda bunu 'görmezden gel'i kapatmalı mıyım yoksa bana verdiği 100'den fazla uyarıyı düzeltmeli miyim?

Eğer bu sadece ekstra anahtar olduğunu düşünüyor musunuz kirli sadece zaten bu yöntemleri inlines derleyici olacak şekilde, kod? (bir nevi sonlandırabileceğiniz her değişkeni beyan etmiyorsunuz ama yapabilirdiniz ).


Emin değilim, ancak bu basitçe bir programlama yardımı olarak görülebilir. Uyarılar, bakılması gereken şeylerin göstergeleridir.
James P.

1
Bu yöntemlerin gerçekleştirdiği işlevselliğin türünü merak ediyorum. Belki de bunlardan bu kadar çok varsa, bir şeyler pek doğru yapılmamıştır.
ArjunShankar

Yanıtlar:


134

Ne zaman bir yöntem yazarsanız, belirli bir kapsamda bir sözleşmeyi yerine getirirsiniz. Kapsam ne kadar dar olursa, hata yazma şansınız o kadar düşük olur.

Bir yöntem statik olduğunda, statik olmayan üyelere erişemezsiniz; dolayısıyla kapsamınız daha dardır. Öyleyse, sözleşmenizi yerine getirmek için statik olmayan üyelere (alt sınıflarda bile) ihtiyacınız yoksa ve asla ihtiyaç duymayacaksanız , neden bu alanlara yönteminize erişim veresiniz? Yöntemin staticbu durumda bildirilmesi, derleyicinin kullanmayı düşünmediğiniz üyeleri kullanmadığınızı kontrol etmesine izin verir.

Ve dahası, kodunuzu okuyan kişilerin sözleşmenin yapısını anlamalarına yardımcı olacaktır.

Bu nedenle, staticaslında statik bir sözleşme uygularken bir yöntemi bildirmek iyi kabul edilir .

Bazı durumlarda, yönteminiz yalnızca sınıfınızın bir örneğine göre bir şey ifade eder ve uygulamasının aslında statik olmayan herhangi bir alan veya örnek kullanmadığı görülür. Bu gibi durumlarda yöntemi işaretlemezsiniz static.

staticAnahtar kelimeyi kullanmayacağınız yerlere örnekler :

  • Hiçbir şey yapmayan (ancak bir alt sınıftaki örnek verileriyle bir şeyler yapabilen) bir uzantı kancası
  • Bir alt sınıfta özelleştirilebilir olması gereken çok basit bir varsayılan davranış.
  • Olay işleyici uygulaması: uygulama, olay işleyicisinin sınıfına göre değişir, ancak olay işleyici örneğinin herhangi bir özelliğini kullanmaz.

1
+1 Bu, kendinizi ayağınızdan vurma fırsatlarını en aza indirmek ve bir yöntemi anlamak için bilmeniz gereken miktarı azaltmakla ilgilidir.
Peter Lawrey

7
Ayrıca, bağımsız, kendi kendine yeten bir işlevi çağırmak için bir örnek almakla uğraşmanıza gerek yok.
Marko Topolnik

1
Öyleyse diğer dünyalarda, örnek değişkenleri kullanmayan herhangi bir yöntem statik olarak bildirilmelidir?
Petr Mensik

18
@PetrMensik Bir privateyöntem statik olarak bildirilebiliyorsa, neredeyse değişmez şekilde olmalıdır . Diğer erişim seviyeleri için, dinamik gönderim gibi dikkate alınması gereken başka faktörler de vardır.
Marko Topolnik

1
@JamesPoulson Demek istediğim dinamik yöntem gönderimi, çağrılacak object.method()yöntemi seçerken ortaya çıkan şey .
Marko Topolnik

16

Burada optimizasyonu olan bir kavram yok.

Bir staticyöntem, yöntemin, staticyalnızca ihtiyaç duymadığı için çevreleyen sınıfın herhangi bir örneğine güvenmediğini açıkça bildirmenizdir. Böylece, belgelerde belirtildiği gibi Eclipse uyarısı:

Etkinleştirildiğinde, derleyici, özel veya nihai olan ve yalnızca statik üyelere başvuran yöntemler için bir hata veya uyarı verir.

Herhangi bir örnek değişkenine ihtiyacınız yoksa ve yönteminiz özel (dışarıdan çağrılamaz) veya nihai ise (geçersiz kılınamaz), bunun statik yerine normal bir yöntem olmasına izin vermeniz için bir neden yoktur. Statik bir yöntem, kendisiyle daha az şey yapmanıza izin verildiği için bile doğası gereği daha güvenlidir (herhangi bir örneğe ihtiyaç duymaz, örtük bir thisnesneniz yoktur).


7

Performans hakkında hiçbir bilgim yok, sanırım en fazla marjinal olarak daha iyi, çünkü kodun türe bağlı olarak dinamik gönderim yapması gerekmiyor.

Bununla birlikte, statik yöntemlere yeniden düzenleme karşı çok daha güçlü bir argüman, şu anda statik kullanımının kötü uygulama olarak kabul edilmesidir. Statik yöntemler / değişkenler, nesne yönelimli bir dile iyi entegre olmaz ve aynı zamanda düzgün bir şekilde test edilmesi zordur. Bu, bazı yeni dillerin statik yöntemler / değişkenler kavramından tamamen vazgeçmesinin veya onu OO ile daha iyi oynayacak şekilde dile içselleştirmeye çalışmasının nedenidir (örneğin, Scala'daki Nesneler).

Çoğu zaman, yalnızca parametreleri girdi olarak kullanan ve bunu kullanarak bir çıktı üreten işlevleri uygulamak için statik yöntemlere ihtiyacınız vardır (örn. Yardımcı işlevler / yardımcı işlevler) Modern dillerde, buna izin veren birinci sınıf bir İşlev kavramı vardır, bu nedenle statik Gerek yok. Java 8 entegre lambda ifadelerine sahip olacak, bu yüzden şimdiden bu yöne doğru ilerliyoruz.


7
Statik yöntemler test etmek için önemsizdir (bağımsız oldukları sürece - özellikle statik bir yöntemin birincil hedefi olan saf fonksiyonlar). OO konseptinin bu durumda sunabileceği hiçbir şey yoktur. Ayrıca, birinci sınıf işlev kavramının statik yöntem kavramıyla çok az ilgisi vardır. Mevcut bir statik yöntemin işini yapan birinci sınıf bir işleve ihtiyacınız varsa, onu uygulamak bir avuç karakter meselesidir.
Marko Topolnik

5
Test edilebilirlik açıklaması muhtemelen doğrudan statik yönteme yönelik değildi, ancak statik yöntemlerin alay edilmesi çok daha zordur, bu nedenle statik yöntemler olarak adlandırılan yöntemlerin test edilmesini karmaşıklaştırırlar.
Buhb

2
JMockit , PowerMock veya Groovy gibi güçlü bir alay çerçevesi kullanıyorsanız, statik yöntemlerle alay etmek kolaydır .
Jeff Olson

Bunlar private staticyöntemlerdir, bu yüzden onlarla dalga geçmenize gerek kalmayacaktır
Blundell

3

1. Beyan yöntemistatichafif performans avantajı sağlar, ancak daha kullanışlı olanı, elinizde bir nesne örneği olmadan kullanılmasına izin verir (örneğin, fabrika yöntemini veya bir tekli almayı düşünün). Ayrıca, yöntemin doğasını anlatmak için belgeleme amacına da hizmet eder. Kod okuyucularına ve API kullanıcılarına yöntemin doğası hakkında anında ipucu verdiği ve aynı zamanda orijinal programcı için bir düşünme aracı olarak hizmet ettiği için bu dokümantasyon amacı göz ardı edilmemelidir - amaçlanan anlam hakkında açık olmak yardımcı olur aynı zamanda doğru düşünür ve daha kaliteli kod üretirsiniz (kişisel deneyimlerime dayanarak düşünüyorum, ancak insanlar farklıdır). Örneğin, mantıklıdır ve bu nedenle, bir tür üzerinde çalışan yöntemler ile türün bir örneğine etki eden yöntemler arasında ayrım yapmak istenir (Jon Skeet bir C # sorusuna yaptığı yorumda ).

staticYöntemler için başka bir kullanım durumu, prosedürel programlama arayüzünü taklit etmektir. java.lang.System.println()Sınıfı ve içindeki yöntemleri ve nitelikleri düşünün . Sınıf java.lang.System, somutlaştırılabilir bir nesne yerine bir gruplama adı alanı gibi kullanılır.

2. Eclipse (veya başka herhangi bir programlanmış veya başka türde - biyolojik olarak birleştirilebilir veya biyolojik olarak birleştirilemez - varlık) hangi yöntemin statik olarak ilan edilebileceğinden nasıl emin olabilir? Bir temel sınıf, örnek değişkenlerine erişmiyorsa veya statik olmayan yöntemleri çağırmıyor olsa bile, miras mekanizması tarafından işler değişebilir. Yalnızca yöntem alt sınıfı miras alarak geçersiz kılınamazsa, yöntemin gerçekten bildirilebileceğini% 100 kesinlikle iddia edebiliriz static. Bir yöntemin geçersiz kılınması, iki durumda

  1. private (hiçbir alt sınıf onu doğrudan kullanamaz ve prensipte bile bilmiyor) veya
  2. final (alt sınıf tarafından erişilebilir olsa bile, örnek verilerine veya işlevlere başvurmak için yöntemi değiştirmenin bir yolu yoktur).

Eclipse seçeneğinin mantığı budur.

3. Orijinal poster aynı zamanda şunu sorar: " Bir yöntemi statik olarak işaret etmek, sanırım herhangi bir örnek değişkeni kullanmadığınızı gösteriyor, bu nedenle bir utils stil sınıfına taşınabilir mi? " Bu çok iyi bir nokta. Bazen bu tür bir tasarım değişikliği uyarı ile belirtilir.

Eclipse kullansam ve Java ile programlasam kişisel olarak etkinleştireceğime emin olacağım çok yararlı bir seçenek.


1

Yöntem kapsamının nasıl değiştiği konusunda Samuel'in cevabına bakın. Sanırım, bir yöntemi statik hale getirmenin ana yönü budur.

Ayrıca performansı sordunuz:

Statik bir yönteme yapılan bir çağrı, parametre olarak örtük "this" başvurusuna ihtiyaç duymadığından, küçük bir performans kazancı olabilir.

Ancak, bu performans etkisi gerçekten çok küçük. Bu nedenle, her şey kapsamla ilgili.


1

Android Performans yönergelerinden:

Statiği Sanal Yerine Tercih Edin Bir nesnenin alanlarına erişmeniz gerekmiyorsa, yönteminizi statik hale getirin. Çağrılar yaklaşık% 15 -% 20 daha hızlı olacaktır. Ayrıca iyi bir uygulamadır, çünkü yöntem imzasından yöntemi çağırmanın nesnenin durumunu değiştiremeyeceğini anlayabilirsiniz.

http://developer.android.com/training/articles/perf-tips.html#PreferStatic


"yöntemi çağırmanın nesnenin durumunu değiştiremeyeceği" - inanılmaz derecede yanıltıcıdır. Seni bilmiyorum, ama kesinlikle bir sınıfın statik özelliklerini bir nesnenin durumunun bir parçası olarak görüyorum.
Adam Parkin

0

Eclipse belgeleri söz konusu uyarı hakkında şunları söylüyor:

Yöntem statik olabilir

Etkinleştirildiğinde, derleyici özel veya nihai olan ve yalnızca statik üyelere başvuran yöntemler için bir hata veya uyarı verir.

Sanırım hemen hemen her şeyi söylüyor. Yöntem özel ve nihai ise ve yalnızca statik üyelere atıfta bulunuyorsa, söz konusu yöntem de statik olarak bildirilebilir ve bu sayede yalnızca ondan statik içeriğe erişmeyi amaçladığımızı ortaya koyar.

Dürüst olmak gerekirse, arkasında başka gizemli bir sebep olduğunu düşünmüyorum.


0

Hız farkları için bazı rakamları kaçırdım. Bu yüzden onları kıyaslamaya çalıştım ki bu çok kolay olmadı: Java döngüsü bazı çalışmalardan / JIT arızasından sonra yavaşlıyor?

Sonunda Caliper kullandım ve sonuçlar testlerimi elle çalıştırmayla aynı:

Statik / dinamik çağrılar için ölçülebilir bir fark yoktur. En azından Linux / AMD64 / Java7 için değil.

Kaliper Sonuçları şu şekildedir: https://microbenchmarks.appspot.com/runs/1426eac9-36ca-48f0-980f-0106af064e8f#r:scenario.benchmarkSpec.methodName,scenario.vmSpec.options.CMSLargeCoalSurplus.pecentSpecenario. CMSLargeSplitSurplusPercent, scenario.vmSpec.options.CMSSmallCoalSurplusPercent, scenario.vmSpec.options.CMSSmallSplitSurplusPercent, scenario.vmSpec.options.FLSLargestBlockCepecationMarkyPic.vmSpec.options.Stario

ve kendi sonuçlarım:

Static: 352 ms
Dynamic: 353 ms
Static: 348 ms
Dynamic: 349 ms
Static: 349 ms
Dynamic: 348 ms
Static: 349 ms
Dynamic: 344 ms

Kaliper Testi sınıfı şöyleydi:

public class TestPerfomanceOfStaticMethodsCaliper extends Benchmark {

    public static void main( String [] args ){

        CaliperMain.main( TestPerfomanceOfStaticMethodsCaliper.class, args );
    }

    public int timeAddDynamic( long reps ){
        int r=0;
        for( int i = 0; i < reps; i++ ) {
            r |= addDynamic( 1, i );
        }
        return r;
    }

    public int timeAddStatic( long reps ){
        int r=0;
        for( int i = 0; i < reps; i++ ) {
            r |= addStatic( 1, i );
        }
        return r;
    }

    public int addDynamic( int a, int b ){

        return a+b;
    }

    private static int addStatic( int a, int b ){

        return a+b;
    }

}

Ve kendi Test sınıfım şuydu:

public class TestPerformanceOfStaticVsDynamicCalls {

    private static final int RUNS = 1_000_000_000;

    public static void main( String [] args ) throws Exception{

        new TestPerformanceOfStaticVsDynamicCalls().run();
    }

    private void run(){

        int r=0;
        long start, end;

        for( int loop = 0; loop<10; loop++ ){

            // Benchmark

            start = System.currentTimeMillis();
            for( int i = 0; i < RUNS; i++ ) {
                r += addStatic( 1, i );
            }
            end = System.currentTimeMillis();
            System.out.println( "Static: " + ( end - start ) + " ms" );

            start = System.currentTimeMillis();
            for( int i = 0; i < RUNS; i++ ) {
                r += addDynamic( 1, i );
            }
            end = System.currentTimeMillis();
            System.out.println( "Dynamic: " + ( end - start ) + " ms" );

            // Do something with r to keep compiler happy
            System.out.println( r );

        }

    }

    private int addDynamic( int a, int b ){

        return a+b;
    }

    private static int addStatic( int a, int b ){

        return a+b;
    }

}

sonuçları çeşitli android cihazlarda ve sürümlerinde görmek ilginç olurdu
Blundell

Evet. İlginizi çekeceğini düşündüm :) Ama android yazılım geliştiriyorsunuz ve muhtemelen dev istasyonunuza bağlı bir android cihazınız olduğundan, sadece kodu seçmenizi, çalıştırmanızı ve sonuçları paylaşmanızı öneririm?
Scheintod

-2

Statik olarak bildirebileceğiniz yöntemler, örnekleme gerektirmeyen yöntemlerdir, örneğin

public class MyClass
{
    public static string InvertText(string text)
    {
        return text.Invert();
    }
}

Daha sonra başka herhangi bir sınıfta o sınıfı vurgulamadan seslenebilirsiniz.

public class MyClassTwo
{
    public void DoSomething()
    {
        var text = "hello world";
        Console.Write(MyClass.InvertText(text));
    }
}

... Ama bu muhtemelen zaten bildiğiniz bir şey. Yöntemin herhangi bir örnek değişkeni kullanmadığını daha açık hale getirmek dışında, size gerçek bir fayda sağlamaz.

Başka bir deyişle, en güvenli şekilde tamamen kapatabilirsiniz. Diğer sınıflarda bir yöntemi asla kullanmayacağınızı biliyorsanız (bu durumda sadece özel olmalıdır), statik olmasına hiç ihtiyacınız yoktur.


1
Bu dil nedir? Bu örnek derleniyor mu? Burada hiçbir şey sabit değil.
Piotr Perak

Aslında, InvertText yönteminden 'statik' kelimesini unutmuşum gibi görünüyor. Ve c #
NeroS
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.