使用自定义注释

问题描述 投票:0回答:5

我发现了几个与此相关(不重复)的问题,但它们并没有让我满意。

我无法理解在哪里以及为什么使用

custom annotations

在书上看过一个自定义标注的例子,但是解释的不够透彻。

@interface MyAnno
{
    String str();
    int val();
}

class MyClass
{
    @MyAnno(str = "Annotation example", val = 100)
    public static void myMeth()
    {
        System.out.println("Inside myMeth()");
    }
}

class CustomAnno
{
    public static void main(String args[])
    {
        MyClass.myMeth();
    }
}

输出符合预期

Inside myMeth()

我对这个例子有几个疑问。

1- 如何在此程序中使用

String str()
int val()
?或

custom annotation
的任何抽象方法有什么用?

2-为什么

custom annotations
。我的意思是它们对任何代码有什么影响。

3-如何创建一个具有像 @override 那样的效果的注释?(我的意思是任何可以注意到的效果)

如果这个例子对你来说没用,那么请给我一个合适的小例子,其中使用了

custom annotation

java annotations
5个回答
13
投票

使用自定义注释的三个主要原因是:

  • 减少编写代码的工作量(编译时注释处理器为您生成代码)。这是教程:第 1 部分第 2 部分
  • 提供额外的正确性保证(编译时注释处理器会警告您错误)。 Checker Framework 是一个很好的工具,它可以防止空指针取消引用、并发错误等。
  • 自定义行为(在运行时,您的代码使用反射检查注释,并根据注释是否存在而表现不同)。诸如Hibernate之类的框架就以这种方式使用注释;另请参阅 Oracle 文章

在每种情况下,与其他非注释方法相比,使用注释可以降低代码中出现错误的可能性。


8
投票

这是一个最小的例子。以下代码演示了自定义注释的使用。

这是关于员工和福利的。如果我们有这样的要求,即 BasicBenefits 必须应用于所有类型的员工,那么我们可以提出自定义注释,例如 BasicBenefits,并使用以下注释注释所有类型的 Employee 实现(例如 CorporateEmployee、ContractEmployee、ManagerEmployee 等)基本福利。

自定义注解类(接口)

import java.lang.annotation.*;
@Inherited
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)

@interface BasicBenefits {
    String bId() default "B-101";
    String bName() default "General Class A Employee";
}

使用自定义注释的类(不需要任何导入):

@BasicBenefits(bId="B-400", bName="General Plus Class A Employee")
public class Employee {
    String eId;
    String eName;
    public Employee(String eId, String eName){
        this.eId = eId;
        this.eName = eName;
    }

    public void getEmployeeDetails(){
        System.out.println("Employee ID: "+eId);
        System.out.println("Employee Name: "+eName);
    }
}

驱动程序类来测试上述内容。

import java.lang.annotation.Annotation;
public class TestCustomAnnotationBasicBenefits {
    public static void main(String[] args) throws Exception{
        Employee emp = new Employee("E-100", "user3320018");
        emp.getEmployeeDetails();
        Class reflectedClass = emp.getClass();
        Annotation hopeBenefitAnn = reflectedClass.getAnnotation(BasicBenefits.class);
        BasicBenefits bBenefits = (BasicBenefits)hopeBenefitAnn;
        System.out.println("Benefit ID: "+bBenefits.bId());
        System.out.println("Benefit Name: "+bBenefits.bName());
    }
}

您的代码看起来差不多了,只需在 main 方法中包含两件事。

1.) 需要引用 MyClass 2.) 需要使用 MyClass 的反射来获取注释。

这里是对您所拥有的代码进行了一些修改:

@Inherited
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnno
{
    String str();
    int val();
}

//using above custom annotation on class level
//can also use method level
//just need to change t @Target(ElementType.METHOD)
@MyAnno(str = "Annotation example", val = 100)
class MyClass
{

    public static void myMeth()
    {
        System.out.println("Inside myMeth()");
    }
}

import java.lang.annotation.Annotation;
class CustomAnno
{
    public static void main(String args[])
    {
        //1. getting reference to the class where the custom annotation is applied.
        //2. then getting the annotation to get the values 
        MyClass myClass = new MyClass();
        Class cls = myClass.getClass();
        Annotation getMyAnno = cls.getAnnotation(MyAnno.class);
        MyAnno myAnno = (MyAnno)getMyAnno;
        MyClass.myMeth(); //left this as is.
        System.out.println("myAnno.str(): "+ myAnno.str());
        System.out.println("myAnno.str(): "+ myAnno.val());     
    }
}

2
投票

注释的抽象方法定义了您可以传递给它的值(在您的情况下

str = "Annotation example", val = 100
)。您可以使用反射来访问它们 (
Method.<T>getAnnotation(Class<T>)
)。自定义注释没有直接影响。仅当您评估它们时它们才有用。

请注意,您必须使用

@Retention(value=RUNTIME)
来注释自定义注释,才能通过反射读取它。


1
投票

要发挥任何作用,必须首先解析注释。内置注释(例如

@Override
@FunctionalInterface
,仅列出最明显的注释)由编译器本身进行解析。至于自定义注释,这些家伙通常由第三方框架解析,尽管我们也可以使用反射机制在独立代码中演示这种技术。

举例来说,下面的代码会根据名为

@SwitchingAnnotation
的自定义注释中声明的字段的值在运行时更改其行为:

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

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface SwitchingAnnotation{
    boolean flag();
}

public class Worker{
    void doThis(){ System.out.println("Doing this"); }
    void doThat(){ System.out.println("Doing that"); }
    @SwitchingAnnotation(
        flag = false
    )
    public void work(boolean flag) {
        if (flag) doThis();
        else doThat();
    }
}

class Test{
    public static void main(String[] args) {
        try{
            SwitchingAnnotation sw = Worker.class.getMethod("work", boolean.class)
                                                 .getAnnotation(SwitchingAnnotation.class);

            new Worker().work(sw.flag());    // prints Doing that
        }
        catch(NoSuchMethodException nsme){
            System.out.println(nsme);
        }
    }
}

0
投票
    In my case I tried with METHOD level annotaions and below is the parsing the annotaion code given.
    
`public static void main(String[] args) throws Exception {
            
            Framework myFramework = new Framework();
            System.out.println("==WithOut-Annotation Parsing==");
            myFramework.serviceCall();
            
            System.out.println("==Annotation Parsing==");
            myFramework.serviceCallx();
        }
    
    @Inherited
    @Documented
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface CustomOne {
    
        String valueOne() default "valueOne";
    
        String valueTwo() default "valueTwo";
    
    }
    
    @Inherited
    @Documented
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface CustomTwo {
    
        String valueThree() default "valueThree";
    
        String valueFour() default "valueFour";
    
    }
    public class Service {
        
        
        @CustomOne(valueOne = "One", valueTwo = "Two")
        @CustomTwo(valueThree = "Three", valueFour = "Four")
        public void test() {
    
            System.out.println("I am inside Service :: test() method");
    
        }
        
        
        @CustomOne
        @CustomTwo
        public void testx() {
            
            System.out.println("I am inside Service :: testx() method");
            
        }
    
    }
    
    public class Framework {
    
        // normal
        public void serviceCall() {
            Service service = new Service();
            service.test();
            service.testx();
        }
    
        // annotation parsing
        public void serviceCallx() throws Exception {
            
            Service service = new Service();
            Method method = service.getClass().getMethod("testx"); // give specific method in string format
    
            if (method.isAnnotationPresent(CustomOne.class)) {
                CustomOne customOne = method.getAnnotation(CustomOne.class);
                
                System.out.println("Custom One Annotation Parsing : " + customOne.valueOne() + " " + customOne.valueTwo());
            }
            if (method.isAnnotationPresent(CustomTwo.class)) {
                CustomTwo customTwo = method.getAnnotation(CustomTwo.class);
                
                System.out.println("Custom Two Annotation Parsing : " + customTwo.valueThree() + " " + customTwo.valueFour());
            }
    
        }
    
    }
    
    
    
    
    `
© www.soinside.com 2019 - 2024. All rights reserved.