Làm cách nào để các chú thích như @Override hoạt động nội bộ trong Java?


93

Ai có thể giải thích cho tôi cách chú thích hoạt động nội bộ trong java không?

Tôi biết cách chúng ta có thể tạo chú thích tùy chỉnh bằng cách sử dụng thư viện java.lang.annotation trong java. Nhưng tôi vẫn không hiểu nó hoạt động như thế nào trong nội bộ, chẳng hạn như chú thích @Override.

Tôi sẽ thực sự biết ơn nếu ai đó có thể giải thích chi tiết điều đó.


4
Bạn có nghĩa là gì khi "làm việc nội bộ"? Trình biên dịch? Thời gian chạy?
chrylis -cautilyoptimistic-

3
@chrylis Hoạt động nội bộ có nghĩa là cách nó tự động xác định rằng phương thức này là phương pháp ghi đè hoặc phương pháp này không phải là phương thức ghi đè. Nó hoạt động trên cả hai thời gian. như việc ghi đè chú thích trong thời gian biên dịch và điều khiển xuân chú thích là làm việc trong thời gian chạy
Chirag Dasani

Câu trả lời:


138

Sự khác biệt chính đầu tiên giữa các loại chú thích là liệu chúng được sử dụng tại thời điểm biên dịch và sau đó bị loại bỏ (giống như @Override) hoặc được đặt trong tệp lớp đã biên dịch và có sẵn trong thời gian chạy (như của Spring @Component). Điều này được xác định bởi chính sách @Retention của chú thích. Nếu bạn đang viết chú thích của riêng mình, bạn cần phải quyết định xem chú thích có hữu ích trong thời gian chạy (có thể là để tự động cấu hình) hay chỉ khi biên dịch (để kiểm tra hoặc tạo mã).

Khi biên dịch mã với các chú thích, trình biên dịch sẽ thấy chú thích giống như nó nhìn thấy các công cụ sửa đổi khác trên các phần tử nguồn, như các công cụ sửa đổi truy cập ( public/ private) hoặc final. Khi nó gặp một chú thích, nó sẽ chạy một bộ xử lý chú thích, giống như một lớp plug-in cho biết nó quan tâm đến một chú thích cụ thể. Bộ xử lý chú thích thường sử dụng API phản chiếu để kiểm tra các phần tử đang được biên dịch và có thể chỉ cần chạy kiểm tra chúng, sửa đổi chúng hoặc tạo mã mới để biên dịch. @Overridelà một ví dụ của người đầu tiên; nó sử dụng Reflection API để đảm bảo rằng nó có thể tìm thấy sự phù hợp cho chữ ký phương thức ở một trong các lớp cha và sử dụng hàm này Messagerđể gây ra lỗi biên dịch nếu nó không thể.

Có một số hướng dẫn về cách viết bộ xử lý chú thích; đây là một cái hữu ích . Xem xét thông qua các phương pháp trên các Processorgiao diện cho cách trình biên dịch gọi một bộ xử lý chú thích; hoạt động chính diễn ra trong processphương thức, được gọi mỗi khi trình biên dịch thấy một phần tử có chú thích phù hợp.


4
thật vui khi chỉ cho chúng tôi biết chính xác cách bộ xử lý chú thích của Spring phân tích cú pháp @Component và đưa lớp vào vùng chứa của nó
Junchen Liu

@shanyangqu Câu hỏi này lạc đề, không dành riêng cho Mùa xuân. Bạn có thể tự đọc các lớp xử lý hậu kỳ.
chrylis -cautilyoptimistic-

42

Bên cạnh những gì người khác đề xuất, tôi khuyên bạn nên viết một chú thích được tùy chỉnh và bộ xử lý của nó từ đầu để xem chú thích hoạt động như thế nào.

Ví dụ, theo cách của riêng tôi, tôi đã viết một chú thích để kiểm tra xem các phương thức có bị quá tải trong thời gian biên dịch hay không.

Đầu tiên, tạo một chú thích có tên Overload. Chú thích này được áp dụng cho phương thức nên tôi chú thích nó bằng@Target(value=ElementType.METHOD)

package gearon.customAnnotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

@Target(value=ElementType.METHOD)
public @interface Overload {

}

Tiếp theo, tạo bộ xử lý tương ứng để xử lý các phần tử được chú thích bởi chú thích xác định. Đối với phương thức được chú thích bởi @Overload, chữ ký của nó phải xuất hiện nhiều lần. Hoặc lỗi được in.

package gearon.customAnnotation;

import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic.Kind;

@SupportedAnnotationTypes("gearon.customAnnotation.Overload")

public class OverloadProcessor extends AbstractProcessor{

    @Override
    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
        // TODO Auto-generated method stub
        HashMap<String, Integer> map = new HashMap<String, Integer>();

        for(Element element : roundEnv.getElementsAnnotatedWith(Overload.class)){
            String signature = element.getSimpleName().toString();
            int count = map.containsKey(signature) ? map.get(signature) : 0;
            map.put(signature, ++count);
        }

        for(Entry<String, Integer> entry: map.entrySet()){
            if(entry.getValue() == 1){
                processingEnv.getMessager().printMessage(Kind.ERROR, "The method which signature is " + entry.getKey() +  " has not been overloaded");
            }
        }
        return true;
    }
}

Sau khi đóng gói chú thích và quy trình của nó vào một tệp jar, hãy tạo một lớp với @Overloadvà sử dụng javac.exe để biên dịch nó.

import gearon.customAnnotation.Overload;

public class OverloadTest {
    @Overload
    public static void foo(){
    }

    @Overload
    public static void foo(String s){

    }

    @Overload
    public static void nonOverloadedMethod(){

    }
} 

nonOverloadedMethod()chưa thực sự bị quá tải, chúng ta sẽ nhận được kết quả như sau:

nhập mô tả hình ảnh ở đây


Thông tin trên là rất tốt cho JDK6 (+1 cho điều đó), nhưng làm thế nào để đạt được điều tương tự khi sử dụng JDK5? Sử dụng JDK6 SupportedAnnotationTypes, lớp AbstractProcessor nó trở nên đơn giản hơn nhưng điều tương tự đã xảy ra như thế nào trong quá khứ (như Spring FrameWork 2.5 trên jdk5)? Làm thế nào JVM phát hiện bộ xử lý chú thích như lớp trong jdk5? bạn có thể vui lòng hướng dẫn bằng cách chỉnh sửa câu trả lời trong 2 phần (một cho JDK5, Phiên bản hiện tại là cho Jdk6 +)?
prajitgandhi

Trong lớp của bạn OverloadProcessor::processtại sao lại như entry.getValue() == 1vậy? Người ta không phải thêm chú thích tại lớp / giao diện mẹ, vì vậy roundEnv.getElementsAnnotatedWith(Overload.class)sẽ không nhận được lớp / giao diện mẹ, phải không?
Mưa

Tôi bối rối ở phần này nhưng tôi nghĩ câu trả lời của bạn rất hữu ích.
Mưa

@ s̮̦̩e̝͓c̮͔̞ṛ̖̖e̬̣̦t̸͉̥̳̼ Nếu một phương thức được coi là Quá tải, thì ít nhất phải có một phương thức khác có cùng tên được xác định trong Lớp.
Eugene

1
@Rain cho một phương thức nói là Overloaded, nó phải xuất hiện nhiều lần trong cùng một lớp, nhưng nếu nó là `== 1` thì đó là lỗi.
KrishPrabakar

5

Đây là @Override: http://www.docjar.com/html/api/java/lang/Override.java.html .

Không có gì đặc biệt về nó để phân biệt nó với một chú thích mà bạn có thể tự viết. Các bit thú vị nằm ở người tiêu dùng của các chú thích. Đối với một chú thích như vậy @Override, nó sẽ nằm trong chính trình biên dịch Java, hoặc một công cụ phân tích mã tĩnh, hoặc IDE của bạn.


1
Tôi biết rằng mã nguồn của Ghi đè chú thích. Nhưng nó hoạt động như thế nào trong nội bộ. như cách nó có thể được xác định phương pháp này không phải là phương pháp ghi đè hay phương pháp này là phương pháp ghi đè? hoặc tôi có thể tạo chú thích ghi đè tùy chỉnh của mình không? và nó phải được công trình chính xác cùng một hành vi như java ghi đè chú thích
Chirag Dasani

3
Như tôi đã nói trong câu trả lời của mình, hành vi không phải là một phần của chú thích. Sự giải thích nằm ở những thứ sử dụng chú thích. Do đó, trừ khi bạn thay đổi người tiêu dùng, bạn thực tế không thể tạo phiên bản tùy chỉnh của riêng mình @Override(hoặc các chú thích tiêu chuẩn khác).
Matt Ball

3

Về cơ bản, chú thích chỉ là các điểm đánh dấu được trình biên dịch hoặc ứng dụng đọc. Tùy thuộc vào chính sách lưu giữ của họ, chúng chỉ có sẵn tại thời điểm biên dịch hoặc có thể đọc được trong thời gian chạy bằng cách sử dụng phản chiếu.

Nhiều khung công tác sử dụng tính năng lưu giữ thời gian chạy, tức là chúng kiểm tra một cách phản ánh xem một số chú thích có hiện diện trên một lớp, phương thức, trường, v.v. hay không và thực hiện điều gì đó nếu chú thích đó có (hay không). Ngoài ra, các thành viên của chú thích có thể được sử dụng để chuyển thêm thông tin.


3

Theo liên kết này . Điều này sẽ cung cấp câu trả lời gần gũi cho vấn đề của bạn. Nếu chúng ta tập trung vào chú thích trong Java, Chú thích đã được giới thiệu trong Java 5 và không dành riêng cho Spring. Nói chung, chú thích cho phép bạn thêm siêu dữ liệu vào một lớp, phương thức hoặc biến. Một chú thích có thể được thông dịch bởi trình biên dịch (ví dụ: chú thích @Override) hoặc bởi một khuôn khổ như spring (ví dụ: chú thích @Component).

Ngoài ra tôi đang bổ sung thêm nhiều tài liệu tham khảo.

  1. http://www.codeproject.com/Articles/272736/Undilities-Annotations-in-Java
  2. http://docs.oracle.com/javase/7/docs/api/java/lang/annotation/package-summary.html
  3. http://www.coderanch.com/how-to/java/AnnotationsExample

@LuiggiMendoza java 1.7 đã thêm tài liệu chú thích
Ruchira Gayan Ranaweera

@Ruchira Tôi đã mở tất cả các liên kết nhưng tôi vẫn chưa rõ nó hoạt động như thế nào. U có thể giải thích cho tôi chi tiết như coi như chú thích mùa xuân. Tôi có thể làm tất cả mọi thứ bằng cách sử dụng chú thích mà không cần viết bất kỳ cấu hình nào trong tệp spring.xml. nó có liên kết nội bộ chú thích với cấu hình xml không?
Chirag Dasani

@ChiragDasani hãy xem này. điều này có thể giúp bạn static.springsource.org/spring/docs/3.0.0.M3/reference/html/... và cũng thấy SO bài này stackoverflow.com/questions/2798181/...
Ruchira Gayan Ranaweera

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.