1.注解
注解(Annotation)是从JDK5.0开始引入的新技术.
Annotation作用:
可以被其它程序读取(比如:编译器等)
Annotation格式:
@注解名存在 比如:@Documented、@Inherited
Annotation在哪里使用:
类、属性、方法等等
2.常用的内置注解
@Override:重写父类方法
@Deprecated:表示方法已过时不推荐使用,但是方法仍然可以使用
@SuppressWarnings抑制警告不显示代码中警告提示
public class Member {
/*
@Override:重写父类方法
*/
@Override
public String toString() {
return super.toString();
}
/*
@Deprecated
表示方法已过时,不推荐使用。
但是方法仍然可以使用
*/
@Deprecated
public static void outSys(){
System.out.println("Deprecated");
}
/*
@SuppressWarnings抑制警告
不显示代码中警告提示
*/
@SuppressWarnings("all")
public void bbaSys(){
List list = null;
}
public static void main(String[] args) {
//调用此方式会出现删除符 表示该方法已经过期,不推荐使用
outSys();
}
}
3.元注解
元注解的作用就是负责注解其它注解,Java定义了4个标准的meta-annotation类型,它们用来
提供对其它annotation类型说明。
@Target:描述注解的使用范围(即:被描述的注解可以用在什么地址。比如:类、属性、方法等)
/** Class, interface (including annotation type), or enum declaration */
TYPE,// 接口、类、枚举
/** Field declaration (includes enum constants) */
FIELD,//字段、枚举的常量
/** Method declaration */
METHOD,//方法
/** Formal parameter declaration */
PARAMETER, //方法参数
/** Constructor declaration */
CONSTRUCTOR, //构造函数
/** Local variable declaration */
LOCAL_VARIABLE,//局部变量
/** Annotation type declaration */
ANNOTATION_TYPE,//注解
/** Package declaration */
PACKAGE,//包
/**
* Type parameter declaration
*
* @since 1.8
*/
TYPE_PARAMETER // 方法参数
@Retention:表示注解生命周期范围
RunTime>Class>Source
RunTime:运行期间注解有效
Class:Class文件中注解有效
Source:原文件中注解有效
@Documented:将注解生成在JavaDoc文档中
@Inherited:子类可以继承该注解
@Target(value = {ElementType.METHOD} )
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MyAnnotation {
}
@interface用来修改注解 表示这是一个注解
@MyAnnotation
public void test01(){
}
4.自定义注解
使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口
注意:
1.@interface用来声明一个注解,格式:public @interface 注解名{定义内容}
2.方法是声明了一个配置参数,方法名称就是参数的名称
3.返回值类型就是参数的类型
4.可以通过default声明参数的默认值
5.如果只有一个参数成员,一般参数名为value
@Target(value = {ElementType.METHOD} )
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface MyAnnotation {
/*
name为参数名 类型是String
如果没用default修饰,使用注解时必须传入参数
*/
String name() default "默认值";
int age() default 0;
String[] items() default {"张三"};
String value();
}
@MyAnnotation(value = "睡觉")
public void test01(){
}
5.注解的使用
1.先定义注解
package com.sl.demo.annotation;
import java.lang.annotation.*;
@Target(value = {ElementType.FIELD,ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MyAnnotation {
int minLength() default 2;
int maxLength() default 4;
String message() default "名称不符合规则";
}
2.使用注解
package com.sl.demo.bean;
import com.sl.demo.annotation.MyAnnotation;
public class User {
@MyAnnotation(minLength = 2,maxLength = 4,message = "名字长度在2~4字符")
private String userName;
private int age;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
3.注解校验
package com.sl.demo.run;
import com.sl.demo.annotation.MyAnnotation;
import com.sl.demo.bean.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Field;
public class ApplicationRun {
private static final String FIELD_TYPE = "class java.lang.String";
private static Logger logger = LoggerFactory.getLogger(ApplicationRun.class);
public static void main(String[] args) throws IllegalAccessException {
User user = new User();
user.setUserName("请叫我司总");
user.setAge(23);
valid(user);
}
public static void valid(Object object) throws IllegalAccessException {
Class<?> clazz = object.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field:fields) {
//获取属性上MyAnnotation注解
MyAnnotation myAnnotation = field.getAnnotation(MyAnnotation.class);
if(null != myAnnotation){
//关闭安全检测 便可以操作私有属性
field.setAccessible(true);
//注解只作用于String类型
if(FIELD_TYPE.equals(field.getGenericType().toString())){
String value = (String)field.get(object);
if(null != value && (value.length() < myAnnotation.minLength() || value.length() > myAnnotation.maxLength())){
logger.error(myAnnotation.message());
}
}
}
}
}
}
输出:
[main] ERROR com.sl.demo.run.ApplicationRun - 名字长度在2~4字符
*SpringBoot结合自定义注解使用
1.导入pom包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
2.创建自定义注解
package com.sl.clear_tomcat.annotation;
import com.sl.clear_tomcat.validator.MyIsNotNullValidator;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
@Target(value = {ElementType.FIELD,ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
@Inherited
@Documented
//指定注解处理逻辑类
@Constraint(validatedBy = {MyIsNotNullValidator.class})
public @interface MyIsNotNull {
//此处参数只能定义为message~~~
String message() default "名称不能为null";
//必须要有 我也不清楚为什么必须要有 ~~~
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
3.创建自定义注解逻辑处理类
package com.sl.clear_tomcat.validator;
import com.sl.clear_tomcat.annotation.MyIsNotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
//ConstraintValidator<MyIsNotNull,String> 第一个参数 为注解类 第二个参数是需要校验的数据类型
public class MyIsNotNullValidator implements ConstraintValidator<MyIsNotNull,String> {
Logger logger = LoggerFactory.getLogger(MyIsNotNullValidator.class);
//第一次访问处理时调用,后面多次调用注解不会触发初始化方法
@Override
public void initialize(MyIsNotNull constraintAnnotation) {
logger.info("MyIsNotNullValidator~~~~~~~~~初始化");
}
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if(null != value && value.length() >0){
return true;
}else{
//注解校验未通过
return false;
}
}
}
4.实体类使用到自定义注解
package com.sl.clear_tomcat.bean;
import com.sl.clear_tomcat.annotation.MyIsNotNull;
import lombok.Data;
@Data
public class User {
@MyIsNotNull(message = "userName不能为null")
private String userName;
}
5.模拟测试
@RestController
@RequestMapping("/index")
public class IndexController {
Logger logger = LoggerFactory.getLogger(MyIsNotNullValidator.class);
@PostMapping("/")
public String index(@RequestBody @Validated User user, BindingResult bindingResult){
if(bindingResult.hasErrors()){
List<ObjectError> allErrors = bindingResult.getAllErrors();
allErrors.forEach( v ->{
logger.error(v.getObjectName()+"======"+v.getDefaultMessage());
});
return "数据校验未通过";
}
return "数据校验通过";
}
}
模拟入参:
{
"userName":""
}
输出日志:
MyIsNotNullValidator~~~~~~~~~初始化
user======userName不能为null
、6.反射概述
反射(Reflection):
反射机制允许程序在执行期间借助于反射API取得任何类的内部信息,并能直接操作任意对象的内部属性
及方法。
Class类:
JRE为每个类都保留了一个不变的Class类型对象,一个Class对象包含了特定的信息。Class本身也是一个
类,一个加载的类在JVM中只会有一个Class实例。
Class类|实例常用方法:如下表格
方法名 c1.getDeclaredFields(); | 作用 获取Class对象里的属性 |
Class.forName("com.ldd.test.User"); | 获取Class对象 |
c1.newInstance(); | 创建Class对象的一个实例 |
c1.getName(); | Class对象对应的包名+类名 |
c1.getSimpleName(); | Class对象对应的类名 |
c1.getClassLoader(); | Class对象的类加载器 |
c1.getInterfaces(); | 获取Class对象的接口 |
c1.getSuperclass(); | 获取Class对象父类Class对象 |
c1.getConstructor(); | 获取对象的构造函数数组 |
c1.getMethods(); | 获取Class对象里的方法 |
获取Class类的实例:
1.Class claszz = User.class;
通过已知类的class属性获取,最为安全可靠,程序性能最高
2.User user = new User(); Class claszz = user.getClass();
通过类的实例,调用实例的getClass()方法获取Class对象
3.Class clazz = Class.forName("com.example.execlpoi.bean.User");
通过类的全路径名获取,可能会抛出ClassNotFoundException异常
7.常见Class类
//接口
Class c0 = Comparable.class;
//一维数组
Class c1 = String[].class;
//二维数据
Class c2 = String[][].class;
//注解
Class c3 = Override.class;
//枚举
Class c4 = ElementType.class;
//void
Class c5 = void.class;
interface java.lang.Comparable
class [Ljava.lang.String;
class [[Ljava.lang.String;
interface java.lang.Override
class java.lang.annotation.ElementType
void
8.类加载内存
加载:将Class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,
然后生成一个代表这个类的java.lang.Class对象。
链接:将Java类的二进制代码合并到JVM的运行状态之中的过程。
验证:确保加载的类信息符合JVM规范,没有安全方面的问题
准备:正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存都将在方法区中进行分配。
解析:虚拟机常量池内的符合引用(常量名)替换为直接引用(地址)的过程。
初始化:
1.执行类构造器<clinit>()方法的过程。类构造器<clinit>()方法是由编译期自动收集类中所有
类变量的赋值动作和静态代码块中的语句合并产生的。(类构造器是构造类信息的,不是构造该类对象
的构造器)
2.当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类的初始化
3.虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确加锁和同步。
9.反射获取类的属性
public static void main(String[] args) throws Exception {
Class c1 = Class.forName("com.example.execlpoi.bean.User");
System.out.println(c1.getName());//包名+类名
System.out.println(c1.getSimpleName());//类名
//getFields() 只能获取public属性
Field[] fields = c1.getFields();
for (Field field : fields) {
System.out.println(field.getName());
}
System.out.println("================");
//getDeclaredFields() 获取所有属性 包含private
fields = c1.getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getName());
}
System.out.println("================");
//获取指定属性
Field car = c1.getField("car");
Field name = c1.getDeclaredField("name");
System.out.println(car);
System.out.println(name);
System.out.println("================");
//获取public方法
Method[] methods = c1.getMethods();
for (Method method : methods) {
System.out.println("public:"+method);
}
//获取全部方法 包含私有的
methods = c1.getDeclaredMethods();
for (Method method : methods) {
System.out.println("all:"+method);
}
System.out.println("================");
//获取指定方法
Method daye = c1.getDeclaredMethod("daye", null);
Method setCar = c1.getMethod("setCar", String.class);
System.out.println(daye);
System.out.println(setCar);
System.out.println("================");
//获取public构造
Constructor[] constructors = c1.getConstructors();
for (Constructor constructor : constructors) {
System.out.println("publuc:"+constructor);
}
//获取全部构造
constructors = c1.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println("all:"+constructor);
}
}
10.反射获取对象
public static void main(String[] args) throws Exception {
Class c1 = Class.forName("com.example.execlpoi.bean.User");
//c1.newInstance() 默认调用的是对象的无参构造方法
//所以 对象需要存在无参构造
User u1 = (User) c1.newInstance();
System.out.println(u1);
//使用指定的构造器构造
Constructor constructor = c1.getDeclaredConstructor(String.class, int.class, int.class, String.class);
User u2 = (User) constructor.newInstance("司总", 20, 88, "BMG");
System.out.println(u2);
//调用方法
Method setCar = c1.getDeclaredMethod("setCar", String.class);
//invoke 激活的意思 第一个参数 挂载的对象 第二参数 方法的入参内容
setCar.invoke(u2,"司总的BBA");
System.out.println(u2.getCar());
//操作属性
Field name = c1.getDeclaredField("name");
//不能直接操作私有属性,设置true关闭安全检测 可以直接操作私有属性
name.setAccessible(true);
name.set(u2,"我是司总");
System.out.println(u2.getName());
}