2016-01-12 15 views
11

Có phương pháp đơn giản sau đây trong Java 8:Tại sao ngữ cảnh là tĩnh trong ví dụ dòng Java 8 này?

public void test(){ 

    Stream<Integer> stream = Stream.of(1,2,3); 
    stream.map(Integer::toString); 
} 

và tôi nhận được hai lỗi:

java: loại không tương thích: không thể suy ra kiểu biến (s) R (lập luận không phù hợp; không hợp lệ phương pháp tham khảo

tham chiếu đến toString là mơ hồ cả phương thức toString (int) trong java.lang.Integer và phương thức toString() trong java.lang.Integer

và:

phương pháp tham khảo không hợp lệ không tĩnh phương thức toString() có thể không được tham chiếu từ một bối cảnh tĩnh

Lỗi đầu tiên là dễ hiểu, Integer lớp có hai phương pháp:

public static String toString(int i) 
public String toString() 

và trình biên dịch không thể suy ra tham chiếu phương pháp mong muốn.

Nhưng liên quan đến ngữ cảnh thứ hai, bối cảnh tĩnh mà trình biên dịch tham chiếu đến ở đâu?

Lỗi có liên quan đến phương thức toString() của lớp Integer không tĩnh, nhưng tại sao ngữ cảnh mà tôi gọi phương thức đó bằng ánh xạ() là tĩnh?

Còn một câu hỏi khác, nếu trình biên dịch phải giải quyết sự mơ hồ giữa hai phương pháp mà một nguyên nhân gây ra lỗi thời gian biên dịch thì không nên chọn phương thức khác?

+0

Tôi không hiểu - bạn gặp lỗi thứ hai như thế nào? Bạn có sửa đổi mã của bạn bằng cách nào đó sau khi nhận được lỗi đầu tiên? –

+0

Lưu ý rằng luồng của bạn không bị chấm dứt. Làm điều đó có thể giúp trình biên dịch. –

+8

Lỗi thứ hai có thể chỉ là một tác dụng phụ của việc không giải quyết được lỗi đầu tiên. – khelwood

Trả lời

5

Lỗi thứ hai là cá trích đỏ. Nó cho thấy một số hoạt động bên trong của trình biên dịch. Vấn đề là có vấn đề mơ hồ, vấn đề thứ hai là hậu quả của điều đó và có thể bỏ qua. Những gì nó có thể làm là như sau.

  1. Kiểm tra xem có phương pháp tĩnh khớp với chữ ký "hợp lệ" hay không. Có, do đó, nó giả định rằng tĩnh là cách để đi. Điều này ngụ ý rằng có một "sở thích" của các loại trong trình biên dịch cho các phương pháp tĩnh, mặc dù điều này có thể là tùy ý.

  2. Sau đó, nó sẽ tìm phương pháp đầu tiên khớp với chữ ký. Nó không tĩnh, vì vậy nó bị nhầm lẫn vì trước đây DID tìm thấy một phương pháp tĩnh với chữ ký đó.

Một nơi nào đó trong hỗn hợp, C ALNG cũng thấy rằng tham chiếu không rõ ràng. Nó không thực sự rõ ràng cho dù bước 1 hoặc 2 là nơi điều này xảy ra, nhưng trình biên dịch không hủy bỏ bởi vì nó đang cố gắng hữu ích và tìm thêm các lỗi biên dịch.

Trình biên dịch về mặt lý thuyết có thể xử lý điều này tốt hơn vì thông báo thứ hai gây nhầm lẫn.

LƯU Ý: Trình biên dịch Eclipse không hiển thị lỗi thứ hai.

+0

Lỗi thứ hai không được hiển thị vì Eclipse không sử dụng 'javac' để biên dịch. Nó sử dụng trình biên dịch riêng của nó. – SubOptimal

1

Lời giải thích tại sao chúng ta đạt được điều đó hai lỗi là phương pháp tham khảo Integer::toString có thể là một tài liệu tham khảo

  • đến một phương pháp thể hiện của một đối tượng của một loại hình cụ
  • đến một phương pháp tĩnh

Đoạn mã sau đây sẽ chứng minh trình biên dịch chọn trong cả hai trường hợp cho Integer::toString.

phương pháp dụ i.toString() sẽ được lựa chọn

static class MyInteger { 
    int value; 
    public MyInteger(int i) { 
     this.value = i; 
    } 
    public String toMyString() { 
     return "instance " + value; 
    } 
} 

Stream<MyInteger> stream = ... 
stream.map(MyInteger::toMyString).forEach(System.out::println); 
/* which would be equivalent to 
    stream.map(new Function<MyInteger, String>() { 
     public String apply(MyInteger t) { 
      return t.toMyString(); 
     } 
    }); 

    // as method argument for stream.map() the compiler generates 
    invokevirtual MyInteger.toMyString:()Ljava/lang/String; 
*/ 

phương pháp tĩnh Integer.toString(i) sẽ được lựa chọn

static class MyInteger { 
    int value; 
    public MyInteger(int i) { 
     this.value = i; 
    } 
    public static String toMyString() { 
     return "static " + value; 
    } 
} 

Stream<MyInteger> stream = ... 
stream.map(MyInteger::toMyString)..forEach(System.out::println); 
/* which would be equivalent to 
    stream.map(new Function<MyInteger, String>() { 
     @Override 
     public String apply(MyInteger t) { 
      return MyInteger.toMyString(t); 
     } 
    }); 

    // as method argument for stream.map() the compiler generates 
    invokestatic MyInteger.toMyString:(LMyInteger;)Ljava/lang/String; 
*/ 

Trong lần đầu tiên vượt qua phân tích cú pháp cố gắng tìm một phương pháp nào có thể được gọi vào một thể hiện đối tượng. Vì cả hai phương thức toMyString()toMyString(MyInteger) có thể được gọi trên một đối tượng thuộc loại MyInteger và cả hai đều đáp ứng yêu cầu cho Function<? super T,? extends R>, chúng tôi nhận được lỗi đầu tiên reference to toString is ambiguous.
(xem trong nguồn: com.sun.tools.javac.comp.Resolve.mostSpecific(...)).

Trong lần thứ hai, trình phân tích cú pháp cố gắng tìm phương thức tĩnh toString. Do tham chiếu đến phương thức (đã được giải quyết trước) toString() không tĩnh nên chúng tôi nhận được lỗi thứ hai non-static method toString() cannot be referenced from a static context.
(xem trong nguồn: com.sun.tools.javac.comp.Resolve.resolveMemberReference(...)).

chỉnh sửa Ví dụ nhỏ để giải thích lý do cho hai lỗi. Trình phân tích cú pháp của số javac không thể biết bạn định làm gì ở số Integer::toString. Bạn có thể có nghĩa là i.toString() hoặc Integer.toString(i) để anh ấy thực hiện xác thực cho cả hai trường hợp. Đó là cách anh ấy cũng làm việc trong các tình huống khác.

Đối với cuộc biểu tình lấy ví dụ này:

class Foo { 
    int x + y = 1; 
} 

Các báo cáo lỗi là

Scratch.java:2: error: ';' expected   
    int x + y = 1; 
     ^        
Scratch.java:2: error: <identifier> expected 
     int x + y = 1; 
       ^       

Trong đoạn nhỏ này phân tích cú pháp cũng không biết ý định của bạn là gì. Xem vài khả năng.

int x; y = 1; // missed the semicolon and the declaration for `y` 
int x = y = 1; // typo at `+` 
int x = y + 1; // swapped `+` and `=` and missed declaration of `y` 
... more possibilities exist 

Trong trường hợp này trình phân tích cú pháp cũng không dừng ngay sau lỗi đầu tiên.

Các vấn đề liên quan