java 注解 题目_java注解面试题总结

在面试的时候,有些面试官会问注解相关的问题, 注解最典型的代表框架就是Spring了,特别是Spring Boot出来之后,用注解代替了XML的配置,非常方便,今天我们就来聊聊注解相关的面试回答。

面试官的问法可能千奇百怪,我在这边总结几个常见的问题:

注解是什么?

注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

简单来说注解其实就是代码中的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行相对应的处理。

JDK内置了哪些注解?

Overried

Overried是告诉编译器要检查该方法是实现父类的方法。

Deprecated

Deprecated用于标记一些过时的代码。

SuppressWarnings

SuppressWarnings用于消除一些警告信息,使用集合的时候,如果没有指定泛型,IDE会提示安全检查的警告。

FunctionalInterface

FunctionalInterface是JDK8中的注解,用来指定该接口是函数式接口。

SafeVarargs

SafeVarargs是JDK 7中的注解,主要目的是处理可变长参数中的泛型,此注解告诉编译器:在可变长参数中的泛型是类型安全的。

怎么自定义一个注解?

在Java中,类使用class定义,接口使用interface定义,注解和接口的定义差不多,增加了一个@符号,即@interface,代码如下:

public @interface EnableAuth {

}

注解中可以定义成员变量,用于信息的描述,跟接口中方法的定义类似,代码如下:

public @interface EnableAuth {

String name();

}

还可以添加默认值:

public @interface EnableAuth {

String name() default "猿天地";

}

上面的介绍只是完成了自定义注解的第一步,开发中日常使用注解大部分是用在类上,方法上,字段上,示列代码如下:

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface EnableAuth {

}

Target

用于指定被修饰的注解修饰哪些程序单元,也就是上面说的类,方法,字段

Retention

用于指定被修饰的注解被保留多长时间,分别SOURCE(注解仅存在于源码中,在class字节码文件中不包含),CLASS(默认的保留策略,注解会在class字节码文件中存在,但运行时无法获取),RUNTIME(注解会在class字节码文件中存在,在运行时可以通过反射获取到)三种类型,如果想要在程序运行过程中通过反射来获取注解的信息需要将Retention设置为RUNTIME

Documented

用于指定被修饰的注解类将被javadoc工具提取成文档

Inherited

用于指定被修饰的注解类将具有继承性

如何获取注解中的值?

可以通过反射来判断类,方法,字段上是否有某个注解以及获取注解中的值, 获取某个类中方法上的注解代码示例如下:

Class> clz = bean.getClass();

Method[] methods = clz.getMethods();

for (Method method : methods) {

if (method.isAnnotationPresent(EnableAuth.class)) {

String name = method.getAnnotation(EnableAuth.class).name();

}

}

通过isAnnotationPresent判断是否存在某个注解,通过getAnnotation获取注解对象,然后获取值

工作中经常接触的注解有哪些?

注解在很多框架中都应用非常多,这个问题你可以说下Spring中的即可,大概的解释下每个注解的含义和用途,除了Spring还有很多别的框架中也有使用注解,比如Swagger, Lombok,JPA,Spring Data等

Component

Controller

Repository

Service

RequestMapping

RequestParam

RequestAttribute

RequestBody

ResponseBody

……

注解的使用场景?

生成文档

Swagger中就是通过注解对接口,实体类中的字段进行描述生成可视化的文档

代替配置文件

Spring中Bean的装载注入

导出数据

可以写一个统一的导出工具类,传入一个List进去即可导出Excel文件,Excel的表头可以用注解加载字段上

框架层面的统一处理

注解在底层框架中用的比较多,在框架中需要考虑到通用性,能用注解做很多事情,比如对API进行权限控制,限流等操作都可以通过自定义注解来标识是否需要进行认证,限流等,还有数据的缓存,典型的就是@Cacheable,还有异步方法的调用@Async,ORM框架中的使用,可以用注解标识表名,字段名,JPA中,Spring Data框架中都有使用

权限控制详细讲解

比如我们有的接口需要认证才能调用,有的不需要,简单的做法就是用配置的方式,将需要认证的接口配置好,然后进行拦截过滤,缺点是需要经常维护配置信息,用注解可以避免这个情况。

可以自定义一个注解,只要加了这个注解我们就对这个接口进行认证拦截操作,接下里详细的讲解下这个功能实现。

定义开启认证的注解,作用在方法上,运行时可获取注解信息

/**

* 开启API权限认证

* @author yinjihuan

*

*/

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface EnableAuth {

}

在需要认证的接口上增加注解

@EnableAuth

@GetMapping("/userCollectCityInfo")

@ApiOperation(value="获取登录用户关注的城市信息", notes="获取登录用户关注的城市信息", produces = "application/json")

@ApiResponses(

@ApiResponse(response = UserCollectCityInfoDto.class, code = 200, message = "")

)

public Response getUserCollectCityInfos(HttpServletRequest request) {

try {

Long uid = UserInfoUtils.getLoginUserId(request);

List citys = cityCollectService.findAllByUid(uid);

List results = citys.stream().map(this::ofCityInfo)

.sorted((l1, l2) -> l1.getRangeLevel().compareTo(l2.getRangeLevel()))

.collect(Collectors.toList());

return Response.ok(results);

} catch (Exception e) {

logger.error("获取登录用户关注的城市信息异常", e);

return Response.fail("获取登录用户关注的城市信息异常");

}

}

在拦截器中进行拦截,拦截需要知道当前请求的接口是不是需要拦截的,我们可以在启动时将所有增加了@EnableAuth的接口信息保存起来,这样在拦截器中就知道哪个接口是需要认证。

初始化需要认证的接口信息代码如下:

/**

* API 验证数据初始化

* @author yinjihuan

*

*/

@Component

@Configuration

public class ApiAuthDataInit implements ApplicationContextAware{

public static List checkApis = new ArrayList();

@Override

public void setApplicationContext(ApplicationContext ctx) throws BeansException{

Map beanMap = ctx.getBeansWithAnnotation(RestController.class);

if (beanMap != null) {

for (Object bean : beanMap.values()) {

Class> clz = bean.getClass();

Method[] methods = clz.getMethods();

for (Method method : methods) {

if (method.isAnnotationPresent(EnableAuth.class)) {

String uri = getApiUri(clz, method);

checkApis.add(uri);

}

}

}

}

}

private String getApiUri(Class> clz, Method method){

StringBuilder uri = new StringBuilder();

uri.append(clz.getAnnotation(RequestMapping.class).value()[0]);

if (method.isAnnotationPresent(GetMapping.class)) {

uri.append(method.getAnnotation(GetMapping.class).value()[0]);

} else if (method.isAnnotationPresent(PostMapping.class)) {

uri.append(method.getAnnotation(PostMapping.class).value()[0]);

} else if (method.isAnnotationPresent(RequestMapping.class)) {

uri.append(method.getAnnotation(RequestMapping.class).value()[0]);

}

return uri.toString();

}

}

实现ApplicationContextAware接口,然后通过getBeansWithAnnotation获取所有接口的bean信息,通过RestController注解来获取,也就是说只要class上增加了RestController注解,这边就都能获取到。

然后通过反射获取bean中所有的方法,如果有增加EnableAuth的话就获取接口的uri存储到map中,这样过滤器中就可以根据map中的值来判断是不是需要进行权限认证了。

cf75d466016a9a8ad7d265623387c443.png

https://blog.fundodoo.com/

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中,可以通过自定义注解来进行数据验证。下面是一个简单的例子: 1. 定义注解 ```java @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation { String value() default ""; int minLength() default 0; int maxLength() default Integer.MAX_VALUE; String regex() default ""; } ``` 这个注解可以用在类的字段上,可以指定字段的值、最小长度、最大长度和正则表达式。 2. 使用注解 ```java public class User { @MyAnnotation(minLength = 3, maxLength = 10, regex = "[a-zA-Z0-9_]+") private String username; // getter and setter } ``` 在这个例子中,我们给User类的username字段加上了MyAnnotation注解,并指定了最小长度为3,最大长度为10,只能包含字母、数字和下划线。 3. 验证数据 ```java public class Validator { public static boolean validate(Object obj) throws IllegalAccessException { Class<?> clazz = obj.getClass(); for (Field field : clazz.getDeclaredFields()) { MyAnnotation annotation = field.getAnnotation(MyAnnotation.class); if (annotation != null) { field.setAccessible(true); String value = (String) field.get(obj); if (value == null || value.length() < annotation.minLength() || value.length() > annotation.maxLength() || !value.matches(annotation.regex())) { return false; } } } return true; } } ``` 这个Validator类可以用来验证任意对象的字段是否符合注解的要求。它通过反射获取对象的所有字段,并检查是否有MyAnnotation注解,然后根据注解的要求验证字段的值。 使用方法: ```java public static void main(String[] args) throws IllegalAccessException { User user = new User(); user.setUsername("abc_123"); boolean isValid = Validator.validate(user); System.out.println(isValid); // true } ``` 在这个例子中,我们创建了一个User对象,并将username设置为"abc_123",然后使用Validator类来验证这个对象的所有字段是否符合注解的要求。由于username符合要求,所以验证结果为true。 这样,我们就可以通过自定义注解来进行数据验证了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值