Statik olmayan bir iç sınıfta neden statik yöntemimiz olamaz?
Eğer iç sınıfı statik yaparsam çalışır. Neden?
static
.")
Statik olmayan bir iç sınıfta neden statik yöntemimiz olamaz?
Eğer iç sınıfı statik yaparsam çalışır. Neden?
static
.")
Yanıtlar:
Bir iç sınıf örneği, dış sınıfının bir örneği ile örtük olarak ilişkili olduğundan, statik yöntemlerin kendisini tanımlayamaz. Statik iç içe bir sınıf, doğrudan çevreleyen sınıfında tanımlanan örnek değişkenlerine veya yöntemlere başvuramadığından, bunları yalnızca bir nesne başvurusu aracılığıyla kullanabilir, statik iç içe bir sınıftaki statik yöntemleri bildirmek güvenlidir.
A.B.sync(X)
hatta (A içinden) B.sync(x)
?
Statik olmayan bir iç sınıfta statik bir yönteme izin vermenin pek bir anlamı yoktur; ona nasıl erişirdin? Bir dış sınıf örneğinden geçmeden statik olmayan bir iç sınıf örneğine erişemezsiniz (en azından başlangıçta). Statik olmayan bir iç sınıf yaratmanın tamamen statik bir yolu yoktur.
Bir dış sınıf için Outer
, aşağıdaki test()
gibi bir statik yönteme erişebilirsiniz :
Outer.test();
Statik bir iç sınıf için Inner
, statik yöntemine şu şekilde erişebilirsiniz innerTest()
:
Outer.Inner.innerTest();
Ancak, Inner
statik değilse, şimdi yönteme başvurmak için tamamen statik bir yol yoktur innertest
. Statik olmayan iç sınıflar, dış sınıflarının belirli bir örneğine bağlıdır. Bir işlev sabitten farklıdır, Outer.Inner.CONSTANT
çünkü bir işlev çağrısının bir işlev çağrısı olmayacak şekilde açık olması garanti edilir Outer.Inner.staticFunction();
. Diyelim ki, içinde tanımlanmış olan Inner.staticFunction()
çağrılarınız var . Bu statik işlevi çağırmaya çalışırsanız, artık Inner sınıfına belirsiz bir başvurunuz olur. Yani, iç sınıfın hangi örneğinde statik işlevi çağırıyorsunuz? Fark eder, önemi var. Bkz. Dış nesneye dolaylı başvuru nedeniyle, bu statik yönteme başvurmak için gerçekten statik bir yol yoktur.getState()
Outer
Paul Bellora, dil tasarımcılarının buna izin verebileceği konusunda haklı. Daha sonra, statik olmayan iç sınıfın statik yöntemlerinde, dış sınıfa örtük referansa erişime dikkatle izin vermek zorunda kalacaklardır. Bu noktada, statik olarak dışında dış sınıfa başvuramazsanız, bunun bir iç sınıf olması ne demektir? Statik erişim iyi ise, neden tüm iç sınıfı statik olarak beyan etmiyorsunuz? Eğer sadece iç sınıfın kendisini statik yaparsanız, o zaman dış sınıfa dolaylı bir referansınız olmaz ve artık bu belirsizliğe sahip olmazsınız.
Statik olmayan bir iç sınıfta aslında statik yöntemlere ihtiyacınız varsa , muhtemelen tasarımınızı yeniden düşünmeniz gerekir.
Outer.Inner i = new Outer().new Inner();
Ayrıca, iç sınıflar vardır statik ilan etmeye izin sabitlerini JLS §15.28 göre.
Outer.Inner.staticMethod()
sadece siz erişebilirsiniz gibi Outer.Inner.CONSTANT
. "Dış sınıf örneğinden geçmeden ... statik olmayan bir iç sınıf örneğine erişemezsiniz." Neden bir örneğe ihtiyacınız var? Outer
Aramak için bir örneğine ihtiyacınız yok Outer.staticMethod()
. Bunun nitpicky olduğunu biliyorum ama benim cevabım cevabınızı bu şekilde çerçevelemek mantıklı değil. IMHO dil tasarımcıları isteseydi buna izin verebilirdi.
Outer.Inner.CONSTANT
ve Outer.Inner.staticMethod()
bir sabit bir referans dolaylı örneği referans şansı olmasıdır Outer
ki burada Inner
örneği edildi. Tüm referanslar Outer.staticMethod()
aynı durumu paylaşır. Tüm referanslar Outer.Inner.CONSTANT
aynı durumu paylaşır. Ancak, başvuruları Outer.Inner.staticMethod()
belirsiz: "statik" durumu, her örneğinde dış sınıfa örtülü başvuru nedeniyle gerçekten statik değil Inner
. Ona erişmenin gerçekten açık ve statik bir yolu yoktur.
Outer.this
. Java dil tasarımcıları ile iç sınıflarda statik yöntemlere veya nihai olmayan statik alanlara izin vermek için hiçbir neden olmadığına katılıyorum, çünkü bir iç sınıftaki her şey kapalı sınıfın bağlamında olmalıdır.
Doğru olabilecek ya da olmayabilecek bir teorim var.
İlk olarak, Java'da iç sınıfların nasıl uygulandığı hakkında bazı şeyler bilmelisiniz. Diyelim ki bu sınıfa sahipsiniz:
class Outer {
private int foo = 0;
class Inner implements Runnable {
public void run(){ foo++; }
}
public Runnable newFooIncrementer(){ return new Inner(); }
}
Derlediğinizde, oluşturulan bayt kodu şöyle bir şey yazmış gibi görünecektir:
class Outer {
private int foo = 0;
static class Inner implements Runnable {
private final Outer this$0;
public Inner(Outer outer){
this$0 = outer;
}
public void run(){ this$0.foo++; }
}
public Runnable newFooIncrementer(){ return new Inner(this); }
}
Şimdi, statik olmayan iç sınıflarda statik yöntemlere izin verdiysek, böyle bir şey yapmak isteyebilirsiniz.
class Outer {
private int foo = 0;
class Inner {
public static void incrFoo(){ foo++; }
}
}
... Inner
sınıfın Outer
örnek başına bir enkarnasyonu olduğu için oldukça makul görünüyor . Ancak yukarıda gördüğümüz gibi, statik olmayan iç sınıflar gerçekten statik "iç" sınıflar için sözdizimsel şekerdir, bu nedenle son örnek yaklaşık olarak eşdeğer olacaktır:
class Outer {
private int foo = 0;
static class Inner {
private final Outer this$0;
public Inner(Outer outer){
this$0 = outer;
}
public static void incrFoo(){ this$0.foo++; }
}
}
... this$0
statik olmadığı için açıkça çalışmaz . Bu tür, statik yöntemlere neden izin verilmediğini (kapalı nesnelere başvurmadıkları sürece statik yöntemlere izin verebileceğiniz argümanı verebilmenize rağmen) ve neden nihai olmayan statik alanlara sahip olamayacağınızı açıklar ( farklı nesnelerden gelen statik olmayan iç sınıfların örneklerinin "statik durum" paylaşması karşı-sezgisel olacaktır). Nihai alanlar nedeni de açıklıyor edilmektedir (yeter ki kapsayan nesne başvurusu yok gibi) izin verdi.
public static double sinDeg(double theta) { ... }
iç matematik programları dersi yazmak istersem ne olur ?
Tek neden "olmazsa olmaz", peki neden desteklemeye zahmet ediyorsunuz?
Sözdizimsel olarak, bir iç sınıfın statik üyelere sahip olmasını yasaklamak için hiçbir neden yoktur. Bir örneği, bir örneğiyle Inner
ilişkilendirilmiş olsa da Outer
, java'nın buna karar vermesi durumunda Outer.Inner.myStatic
statik bir üyeye başvurmak hala mümkündür Inner
.
Eğer tüm örnekler arasında bir şeyler paylaşmanız gerekiyorsa Inner
, bunları Outer
statik üyeler olarak koyabilirsiniz . Bu statik üyeleri kullanmak daha kötü Inner
, Outer
hala herhangi özel üyesini erişebilir Inner
(kapsülleme iyileştirmez) neyse.
Bir nesnenin Inner
yarattığı tüm örnekler arasında bir şey paylaşmanız gerekiyorsa outer
, bunları Outer
sıradan üyeler olarak sınıfa koymak daha mantıklıdır .
"Statik iç içe bir sınıfın neredeyse sadece üst düzey bir sınıf olduğu" fikrine katılmıyorum. Statik iç içe bir sınıfı / iç sınıfı gerçekten dış sınıfın bir parçası olarak görmenin daha iyi olduğunu düşünüyorum, çünkü dış sınıfın özel üyelerine erişebilirler. Dış sınıf üyeleri de "iç sınıf üyeleri" dir. Bu yüzden iç sınıfta statik üyeyi desteklemeye gerek yoktur. Dış sınıftaki sıradan / statik bir üye yeterli olacaktır.
Gönderen: https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html
Örnek yöntemleri ve değişkenlerinde olduğu gibi, bir iç sınıf, çevreleyen sınıfının bir örneğiyle ilişkilidir ve o nesnenin yöntemlerine ve alanlarına doğrudan erişime sahiptir. Ayrıca, bir iç sınıf bir örnekle ilişkilendirildiğinden, statik üyelerin kendisini tanımlayamaz.
Oracle'ın açıklaması yüzeysel ve el dalgalarıdır. Bir iç sınıftaki statik üyeleri (C # gibi diğer dillerde izin verilir) ön planda tutmak için teknik veya sözdizimsel bir neden olmadığından, Java tasarımcılarının motivasyonu muhtemelen kavramsal bir zevk ve / veya teknik kolaylık meselesiydi.
İşte spekülasyonum:
Üst düzey sınıflardan farklı olarak, iç sınıflar örneğe bağımlıdır: bir iç sınıf örneği, dış sınıflarının her birinin bir örneğiyle ilişkilidir ve üyelerine doğrudan erişime sahiptir. Bu onları Java'da kullanmak için başlıca motivasyon. Başka bir ifadeyle: bir iç sınıf, bir dış sınıf örneği bağlamında örnekleme içindir . Bir dış sınıf örneği olmadan, bir iç sınıf , dış sınıfın diğer örnek üyelerinden daha fazla kullanılabilir olmamalıdır. Buna iç sınıfların örneğe bağlı ruhu olarak bakalım .
Statik elemanların doğası (nesne yönelimli DEĞİLDİR) , iç sınıfların örneğe bağlı ruhu ile (ki nesne yönelimli) çakışır, çünkü bir dış sınıf örneği olmayan bir iç sınıfın statik bir üyesine nitelikli iç sınıf adını kullanarak.
Özellikle statik değişkenler yine başka bir şekilde kırılabilir: bir iç sınıfın, dış sınıfın farklı örnekleriyle ilişkilendirilmiş iki örneği statik değişkenleri paylaşır. Değişkenler durumun bir bileşeni olduğu için, iki iç sınıf örneği, aslında ilişkili oldukları dış sınıf örneklerinden bağımsız olarak durumu paylaşır. Statik değişkenlerin bu şekilde çalışması kabul edilemez değildir (Java'da OOP saflığına karşı makul bir uzlaşma olarak kabul ediyoruz), ancak örnekleri zaten dış sınıf örnekleriyle eşleştirilmiş iç sınıflarda izin vererek daha derin bir suç var. tasarım. İç sınıflardaki statik üyelerin örneğe bağımlı ruh lehine yasaklanması, bu daha derin OOP suçunu önleme avantajını ortaya çıkarır.
Öte yandan, anlamlı bir şekilde devleti oluşturmayan statik sabitler tarafından böyle bir suç söz konusu değildir ve bu nedenle bunlara izin verilebilir. Neden örneğe bağlı ruhla maksimum tutarlılık için statik sabitleri yasaklamıyorsunuz ? Belki de sabitlerin gereğinden fazla bellek alması gerekmediği için (statik olmaya zorlandıkları takdirde, potansiyel olarak israfa yol açan her iç sınıf örneğine kopyalanırlar). Aksi takdirde istisnanın nedenini hayal edemiyorum.
Kaya gibi sağlam bir akıl yürütme olmayabilir, ancak IMO, Oracle'ın konuyla ilgili sözlü ifadesini en mantıklı kılıyor.
Kısa cevap: Çoğu programcının kapsamın nasıl çalıştığına dair zihinsel model, javac tarafından kullanılan model değildir. Daha sezgisel modeli eşleştirmek, javac'ın çalışma biçiminde büyük bir değişiklik gerektirecektir.
İç sınıflardaki statik elemanların istenmesinin temel nedeni kod temizliğidir - dış sınıfa yerleştirilmek yerine sadece iç sınıf tarafından kullanılan statik bir eleman. Düşünmek:
class Outer {
int outID;
class Inner {
static int nextID;
int id = nextID++;
String getID() {
return outID + ":" + id;
}
}
}
Niteliksiz tanımlayıcı "outID" kullandığımda getID () içinde neler olduğunu düşünün. Bu tanımlayıcının göründüğü kapsam şöyle görünür:
Outer -> Inner -> getID()
Yine, javac'ın işleyişi bu şekilde olduğu için, kapsamın "Outer" seviyesi Outer'ın hem statik hem de örnek üyelerini içerir. Bu kafa karıştırıcıdır çünkü genellikle bir sınıfın statik kısmını kapsamın başka bir seviyesi olarak düşünmemiz söylenir:
Outer static -> Outer instance -> instanceMethod()
\----> staticMethod()
Bunu düşünmenin bu şekilde, elbette staticMethod () sadece Outer'ın statik üyelerini görebilir. Ancak javac bu şekilde çalışırsa, statik bir yöntemde bir örnek değişkenine başvurmak "ad çözümlenemez" hatasıyla sonuçlanır. Gerçekten olan şey, adın kapsamda bulunmasıdır, ancak daha sonra fazladan bir kontrol başlar ve adın bir örnek bağlamında bildirildiğini ve statik bir bağlamdan referans alındığını anlar.
Tamam, bunun iç sınıflarla nasıl bir ilişkisi var? Safça, iç sınıfların statik bir kapsama sahip olmasının bir nedeni olmadığını düşünüyoruz, çünkü kapsamı şu şekilde çalışıyoruz:
Outer static -> Outer instance -> Inner instance -> getID()
\------ Inner static ------^
Başka bir deyişle, iç sınıftaki statik bildirimler ve dış sınıftaki örnek bildirimler hem iç sınıfın örnek bağlamı kapsamındadır, ancak bunların hiçbiri aslında diğerinde iç içe değildir; her ikisi de Dış'ın statik kapsamına yerleştirilir.
Javac bu şekilde çalışmaz - hem statik hem de yönetim ortamı üyeleri için tek bir kapsam düzeyi vardır ve kapsam her zaman kesin olarak iç içe geçer. Kalıtım bile, bildirimleri dallamak ve üst sınıf kapsamını aramak yerine alt sınıfa kopyalayarak uygulanır.
İç sınıfların statik üyelerini desteklemek için, javac ya statik ve örnek kapsamlarını ayırmalı ve dallanma ve yeniden birleşen kapsam hiyerarşilerini desteklemeli ya da tüm düzeylerdeki bağlam türünü izlemek için değiştirmek için basit boole "statik bağlam" fikrini genişletmek zorunda kalacaktı. geçerli kapsamdaki iç içe sınıfın.
Statik olmayan bir iç sınıfta neden statik yöntemimiz olamaz?
Not: Statik olmayan bir iç içe sınıf, iç sınıf olarak bilinir, böylece böyle olmaz non-static inner class
.
Bir iç sınıf örneğinin karşılık gelen bir dış sınıf örneği olmadan varlığı yoktur. Bir iç sınıf, zaman sabitleri dışında statik üyeler bildiremez. İzin verilmiş olsaydı, anlamıyla ilgili bir belirsizlik olurdu static
. Bu durumda bazı karışıklıklar olurdu:
Bu yüzden tasarımcılar muhtemelen bu konuyu ele almama kararını aldılar.
Eğer iç sınıfı statik yaparsam çalışır. Neden ?
Yine bir iç sınıfı statik hale getiremezsiniz, bunun yerine statik bir sınıfı iç içe olarak bildirebilirsiniz. Bu durumda, bu iç içe sınıf aslında dış sınıfın bir parçasıdır ve herhangi bir sorun olmadan statik üyelere sahip olabilir.
Bu konu birçok kişinin dikkatini çekti, yine de en basit şekilde açıklamaya çalışacağım.
İlk olarak, http://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.4.1 referans alınarak , bir sınıf veya arayüz ilk ortaya çıkmadan / çağrılmadan hemen önce başlatılır. statik anahtar kelime ile önceden gelen tüm üyelerin.
Bu nedenle, bir iç sınıf içinde statik bir üye koyarsak, mutlaka dış / çevreleyen sınıf değil, iç sınıfın başlatılmasına yol açacaktır. Bu yüzden, sınıf başlatma sırasını engelliyoruz.
Ayrıca, statik olmayan bir iç sınıfın bir çevreleyen / dış sınıf örneğiyle ilişkili olduğunu düşünün. Yani, bir örnekle ilişkilendirmek, iç sınıfın Outer sınıfı bir örnek içinde var olacağı ve örnekler arasında farklı olacağı anlamına gelecektir.
Noktayı basitleştirmek için, statik üyeye erişmek için, yine statik olmayan bir iç sınıf örneği oluşturmamız gereken bir Dış sınıf örneğine ihtiyacımız var. Statik üyelerin örneklere bağlı olması gerekmez ve bu nedenle bir derleme hatası alırsınız.
Her ikisi de sözdiziminde benzer olmasına rağmen, bir iç sınıf statik iç içe bir sınıftan tamamen farklı bir şeydir. Statik iç içe sınıflar sadece gruplama için bir araçtır, oysa iç sınıflar dış sınıflarının güçlü bir ilişkisine ve tüm değerlerine erişime sahiptir. Neden bir iç sınıf kullanmak istediğinizden emin olmalısınız ve sonra hangisini kullanmanız gerektiği oldukça doğal olmalıdır. Statik bir yöntem bildirmeniz gerekiyorsa, muhtemelen yine de istediğiniz statik bir iç içe sınıftır.
Dış sınıfın iki örneği olduğunu varsayalım ve her ikisinde de iç sınıf örneği var.Şimdi iç sınıfın statik bir üyesi varsa, o zaman yığın alanında o üyenin yalnızca bir kopyasını tutacaktır.Bu durumda dış sınıfın her iki nesnesi de tek kopya & birlikte birlikte değiştirebilirsiniz.Bu, bu Java bu kısıtlamayı uygulamak önlemek için "Kirli okuma" duruma neden olabilir.Bu argümanı desteklemek için bir başka güçlü nokta, java burada son statik üyelere izin verir, değerleri olamaz dış sınıf nesnesinin herhangi birinden değiştirildi. Yanılıyorsam lütfen izin ver.
Öncelikle neden birisi statik olmayan bir iç sınıfta statik üyeyi tanımlamak istiyor? cevap, böylece dış sınıf üyesi sadece iç sınıf adıyla bu statik üyeyi kullanabilirsiniz, değil mi?
Ancak bu durumda üyeyi doğrudan dış sınıfta tanımlayabiliriz. dış sınıf örneği içindeki iç sınıfın tüm nesnesiyle ilişkilendirilecektir.
aşağıdaki kod gibi,
public class Outer {
class Inner {
public static void method() {
}
}
}
böyle yazılabilir
public class Outer {
void method() {
}
class Inner {
}
}
Bence java tasarımcısı kod karmaşıklaştırmak değil bu işleve izin vermiyor ya da biz daha fazla özellik ile gelecekteki sürümlerde bu işlevselliği görebilirsiniz.
Sınıfa normal bir alan gibi davranmaya çalışın, o zaman anlayacaksınız.
//something must be static. Suppose something is an inner class, then it has static keyword which means it's a static class
Outer.something
İç sınıf üyelerini statik olarak kullanmak işe yaramaz çünkü ilk etapta onlara erişemezsiniz.
Bunu düşünün, className.memberName kullandığınız statik bir üyeye erişmek için, bizim durumumuzda, bu outerclassName.innerclassName.memberName gibi bir şey olmalı, şimdi iç sınıfın neden statik olması gerektiğini görüyorsunuz ....