0. Có sự khác biệt nào giữa hai lỗi không?
Không hẳn vậy. "Không thể tìm thấy biểu tượng" và "Không thể giải quyết biểu tượng" có nghĩa tương tự. Một số trình biên dịch Java sử dụng một cụm từ và một số cụm từ khác.
1. Lỗi "Không thể tìm thấy biểu tượng" nghĩa là gì?
Thứ nhất, đó là lỗi biên dịch 1 . Điều đó có nghĩa là có một vấn đề trong mã nguồn Java của bạn hoặc có một vấn đề trong cách bạn biên dịch nó.
Mã nguồn Java của bạn bao gồm những điều sau đây:
- Từ khóa: như
true
, false
, class
, while
, và vân vân.
- Literals: như
42
và 'X'
và "Hi mum!"
.
- Các nhà khai thác và thẻ không tự chữ và số khác: như
+
, =
, {
, và vân vân.
- Định danh: như
Reader
, i
, toString
, processEquibalancedElephants
, và vân vân.
- Bình luận và khoảng trắng.
Một lỗi "Không thể tìm thấy biểu tượng" là về các định danh. Khi mã của bạn được biên dịch, trình biên dịch cần tìm ra ý nghĩa của mỗi và mọi mã định danh trong mã của bạn.
Một lỗi "Không thể tìm thấy biểu tượng" có nghĩa là trình biên dịch không thể làm điều này. Mã của bạn dường như đề cập đến một cái gì đó mà trình biên dịch không hiểu.
2. Điều gì có thể gây ra lỗi "Không thể tìm thấy biểu tượng"?
Là một đơn đặt hàng đầu tiên, chỉ có một nguyên nhân. Trình biên dịch đã xem xét tất cả các vị trí cần xác định định danh và không thể tìm thấy định nghĩa. Điều này có thể được gây ra bởi một số điều. Những cái phổ biến như sau:
- Đối với định danh nói chung:
- Có lẽ bạn đánh vần tên không chính xác; tức là
StringBiulder
thay vì StringBuilder
. Java không thể và sẽ không cố gắng bù cho lỗi chính tả hoặc lỗi đánh máy.
- Có lẽ bạn đã hiểu sai trường hợp; tức là
stringBuilder
thay vì StringBuilder
. Tất cả các định danh Java đều phân biệt chữ hoa chữ thường.
- Có lẽ bạn đã sử dụng dấu gạch dưới không phù hợp; tức là
mystring
và my_string
khác nhau (Nếu bạn tuân thủ các quy tắc kiểu Java, bạn sẽ được bảo vệ phần lớn khỏi sai lầm này ...)
- Có lẽ bạn đang cố gắng sử dụng một cái gì đó được tuyên bố là "ở một nơi khác"; tức là trong một bối cảnh khác với nơi mà bạn đã ngầm bảo trình biên dịch tìm. (Một lớp khác nhau? Một phạm vi khác nhau? Một gói khác nhau? Một cơ sở mã khác nhau?)
- Đối với các định danh nên tham khảo các biến:
- Có lẽ bạn đã quên khai báo biến.
- Có lẽ khai báo biến nằm ngoài phạm vi tại điểm bạn đã cố sử dụng nó. (Xem ví dụ bên dưới)
Đối với các định danh phải là tên phương thức hoặc trường:
Đối với các định danh phải là tên lớp:
Đối với trường hợp loại hoặc thể hiện không có thành viên bạn mong muốn có:
- Có lẽ bạn đã khai báo một lớp lồng nhau hoặc một tham số chung làm mờ loại bạn muốn sử dụng.
- Có lẽ bạn đang theo dõi một biến tĩnh hoặc ví dụ.
- Có lẽ bạn đã nhập sai loại; ví dụ do hoàn thành IDE hoặc tự động sửa.
- Có lẽ bạn đang sử dụng (biên dịch lại) phiên bản API sai.
- Có lẽ bạn đã quên bỏ đối tượng của mình vào một lớp con thích hợp.
Vấn đề thường là sự kết hợp của những điều trên. Ví dụ: có thể bạn "sao" đã nhập java.io.*
và sau đó thử sử dụng Files
lớp ... java.nio
không có java.io
. Hoặc có lẽ bạn muốn viết File
... đó là một lớp học java.io
.
Dưới đây là một ví dụ về cách phạm vi biến không chính xác có thể dẫn đến lỗi "Không thể tìm thấy biểu tượng":
List<String> strings = ...
for (int i = 0; i < strings.size(); i++) {
if (strings.get(i).equalsIgnoreCase("fnord")) {
break;
}
}
if (i < strings.size()) {
...
}
Điều này sẽ đưa ra lỗi "Không thể tìm thấy biểu tượng" i
trong if
câu lệnh. Mặc dù trước đây chúng tôi đã tuyên bố i
, tuyên bố đó chỉ nằm trong phạm vi cho for
tuyên bố và nội dung của nó. Tham chiếu đến i
trong if
tuyên bố không thể thấy tuyên bố đó i
. Nó nằm ngoài phạm vi .
(Một điều chỉnh thích hợp ở đây có thể là di chuyển if
câu lệnh bên trong vòng lặp hoặc khai báo i
trước khi bắt đầu vòng lặp.)
Dưới đây là một ví dụ gây ra sự khó hiểu khi lỗi chính tả dẫn đến lỗi "Biểu tượng không thể tìm thấy" dường như không thể giải thích được:
for (int i = 0; i < 100; i++); {
System.out.println("i is " + i);
}
Điều này sẽ cung cấp cho bạn một lỗi biên dịch trong println
cuộc gọi nói rằng i
không thể tìm thấy. Nhưng (tôi nghe bạn nói) Tôi đã tuyên bố điều đó!
Vấn đề là dấu chấm phẩy lén lút ( ;
) trước {
. Cú pháp ngôn ngữ Java định nghĩa một dấu chấm phẩy trong ngữ cảnh đó là một câu lệnh trống . Câu lệnh trống sau đó trở thành phần thân của for
vòng lặp. Vì vậy, mã thực sự có nghĩa này:
for (int i = 0; i < 100; i++);
// The previous and following are separate statements!!
{
System.out.println("i is " + i);
}
Các { ... }
khối KHÔNG phải là cơ thể của for
vòng lặp, và do đó việc khai báo trước đó của i
trong for
tuyên bố là ra khỏi phạm vi trong khối.
Dưới đây là một ví dụ khác về lỗi "Không thể tìm thấy biểu tượng" do lỗi chính tả gây ra.
int tmp = ...
int res = tmp(a + b);
Mặc dù tuyên bố trước đó, tmp
trong tmp(...)
biểu thức là sai lầm. Trình biên dịch sẽ tìm kiếm một phương thức được gọi tmp
và sẽ không tìm thấy một phương thức nào. Khai báo trước đó tmp
là trong không gian tên cho các biến, không phải là không gian tên cho các phương thức.
Trong ví dụ tôi đi qua, lập trình viên đã thực sự bỏ qua một toán tử. Những gì ông muốn viết là đây:
int res = tmp * (a + b);
Có một lý do khác khiến trình biên dịch có thể không tìm thấy ký hiệu nếu bạn biên dịch từ dòng lệnh. Bạn có thể chỉ đơn giản là quên biên dịch hoặc biên dịch lại một số lớp khác. Ví dụ, nếu bạn có các lớp Foo
và Bar
nơi Foo
sử dụng Bar
. Nếu bạn chưa bao giờ biên dịch Bar
và bạn chạy javac Foo.java
, bạn có thể thấy rằng trình biên dịch không thể tìm thấy biểu tượng Bar
. Câu trả lời đơn giản là biên dịch Foo
và Bar
cùng nhau; ví dụ javac Foo.java Bar.java
hay javac *.java
. Hoặc tốt hơn là vẫn sử dụng một công cụ xây dựng Java; ví dụ: Ant, Maven, Gradle, v.v.
Có một số nguyên nhân mơ hồ khác nữa ... mà tôi sẽ giải quyết dưới đây.
3. Làm thế nào để tôi sửa những lỗi này?
Nói chung, bạn bắt đầu bằng cách tìm ra nguyên nhân gây ra lỗi biên dịch.
- Nhìn vào dòng trong tệp được chỉ định bởi thông báo lỗi biên dịch.
- Xác định biểu tượng mà thông báo lỗi đang nói về.
- Tìm hiểu tại sao trình biên dịch nói rằng nó không thể tìm thấy biểu tượng; xem ở trên!
Sau đó, bạn nghĩ về những gì mã của bạn được cho là nói. Sau đó, cuối cùng bạn tìm ra cách chỉnh sửa mà bạn cần thực hiện đối với mã nguồn của mình để làm những gì bạn muốn.
Lưu ý rằng không phải mọi "hiệu chỉnh" đều đúng. Xem xét điều này:
for (int i = 1; i < 10; i++) {
for (j = 1; j < 10; j++) {
...
}
}
Giả sử rằng trình biên dịch nói "Không thể tìm thấy biểu tượng" cho j
. Có nhiều cách tôi có thể "sửa" điều đó:
- Tôi có thể thay đổi bên trong
for
để for (int j = 1; j < 10; j++)
- có thể chính xác.
- Tôi có thể thêm một khai báo cho
j
trướcfor
vòng lặp bên trong hoặc for
vòng lặp bên ngoài - có thể đúng.
- Tôi có thể thay đổi
j
để i
trong khu vực nội for
loop - có lẽ sai!
- và như thế.
Vấn đề là bạn cần hiểu mã của bạn đang cố gắng làm gì để tìm ra cách khắc phục phù hợp.
4. Nguyên nhân tối nghĩa
Dưới đây là một vài trường hợp "Biểu tượng không thể tìm thấy" dường như không thể giải thích được ... cho đến khi bạn nhìn gần hơn.
Phụ thuộc không chính xác : Nếu bạn đang sử dụng IDE hoặc công cụ xây dựng quản lý đường dẫn xây dựng và phụ thuộc dự án, bạn có thể đã mắc lỗi với các phụ thuộc; ví dụ bỏ qua một phụ thuộc hoặc chọn phiên bản sai. Nếu bạn đang sử dụng một công cụ xây dựng (Ant, Maven, Gradle, v.v.), hãy kiểm tra tệp xây dựng của dự án. Nếu bạn đang sử dụng IDE, hãy kiểm tra cấu hình đường dẫn xây dựng của dự án.
Bạn không biên dịch lại : Đôi khi xảy ra việc các lập trình viên Java mới không hiểu cách thức chuỗi công cụ Java hoạt động hoặc không thực hiện "quy trình xây dựng" lặp lại; ví dụ: sử dụng IDE, Ant, Maven, Gradle, v.v. Trong tình huống như vậy, lập trình viên cuối cùng có thể đuổi theo đuôi của mình để tìm kiếm một lỗi ảo tưởng thực sự gây ra do không biên dịch lại mã đúng, và tương tự ...
Một vấn đề xây dựng trước đó : Có thể là một bản dựng trước đó đã thất bại theo cách đưa ra một tệp JAR với các lớp bị thiếu. Một lỗi như vậy thường sẽ được chú ý nếu bạn đang sử dụng một công cụ xây dựng. Tuy nhiên, nếu bạn đang nhận tệp JAR từ người khác, bạn phụ thuộc vào việc họ xây dựng đúng cách và nhận thấy lỗi. Nếu bạn nghi ngờ điều này, hãy sử dụng tar -tvf
để liệt kê nội dung của tệp JAR nghi ngờ.
Các vấn đề về IDE : Mọi người đã báo cáo các trường hợp IDE của họ bị lẫn lộn và trình biên dịch trong IDE không thể tìm thấy một lớp tồn tại ... hoặc tình huống ngược lại.
Điều này có thể xảy ra nếu IDE đã được cấu hình với phiên bản JDK sai.
Điều này có thể xảy ra nếu bộ nhớ cache của IDE không đồng bộ với hệ thống tệp. Có những cách cụ thể IDE để khắc phục điều đó.
Đây có thể là một lỗi IDE. Ví dụ @Joel Costigliola mô tả một kịch bản trong đó Eclipse không xử lý chính xác cây "kiểm tra" Maven: xem câu trả lời này .
Sự cố của Android : Khi bạn đang lập trình cho Android và bạn có các lỗi "Không thể tìm thấy biểu tượng" liên quan đến R
, hãy lưu ý rằng các R
biểu tượng được xác định bởi context.xml
tệp. Kiểm tra xem context.xml
tệp của bạn có đúng và ở đúng vị trí không, và R
tệp lớp tương ứng đã được tạo / biên dịch chưa. Lưu ý rằng các ký hiệu Java có phân biệt chữ hoa chữ thường, vì vậy các id XML tương ứng cũng phân biệt chữ hoa chữ thường.
Các lỗi biểu tượng khác trên Android có thể là do các lý do đã đề cập trước đó; ví dụ: phụ thuộc bị thiếu hoặc không chính xác, tên gói, phương thức hoặc trường không chính xác không tồn tại trong một phiên bản API cụ thể, lỗi chính tả / đánh máy, v.v.
Xác định lại các lớp hệ thống : Tôi đã thấy các trường hợp trình biên dịch phàn nàn rằng đó substring
là một biểu tượng không xác định trong một cái gì đó như sau
String s = ...
String s1 = s.substring(1);
Hóa ra là lập trình viên đã tạo ra phiên bản của riêng họ String
và phiên bản lớp của anh ta không định nghĩa một substring
phương thức.
Bài học: Đừng định nghĩa các lớp của riêng bạn có cùng tên với các lớp thư viện chung!
Homoglyphs: Nếu bạn sử dụng mã hóa UTF-8 cho các tệp nguồn của mình, có thể có các mã định danh trông giống nhau, nhưng thực tế lại khác nhau vì chúng chứa homoglyphs. Xem trang này để biết thêm thông tin.
Bạn có thể tránh điều này bằng cách giới hạn bản thân ở ASCII hoặc Latin-1 dưới dạng mã hóa tệp nguồn và sử dụng các \uxxxx
lối thoát Java cho các ký tự khác.
1 - Nếu tình cờ, bạn làm thấy điều này trong một ngoại lệ thời gian chạy hoặc thông báo lỗi, sau đó hoặc là bạn đã cấu hình IDE của bạn để mã chạy với lỗi biên dịch, hoặc ứng dụng của bạn được tạo ra và biên dịch mã .. khi chạy.
2 - Ba nguyên tắc cơ bản của Kỹ thuật Xây dựng: nước không chảy lên dốc, một tấm ván mạnh hơn về phía nó và bạn không thể đẩy lên một chuỗi .