Kotlin'de statik uzatma yöntemleri


142

Kotlin'de statik uzatma yöntemini nasıl tanımlıyorsunuz? Bu mümkün mü? Şu anda aşağıda gösterildiği gibi bir uzantı yöntemim var.

public fun Uber.doMagic(context: Context) {
    // ...
}

Yukarıdaki uzantı bir örnek üzerinde çağrılabilir.

uberInstance.doMagic(context) // Instance method

ama aşağıda gösterildiği gibi statik yöntemi nasıl yapabilirim.

Uber.doMagic(context)         // Static or class method

1
"Statik uzatma yöntemi" ile ne demek istiyorsun?
Andrey Breslav

3
Bir örnek olmadan arayabildiğim, ancak yine de sınıfın bir uzantısı olan bir yöntem. (Düzenli Java statik yöntemleri)
Ragunath Jawahar

Ben Kotlin uzantıları iyi soru amaçlanan kullanımı olmayabilir düşünüyorum , ben aynı şeyi düşündüm C # konseptini tahmin etmek için çalışırken. Ancak pratikte kullanım oldukça benzerdir. Kotlin uzantıları, statik olarak gönderildiğini iddia etseler de, böyle bir şey varsa veya örneğe geç bağlıysa, dinamik olarak "bağlı" gibi hissederler. Yanılmıyorsam ... veya belki de tamamen yanlış anladım :)
Dan

7
Şu anda, sınıf örneğinin aksine, sınıf adına çağrılacak bir uzantı yöntemi yazamazsınız. Aslında, uzantı işlevi bir örnek olan bir alıcı parametresi alır , bu nedenle bu bölümü atlamanın bir yolu yoktur. Öte yandan, sınıf nesnelerine uzantılar yazmanın bir yolu üzerinde çalışıyoruz, böylece onu bir sınıf adına çağırıyorsunuz, ancak alıcı sınıf nesnesinin türüne sahip
Andrey Breslav

@AndreyBreslav Bize statik uzatma işlevlerine izin verilip verilmeyeceğini güncelleyebilir misiniz? Ben de özlüyorum.
Lars Blumberg

Yanıtlar:


143

Başarmak için Uber.doMagic(context)size bir uzantı yazabilirsiniz, refakatçi nesnenin içinde Uber(refakatçi nesne beyanı gereklidir):

class Uber {
    companion object {}
}

fun Uber.Companion.doMagic(context: Context) { }

79
Bu güzel ama ya bir Java sınıfı ya da refakatçi olmayan bir sınıfsa?
Jire

31
@Bu durumlarda, Kotlin 1.0'da destek yok
Andrey Breslav

2
Etki alanı mantığınızın gerektirmesi durumunda varsayılan değerlerle örneğin String.DEFAULT veya Int.DEFAULT gibi JVM çerçeve sınıflarını genişletme konusunda bir usecase görebiliyordum (mayın şu anda boş veri sınıflarıyla birlikte).
Steffen Funke

36
Sadece Uber bir Kotlin sınıfı olduğu sürece çalışır . Java sınıflarını da statik olarak genişletme imkanına sahip olmak iyi olurdu
kosiara - Bartosz Kosarzycki

6
Burada gördüğünüz gibi hala bu mümkün değil: youtrack.jetbrains.com/issue/KT-11968 Burada ilgili bir SO iş parçacığı var: stackoverflow.com/questions/33911457/…
narko

12

Resmi belgeler şöyle diyor:

Kotlin, paket seviyesi işlevleri için statik yöntemler üretir. Kotlin ayrıca, @JvmStatic olarak bu işlevlere açıklama eklediğinizde, adlandırılmış nesnelerde veya tamamlayıcı nesnelerde tanımlanan işlevler için statik yöntemler oluşturabilir. Örneğin:

Kotlin statik yöntemleri

class C {
  companion object {
    @JvmStatic fun foo() {}
    fun bar() {}
  }
}

Şimdi, foo () Java'da statikken, bar ():

C.foo(); // works fine
C.bar(); // error: not a static method

8

Aslında 30 dakika önce bu soruyu sordum, bu yüzden kazmaya başladım ve bunun için herhangi bir çözüm veya geçici çözüm bulamadım, ancak arama yaparken Kotlinglang web sitesinde bu bölümü buldum :

Uzantıların boş bir alıcı türüyle tanımlanabileceğini unutmayın. Bu uzantılar, değeri boş olsa bile bir nesne değişkeninde çağrılabilir.

Öyleyse, en çılgın fikrim vardı, neden boş bir alıcıyla (aslında bu alıcıyı kullanmadan) bir uzatma işlevi tanımlamıyorsunuz ve null bir nesnede çağırıyorsunuz! Bu yüzden denedim ve oldukça iyi çalıştı, ama çok çirkin görünüyordu. Şöyleydi:

(null as Type?).staticFunction(param1, param2)

Bu yüzden, alıcı türü uzantıları dosyamda null değeri olan bir val oluşturarak ve sonra diğer sınıfımda kullanarak bunu dolaştım. Yani, örnek olarak, ben NavigationAndroid için sınıf için bir "statik" uzantısı işlevini nasıl uygulandığı : NavigationExtensions.kt dosyamda:

val SNavigation: Navigation? = null
fun Navigation?.createNavigateOnClickListener(@IdRes resId: Int, args: Bundle? = null, navOptions: NavOptions? = null,
                                                navigationExtras: Navigator.Extras? = null) : (View) -> Unit {
    //This is just implementation details, don't worry too much about them, just focus on the Navigation? part in the method declaration
    return { view: View -> view.navigate(resId, args, navOptions, navigationExtras) }
}

Bunu kullanan kodda:

SNavigation.createNavigateOnClickListener(R.id.action_gameWonFragment_to_gameFragment)

Açıkçası, bu bir sınıf adı değil, sadece bir null değeri olan sınıf türünün bir değişkeni. Bu açıkça uzantı yapıcı tarafında (değişkeni yaratmak zorunda oldukları için) ve geliştirici tarafında ( STypegerçek sınıf adı yerine biçimi kullanmak zorunda oldukları için) çirkin , ama şu anda elde edilebilecek en yakın olanı gerçek statik fonksiyonlara kıyasla. İnşallah, Kotlin dil yapıcıları oluşturulan soruna cevap verecek ve bu özelliği dile ekleyeceklerdir.


2
Hacky bu olabilir. Ama aynı zamanda zeki havalı. Bu soruya en açık yanıt. Kotlin birinci sınıf uzantılar sağlamak için elinden gelenin en iyisini yapıyor, bu yüzden IMO, inançlarıyla başa çıkmak için yapabileceğiniz en iyi çözümleri kullanıyorsunuz. Güzel.
Travis Griggs

5

Companion nesnesini kullanarak statik bir yöntem oluşturabilirsiniz:

class Foo {
    // ...
    companion object {
        public fun bar() {
            // do anything
        }
    }
}

ve sonra şöyle diyebilirsiniz:

class Baz {
    // ...
    private fun callBar() {
        Foo.bar()
    }
}

Bunun aslında statik olmadığına inanıyorum. Tamamlayıcı nesneler sınıf adını kullanarak arama yapmanızı sağlar, ancak yine de sınıfın bir örneğini kullanır. Ayrıca, soru sadece statik fonksiyonlarla değil, statik uzatma fonksiyonlarıyla ilgilidir. Ancak statik işlevlere sahip olmak için platformStaticek açıklamayı kullanabilirsiniz .
Ragunath Jawahar

1
platformStaticJvmStaticmevcut Kotlin'de yeniden adlandırıldı .
Jayson Minard

0

Bu bağlantıya bakmanızı tavsiye ederiz . Gördüğünüz gibi, sadece paketin (dosya) üst düzeyinde yöntem bildirmelisiniz:

package strings
public fun joinToString(...): String { ... }

Bu eşittir

package strings;

public class JoinKt {
    public static String joinToString(...) { ... }
}

Sabitlerle her şey aynıdır. Bu beyan

val UNIX_LINE_SEPARATOR = "\n"

eşittir

public static final String UNIX_LINE_SEPARATOR = "\n";

-3

Ayrıca Kotlin'e statik uzatma yöntemleri ekleme olanağına da oldukça meraklıyım. Şimdilik bir çözüm olarak, hepsinde tek bir statik uzatma yöntemi kullanmak yerine, birden fazla sınıfa exntension yöntemini ekliyorum.

class Util    

fun Util.isDeviceOnline(context: Context): Boolean {
    val connMgr = context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
    val networkInfo = connMgr.activeNetworkInfo
    return networkInfo != null && networkInfo.isConnected
}

fun Activity.isDeviceOnline(context: Context) = { Util().isDeviceOnline(context) }
fun OkHttpClient.isDeviceOnline(context: Context) = { Util().isDeviceOnline(context) }

2
Orijinal soru, bir javaclass'ın statik bir yöntemle nasıl genişletilebileceği ile ilgiliydi . Sizin durumunuzda bu, Activity.isDeviceOnline(...)bir örneği olmadan kelimenin tam anlamıyla arayabileceğiniz anlamına gelir Activity.
Fabian Zeindl

-4

Kotlin'de bir uzantı yöntemi oluşturmak için bir kotlin dosyası (bir sınıf değil) oluşturmanız ve ardından yönteminizi dosyada bildirmeniz gerekir:

public fun String.toLowercase(){
    // **this** is the string object
}

Fonksiyonu üzerinde çalıştığınız sınıf veya dosyaya aktarın ve kullanın.


Başlık bir soru bile değil
daniel.jbatiz
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.