熬夜刚完的注解与反射
Posted 野生java研究僧
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了熬夜刚完的注解与反射相关的知识,希望对你有一定的参考价值。
注解与反射
1.反射的概述
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.
反射是比较重要的一个知识,现在的大多数框架都使用得到了反射+注解的形式,对我们的程序进行封装,让我们开箱即用,大大的减少了我们的开发时间,提升了我们的开发效率,使用反射+注解使得我们的程序变得更加的灵活多变
反射就是把java类中的属性和方法映射成与之对应的Java对象,一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把这些组成一个完整类的成员,拆分为一个一个的java对象。
Class 类的实例表示正在运行的 Java 应用程序中的类和接口。也就是说jvm中每个实例都应该属于某个Class对象与之对应。(包括基本数据类型)
Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的defineClass 方法自动构造的。也就是这不需要我们自己去处理创建,JVM已经帮我们创建好了。
**我们来看下Class类的一些方法:**当然太多,等下挑常用的讲
Modifier and Type | Method and Description |
---|---|
<U> 类<? extends U> | asSubclass(类<U> clazz) 类 这个 类 对象来表示由指定的类对象表示的类的子类。 |
T | cast(Object obj) 施放一个目的是通过本表示的类或接口 类 对象。 |
boolean | desiredAssertionStatus() 如果要在调用此方法时初始化该类,则返回将分配给此类的断言状态。 |
static 类<?> | forName(String className) 返回与给定字符串名称的类或接口相关联的 类 对象。 |
static 类<?> | forName(String name, boolean initialize, ClassLoader loader) 使用给定的类加载器返回与给定字符串名称的类或接口相关联的 类 对象。 |
AnnotatedType[] | getAnnotatedInterfaces() 返回一个 AnnotatedType 对象的数组, AnnotatedType 使用类型指定由此 AnnotatedType 对象表示的实体的超级 类 。 |
AnnotatedType | getAnnotatedSuperclass() 返回一个 AnnotatedType 对象,该对象表示使用类型来指定由此 类 对象表示的实体的 类 类。 |
<A extends Annotation>A | getAnnotation(类<A> annotationClass) 返回该元素的,如果这样的注释 *,*否则返回null指定类型的注释。 |
Annotation[] | getAnnotations() 返回此元素上 存在的注释。 |
<A extends Annotation>A[] | getAnnotationsByType(类<A> annotationClass) 返回与此元素相关 联的注释 。 |
String | getCanonicalName() 返回由Java语言规范定义的基础类的规范名称。 |
类<?>[] | getClasses() 返回包含一个数组 类 表示所有的公共类和由此表示的类的成员接口的对象 类 对象。 |
ClassLoader | getClassLoader() 返回类的类加载器。 |
类<?> | getComponentType() 返回 类 数组的组件类型的Class。 |
Constructor<T> | getConstructor(类<?>... parameterTypes) 返回一个 Constructor 对象,该对象反映 Constructor 对象表示的类的指定的公共 类 函数。 |
Constructor<?>[] | getConstructors() 返回包含一个数组 Constructor 对象反射由此表示的类的所有公共构造 类 对象。 |
<A extends Annotation>A | getDeclaredAnnotation(类<A> annotationClass) 如果这样的注释 直接存在 ,则返回指定类型的元素注释,否则返回null。 |
Annotation[] | getDeclaredAnnotations() 返回 直接存在于此元素上的注释。 |
<A extends Annotation>A[] | getDeclaredAnnotationsByType(类<A> annotationClass) 如果此类注释 直接存在或 *间接存在,*则返回该元素的注释(指定类型)。 |
类<?>[] | getDeclaredClasses() 返回一个反映所有被这个 类 对象表示的类的成员声明的类和 类 对象的数组。 |
Constructor<T> | getDeclaredConstructor(类<?>... parameterTypes) 返回一个 Constructor 对象,该对象反映 Constructor 对象表示的类或接口的指定 类 函数。 |
Constructor<?>[] | getDeclaredConstructors() 返回一个反映 Constructor 对象表示的类声明的所有 Constructor 对象的数组 类 。 |
Field | getDeclaredField(String name) 返回一个 Field 对象,它反映此表示的类或接口的指定已声明字段 类 对象。 |
Field[] | getDeclaredFields() 返回的数组 Field 对象反映此表示的类或接口声明的所有字段 类 对象。 |
方法 | getDeclaredMethod(String name, 类<?>... parameterTypes) 返回一个 方法 对象,它反映此表示的类或接口的指定声明的方法 类 对象。 |
方法[] | getDeclaredMethods() 返回包含一个数组 方法 对象反射的类或接口的所有声明的方法,通过此表示 类 对象,包括公共,保护,默认(包)访问和私有方法,但不包括继承的方法。 |
类<?> | getDeclaringClass() 如果由此 类 对象表示的类或接口是另一个类的成员,则返回表示其声明的类的 类 对象。 |
类<?> | getEnclosingClass() 返回底层类的即时封闭类。 |
Constructor<?> | getEnclosingConstructor() 如果此类 对象表示构造函数中的本地或匿名类,则返回表示底层类的立即封闭构造函数的Constructor 对象。 |
方法 | getEnclosingMethod() 如果此类 对象表示方法中的本地或匿名类,则返回表示基础类的即时封闭方法的方法 对象。 |
T[] | getEnumConstants() 返回此枚举类的元素,如果此Class对象不表示枚举类型,则返回null。 |
Field | getField(String name) 返回一个 Field 对象,它反映此表示的类或接口的指定公共成员字段 类 对象。 |
Field[] | getFields() 返回包含一个数组 Field 对象反射由此表示的类或接口的所有可访问的公共字段 类 对象。 |
Type[] | getGenericInterfaces() 返回 Type 表示通过由该对象所表示的类或接口直接实现的接口秒。 |
Type | getGenericSuperclass() 返回 Type 表示此所表示的实体(类,接口,基本类型或void)的直接超类 类 。 |
类<?>[] | getInterfaces() 确定由该对象表示的类或接口实现的接口。 |
方法 | getMethod(String name, 类<?>... parameterTypes) 返回一个 方法 对象,它反映此表示的类或接口的指定公共成员方法 类 对象。 |
方法[] | getMethods() 返回包含一个数组 方法 对象反射由此表示的类或接口的所有公共方法 类 对象,包括那些由类或接口和那些从超类和超接口继承的声明。 |
int | getModifiers() 返回此类或接口的Java语言修饰符,以整数编码。 |
String | getName() 返回由 类 对象表示的实体(类,接口,数组类,原始类型或空白)的名称,作为 String 。 |
软件包 | getPackage() 获取此类的包。 |
ProtectionDomain | getProtectionDomain() 返回 ProtectionDomain 。 |
URL | getResource(String name) 查找具有给定名称的资源。 |
InputStream | getResourceAsStream(String name) 查找具有给定名称的资源。 |
Object[] | getSigners() 获得这个类的签名者。 |
String | getSimpleName() 返回源代码中给出的基础类的简单名称。 |
类<? super T> | getSuperclass() 返回 类 表示此所表示的实体(类,接口,基本类型或void)的超类 类 。 |
String | getTypeName() 为此类型的名称返回一个内容丰富的字符串。 |
TypeVariable<类<T>>[] | getTypeParameters() 返回一个 TypeVariable 对象的数组,它们以声明顺序表示由此 GenericDeclaration 对象表示的通用声明声明的类型变量。 |
boolean | isAnnotation() 如果此 类 对象表示注释类型,则返回true。 |
boolean | isAnnotationPresent(类<? extends Annotation> annotationClass) 如果此元素上 存在指定类型的注释,则返回true,否则返回false。 |
boolean | isAnonymousClass() 返回 true 当且仅当基础类是匿名类时。 |
boolean | isArray() 确定此 类 对象是否表示数组类。 |
boolean | isAssignableFrom(类<?> cls) 确定由此 类 对象表示的类或接口是否与由指定的Class 类 表示的类或接口相同或是超类或 类 接口。 |
boolean | isEnum() 当且仅当该类在源代码中被声明为枚举时才返回true。 |
boolean | isInstance(Object obj) 确定指定的Object是否与此 Object 表示的对象分配 类 。 |
boolean | isInterface() 确定指定 类 对象表示接口类型。 |
boolean | isLocalClass() 返回 true 当且仅当基础类是本地类时。 |
boolean | isMemberClass() 返回 true 当且仅当基础类是成员类时。 |
boolean | isPrimitive() 确定指定 类 对象表示一个基本类型。 |
boolean | isSynthetic() 如果这个类是一个合成类,返回true ; 返回false 其他。 |
T | newInstance() 创建由此 类 对象表示的类的新实例。 |
String | toGenericString() 返回描述此 类 的字符串,包括有关修饰符和类型参数的信息。 |
String | toString() 将对象转换为字符串。 |
2.反射基本使用
User:案例类
package test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* Created with IntelliJ IDEA.
*
* @Author: compass
* @Date: 2021-10-23-0:00
* @Version:1.0
* @Description:
*/
public class User {
private int id;
private int age;
private String name;
private String sex;
public static List<User> getUserList(){
List<User> userList = new ArrayList<>();
userList.add(new User(1,29,"小明","男"));
userList.add(new User(2,21,"小王","男"));
userList.add(new User(3,18,"小李","女"));
userList.add(new User(4,23,"小华","女"));
userList.add(new User(7,50,"小花","女"));
userList.add(new User(5,50,"小k","男"));
userList.add(new User(6,60,"小浪","女"));
return userList;
}
public User(int id, int age, String name, String sex) {
this.id = id;
this.age = age;
this.name = name;
this.sex=sex;
}
public User(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
public User( String name) {
this.name = name;
}
public User(int id, String name) {
this.id=id;
this.name = name;
}
public User() {
}
public String getSex() {
return sex;
}
public void setSex(int id) {
this.sex = sex;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", age=" + age +
", name='" + name + '\\'' +
'}';
}
/**
* 获取一个User对象
* @return
*/
public User getUser(){
return new User(1,29,"小明","男");
}
}
1.获取Class的三种方法
// 1.使用Object的方法getClass(),Object是所有类的父类,那么任何一个对象,都应该有getClass()方法
User u = new User();
Class<? extends User> uClass = u.getClass();
//2.任何数据类型都包含了一个class属性,类型.class的方式
Class<User> aClass = User.class;
//3.常用的 Class.classFrom(String arg),传递一个String类型的从类路径到该类的具体路径
// Class.forName("test.User") : 这个代码会导致我们的静态代码块加载,如果只是想执行某个类的静态代码块,那么可以使用该方法
Class<?> bClass = Class.forName("test.User");
获取到某个类的Class对象有什么用?
我们可以通过该类的class对象,通过newInstance() 方法对该类进行实例化,不用我们手动去new,注意该方法,默认调用的是无参构造方法,如果一个类没有任何构造方法,默认有一个无参构造,如果你重写了有参构造,记得无参构造一定要带上,否则newInstance() 方法将创建对象失败。
User user = (User)bClass.newInstance();
2.通过反射获取构造方法
@Test
void test1() throws Exception{
// 获取共有的构造方法(public进行修饰的方法),并且返回一个 Constructor数组
Constructor<?>[] constructors = User.class.getConstructors();
for (Constructor constructor: constructors){
System.out.println(constructor);
}
System.out.println("----------------------------------------------");
// 获取指定某个构造方法,不传递任何参数,默认获取无参构造,如果要获取有参的需要跟上参数类型,必须和构造方法中参数顺序一致
Constructor<User> constructor1 = User.class.getConstructor(); // 获取无参构造
System.out.println("无参构造="+constructor1);
System.out.println("----------------------------------------------");
Constructor<User> constructor2 = User.class.getConstructor(String.class); // 获取有参构造 User(String name)
System.out.println("有参构造="+constructor2);
System.out.println("----------------------------------------------");
// 获取私有、受保护、默认、公有的构造方法,并且返回一个 Constructor数组
Constructor<?>[] dc1 = User.class.getDeclaredConstructors();
for (int i = 0; i < dc1.length; i++) {
System.out.println("private="+dc1[i]);
}
System.out.println("----------------------------------------------");
// 获取私有、受保护、默认、公有的构造方法,获取单个的(自定义)
Constructor dc2 = User.class.getDeclaredConstructor(int.class,String.class);
System.out.println(dc2);
// 如果该构造方法是私有的,不能直接进行访问,需要先设置为可访问的
if (!dc2.isAccessible()){ // 先判断该方法是否可以进行访问,如果不可以,进行修改,设置为可访问的
dc2.setAccessible(true); // 将private修饰的方法修饰为可访问的
}
// 调用 获取到的构造方法,可以跟参数(不过要和获取到的构造方法中的参数对应,否则抛出:IllegalArgumentException)
User user1 = (User)dc2.newInstance(1, "张三");
System.out.println("name="+user1.getName());
}
3.通过反射获取到属性字段
@Test // 通过class对象获取到属性
void test2() throws Exception{
// 获取到User类中的所有(公共)属性 ,返回一个 Field[]数组
Field[] fields = User.class.getFields();
for (Field field : fields) {
System.out.println("filed = "+field);
}
System.out.println("----------------------------------------");
// 获取到User类中单个属性,返回一个Field对象
Field emailFiled = User.class.getField("email");
System.out.println("emailFiled = "+emailFiled);
System.out.println("----------------------------------------");
// 获取到User类中的所有属性(私有、受保护、默认)
Field[] df1 = User.class.getDeclaredFields();
for (Field field : df1) {
System.out.println("field = "+field);
}
System.out.println("----------------------------------------");
// 获取到User类中的单个的属性(私有、受保护、默认)
Field emailAttributes = User.class.getDeclaredField("email");
System.out.println("emailAttributes ="+emailAttributes);
System.out.println("----------------------------------------");
// 通过反射实例化一个对象,并且获取到该类中的字段(email),并且给其赋值
Class<User> userClass = User.class; // 获得一个User.class对象
User user = userClass.newInstance();
Field[] declaredFields = userClass.getDeclaredFields(); // 获取到user类中所有的属性
for (int i = 0; i < declaredFields.length; i++) { // 遍历User类中所有的属性,找到email属性,为其赋值
if (declaredFields[i].toString().contains("email")){
declaredFields[i].setAccessible(true);//设置为可访问的,以免程序出错
declaredFields[i].set(user,"admin@qq.com");
}
}
System.out.println(user.email);
}
4.通过反射获取方法
@Test // 同过class对象获取到类中的所有方法,以及调用方法
void test3() throws Exception{
// 获取到User类中所有的public方法,包括父类的
Method[] methods = User.class.getMethods();
for (Method method : methods) {
System.out.println(" method = "+method);
}
System.out.println("----------------------------------------");
// 获取到User类中单个的public方法,包括父类的
Method equals = User.class.getMethod("equals", Object.class);
System.out.println("equals ="+equals);
System.out.println("----------------------------------------");
// 获取到User类中所有的(私有、受保护、默认)方法
Method[] methods2 = User.class.getDeclaredMethods();
for (Method method : methods2) {
System.out.println(" method = "+method);
}
Day17-注解与反射