Apa yang dimaksud dengan kesalahan "Tidak dapat menemukan simbol" atau "Tidak dapat menyelesaikan simbol"?
Harap jelaskan hal berikut tentang kesalahan "Tidak dapat menemukan simbol", "Tidak dapat menyelesaikan simbol", atau "Simbol tidak ditemukan":
- Apa yang mereka maksud?
- Hal apa yang bisa menyebabkan mereka?
- Bagaimana cara programmer memperbaikinya?
Pertanyaan ini dirancang untuk memasukkan T&J yang komprehensif tentang kesalahan kompilasi umum ini di Java.
Jawaban
0. Apakah ada perbedaan antara kedua kesalahan tersebut?
Tidak juga. "Tidak dapat menemukan simbol", "Tidak dapat menyelesaikan simbol" dan "Simbol tidak ditemukan" semuanya memiliki arti yang sama. Kompiler Java yang berbeda menggunakan fraseologi yang berbeda.
1. Apa yang dimaksud dengan 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.
Kesalahan "Tidak dapat menemukan simbol" adalah tentang pengenal. Ketika kode Anda dikompilasi, kompilator perlu mencari tahu apa arti setiap pengenal dalam kode Anda.
Kesalahan "Tidak dapat menemukan simbol" berarti kompilator tidak dapat melakukan ini. Kode Anda tampaknya mengacu pada sesuatu yang tidak dipahami oleh kompilator.
2. Apa yang dapat menyebabkan kesalahan "Tidak dapat menemukan simbol"?
Sebagai urutan pertama, hanya ada satu penyebab. Kompilator mencari di semua tempat di mana pengenal harus didefinisikan, dan tidak dapat menemukan definisinya. Ini bisa disebabkan oleh beberapa hal. Yang umum adalah sebagai berikut:
Untuk pengenal secara umum:
- Mungkin Anda salah mengeja nama; yaitu,
StringBiulder
bukanStringBuilder
. Java tidak dapat dan tidak akan mencoba untuk mengkompensasi kesalahan ejaan atau pengetikan yang buruk. - Mungkin kasus Anda salah; yaitu,
stringBuilder
bukanStringBuilder
. Semua pengenal Java peka huruf besar / kecil. - Mungkin Anda menggunakan garis bawah secara tidak tepat; yaitu
mystring
danmy_string
berbeda. (Jika Anda tetap berpegang pada aturan gaya Java, Anda akan sangat terlindungi dari kesalahan ini ...) - Mungkin Anda mencoba menggunakan sesuatu yang dideklarasikan "di tempat lain"; yaitu dalam konteks yang berbeda di mana Anda secara implisit memberi tahu kompilator untuk melihatnya. (Kelas yang berbeda? Ruang lingkup yang berbeda? Paket yang berbeda? Basis kode yang berbeda?)
- Mungkin Anda salah mengeja nama; yaitu,
Untuk pengenal yang harus mengacu pada variabel:
- Mungkin Anda lupa mendeklarasikan variabel.
- Mungkin deklarasi variabel berada di luar ruang lingkup pada titik Anda mencoba menggunakannya. (Lihat contoh di bawah)
Untuk pengidentifikasi yang harus berupa nama metode atau bidang:
Mungkin Anda mencoba merujuk ke metode atau bidang yang diwariskan yang tidak dideklarasikan di kelas atau antarmuka induk / leluhur.
Mungkin Anda mencoba merujuk ke metode atau bidang yang tidak ada (yaitu belum dideklarasikan) dalam tipe yang Anda gunakan; misalnya
"someString".push()
2 .Mungkin Anda mencoba menggunakan metode sebagai bidang, atau sebaliknya; misalnya
"someString".length
atausomeArray.length()
.Mungkin Anda salah mengoperasikan array daripada elemen array; misalnya
String strings[] = ... if (strings.charAt(3)) { ... } // maybe that should be 'strings[0].charAt(3)'
Untuk pengenal yang harus berupa nama kelas:
Mungkin Anda lupa mengimpor kelas.
Mungkin Anda menggunakan impor "bintang", tetapi kelasnya tidak ditentukan dalam paket mana pun yang Anda impor.
Mungkin Anda lupa
new
seperti:String s = String(); // should be 'new String()'
Untuk kasus di mana jenis atau instance tampaknya tidak memiliki anggota yang Anda harapkan:
- Mungkin Anda telah mendeklarasikan kelas bersarang atau parameter umum yang membayangi tipe yang ingin Anda gunakan.
- Mungkin Anda membayangi variabel statis atau instance.
- Mungkin Anda mengimpor jenis yang salah; misalnya karena penyelesaian IDE atau koreksi otomatis.
- Mungkin Anda menggunakan (mengompilasi) versi API yang salah.
- Mungkin Anda lupa mentransmisikan objek Anda ke subkelas yang sesuai.
Masalahnya seringkali merupakan kombinasi dari hal-hal di atas. Misalnya, mungkin Anda "membintangi" mengimpor java.io.*
dan kemudian mencoba menggunakan Files
kelas ... yang ada di java.nio
bukan java.io
. Atau mungkin Anda bermaksud untuk menulis File
... yang merupakan salah satu kelas java.io
.
Berikut ini contoh bagaimana cakupan 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 kita sebelumnya menyatakan i
, bahwa deklarasi hanya dalam lingkup untuk for
pernyataan dan tubuhnya. Referensi ke i
dalam if
pernyataan tidak dapat melihat deklarasi tersebut i
. Itu di luar ruang lingkup .
(Koreksi yang sesuai di sini mungkin untuk memindahkan if
pernyataan di dalam loop, atau mendeklarasikan i
sebelum dimulainya loop.)
Berikut adalah contoh yang menyebabkan kebingungan ketika salah ketik mengarah ke kesalahan "Tidak dapat menemukan simbol" yang tampaknya tidak dapat dijelaskan:
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. Tapi (Saya mendengar Anda berkata) Saya menyatakannya!
Masalahnya adalah titik koma licik ( ;
) sebelum {
. Sintaks bahasa Java mendefinisikan titik koma dalam konteks itu sebagai 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);
Terlepas dari pernyataan sebelumnya, ekspresi tmp
dalam tmp(...)
ekspresi salah. Kompilator akan mencari metode yang dipanggil tmp
, dan tidak akan menemukannya. Yang dideklarasikan sebelumnya tmp
ada di namespace untuk variabel, bukan namespace untuk metode.
Dalam contoh yang saya temukan, pemrogram sebenarnya telah meninggalkan operator. Yang ingin dia tulis adalah ini:
int res = tmp * (a + b);
Ada alasan lain mengapa kompilator mungkin tidak menemukan simbol jika Anda mengkompilasi dari baris perintah. Anda mungkin lupa untuk mengkompilasi atau mengkompilasi ulang beberapa kelas lain. Misalnya, jika Anda memiliki kelas Foo
dan Bar
tempat Foo
penggunaan Bar
. Jika Anda belum pernah mengkompilasi Bar
dan menjalankannya javac Foo.java
, Anda mungkin akan menemukan bahwa kompilator tidak dapat menemukan simbolnya Bar
. Jawaban sederhananya adalah dengan mengumpulkan Foo
dan Bar
bersama; misalnya javac Foo.java Bar.java
atau javac *.java
. Atau lebih baik lagi menggunakan alat build Java; misalnya Ant, Maven, Gradle dan sebagainya.
Ada beberapa penyebab lain yang lebih tidak jelas juga ... yang akan saya bahas di bawah ini.
3. Bagaimana cara memperbaiki kesalahan ini?
Secara umum, Anda memulai dengan mencari tahu apa yang menyebabkan kesalahan kompilasi.
- Lihat baris di file yang ditunjukkan oleh pesan kesalahan kompilasi.
- Identifikasi simbol mana yang dibicarakan oleh pesan kesalahan tersebut.
- Cari tahu mengapa kompilator mengatakan bahwa ia tidak dapat menemukan simbol; Lihat di atas!
Kemudian Anda berpikir tentang apa yang seharusnya dikatakan kode Anda. Kemudian akhirnya Anda menentukan koreksi apa yang perlu Anda lakukan pada kode sumber Anda untuk melakukan apa yang Anda inginkan.
Perhatikan bahwa tidak semua "koreksi" itu benar. Pertimbangkan ini:
for (int i = 1; i < 10; i++) {
for (j = 1; j < 10; j++) {
...
}
}
Misalkan kompilator mengatakan "Tidak dapat menemukan simbol" untuk j
. Ada banyak cara saya bisa "memperbaiki" itu:
- Saya bisa mengubah batin
for
menjadifor (int j = 1; j < 10; j++)
- mungkin benar. - Saya bisa menambahkan deklarasi
j
sebelumfor
loop dalam , ataufor
loop luar - mungkin benar. - Saya bisa mengubah
j
kei
dalamfor
loop dalam - mungkin salah! - dan seterusnya.
Intinya adalah Anda perlu memahami apa yang coba dilakukan kode Anda untuk menemukan perbaikan yang tepat.
4. Penyebab tidak jelas
Berikut adalah beberapa kasus di mana "Tidak dapat menemukan simbol" tampaknya tidak dapat dijelaskan ... sampai Anda melihat lebih dekat.
Dependensi salah : Jika Anda menggunakan IDE atau fitur build yang mengelola jalur build dan dependensi project, 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 tersebut. Jika Anda menggunakan IDE, periksa konfigurasi jalur build proyek.
Anda tidak mengkompilasi ulang : Kadang-kadang terjadi bahwa programmer Java baru tidak memahami cara kerja rantai alat Java, atau belum menerapkan "proses pembangunan" yang berulang; misalnya menggunakan IDE, Ant, Maven, Gradle, dan sebagainya. Dalam situasi seperti itu, programmer bisa saja mengejar ekornya untuk 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 class 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 hal ini, gunakan
tar -tvf
untuk mendaftar isi file JAR tersangka.Masalah IDE : Orang-orang telah melaporkan kasus-kasus di mana IDE mereka menjadi bingung dan compiler di IDE tidak dapat menemukan kelas yang ada ... atau situasi sebaliknya.
Ini dapat 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 mungkin 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 dengannya
R
, ketahuilah bahwaR
simbol ditentukan olehcontext.xml
file. Periksa apakahcontext.xml
file Anda benar dan di tempat yang benar, dan bahwaR
file kelas yang sesuai telah dibuat / dikompilasi. Perhatikan bahwa simbol Java peka huruf besar / kecil, jadi ID XML yang sesuai juga peka huruf besar / kecil.Kesalahan simbol lainnya pada Android kemungkinan besar disebabkan oleh alasan yang disebutkan sebelumnya; misalnya ketergantungan hilang atau salah, nama paket salah, metode atau bidang yang tidak ada dalam versi API tertentu, kesalahan ejaan / pengetikan, dan sebagainya.
Mendefinisikan ulang kelas sistem : Saya telah melihat kasus di mana kompilator mengeluh bahwa
substring
simbol yang tidak dikenal dalam sesuatu seperti berikut iniString s = ... String s1 = s.substring(1);
Ternyata pemrogram telah membuat versi mereka sendiri
String
dan versi kelasnya tidak menentukansubstring
metode.Pelajaran: Jangan mendefinisikan kelas Anda sendiri dengan nama yang sama dengan kelas perpustakaan umum!
Homoglyphs: Jika Anda menggunakan encoding UTF-8 untuk file sumber Anda, mungkin saja memiliki pengenal yang terlihat sama, tetapi sebenarnya berbeda karena mengandung homoglyph. Lihat halaman ini untuk informasi lebih lanjut.
Anda dapat menghindari ini dengan membatasi diri Anda pada ASCII atau Latin-1 sebagai pengkodean file sumber, dan menggunakan
\uxxxx
pelolosan Java 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 ke atas bukit, papan lebih kuat pada sisinya, dan Anda tidak dapat mendorong tali .
Anda juga akan mendapatkan kesalahan ini jika lupa new
:
String s = String();
melawan
String s = new String();
karena panggilan tanpa new
kata kunci akan mencoba dan mencari metode (lokal) yang dipanggil String
tanpa argumen - dan tanda tangan metode tersebut kemungkinan besar tidak ditentukan.
Satu lagi contoh 'Variabel di luar ruang lingkup'
Seperti yang telah saya lihat pertanyaan semacam itu beberapa kali, mungkin satu contoh lagi tentang apa yang ilegal meskipun mungkin terasa oke.
Pertimbangkan kode ini:
if(somethingIsTrue()) {
String message = "Everything is fine";
} else {
String message = "We have an error";
}
System.out.println(message);
Itu kode yang tidak valid. Karena tak satu pun dari variabel bernama message
terlihat di luar cakupan masing-masing - yang akan menjadi tanda kurung {}
di sekitarnya dalam kasus ini.
Anda mungkin mengatakan: "Tetapi variabel bernama pesan didefinisikan dengan cara baik - sehingga pesan yang didefinisikan setelah if
".
Tapi Anda salah.
Java tidak memiliki operator free()
atau delete
, sehingga harus bergantung pada cakupan variabel pelacakan untuk mengetahui kapan variabel tidak lagi digunakan (bersama dengan referensi ke variabel penyebab ini).
Ini sangat buruk jika Anda pikir Anda melakukan sesuatu yang baik. Saya telah melihat jenis kesalahan ini setelah "mengoptimalkan" kode seperti ini:
if(somethingIsTrue()) {
String message = "Everything is fine";
System.out.println(message);
} else {
String message = "We have an error";
System.out.println(message);
}
"Oh, ada kode duplikat, mari kita tarik keluar baris yang umum itu" -> dan begitulah.
Cara paling umum untuk menangani masalah ruang lingkup semacam ini adalah dengan menetapkan nilai lain ke nama variabel di lingkup luar dan kemudian menetapkan kembali jika:
String message = "We have an error";
if(somethingIsTrue()) {
message = "Everything is fine";
}
System.out.println(message);
Salah satu cara untuk mendapatkan kesalahan ini di Eclipse:
- Tentukan kelas
A
disrc/test/java
. - Tentukan kelas lain
B
di kelassrc/main/java
yang menggunakan ituA
.
Hasil: Eclipse akan mengkompilasi kode, tetapi maven akan memberikan "Tidak dapat menemukan simbol".
Penyebab mendasar: Gerhana menggunakan jalur build gabungan untuk pohon utama dan pohon uji. Sayangnya, ini tidak mendukung penggunaan jalur build yang berbeda untuk bagian berbeda dari proyek Eclipse, yang dibutuhkan Maven.
Solusi:
- Jangan mendefinisikan dependensi Anda seperti itu; yaitu jangan membuat kesalahan ini.
- Buat basis kode Anda secara teratur menggunakan Maven sehingga Anda melihat kesalahan ini lebih awal. Salah satu cara untuk melakukannya adalah dengan menggunakan server CI.
"Tidak dapat menemukan" artinya, compiler yang tidak dapat menemukan variabel yang sesuai, metode, kelas dll ... jika Anda mendapat pesan kesalahan itu, pertama-tama Anda ingin mencari baris kode di mana mendapatkan pijat kesalahan .. Dan kemudian Anda akan dapat menemukan variabel, metode atau kelas mana yang belum ditentukan sebelum menggunakannya. Setelah konfirmasi, inisialisasi variabel, metode atau kelas tersebut dapat digunakan untuk nanti membutuhkan ... Perhatikan contoh berikut.
Saya akan membuat kelas demo dan mencetak nama ...
class demo{
public static void main(String a[]){
System.out.print(name);
}
}
Sekarang lihat hasilnya ..
Kesalahan itu mengatakan, "nama variabel tidak dapat menemukan" .. Mendefinisikan dan menginisialisasi nilai untuk variabel 'nama' dapat menghapus kesalahan itu .. Sebenarnya seperti ini,
class demo{
public static void main(String a[]){
String name="smith";
System.out.print(name);
}
}
Sekarang lihat keluaran baru ...
Ok Berhasil memecahkan kesalahan itu .. Pada saat yang sama, jika Anda bisa mendapatkan sesuatu "tidak dapat menemukan metode" atau "tidak dapat menemukan kelas", Pertama-tama, tentukan kelas atau metode dan setelah menggunakannya ..
Jika Anda mendapatkan kesalahan ini di build di tempat lain, sementara IDE Anda mengatakan semuanya baik-baik saja, periksa apakah Anda menggunakan versi Java yang sama di kedua tempat.
Misalnya, Java 7 dan Java 8 memiliki API yang berbeda, jadi memanggil API yang tidak ada di versi Java yang lebih lama akan menyebabkan kesalahan ini.
TERPECAHKAN
Menggunakan IntelliJ
Pilih Build -> Rebuild Project akan menyelesaikannya
Saya juga mendapatkan kesalahan ini. (yang saya cari di Google dan saya diarahkan ke halaman ini)
Masalah: Saya memanggil metode statis yang ditentukan di kelas proyek A dari kelas yang ditentukan di proyek lain B. Saya mendapatkan kesalahan berikut:
error: cannot find symbol
Solusi: Saya menyelesaikan ini dengan terlebih dahulu membangun proyek tempat metode ditentukan, lalu proyek tempat metode itu dipanggil.
Jika path build Java eclipse dipetakan ke 7, 8 dan di Project pom.xml properti Maven java.version disebutkan versi Java yang lebih tinggi (9,10,11, dll ..,) daripada 7,8, Anda perlu memperbarui di pom. file xml.
Di Eclipse jika Java dipetakan ke Java versi 11 dan di pom.xml itu dipetakan ke Java versi 8. Perbarui dukungan Eclipse ke Java 11 dengan melalui langkah-langkah di bawah ini di Bantuan IDE eclipse -> Instal Perangkat Lunak Baru ->
Tempel tautan berikut http://download.eclipse.org/eclipse/updates/4.9-P-builds di Work With
atau
Tambahkan (Jendela Popup akan terbuka) ->
Name:
Dukungan Java 11
Location:
http://download.eclipse.org/eclipse/updates/4.9-P-builds
kemudian perbarui versi Java di properti Maven dari file pom.xml seperti di bawah ini
<java.version>11</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
Terakhir lakukan klik kanan pada project Debug as -> Maven clean, langkah build Maven
Ada berbagai skenario seperti yang disebutkan orang di atas. Beberapa hal yang telah membantu saya menyelesaikan masalah ini.
Jika Anda menggunakan IntelliJ
File -> 'Invalidate Caches/Restart'
ATAU
Kelas yang direferensikan berada di proyek lain dan ketergantungan itu tidak ditambahkan ke file build Gradle dari proyek saya. Jadi saya menambahkan ketergantungan menggunakan
compile project(':anotherProject')
dan itu berhasil. HTH!
Anda mengkompilasi kode Anda menggunakan kompilasi maven dan kemudian menggunakan uji maven untuk menjalankannya dengan baik. Sekarang jika Anda mengubah sesuatu dalam kode Anda dan kemudian tanpa kompilasi Anda menjalankannya, Anda akan mendapatkan kesalahan ini.
Solusi: Sekali lagi kompilasi dan kemudian jalankan pengujian. Bagi saya, cara itu berhasil.
Dalam kasus saya - saya harus melakukan operasi di bawah ini:
- Pindahkan
context.xml
file darisrc/java/package
keresource
direktori (IntelliJ IDE) target
Direktori bersih .
Sebagai petunjuk, lihat lebih dekat nama kelas yang memunculkan kesalahan dan nomor baris, contoh: Kegagalan kompilasi [ERROR] \ application \ xxxxx.java: [44,30] error: tidak dapat menemukan simbol
Satu penyebab lainnya adalah metode yang tidak didukung untuk versi java, katakan jdk7 vs 8. Periksa% JAVA_HOME% Anda
Kami mendapatkan kesalahan dalam proyek Java yang disiapkan sebagai build multi-proyek Gradle. Ternyata salah satu subproyek tidak memiliki plugin Gradle Java Library . Ini mencegah file kelas subproyek terlihat oleh proyek lain dalam build.
Setelah menambahkan plugin pustaka Java ke subproyek build.gradle
dengan cara berikut, kesalahannya hilang:
plugins {
...
id 'java-library'
}
Saya memecahkan kesalahan ini seperti ini ... Kegilaan android. Saya memiliki nama paket sebagai Adaptor dan saya mengubah nama menjadi adaptor dengan "a" dan bukan "A" dan memecahkan kesalahan.