Arayüz içinde iç sınıf


98

Bir arayüz içinde bir iç sınıf oluşturmak mümkün müdür ?
Mümkünse, herhangi bir arayüz nesnesi oluşturmayacağımız için neden böyle bir iç sınıf yaratmak isteyelim?

Bu iç sınıflar herhangi bir geliştirme sürecinde yardımcı oluyor mu?

Yanıtlar:


51

Evet, yapabilirsiniz iç içe geçmiş bir sınıf veya bir Java arayüzünden (aksine kanının bir "diye bir şey yoktur notu içindeki bir iç sınıfı oluşturmak, hem de statik iç sınıf ' 'iç' ve hiçbir şey yok, bu tamamen mantıksız:' outter "sınıfı, yuvalanmış bir sınıf statik olduğunda, bu nedenle" statik iç "olamaz).

Her neyse, aşağıdaki iyi derler:

public interface A {
    class B {
    }
}

Arayüz tanımına doğrudan bir tür "sözleşme denetleyicisi" koyduğunu gördüm (iyi, arayüzde yuvalanmış sınıfta, statik yöntemlere sahip olabilir, arayüzün kendisinin aksine, olamaz). Doğru hatırlıyorsam böyle görünüyorum.

public interface A {
    static class B {
        public static boolean verifyState( A a ) {
            return (true if object implementing class A looks to be in a valid state)
        }
    }
}

Böyle bir şeyin yararlılığı hakkında yorum yapmadığıma dikkat edin, sadece sorunuzu yanıtlıyorum: yapılabilir ve bu, ondan yapıldığını gördüğüm türden bir kullanımdır.

Şimdi böyle bir yapının yararlılığı üzerine yorum yapmayacağım ve şunu gördüm: Onu gördüm, ama çok yaygın bir yapı değil.

Burada 200KLOC kod tabanı, bunun tam olarak sıfır zamanda gerçekleştiği yerde (ama daha sonra, diğer insanların tamamen normal bulacağı şekilde tam olarak sıfır zamanda gerçekleşen kötü uygulamaları düşündüğümüz birçok başka şey de var ...


Bazı kullanım örnekleri ekleyebilir misiniz? Bir süre önce benzer bir şeyi test ettim ve bu yapıyı kullanarak ne kazanabileceğimi anlamadım.
Roman

@Roman: Bununla bazı projelerde karşılaştığımı hatırlıyorum (nispeten temiz bir proje eklerdim ama benim değillerdi) ama gerçekten temiz olup olmadığını bilmiyorum. Gördüğüme benzeyen küçük bir örnek ekledim ama bir kez daha: bu benim kodum değildi ve bu yapıyı kullanmıyorum, bu yüzden geçerli örnekler bulmak için en nitelikli kişi değilim :) IIRC içindeki sınıf her zaman adlandırılmıştır, örneğin StateChecker ve çağrılar her zaman şöyle görünür: A.StateChecker.check (a) veya bunun gibi bir şey.
SözdizimiT3rr0r

8
Eğer “bir diye bir şey yoktur 'derseniz statik iç sınıf ' siz” o Cevabınız ‘ olabilir bir Java arayüzü içinde yuvalanmış bir sınıf veya bir iç sınıfı oluşturmak, hem de’ temelden yanlıştır. Senin daralmış tanımını kullanarak, interfaces yapabilirsiniz değil iç sınıfları var. İç içe geçmiş bir sınıfın staticdeğiştiricisini atlayabilirsiniz, interfaceancak yine de bu bir iç sınıf değil, iç içe geçmiş bir sınıftır.
Holger

6
Bu cevap yanlış. Arabirimlerde statik yuvalanmış sınıflar olabilir, ancak iç sınıflar olamaz.
Paul Boddington

1
@PaulBoddington Haklısın. 'Statik' kaldırıldığında bile, Bsınıf statik bir iç içe geçmiş sınıftır ve iç sınıf değildir; arayüzler özel muamele görür. Spesifikasyonun kendisi haricinde çevrimiçi olarak bundan bahsedemedim: "Bir arayüzün üye sınıfı dolaylı olarak statiktir, bu nedenle asla bir iç sınıf olarak kabul edilmez." docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.1.3
Max Barraclough

110

Evet, arayüzlerin içinde sınıflarımız olabilir. Bir kullanım örneği olabilir

public interface Input
{
    public static class KeyEvent {
         public static final int KEY_DOWN = 0;
         public static final int KEY_UP = 1;
         public int type;
         public int keyCode;
         public char keyChar;
    }
    public static class TouchEvent {
         public static final int TOUCH_DOWN = 0;
         public static final int TOUCH_UP = 1;
         public static final int TOUCH_DRAGGED = 2;
         public int type;
         public int x, y;
         public int pointer;
    }
    public boolean isKeyPressed(int keyCode);
    public boolean isTouchDown(int pointer);
    public int getTouchX(int pointer);
    public int getTouchY(int pointer);
    public float getAccelX();
    public float getAccelY();
    public float getAccelZ();
    public List<KeyEvent> getKeyEvents();
    public List<TouchEvent> getTouchEvents();
}

Burada kod, daha sonra getKeyEvents () gibi yöntem tanımlarında kullanılan olay nesneleri hakkındaki bilgileri kapsüllemek için iki iç içe geçmiş sınıfa sahiptir. Bunları Giriş arayüzünde bulundurmak, uyumu geliştirir.


3
@Levit Sadece merak ediyorum, uygulanan sınıf nasıl görünecek?
overerexchange

1
Yukarıdaki kullanım için eylem halinde bir uygulama görmek isterim. Teşekkür ederim.
Prakash K

46

Geçerli bir kullanım olan IMHO, çevreleyen arayüz yöntemleri tarafından alınan veya döndürülen nesneleri tanımlamaktır. Tipik olarak veri tutma yapıları. Bu şekilde, nesne sadece o arayüz için kullanılıyorsa, daha uyumlu bir şekilde her şeye sahip olursunuz.

Örnek olarak:

interface UserChecker {
   Ticket validateUser(Credentials credentials);

   class Credentials {
      // user and password
   }

   class Ticket {
      // some obscure implementation
   }
}

Ama her neyse ... bu sadece bir zevk meselesi.


36

Java 7 spesifikasyonundan alıntı :

Arayüzler üye türü bildirimleri içerebilir (§8.5).

Bir arabirimdeki üye türü bildirimi örtük olarak statik ve geneldir. Bu değiştiricilerden birini veya her ikisini fazladan belirtmeye izin verilir.

Bir Java arabirimi içinde statik olmayan sınıfları bildirmek mümkün DEĞİL, bu bana mantıklı geliyor.


Teşekkür ederim. Bu muhtemelen en kısa cevaptır.
Joseph

1
Bu aradığım cevap .. ama OP birkaç soru soruyor .. her neyse, benim kabarıklığım var.
Charlie Wallace

11

İlginç bir kullanım örneği, burada açıklandığı gibi bir iç sınıf aracılığıyla arayüz yöntemlerine bir tür varsayılan uygulama sağlamaktır: https://stackoverflow.com/a/3442218/454667 (tek sınıflı kalıtım sorununun üstesinden gelmek için).


Ve bu tam olarak özel üye sınıflarının mantıklı olmasının nedenidir.
Vincent

7

Kesinlikle mümkündür ve yararlı bulduğum bir durum, bir arayüzün özel istisnalar atması gerektiği durumdur. İstisnaları, kaynak ağacınızı önemsiz istisna dosyalarının yığınlarıyla doldurmaktan daha temiz olduğunu düşündüğüm ilişkili arayüzleriyle koruyun.

interface MyInterface {

   public static class MyInterfaceException extends Exception {
   }

   void doSomething() throws MyInterfaceException;
}

7

Evet, bir arabirim içinde statik sınıf tanımlarına sahip olmak mümkündür, ancak bu özelliğin belki de en kullanışlı yönü, enum türlerini (özel tür statik sınıflardır) kullanırken olabilir. Örneğin şuna benzer bir şeye sahip olabilirsiniz:

public interface User {
    public enum Role {
        ADMIN("administrator"),
        EDITOR("editor"),
        VANILLA("regular user");

        private String description;

        private Role(String description) {
            this.description = description;
        }

        public String getDescription() {
            return description;
        }
    }

    public String getName();
    public void setName(String name);
    public Role getRole();
    public void setRole(Role role);
    ...
}


1

Belki bazı farklı uygulama davranışları gibi daha karmaşık yapılar istediğinizde, şunları göz önünde bulundurun:

public interface A {
    public void foo();

    public static class B implements A {
        @Override
        public void foo() {
            System.out.println("B foo");
        }
    }
}

Bu sizin arayüzünüzdür ve uygulayıcı bu olacaktır:

public class C implements A {
    @Override
    public void foo() {
        A.B b = new A.B();
        b.foo(); 
    }

    public static void main(String[] strings) {
        C c = new C();
        c.foo();
    }
}

Bazı statik uygulamalar sağlayabilir, ancak bu kafa karıştırıcı olmaz, bilmiyorum.


0

Bu tür bir yapı için bir kullanım buldum.

  1. Tüm statik son sabitleri tanımlamak ve gruplamak için bu yapıyı kullanabilirsiniz.
  2. Bir arayüz olduğu için bunu bir sınıf üzerinde uygulayabilirsiniz.

Gruplanmış tüm sabitlere erişebilirsiniz; sınıfın adı bu durumda bir ad alanı görevi görür.


0

Ayrıca, bu arayüzü uygulayan nesneler için ortak işlevsellik için "Yardımcı" statik sınıflar oluşturabilirsiniz:

public interface A {
    static class Helper {
        public static void commonlyUsedMethod( A a ) {
           ...
        }
    }
}

0

Şu anda ihtiyacım var. Çeşitli yöntemlerinden benzersiz bir sınıf döndürmenin uygun olacağı bir arayüzüm var. Bu sınıf, yalnızca bu arabirimin yöntemlerinden gelen yanıtlar için bir kap olarak anlamlıdır.

Bu nedenle, yalnızca bu arabirimle ilişkilendirilen statik bir iç içe geçmiş sınıf tanımına sahip olmak uygun olacaktır, çünkü bu arabirim bu sonuçların kapsayıcı sınıfının oluşturulduğu tek yer olmalıdır.


0

Örneğin Groovy'deki özellikler (uygulanan yöntemlerle smth benzeri arabirim). Tüm yöntemlerin uygulandığı iç sınıfı içeren bir arayüzde derlenirler.

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.