Bagaimana cara membuat metode Java Generic statis?

173

Berikut ini adalah cuplikan tentang cara membuat kelas generik java untuk menambahkan satu item ke array. Bagaimana saya bisa membuat appendToArray metode statis. Menambahkan statis ke hasil tanda tangan metode dalam kesalahan kompilasi.

public class ArrayUtils<E> {

        public E[] appendToArray(E[] array, E item) {
            E[] result = (E[])new Object[array.length+1];
            result[array.length] = item;
            return result;
        }
}
Chris Johnson
sumber
Apa kesalahan kompilasi yang Anda dapatkan? Juga, mengapa tidak hanya menggunakan salah satu wadah perpustakaan standar?
Karl Knechtel
1
Kompilasi Kesalahan: Saya sebenarnya menambahkan pengubah statis salah .. Menggunakan Koleksi: Ya menggunakan koleksi akan ideal namun pertanyaannya bukan tentang koleksi vs array, kasus penggunaan saya memerlukan array.
Chris Johnson
Catatan Anda harus menggunakan refleksi (EVIL) untuk menghentikan kode klien melemparkan pengecualian dalam beberapa tetapi tidak semua keadaan (baik). Yang terbaik adalah menghindari array referensi.
Tom Hawtin - tackline

Jawaban:

283

satu-satunya hal yang dapat Anda lakukan adalah mengubah tanda tangan Anda

public static <E> E[] appendToArray(E[] array, E item)

Detail penting:

Ekspresi generik sebelum nilai kembali selalu memperkenalkan (menyatakan) variabel tipe generik baru.

Selain itu, ketik variabel antara types ( ArrayUtils) dan metode statis ( appendToArray) tidak pernah saling mengganggu.

Jadi, apa artinya ini: Dalam jawaban saya <E>akan menyembunyikan Edari ArrayUtils<E>jika metode tidak akan static. DAN <E>tidak ada hubungannya dengan Edari ArrayUtils<E>.

Untuk mencerminkan fakta ini dengan lebih baik, jawaban yang lebih benar adalah:

public static <I> I[] appendToArray(I[] array, I item)
scheffield
sumber
30
Perlu diketahui juga bahwa sama sekali tidak ada hubungan antara variabel tipe level kelas Edan variabel tipe metode statis E. Saya menganggap itu praktik yang jauh lebih baik untuk menggunakan nama variabel yang berbeda ketika mendeklarasikan metode generik, statis atau sebaliknya, di dalam kelas generik.
Hakim Mental
tetapi dalam hal ini saya bisa memasukkan satu objek dari jenis yang berbeda ke dalam params. Seperti saya bisa meneruskan array Integer [] sebagai param pertama dan item ganda.
pinkpanther
pinkpanther: Benar, tetapi tidak ada salahnya, karena metode statis hanya pernah beroperasi pada objek array yang diteruskan melalui parameter, jadi elemen-elemennya pasti memiliki tipe yang benar.
Dabbler
80
public static <E> E[] appendToArray(E[] array, E item) { ...

Perhatikan <E>.

Metode generik statis memerlukan deklarasi generik sendiri ( public static <E>) terpisah dari deklarasi generik kelas ( public class ArrayUtils<E>).

Jika kompiler mengeluh tentang ambiguitas jenis dalam memanggil metode generik statis (sekali lagi tidak mungkin dalam kasus Anda, tetapi, secara umum, untuk berjaga-jaga), berikut ini cara memanggil metode generik statis secara eksplisit menggunakan jenis tertentu ( _class_.<_generictypeparams_>_methodname_):

String[] newStrings = ArrayUtils.<String>appendToArray(strings, "another string");

Ini hanya akan terjadi jika kompilator tidak dapat menentukan tipe generik karena, misalnya tipe generik tidak terkait dengan argumen metode.

Bert F
sumber
10

Anda perlu memindahkan parameter tipe ke level metode untuk menunjukkan bahwa Anda memiliki metode generik daripada kelas generik:

public class ArrayUtils {
    public static <T> E[] appendToArray(E[] array, E item) {
        E[] result = (E[])new Object[array.length+1];
        result[array.length] = item;
        return result;
    }
}
axtavt
sumber
1
Ini tidak akan berfungsi karena Anda belum mendefinisikan tipe generik E. Dalam hal ini Anda masih harus memiliki tipe generik <E> dalam definisi kelas.
George Xavier
0

Saya akan menjelaskannya dengan cara yang sederhana.

Generik yang didefinisikan pada level Kelas sepenuhnya terpisah dari generik yang didefinisikan pada level metode (statis).

class Greet<T> {

    public static <T> void sayHello(T obj) {
        System.out.println("Hello " + obj);
    }
}

Ketika Anda melihat kode di atas di mana saja, harap dicatat bahwa T yang didefinisikan di tingkat kelas tidak ada hubungannya dengan T yang didefinisikan dalam metode statis. Kode berikut ini juga sepenuhnya valid dan setara dengan kode di atas.

class Greet<T> {

    public static <E> void sayHello(E obj) {
        System.out.println("Hello " + obj);
    }
}

Mengapa metode statis perlu memiliki generiknya sendiri yang terpisah dari kelas?

Ini karena, metode statis dapat dipanggil tanpa bahkan instantiating Kelas. Jadi jika Kelas belum dipakai, kita belum tahu apa itu T. Ini adalah alasan mengapa metode statis perlu memiliki generiknya sendiri.

Jadi, setiap kali Anda memanggil metode statis,

Greet.sayHello("Bob");
Greet.sayHello(123);

JVM mengartikannya sebagai berikut.

Greet.<String>sayHello("Bob");
Greet.<Integer>sayHello(123);

Keduanya memberikan output yang sama.

Hello Bob
Hello 123
Wisnu Vivek
sumber