Soru Java'da, neden soyut bir statik yöntem tanımlayamıyorum? Örneğin
abstract class foo {
abstract void bar( ); // <-- this is ok
abstract static void bar2(); //<-- this isn't why?
}
Soru Java'da, neden soyut bir statik yöntem tanımlayamıyorum? Örneğin
abstract class foo {
abstract void bar( ); // <-- this is ok
abstract static void bar2(); //<-- this isn't why?
}
Yanıtlar:
Çünkü "soyut" şu anlama gelir: "Hiçbir işlevsellik uygulamaz" ve "statik" şu anlama gelir: "Bir nesne örneğiniz olmasa bile işlevsellik vardır". Ve bu mantıklı bir çelişki.
abstract static
olsaydı mükemmel bir mantıklı olurdu. Alt sınıf nesnelerinin uygulaması gereken sınıf nesnesinin kendisinin bir yöntemi olurdu. Tabii ki, dili kavramaya rağmen işlerin cevabınızı temsil etme şekli doğru.
abstract static
: "alt sınıfta uygulanan" A fonksiyon X olamaz aynı anda "sınıfına infaz" edilecek - Yalnızca alt sınıf . O zaman artık soyut değil.
static
"boş değil" anlamına gelmez - bu sadece Java'nın statik yöntemlerin soyut olmasına izin vermemesinin bir sonucudur. "Sınıfta çağrılabilir" anlamına gelir. (Bu " sadece sınıfta çağrılabilir" anlamına gelmelidir , ancak bu başka bir konudur.) Java tarafından desteklenen abstract static
yöntemler, yöntem 1) alt sınıflar tarafından uygulanmalı ve 2) alt sınıfın bir sınıf yöntemidir anlamına gelmesini beklerdim. Bazı yöntemler örnek yöntemler olarak anlamsızdır. Ne yazık ki Java, soyut bir temel sınıf (veya arabirim) oluştururken bunu belirtmenize izin vermez.
Kötü dil tasarımı. Doğrudan statik soyut yöntemi çağırmak, yalnızca bu soyut yöntemi kullanmak için bir örnek oluşturmaktan çok daha etkili olacaktır. Özellikle, soyut bir sınıfı, numaralandırmanın uzamaması için bir geçici çözüm olarak kullanırken, bu da başka bir kötü tasarım örneğidir. Umarım bu sınırlamaları bir sonraki sürümde çözerler.
static
kendi kavramının zaten bir ihlal olduğunu söyleyen insanlar var ....
Statik bir yöntemi geçersiz kılamazsınız, bu yüzden soyut yapmak anlamsız olur. Dahası, soyut bir sınıftaki statik bir yöntem, o sınıfa ait olan sınıfa değil, o sınıfa ait olacaktır, bu yüzden yine de kullanılamazdı.
abstract
Bir yönteme ek açıklama yöntemi alt sınıfta geçersiz kılınmalıdır belirtir.
Java'da, bir static
üye (yöntem veya alan) alt sınıflar tarafından geçersiz kılınamaz (bu, diğer nesne yönelimli dillerde mutlaka doğru değildir, bkz. SmallTalk.) Bir static
üye gizlenmiş olabilir , ancak bu geçersiz kılınandan temelde farklıdır .
Statik üyeler bir alt sınıfta geçersiz kılınamayacağından, abstract
ek açıklama onlara uygulanamaz.
Bir kenara, diğer diller tıpkı örnek miras gibi statik mirası desteklemektedir. Sözdizimi açısından bakıldığında, bu diller genellikle sınıf adının ifadeye dahil edilmesini gerektirir. Örneğin, Java'da, ClassA'da kod yazdığınızı varsayarsak, bunlar eşdeğer ifadelerdir (methodA () statik bir yöntemse ve aynı imzalı bir örnek yöntemi yoksa):
ClassA.methodA();
ve
methodA();
SmallTalk'ta, sınıf adı isteğe bağlı değildir, bu nedenle sözdizimi (SmallTalk'ın "konuyu" ve "fiili" ayırmak için.
ClassA methodA.
Sınıf adı her zaman gerekli olduğundan, yöntemin doğru "sürümü" her zaman sınıf hiyerarşisinde gezilerek belirlenebilir. Değeri ne static
olursa olsun, zaman zaman miras kaçırıyorum ve ilk başladığımda Java statik miras eksikliği tarafından ısırıldı. Buna ek olarak, SmallTalk ördek türündedir (ve böylece sözleşme-programını desteklemez.) Bu nedenle, abstract
sınıf üyeleri için değiştirici yoktur .
Aynı soruyu da sordum, işte neden
Abstract sınıfı dediği gibi, uygulama vermeyecek ve alt sınıfın vermesine izin vermeyecektir.
bu yüzden Alt Sınıf, Üst Sınıf yöntemlerini geçersiz kılmak zorundadır,
KURAL NO 1 - Statik bir yöntem geçersiz kılınamaz
Statik üyeler ve yöntemler derleme zamanı öğeleri olduğundan, bu nedenle Statik yöntemlerin Aşırı Yüklemesine (Derleme zamanı Polimorfizmi) Geçersiz Kılma (Çalışma Zamanı Polimorfizmi) yerine izin verilir
Yani, Soyut olamazlar.
Soyut statik gibi bir şey yoktur <--- Java Universe'de izin verilmiyor
abstract static
bkz. Stackoverflow.com/questions/370962/… . Gerçek nedeni Java statik yöntemler geçersiz kılınan olmasına izin vermez, çünkü Java statik yöntemler geçersiz kılınan olmasına izin vermez nedeni budur.
foo(String)
aynı değil foo(Integer)
- hepsi bu.
Bu korkunç bir dil tasarımı ve neden mümkün olamayacağına dair hiçbir sebep yok.
Aslında, burada nasıl bir uygulamasıdır CAN yapılabilir JAVA :
public class Main {
public static void main(String[] args) {
// This is done once in your application, usually at startup
Request.setRequest(new RequestImplementationOther());
Request.doSomething();
}
public static final class RequestImplementationDefault extends Request {
@Override
void doSomethingImpl() {
System.out.println("I am doing something AAAAAA");
}
}
public static final class RequestImplementaionOther extends Request {
@Override
void doSomethingImpl() {
System.out.println("I am doing something BBBBBB");
}
}
// Static methods in here can be overriden
public static abstract class Request {
abstract void doSomethingImpl();
// Static method
public static void doSomething() {
getRequest().doSomethingImpl();
}
private static Request request;
private static Request getRequest() {
// If setRequest is never called prior, it will default to a default implementation. Of course you could ignore that too.
if ( request == null ) {
return request = new RequestImplementationDefault();
}
return request;
}
public static Request setRequest(Request r){
return request = r;
}
}
}
================= Aşağıdaki eski örnek ==================
GetRequest öğesini arayın ve çağrı yapılmadan önce uygulamayı değiştirmek için getRequestImpl ... setInstance çağrılabilir.
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
/**
* @author Mo. Joseph
* @date 16 mar 2012
**/
public abstract class Core {
// ---------------------------------------------------------------
private static Core singleton;
private static Core getInstance() {
if ( singleton == null )
setInstance( new Core.CoreDefaultImpl() ); // See bottom for CoreDefaultImpl
return singleton;
}
public static void setInstance(Core core) {
Core.singleton = core;
}
// ---------------------------------------------------------------
// Static public method
public static HttpServletRequest getRequest() {
return getInstance().getRequestImpl();
}
// A new implementation would override this one and call setInstance above with that implementation instance
protected abstract HttpServletRequest getRequestImpl();
// ============================ CLASSES =================================
// ======================================================================
// == Two example implementations, to alter getRequest() call behaviour
// == getInstance() have to be called in all static methods for this to work
// == static method getRequest is altered through implementation of getRequestImpl
// ======================================================================
/** Static inner class CoreDefaultImpl */
public static class CoreDefaultImpl extends Core {
protected HttpServletRequest getRequestImpl() {
return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
}
}
/** Static inner class CoreTestImpl : Alternative implementation */
public static class CoreTestImpl extends Core {
protected HttpServletRequest getRequestImpl() {
return new MockedRequest();
}
}
}
Aşağıdaki gibi kullanılır:
static {
Core.setSingleton(new Core.CoreDefaultImpl());
// Or
Core.setSingleton(new Core.CoreTestImpl());
// Later in the application you might use
Core.getRequest();
}
abstract static
Soruda sorulduğu gibi bir yöntem örneği nereden sağladığınızı anlamadım ve kalın yazdınız JAVA'DA YAPILABİLİRSİNİZ . Bu tamamen yanlış yönlendirici.
Soyut bir yöntem yalnızca bir alt sınıfta geçersiz kılınabilmesi için tanımlanır. Ancak, statik yöntemler geçersiz kılınamaz. Bu nedenle, soyut, statik bir yönteme sahip olmak derleme zamanı hatasıdır.
Şimdi bir sonraki soru neden statik yöntemler geçersiz kılınamaz?
Çünkü statik yöntemler örneğine değil, belirli bir sınıfa aittir. Statik bir yöntemi geçersiz kılmaya çalışırsanız, herhangi bir derleme veya çalışma zamanı hatası almayacaksınız, ancak derleyici statik üst sınıf statik yöntemini gizleyecektir.
Statik bir yöntemin tanım gereği bilmesi gerekmez this
. Bu nedenle, sanal bir yöntem olamaz (bu, mevcut alt sınıf bilgilerine göre aşırı yüklenir)this
); bunun yerine, statik yöntem aşırı yüklemesi yalnızca derleme zamanında mevcut olan bilgilere dayanır (bunun anlamı: statik bir üst sınıf yöntemine başvurduğunuzda, üst sınıf yöntemini çağırırsınız, ancak hiçbir zaman bir alt sınıf yöntemini çağırmazsınız).
Buna göre, soyut statik yöntemler oldukça işe yaramaz çünkü referansını asla tanımlanmış bir bedenle değiştirmeyeceksiniz.
Görüyorum ki zaten bir tanrı-milyon yanıt var ama pratik çözüm görmüyorum. Tabii ki bu gerçek bir problem ve bu sözdizimini Java'da hariç tutmak için iyi bir neden yok. Orijinal soru, bunun gerekli olabileceği bir bağlamdan yoksun olduğundan, hem bir bağlam hem de bir çözüm sağlarım:
Aynı sınıfta bir grup statik yönteminiz olduğunu varsayalım. Bu yöntemler sınıfa özgü statik bir yöntemi çağırır:
class C1 {
static void doWork() {
...
for (int k: list)
doMoreWork(k);
...
}
private static void doMoreWork(int k) {
// code specific to class C1
}
}
class C2 {
static void doWork() {
...
for (int k: list)
doMoreWork(k);
...
}
private static void doMoreWork(int k) {
// code specific to class C2
}
}
doWork()
C1
ve C2
içindeki yöntemler aynıdır. Bu calsseslerin birçoğu olabilir: C3
C4
vb. static abstract
İzin verildiyse , aşağıdaki gibi bir şey yaparak yinelenen kodu ortadan kaldırırsınız:
abstract class C {
static void doWork() {
...
for (int k: list)
doMoreWork(k);
...
}
static abstract void doMoreWork(int k);
}
class C1 extends C {
private static void doMoreWork(int k) {
// code for class C1
}
}
class C2 extends C {
private static void doMoreWork(int k) {
// code for class C2
}
}
ancak bu, derlemeye static abstract
izin verilmediği için derlenmez . Bununla birlikte, bu static class
izin verilen yapı ile atlatılabilir :
abstract class C {
void doWork() {
...
for (int k: list)
doMoreWork(k);
...
}
abstract void doMoreWork(int k);
}
class C1 {
private static final C c = new C(){
@Override void doMoreWork(int k) {
System.out.println("code for C1");
}
};
public static void doWork() {
c.doWork();
}
}
class C2 {
private static final C c = new C() {
@Override void doMoreWork(int k) {
System.out.println("code for C2");
}
};
public static void doWork() {
c.doWork();
}
}
Bu çözüm ile çoğaltılan tek kod
public static void doWork() {
c.doWork();
}
C1.doWork()
ya da C2.doWork()
Ama arayamazsınız C.doWork()
. Ayrıca, sağladığınız örnekte, çalışmayan, izin verilip verilmediğini varsayalım, sınıfın C
uygulanmasını nasıl bulacaktır doMoreWork()
? Sonunda bağlam kodunuza kötü tasarım diyorum. Neden? basitçe, kod için ortak bir işlev oluşturmak ve sonra sınıfta statik bir işlev uygulamak yerine benzersiz bir kod yaratmış olmanızdır C
. Bu daha kolay !!!
Varsayalım ki iki sınıf vardır Parent
ve Child
. Parent
olduğunu abstract
. Beyanlar aşağıdaki gibidir:
abstract class Parent {
abstract void run();
}
class Child extends Parent {
void run() {}
}
Herhangi örneği olduğunu bu araçlar Parent
nasıl belirtmelisinizrun()
yürütüleceğini .
Ancak, şimdi öyle Parent
olmadığını varsayalım abstract
.
class Parent {
static void run() {}
}
Bunun anlamı şudur ki Parent.run()
, statik yöntemi çalıştıracağı .
An'un tanımı abstract
yöntemin , "bildirilen ancak uygulanmayan bir yöntemdir", yani hiçbir şey döndürmez.
A'un tanımı static
yöntemin , "çağrıldığı örnek ne olursa olsun aynı parametreler için aynı değeri döndüren bir yöntemdir".
abstract
Örnek değiştikçe bir yöntemin dönüş değeri değişecektir. Bir static
yöntem olmaz. birstatic abstract
yöntem hemen hemen dönüş değeri sabit olan bir yöntemdir, ancak hiçbir şey döndürmez. Bu mantıklı bir çelişki.
Ayrıca, bir static abstract
yöntemin gerçekten fazla bir nedeni yoktur .
Soyut bir sınıfın statik bir yöntemi olamaz çünkü statik yöntemler işlevlerine statik olarak bağlanırken DYNAMIC BINDING elde etmek için soyutlama yapılır. Statik yöntemler nesneye değil sınıfa aittir. Her nesne ile paylaşıldığı PERMGEN olarak bilinen bir bellek alanında saklanırlar. Soyut sınıftaki yöntemler işlevselliklerine dinamik olarak bağlanır.
Bir yöntemi static
araç olarak tanımlamak , sınıf yöntemiyle bu yöntemi çağırabiliriz ve bu sınıf da varsa, abstract
herhangi bir gövde içermediği için bu yöntemi çağırmanın bir anlamı yoktur ve bu nedenle bir yöntemi hem static
ve olarak ilan edemeyiz abstract
.
Soyut yöntemler sınıfa ait olduğundan ve uygulayıcı sınıf tarafından geçersiz kılınamayacağından, aynı imzalı statik bir yöntem olsa bile, yöntemi gizler, geçersiz kılmaz. Bu nedenle, soyut yöntemi asla vücudu alamayacağı kadar statik olarak ilan etmek önemsizdir.Bu nedenle, zaman hatasını derler.
Statik bir yöntem, sınıfın bir örneği olmadan çağrılabilir. Örneğinizde foo.bar2 () öğesini çağırabilirsiniz, ancak foo.bar () öğesini çağırabilirsiniz, çünkü bar için bir örneğe ihtiyacınız vardır. Aşağıdaki kod işe yarar:
foo var = new ImplementsFoo();
var.bar();
Statik bir yöntem çağırırsanız, her zaman aynı kod yürütülür. Yukarıdaki örnekte, ImplementsFoo'da bar2'yi yeniden tanımlasanız bile var.bar2 () öğesine yapılan bir çağrı foo.bar2 () işlemini yürütür.
Bar2'nin artık bir uygulaması yoksa (soyutun anlamı budur), bir yöntemi uygulama olmadan çağırabilirsiniz. Bu çok zararlı.
Bu sorunun cevabını, bir arabirimin yöntemlerinin (bir ana sınıfta soyut yöntemler gibi çalışan) neden statik olamayacağı şeklinde bulduğuma inanıyorum. İşte tam cevap (benim değil)
Temel olarak statik yöntemler derleme zamanında bağlanabilir, çünkü bunları çağırmak için bir sınıf belirtmeniz gerekir. Bu, yöntemi çağırdığınız başvuru sınıfının derleme zamanında bilinmiyor olabileceği örnek yöntemlerden farklıdır (bu nedenle hangi kod bloğunun çağrıldığı yalnızca çalışma zamanında belirlenebilir).
Statik bir yöntem çağırıyorsanız, uygulandığı sınıfı veya doğrudan alt sınıflarını zaten biliyorsunuzdur. Eğer tanımlarsan
abstract class Foo {
abstract static void bar();
}
class Foo2 {
@Override
static void bar() {}
}
O zaman herhangi bir Foo.bar();
çağrı açıkça yasa dışıdır ve her zaman kullanacaksınız Foo2.bar();
.
Bunu akılda tutarak, statik bir soyut yöntemin tek amacı, böyle bir yöntemi uygulamak için alt sınıfları zorlamak olacaktır. Başlangıçta bu çok yanlış olduğunu düşünebilir, ancak bir genel tür parametresi varsa <E extends MySuperClass>
o arayüzü üzerinden bu teminat güzel olurdu E
kutu .doSomething()
. Tür silme jeneriklerinin sadece derleme zamanında bulunduğunu unutmayın.
Peki, faydalı olur mu? Evet, ve belki de bu yüzden Java 8 arabirimlerde statik yöntemlere izin veriyor (yalnızca varsayılan bir uygulamada olsa da). Neden sınıflarda varsayılan bir uygulama ile soyut statik yöntemler? Çünkü varsayılan bir uygulamaya sahip soyut bir yöntem aslında somut bir yöntemdir.
Varsayılan uygulama olmadan neden özet / arabirim statik yöntemleri olmasın? Görünüşe göre, sadece Java'nın hangi kod bloğunu yürütmesi gerektiğini tanımlama biçiminden dolayı (cevabımın ilk kısmı).
Çünkü soyut sınıf bir OOPS kavramı ve statik üyeler OOPS'un bir parçası değildir ....
Şimdi şey şu ki, arabirimde statik tam yöntemler bildirebiliriz ve bir arabirim içindeki ana yöntemi bildirerek arabirimi yürütebiliriz
interface Demo
{
public static void main(String [] args) {
System.out.println("I am from interface");
}
}
Soyut bir statik yönteme sahip olma fikri, söz konusu soyut sınıfı doğrudan bu yöntem için kullanamayacağınızdır, ancak bu statik yöntemi (veya jenerikler için: genel jenerasyonun gerçek sınıfı) uygulamaya yalnızca ilk türev kullanımı).
Bu şekilde, örneğin sıralama seçeneklerinin parametrelerini tanımlayan bir sortableObject soyut sınıfı veya hatta (auto-) soyut statik yöntemlerle arabirim oluşturabilirsiniz:
public interface SortableObject {
public [abstract] static String [] getSortableTypes();
public String getSortableValueByType(String type);
}
Artık tüm bu nesneler için aynı olan ana türlere göre sıralanabilen sıralanabilir bir nesne tanımlayabilirsiniz:
public class MyDataObject implements SortableObject {
final static String [] SORT_TYPES = {
"Name","Date of Birth"
}
static long newDataIndex = 0L ;
String fullName ;
String sortableDate ;
long dataIndex = -1L ;
public MyDataObject(String name, int year, int month, int day) {
if(name == null || name.length() == 0) throw new IllegalArgumentException("Null/empty name not allowed.");
if(!validateDate(year,month,day)) throw new IllegalArgumentException("Date parameters do not compose a legal date.");
this.fullName = name ;
this.sortableDate = MyUtils.createSortableDate(year,month,day);
this.dataIndex = MyDataObject.newDataIndex++ ;
}
public String toString() {
return ""+this.dataIndex+". "this.fullName+" ("+this.sortableDate+")";
}
// override SortableObject
public static String [] getSortableTypes() { return SORT_TYPES ; }
public String getSortableValueByType(String type) {
int index = MyUtils.getStringArrayIndex(SORT_TYPES, type);
switch(index) {
case 0: return this.name ;
case 1: return this.sortableDate ;
}
return toString(); // in the order they were created when compared
}
}
Şimdi bir
public class SortableList<T extends SortableObject>
türleri alabilir, sıralanacak bir tür seçmek için bir açılır menü oluşturabilir ve bu türden veri alarak listeye başvurabilir ve bir sıralama türü seçildiğinde otomatik olarak -yeni öğeleri sıralayın. SortableList örneğinin "T" statik yöntemine doğrudan erişebileceğini unutmayın:
String [] MenuItems = T.getSortableTypes();
Bir örneği kullanmakla ilgili sorun, SortableList öğesinde henüz öğe bulunmayabilir, ancak zaten tercih edilen sıralamayı sağlaması gerekir.
Cheerio, Olaf.
İlk olarak, soyut sınıflarla ilgili önemli bir nokta - Soyut bir sınıf somutlaştırılamaz (bkz. Wiki ). Yani, yaratamaz herhangi soyut bir sınıfın örneğini.
Şimdi, java'nın statik yöntemlerle ilgilenme yöntemi, yöntemi bu sınıfın tüm örnekleriyle paylaşmaktır .
Bu nedenle, bir sınıfı başlatamıyorsanız, soyut bir yöntem genişletilmeye çalıştığı için o sınıfın soyut statik yöntemleri olamaz.
Boom.
Java belgesine göre :
Statik yöntem, herhangi bir nesneyle değil, tanımlandığı sınıfla ilişkilendirilmiş bir yöntemdir. Sınıfın her örneği statik yöntemlerini paylaşır
Java 8'de, varsayılan yöntemlerle birlikte bir arabirimde statik yöntemlere de izin verilir. Bu, kütüphanelerimizde yardımcı yöntemler düzenlememizi kolaylaştırır. Bir arabirime özgü statik yöntemleri ayrı bir sınıftan ziyade aynı arabirimde tutabiliriz.
Buna güzel bir örnek:
list.sort(ordering);
onun yerine
Collections.sort(list, ordering);
Statik yöntemleri kullanmanın başka bir örneği de dokümanın kendisinde verilmiştir :
public interface TimeClient {
// ...
static public ZoneId getZoneId (String zoneString) {
try {
return ZoneId.of(zoneString);
} catch (DateTimeException e) {
System.err.println("Invalid time zone: " + zoneString +
"; using default time zone instead.");
return ZoneId.systemDefault();
}
}
default public ZonedDateTime getZonedDateTime(String zoneString) {
return ZonedDateTime.of(getLocalDateTime(), getZoneId(zoneString));
}
}
Çünkü 'soyut', yöntemin geçersiz kılınması anlamına gelir ve 'statik' yöntemleri geçersiz kılamaz.
Düzenli yöntemler, alt sınıflar tarafından geçersiz kılınması ve işlevsellik sağlaması durumunda soyut olabilir. Sınıfın Foo
genişlediğini düşününBar1, Bar2, Bar3
vb. . Yani, her birinin ihtiyaçlarına göre soyut sınıfın kendi versiyonu olacaktır.
Şimdi, tanım gereği statik yöntemler sınıfa aittir, sınıfın nesneleri veya alt sınıflarının nesneleri ile ilgisi yoktur. Var olmalarına bile gerek yok, sınıfları somutlaştırmadan kullanılabilirler. Bu nedenle, kullanıma hazır olmaları gerekir ve bunlara işlevsellik eklemek için alt sınıflara güvenemezler.
Özet, Abstract yöntemlerine uygulanan bir anahtar kelime olduğu için bir gövde belirtmez. Ve statik anahtar kelime hakkında konuşursak, bu sınıf alanına aittir.
Bunu Java 8'deki arabirimlerle yapabilirsiniz.
Bu konuda resmi belgeler:
https://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html
Çünkü bir sınıf soyut bir sınıfı genişletirse, o zaman soyut yöntemleri geçersiz kılmak zorundadır ve bu zorunludur. Statik yöntemler derleme zamanında çözülen sınıf yöntemleri olduğu için geçersiz kılınmış yöntemler çalışma zamanında ve dinamik polimorfizmi takip eden örnek yöntemlerdir.