一、反射
- 概述:反射是一种机制,利用该机制可以在程序运行过程中对类进行解剖并操作类中的方
法,属性,构造方法等成员 - 使用反射机制解剖类需要先获得字节码文件对象(Class类型对象),那为什么要获得这个类呢?
- 默认情况下:每创建一个类,内存中对应一个Class对象
- 获得Class的三种方法:
//方式一:类名.class Class userClazz1 = User.class; //方式二:对象名.getClass(); User user=new User(); Class userClazz2 = user.getClass(); //方式三:Class.forName("类的全限定名") 全限定名:包名+类名 Class userClazz3 = Class.forName("zongjie.User");
- 创建此Class对象所表示的类的一个新实例,依赖的是无参构造:
Object obj = userClazz3.newInstance();
- 获得字节码对象之后有什么用?
user.java
public class User{
public String username;
public String password;
private Integer age;
private String sex;
public User() {
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
public User(String username, String password, Integer age, String sex) {
this.username = username;
this.password = password;
this.age = age;
this.sex = sex;
}
private User(Integer age, String sex) {
this.age = age;
this.sex = sex;
}
@Override
public String toString() {
return "Useraa{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
'}';
}
public void study(String username){
}
public void sleep(){
}
}
- Constructor对象、Filed对象、Method对象分别代表什么?
- Constructor对象:类中的每一个构造方法都是Constructor对象
- Constructor对象中的方法:
User user = new User(); //Constructor演示 Class userClazz = User.class; //1.获得所有public类型的构造方法 Constructor[] constructors = userClazz.getConstructors();//length:3 //2.获得所有构造方法(包含私有的) Method[] declaredMethods = userClazz.getDeclaredMethods();//length:4 //3.userClazz.getConstructor(参数类型...);//获得指定参数列表public类型的构造方法 //3.1 获得public Useraa(String username, String password)构造方法的Constructor对象 Constructor constructor = userClazz.getConstructor(String.class, String.class); //4.clazz.getDeclaredConstructor(参数类型...);//获得指定参数列表构造方法(包含私有) //4.1 获得private Useraa(Integer age, String sex)构造方法的Constructor对象 Constructor constructor1 = userClazz.getDeclaredConstructor(Integer.class, String.class); //5.根据构造方法创建一个对象 //5.1 当构造方法为private修饰时,需要暴力反射才能使用该构造方法 constructor1.setAccessible(true); //5.2 public T newInstance(Object ... initargs) 参数:要什么构造方法,就根据构造方法参数列表进行传参 User man = (User)constructor1.newInstance(100, "男"); System.out.println(man);
- Filed对象:类中的每一个字段(成员变量)都是Field对象
- Filde对象中的方法:
Class userClazz = User.class; //1.获得所有public类型的字段(包括父类的) Field[] fields = userClazz.getFields();//length:2 System.out.println(fields.length); //2.获得所有字段(包括私有的,不包括父类的) Field[] declaredFields = userClazz.getDeclaredFields();//length:4 //3.获得指定public类型的字段 public String username Field username = userClazz.getField("username"); //4.获得指定字段(包括私有的) private String sex; Field sexField = userClazz.getDeclaredField("sex"); //4.1当字段被private修饰时,需要暴力反射才能使用该字段 sexField.setAccessible(true); //4.2赋值 参数1:Class对象对应的类的对象 参数2:要赋的值 sexField.set(user,"女");; //4.3获取值 参数:Class对象对应的类的对象 Object sexStr= sexField.get(user); System.out.println(sexStr);
- Method:类中的每一个方法都是Method对象
- Method对象中的方法:
Class userClazz = User.class; //1.获得所有public类型的方法(包括父类的) Method[] methods = userClazz.getMethods(); //2.获得所有方法(包括私有的,不包括父类) Method[] declaredMethods = userClazz.getDeclaredMethods(); //3.获得指定public类型的方法 public void Study(String username) 参数1:方法名 参数2:方法名中的参数类型 Method method = userClazz.getMethod("study", String.class); //4.获得指定方法(包括私有的) private void eat(String[] username)参数1:方法名 参数2:方法名中的参数类型 Method eat = userClazz.getDeclaredMethod("eat", String[].class); //4.1当方法被private修饰时,需要暴力反射才能使用该方法 eat.setAccessible(true); //4.2调用方法 参数1:调用方法的对象 参数2:可变参数会把数据解析成多个参数, // 传递到eat()方法中的new String[]{"张三", "李四"}实际上是 "张三" ,"李四"这两个参数,所以需要强转 // ps:如果不需要调用方法的对象(main方法)则传null Object obj = eat.invoke(user, (Object) new String[]{"张三", "李四"}); System.out.println(obj);
- Constructor对象:类中的每一个构造方法都是Constructor对象
二、注解
-
什么是注解:供编译器或JVM使用,可以根据注解完成对应的功能
-
作用的位置:包,类,字段,方法,方法参数以及局部变量上
-
作用:
- 编译见检查:@Override
- 框架的配置:
-
创建格式:
public @interface 注解名(){}
-
注解中可以定义注解属性:
public @interface 注解名(){ 类型 属性名();//没有默认值c 类型 属性名 default 值;//设置默认值 }
- 类型可以为:
- 基本类型(四类8种)
- String
- 枚举类型
- 注解类型
- Class类型
- 以上类型的一维数组类型
- 类型可以为:
-
使用注解:
@注解名(属性名=值,属性名2=值2)
//没有默认值的必须要赋值,有默认值可以不用赋值Anno.java
@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface Anno { String username(); String[] str(); } @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @interface Anno1{ String value(); } @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @interface Anno2{ String[] value(); }
@Anno(username = "张三",str={"str1","str2","str3"}) public void method1(){ } //当注解属性只有一个且名为value可以省略名 @Anno1("张三") public void method2(){ } //注解只有一个String数组名为value且只存一个值 @Anno2("李四") public void method3(){ }
-
元注解:定义注解的注解
-
@Target:定义该注解作用在什么上面(位置),默认是任何位置
@Target(ElementType.METHOD)
:定义在方法上@Target(ElementType.TYPE)
:定义在类上@Target(ElementType.FIELD)
:定义在属性上@Target(ElementType.CONSTRUCTOR)
:定义在构造方法上
-
@Retention:定义该注解保留到那个代码阶段,默认只在源码阶段保留
@Retention(RetentionPolicy.SOURCE)
:只在源码上保留(默认)
*@Retention(RetentionPolicy.CLASS)
:在源码和字节码上保留@Retention(RetentionPolicy.RUNTIME)
:在所有的阶段都保留
-
-
注解解析
//获得clazz对象 Class clazz = Test2.class; //通过clazz对象获得method对象 Method method = clazz.getMethod("method1"); //判断是否方法上是否有注解 if (method.isAnnotationPresent(Anno.class)) { //通过method对象获得方法上的注解对象 Anno anno = method.getAnnotation(Anno.class); String[] str = anno.str(); String username = anno.username(); System.out.println(Arrays.toString(str)); System.out.println(username); }
三、BeanUtils工具类
-
作用:
- 对JavaBean的属性进行赋值和取值。
- 将一个JavaBean所有属性赋值给另一个JavaBean对象中。
- 将一个Map集合的数据封装到一个JavaBean对象中。
-
JavaBean:
- 类必须使用public修饰。
- 提供无参数的构造器。
- 提供getter和setter方法访问属性。
- 实现序列化接口(一般不写)
注意:字段:就是成员变量,字段名就是成员变量名。
属性:属性名通过setter/getter方法去掉set/get前缀,首字母小写获得
- 使用:
//把Map中的值封装到javaBean中 HashMap<String,String> map=new HashMap<>(); //key需和属性相同(不是字段),value会把"18"尝试转换为18,转换失败有默认值0 //配合Map<String, String[]> parameterMap = request.getParameterMap();使用 map.put("username","张三"); map.put("age","18a"); map.put("sex","男"); User1 user1 = new User1(); //封装的方法 BeanUtils.populate(user1,map); System.out.println(user1);