Java'da anonim bir işlevi nasıl yazabilirim?


89

Hatta mümkün mü?


6
Bunun Java 8'de artık mümkün olduğuna dikkat edin - aşağıdaki Mark Rotteveel'in Lambda İfadeleri hakkındaki yanıta bakın.
Josiah Yoder

Yanıtlar:


81

anonim bir işlevi kastediyorsanız ve Java 8'den önceki bir Java sürümünü kullanıyorsanız, o zaman kısaca hayır. ( Java 8+ kullanıyorsanız lambda ifadeleri hakkındaki bilgileri okuyun )

Ancak, aşağıdaki gibi bir işleve sahip bir arayüz uygulayabilirsiniz:

Comparator<String> c = new Comparator<String>() {
    int compare(String s, String s2) { ... }
};

ve bunu neredeyse anonim bir işlev elde etmek için iç sınıflarla kullanabilirsiniz :)


6
Henüz değil. Java 7'de bu mümkün olacak: stackoverflow.com/questions/233579/closures-in-java-7
Ilya Boyandin

2
Bu arada, JDK7'yi beklerken, anonim yöntemler en.wikipedia.org/wiki/Command_pattern
gpampara

1
kapatılan Java 7'ye ulaşamadı.
Thorbjørn Ravn Andersen

5
Java 8 ile anonim işlevimiz olduğu için cevabınızı değiştirmeniz gerektiğini düşünüyorum.
Node.JS

45

İşte anonim bir iç sınıf örneği.

System.out.println(new Object() {
    @Override public String toString() {
        return "Hello world!";
    }
}); // prints "Hello world!"

İşte bu kadar çok kullanışlı değildir, ancak bir anonim iç bu sınıfın bir örneğini nasıl oluşturulacağını gösterir extends Objectve @Overrideonun toString()yöntemine.

Ayrıca bakınız


Anonim iç sınıflar, çok fazla interfaceyeniden kullanılamayabilecek (ve bu nedenle kendi adlandırılmış sınıfına yeniden düzenleme yapmaya değmeyen) bir uygulamaya ihtiyacınız olduğunda çok kullanışlıdır . Öğretici bir örnek, bir gelenek kullanmaktırjava.util.Comparator<T> sıralama için .

İşte bir String[]temel alarak nasıl sıralayabileceğinize dair bir örnek String.length().

import java.util.*;
//...

String[] arr = { "xxx", "cd", "ab", "z" };
Arrays.sort(arr, new Comparator<String>() {
    @Override public int compare(String s1, String s2) {
        return s1.length() - s2.length();
    }           
});
System.out.println(Arrays.toString(arr));
// prints "[z, cd, ab, xxx]"

Burada kullanılan çıkarma yoluyla karşılaştırma hilesine dikkat edin. Bu tekniğin genel olarak bozulmuş olduğu söylenmelidir: yalnızca taşmayacağını garanti edebildiğinizde uygulanabilir (durum böyledir.String uzunluklarda ).

Ayrıca bakınız


5
Diğer oluşumların çoğu EventListener, ortalama Swing uygulamasında (alt) uygulamalar olarak bulunabilir .
BalusC

@BalusC: "bunlar nasıl kullanılıyor vardır" sorusuna eklenen bağlantı
polygenelubricants

@BalusC: stackoverflow yakın zamanda Linkedkenar çubuğunu ekledi , bu yüzden onu kullanmak için elimden gelenin en iyisini yapıyorum.
poligenelubricants

12

Java 8'de lambda ifadesinin tanıtılmasıyla artık anonim yöntemlere sahip olabilirsiniz.

Diyelim ki bir sınıfım var Alphave e-postaları Alphabelirli bir koşulda filtrelemek istiyorum . Bunu yapmak için bir Predicate<Alpha>. Bu, testkabul eden Alphave döndüren bir yönteme sahip işlevsel bir arayüzdür.boolean .

Filtre yönteminin şu imzaya sahip olduğunu varsayarsak:

List<Alpha> filter(Predicate<Alpha> filterPredicate)

Eski anonim sınıf çözümüyle şunun gibi bir şeye ihtiyacınız olacaktı:

filter(new Predicate<Alpha>() {
   boolean test(Alpha alpha) {
      return alpha.centauri > 1;
   }
});

Java 8 lambdas ile şunları yapabilirsiniz:

filter(alpha -> alpha.centauri > 1);

Daha ayrıntılı bilgi için Lambda İfadeleri eğitimine bakın


2
Yöntem referansları da faydalıdır. örneğin sort (String :: CompareToIgnoreCase
Josiah Yoder

9

Mevcut bir tipin arayüzünü uygulayan veya genişleten anonim iç sınıflar, diğer cevaplarda yapılmıştır, ancak birden fazla yöntemin uygulanabileceğini belirtmek gerekir (örneğin JavaBean tarzı olaylarla).

Biraz tanınan bir özellik, anonim iç sınıfların bir adı olmasa da, bir türlerinin olmasıdır. Arayüze yeni yöntemler eklenebilir. Bu yöntemler yalnızca sınırlı durumlarda çağrılabilir. Esas olarak doğrudan newifadenin kendisi ve sınıf içinde (örnek başlatıcıları dahil). Yeni başlayanların kafasını karıştırabilir, ancak özyineleme için "ilginç" olabilir.

private static String pretty(Node node) {
    return "Node: " + new Object() {
        String print(Node cur) {
            return cur.isTerminal() ?
                cur.name() :
                ("("+print(cur.left())+":"+print(cur.right())+")");
        }
    }.print(node);
}

(Başlangıçta kullanarak bu yazmış nodeziyade curiçinde printyöntemle. Say NO "örtük yakalamanın final" yerli? )


nodefinalburada beyan edilmelidir .
BalusC

@BalusC Güzel yakala. Aslında benim hatam kullanmamaktı cur.
Tom Hawtin -

@Tom: +1 güzel teknik! Aslında pratikte herhangi bir yerde kullanılıyor mu? Bu özel kalıp için herhangi bir isim var mı?
poligenelubricants

@polygenelubricants Bildiğim kadarıyla değil. Ekstra bir nesneye mal olur! (Ve bir sınıf.) Hemen hemen aynısı çift küme ayracı deyimi için de geçerliydi. Doğru düşünen insanlar, Execute Around deyimine aldırış etmiyor gibi görünüyor.
Tom Hawtin - tackline

@polygenelubricants Aslında pek çok (kendi kendine yeten) yinelemeli algoritma görünmüyorum. Özellikle kuyruk özyinelemeli olmayanlar (veya kolayca yapılabilenler) ve genel yöntemi çağırarak uygulanamayanlar ( "Node" +ikinci bir yöntemi gerekli kılmak için biraz ilgisiz olanı not edin ). / Benim bir adım yok. Belki bir adlandırma "anket" (CW) sorusu oluşturabilir ve onu unutulmaya itebilirim.
Tom Hawtin - tackline

1

Evet, en son java olan sürüm 8'i kullanıyorsanız. Java8, önceki sürümlerde imkansız olan anonim işlevleri tanımlamayı mümkün kılar.

Anonim fonksiyonları, sınıfları nasıl tanımlayabileceğimizi öğrenmek için java dokümanlarından örnek alalım

Aşağıdaki örnek, HelloWorldAnonymousClasses, frenchGreeting ve spanishGreeting yerel değişkenlerinin başlatma ifadelerinde anonim sınıflar kullanır, ancak englishGreeting değişkeninin başlatılması için yerel bir sınıf kullanır:

public class HelloWorldAnonymousClasses {

    interface HelloWorld {
        public void greet();
        public void greetSomeone(String someone);
    }

    public void sayHello() {

        class EnglishGreeting implements HelloWorld {
            String name = "world";
            public void greet() {
                greetSomeone("world");
            }
            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("Hello " + name);
            }
        }

        HelloWorld englishGreeting = new EnglishGreeting();

        HelloWorld frenchGreeting = new HelloWorld() {
            String name = "tout le monde";
            public void greet() {
                greetSomeone("tout le monde");
            }
            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("Salut " + name);
            }
        };

        HelloWorld spanishGreeting = new HelloWorld() {
            String name = "mundo";
            public void greet() {
                greetSomeone("mundo");
            }
            public void greetSomeone(String someone) {
                name = someone;
                System.out.println("Hola, " + name);
            }
        };
        englishGreeting.greet();
        frenchGreeting.greetSomeone("Fred");
        spanishGreeting.greet();
    }

    public static void main(String... args) {
        HelloWorldAnonymousClasses myApp =
            new HelloWorldAnonymousClasses();
        myApp.sayHello();
    }            
}

Anonim Sınıfların Sözdizimi

FrenchGreeting nesnesinin somutlaştırılmasını düşünün:

    HelloWorld frenchGreeting = new HelloWorld() {
        String name = "tout le monde";
        public void greet() {
            greetSomeone("tout le monde");
        }
        public void greetSomeone(String someone) {
            name = someone;
            System.out.println("Salut " + name);
        }
    };

Anonim sınıf ifadesi aşağıdakilerden oluşur:

  • newoperatör
  • Uygulanacak arabirimin veya genişletilecek sınıfın adı. Bu örnekte, anonim sınıf HelloWorld arabirimini uyguluyor.

  • Normal bir sınıf örneği oluşturma ifadesi gibi, bir kurucuya yönelik argümanları içeren parantezler. Not: Bir arabirim uyguladığınızda, yapıcı yoktur, bu nedenle bu örnekte olduğu gibi boş bir parantez çifti kullanırsınız.

  • Sınıf beyannamesi kuruluşu olan bir kuruluş. Daha spesifik olarak, vücutta yöntem bildirimlerine izin verilir ancak ifadelere izin verilmez.

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.