0. Apakah ada perbedaan antara kedua kesalahan?
Tidak juga. "Tidak dapat menemukan simbol" dan "Tidak dapat menyelesaikan simbol" memiliki arti yang sama. Beberapa kompiler Java menggunakan satu frase, dan beberapa yang lain.
1. Apa artinya kesalahan "Tidak dapat menemukan simbol"?
Pertama, ini adalah kesalahan kompilasi 1 . Ini berarti bahwa baik ada masalah dalam kode sumber Java Anda, atau ada masalah dalam cara yang Anda mengkompilasinya.
Kode sumber Java Anda terdiri dari hal-hal berikut:
- Kata kunci: seperti
true
, false
, class
, while
, dan sebagainya.
- Literal: suka
42
dan 'X'
dan "Hi mum!"
.
- Operator dan token non-alfanumerik lain: seperti
+
, =
, {
, dan sebagainya.
- Pengidentifikasi: seperti
Reader
, i
, toString
, processEquibalancedElephants
, dan sebagainya.
- Komentar dan spasi putih.
Kesalahan "Tidak dapat menemukan simbol" adalah tentang pengidentifikasi. Ketika kode Anda dikompilasi, kompiler perlu mengetahui apa arti setiap pengidentifikasi dalam kode Anda.
Kesalahan "Tidak dapat menemukan simbol" berarti bahwa kompiler tidak dapat melakukan ini. Kode Anda tampaknya merujuk pada sesuatu yang tidak dimengerti oleh kompiler.
2. Apa yang dapat menyebabkan kesalahan "Tidak dapat menemukan simbol"?
Sebagai urutan pertama, hanya ada satu penyebab. Kompiler mencari di semua tempat di mana pengidentifikasi harus didefinisikan, dan tidak dapat menemukan definisi. Ini bisa disebabkan oleh beberapa hal. Yang umum adalah sebagai berikut:
- Untuk pengidentifikasi secara umum:
- Mungkin Anda salah mengeja namanya; yaitu
StringBiulder
bukannya StringBuilder
. Java tidak dapat dan tidak akan mencoba mengkompensasi kesalahan pengejaan atau pengetikan yang buruk.
- Mungkin Anda salah kasus; yaitu
stringBuilder
bukannya StringBuilder
. Semua pengidentifikasi Java peka huruf besar-kecil.
- Mungkin Anda menggunakan garis bawah secara tidak tepat; yaitu
mystring
dan my_string
berbeda. (Jika Anda tetap berpegang pada aturan gaya Java, sebagian besar Anda akan terlindungi dari kesalahan ini ...)
- Mungkin Anda mencoba menggunakan sesuatu yang dinyatakan "di tempat lain"; yaitu dalam konteks yang berbeda ke tempat Anda secara implisit mengatakan kepada kompiler untuk melihat. (Kelas yang berbeda? Ruang lingkup yang berbeda? Paket yang berbeda? Pangkalan kode yang berbeda?)
- Untuk pengidentifikasi yang harus merujuk ke variabel:
- Mungkin Anda lupa mendeklarasikan variabel.
- Mungkin deklarasi variabel berada di luar cakupan pada titik Anda mencoba menggunakannya. (Lihat contoh di bawah)
Untuk pengidentifikasi yang harus berupa metode atau nama bidang:
Untuk pengidentifikasi yang harus berupa nama kelas:
Untuk kasus di mana jenis atau instance tampaknya tidak memiliki anggota yang Anda harapkan memiliki:
- Mungkin Anda telah mendeklarasikan kelas bersarang atau parameter umum yang membayangi tipe yang ingin Anda gunakan.
- Mungkin Anda membayangi variabel statis atau instan.
- Mungkin Anda mengimpor jenis yang salah; misalnya karena penyelesaian IDE atau koreksi otomatis.
- Mungkin Anda menggunakan (kompilasi melawan) versi API yang salah.
- Mungkin Anda lupa melemparkan objek ke subkelas yang sesuai.
Masalahnya sering merupakan kombinasi dari yang di atas. Sebagai contoh, mungkin Anda "membintangi" diimpor java.io.*
dan kemudian mencoba menggunakan Files
kelas ... yang java.nio
tidak java.io
. Atau mungkin Anda bermaksud menulis File
... yang merupakan kelas di java.io
.
Berikut adalah contoh bagaimana pelingkupan variabel yang salah dapat menyebabkan kesalahan "Tidak dapat menemukan simbol":
List<String> strings = ...
for (int i = 0; i < strings.size(); i++) {
if (strings.get(i).equalsIgnoreCase("fnord")) {
break;
}
}
if (i < strings.size()) {
...
}
Ini akan memberikan kesalahan "Tidak dapat menemukan simbol" untuk i
dalam if
pernyataan. Meskipun kami sebelumnya menyatakan i
, deklarasi itu hanya dalam ruang lingkup untuk for
pernyataan dan badannya. Referensi i
dalam if
pernyataan tidak dapat melihat deklarasi itu i
. Itu di luar jangkauan .
(Koreksi yang tepat di sini mungkin untuk memindahkan if
pernyataan di dalam loop, atau untuk menyatakan i
sebelum dimulainya loop.)
Berikut adalah contoh yang menyebabkan kebingungan di mana kesalahan ketik menyebabkan kesalahan yang tampaknya tidak dapat dijelaskan: "Tidak dapat menemukan simbol":
for (int i = 0; i < 100; i++); {
System.out.println("i is " + i);
}
Ini akan memberi Anda kesalahan kompilasi dalam println
panggilan yang mengatakan bahwa i
tidak dapat ditemukan. Tetapi (saya mendengar Anda berkata) saya menyatakannya!
Masalahnya adalah titik koma licik ( ;
) sebelum {
. Sintaks bahasa Java mendefinisikan titik koma dalam konteks itu menjadi pernyataan kosong . Pernyataan kosong kemudian menjadi badan for
loop. Jadi kode itu sebenarnya berarti ini:
for (int i = 0; i < 100; i++);
// The previous and following are separate statements!!
{
System.out.println("i is " + i);
}
The { ... }
blok TIDAK tubuh for
lingkaran, dan oleh karena itu deklarasi sebelumnya i
dalam for
pernyataan keluar dari ruang lingkup di blok tersebut.
Berikut adalah contoh lain dari kesalahan "Tidak dapat menemukan simbol" yang disebabkan oleh kesalahan ketik.
int tmp = ...
int res = tmp(a + b);
Meskipun deklarasi sebelumnya, tmp
dalam tmp(...)
ungkapan itu keliru. Kompiler akan mencari metode yang disebut tmp
, dan tidak akan menemukannya. Yang dideklarasikan sebelumnya tmp
adalah dalam namespace untuk variabel, bukan namespace untuk metode.
Dalam contoh yang saya temui, programmer sebenarnya telah meninggalkan operator. Apa yang ingin ia tulis adalah ini:
int res = tmp * (a + b);
Ada alasan lain mengapa kompiler mungkin tidak menemukan simbol jika Anda mengkompilasi dari baris perintah. Anda mungkin lupa kompilasi atau kompilasi ulang beberapa kelas lain. Misalnya, jika Anda memiliki kelas Foo
dan di Bar
mana Foo
menggunakan Bar
. Jika Anda belum pernah mengkompilasi Bar
dan menjalankan javac Foo.java
, Anda dapat menemukan bahwa kompiler tidak dapat menemukan simbol Bar
. Jawaban sederhananya adalah mengkompilasi Foo
dan Bar
bersama - sama; misalnya javac Foo.java Bar.java
atau javac *.java
. Atau lebih baik lagi menggunakan alat Java build; misal Ant, Maven, Gradle dan sebagainya.
Ada beberapa penyebab lain yang lebih tidak jelas ... yang akan saya bahas di bawah ini.
3. Bagaimana cara memperbaiki kesalahan ini?
Secara umum, Anda mulai dengan mencari tahu apa yang menyebabkan kesalahan kompilasi.
- Lihatlah baris dalam file yang ditunjukkan oleh pesan kesalahan kompilasi.
- Identifikasi simbol mana yang dibicarakan oleh pesan kesalahan.
- Cari tahu mengapa kompiler mengatakan bahwa ia tidak dapat menemukan simbol; Lihat di atas!
Kemudian Anda berpikir tentang apa yang seharusnya dikatakan oleh kode Anda. Lalu akhirnya Anda mencari koreksi apa yang perlu Anda lakukan untuk kode sumber Anda untuk melakukan apa yang Anda inginkan.
Perhatikan bahwa tidak setiap "koreksi" benar. Pertimbangkan ini:
for (int i = 1; i < 10; i++) {
for (j = 1; j < 10; j++) {
...
}
}
Misalkan kompiler mengatakan "Tidak dapat menemukan simbol" untuk j
. Ada banyak cara saya bisa "memperbaiki" itu:
- Aku bisa mengubah batin
for
untuk for (int j = 1; j < 10; j++)
- mungkin benar.
- Saya bisa menambahkan deklarasi untuk
j
sebelumfor
loop dalam , atau for
loop luar - mungkin benar.
- Saya dapat mengubah
j
ke i
dalam for
lingkaran dalam - mungkin salah!
- dan seterusnya.
Intinya adalah bahwa Anda perlu memahami apa yang kode Anda coba lakukan untuk menemukan perbaikan yang tepat.
4. Penyebab yang tidak jelas
Berikut adalah beberapa kasus di mana "Tidak dapat menemukan simbol" tampaknya tidak dapat dijelaskan ... sampai Anda melihat lebih dekat.
Ketergantungan yang salah : Jika Anda menggunakan IDE atau alat build yang mengelola path build dan dependensi proyek, Anda mungkin telah membuat kesalahan dengan dependensi; mis. meninggalkan ketergantungan, atau memilih versi yang salah. Jika Anda menggunakan alat build (Ant, Maven, Gradle, dll), periksa file build proyek. Jika Anda menggunakan IDE, periksa konfigurasi path build proyek.
Anda tidak mengkompilasi ulang : Terkadang terjadi bahwa programmer Java yang baru tidak memahami bagaimana rantai alat Java bekerja, atau belum menerapkan "proses pembangunan" yang berulang; misal menggunakan IDE, Ant, Maven, Gradle dan sebagainya. Dalam situasi seperti itu, programmer dapat akhirnya mengejar ekornya mencari kesalahan ilusi yang sebenarnya disebabkan oleh tidak mengkompilasi ulang kode dengan benar, dan sejenisnya ...
Masalah build sebelumnya : Ada kemungkinan bahwa build sebelumnya gagal dengan cara yang memberikan file JAR dengan kelas yang hilang. Kegagalan seperti itu biasanya akan diperhatikan jika Anda menggunakan alat build. Namun jika Anda mendapatkan file JAR dari orang lain, Anda bergantung padanya untuk membangun dengan benar, dan memperhatikan kesalahan. Jika Anda mencurigai ini, gunakan tar -tvf
untuk membuat daftar isi file JAR yang dicurigai.
Masalah IDE : Orang-orang telah melaporkan kasus di mana IDE mereka menjadi bingung dan kompiler di IDE tidak dapat menemukan kelas yang ada ... atau situasi sebaliknya.
Ini bisa terjadi jika IDE telah dikonfigurasi dengan versi JDK yang salah.
Ini bisa terjadi jika cache IDE tidak sinkron dengan sistem file. Ada cara khusus IDE untuk memperbaikinya.
Ini bisa menjadi bug IDE. Misalnya @ Joel Costigliola menjelaskan skenario di mana Eclipse tidak menangani pohon "tes" Maven dengan benar: lihat jawaban ini .
Masalah Android : Saat Anda memprogram untuk Android, dan Anda memiliki kesalahan "Tidak dapat menemukan simbol" yang terkait R
, perlu diketahui bahwa R
simbol ditentukan oleh context.xml
file. Periksa apakah context.xml
file Anda benar dan di tempat yang benar, dan bahwa R
file kelas yang sesuai telah dihasilkan / dikompilasi. Perhatikan bahwa simbol Java peka terhadap huruf besar-kecil, sehingga id XML yang terkait juga peka terhadap huruf besar-kecil.
Kesalahan simbol lain pada Android kemungkinan disebabkan oleh alasan yang disebutkan sebelumnya; mis. dependensi yang hilang atau salah, nama paket salah, metode atau bidang yang tidak ada dalam versi API tertentu, kesalahan pengejaan / pengetikan, dan sebagainya.
Mendefinisikan ulang kelas sistem : Saya telah melihat kasus-kasus di mana kompiler mengeluh bahwa itu substring
adalah simbol yang tidak dikenal dalam sesuatu seperti berikut ini
String s = ...
String s1 = s.substring(1);
Ternyata programmer telah membuat versinya sendiri String
dan versinya tentang kelas tidak mendefinisikan substring
metode.
Pelajaran: Jangan mendefinisikan kelas Anda sendiri dengan nama yang sama dengan kelas perpustakaan umum!
Homoglyphs: Jika Anda menggunakan pengkodean UTF-8 untuk file sumber Anda, dimungkinkan untuk memiliki pengidentifikasi yang terlihat sama, tetapi pada kenyataannya berbeda karena mengandung homoglyphs. Lihat halaman ini untuk informasi lebih lanjut.
Anda dapat menghindari ini dengan membatasi diri Anda ke ASCII atau Latin-1 sebagai pengkodean file sumber, dan menggunakan Java \uxxxx
escapes untuk karakter lain.
1 - Jika, barangkali, Anda jangan melihat ini dalam pengecualian runtime atau pesan error, maka baik Anda telah mengkonfigurasi IDE Anda untuk menjalankan kode dengan kesalahan kompilasi, atau aplikasi Anda menghasilkan dan kode kompilasi .. pada saat runtime.
2 - Tiga prinsip dasar Teknik Sipil: air tidak mengalir menanjak, papan lebih kuat di sisinya, dan Anda tidak bisa mendorong tali .