Java反射通俗易懂
2020-06-30 本文已影响0人
info_gu
反射的核心是 JVM 在运行时才动态加载类或调用方法/访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是谁
1.获取Class对象
// 获取Class对象
// 1.Class.forName
Class<?> aClass = Class.forName("bean.Student");
System.out.println(aClass);
// 2.Student.class
Class<Student> aClass1 = Student.class;
System.out.println(aClass1);
// 3.lisi.getClass()
Student lisi = new Student(18, "lisi");
Class<? extends Student> aClass2 = lisi.getClass();
System.out.println(aClass2);
2.判断是否为某个类的实例
public class Test_Gu {
public static void main(String[] args) {
Class<Student> studentClass = Student.class;
Student student = new Student();
if (studentClass.isInstance(student)){
System.out.printf("1");
}
}
}
运行结果如图:
image.png
3.通过反射来生成对象
1.使用Class对象的newInstance()方法来创建Class对象对应类的实例
public class Test_Gu {
public static void main(String[] args) throws IllegalAccessException, InstantiationException {
// 通过反射来生成对象
Class<Student> studentClass = Student.class;
Student student = studentClass.newInstance();
}
}
2.使用Class对象的newInstance()方法来创建Class对象对应类的实例
public class Test_Gu {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
// 先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建实例。这种方法可以用指定的构造器构造类的实例
Class<Student> studentClass = Student.class;
Constructor<Student> constructor = studentClass.getConstructor(int.class, String.class);
Student student = constructor.newInstance(Student.class);
}
}
4.获取某个Class对象的方法
getDeclaredMethods 方法返回类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
public Method[] getDeclaredMethods() throws SecurityException
public class Test_Gu {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class<Student> studentClass = Student.class;
Method[] declaredMethods = studentClass.getDeclaredMethods();
for (Method m :declaredMethods) {
System.out.println(m);
}
}
}
控制台输出:
private int bean.Student.add(int,int)
public java.lang.String bean.Student.getName()
public void bean.Student.setName(java.lang.String)
public int bean.Student.getAge()
public void bean.Student.setAge(int)
Process finished with exit code 0
getMethods 方法返回某个类的所有公用(public)方法,包括其继承类的公用方法。
public Method[] getMethods() throws SecurityException
public class Test_Gu {
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class<Student> studentClass = Student.class;
Method[] methods = studentClass.getMethods();
for (Method m :methods) {
System.out.println(m);
}
}
}
控制台输出:
public java.lang.String bean.Student.getName()
public void bean.Student.setName(java.lang.String)
public int bean.Student.getAge()
public void bean.Student.setAge(int)
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
Process finished with exit code 0
getMethod 方法返回一个特定的方法,其中第一个参数为方法名称,后面的参数为方法的参数对应Class的对象
public Method getMethod(String name, Class<?>... parameterTypes)
注意:getMethod不能获取私有方法
举例说明中的Student类
package bean;
import java.util.stream.Stream;
/**
* @PACKAGE_NAME: bean
* @NAME: Student
* @USER: "guzhenhua"
* @PROJECT_NAME: JavaBase
*/
public class Student {
int age;
String name;
public Student() {
}
public Student(int age, String name) {
this.age = age;
this.name = name;
}
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;
}
private int add(int a,int b){
return a+b;
}
}
5.获取构造器信息(通过不同构造函数创建实例)
public class Test_Gu {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<Student> studentClass = Student.class;
Constructor<Student> constructor = studentClass.getConstructor(int.class,String.class);
Student student = constructor.newInstance(18,"lisi");
System.out.println(student.toString());
}
}
6.获取类的成员变量(字段)信息
getFileds:访问公有的成员变量
getDeclaredField:所有已声明的成员变量,但不能得到其父类的成员变量.私有也可以获取
public class Test_Gu {
public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
// getFileds:访问公有的成员变量
Student student = new Student(18,"lisi");
Class<? extends Student> aClass = student.getClass();
Field[] fields = aClass.getFields();
for (Field field : fields) {
Class<?> type = field.getType();
String typeName = type.getTypeName();
//获得成员变量的名称
String fieldName = field.getName();
System.out.println(typeName + " " + fieldName);
}
System.out.println("------------------");
// getDeclaredField:所有已声明的成员变量,但不能得到其父类的成员变量
Field[] declaredFields = aClass.getDeclaredFields();
for (Field field : declaredFields) {
Class<?> type = field.getType();
String typeName = type.getTypeName();
//获得成员变量的名称
String fieldName = field.getName();
System.out.println(typeName + " " + fieldName);
}
}
}
控制台输出:
int age
java.lang.String name
------------------
int age
java.lang.String name
7.调用方法
当我们从类中获取了一个方法后,我们就可以用 invoke() 方法来调用这个方法
public Object invoke(Object obj, Object... args)
//bean-Student类中定义了
public int add(int a,int b){
return a+b;
}
public class Test_Gu {
public static void main(String[] args) throws, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<Student> studentClass = Student.class;
Student student = studentClass.newInstance();
Method method = studentClass.getMethod("add", int.class, int.class);
Object o = method.invoke(student, 18, 12);
System.out.println(o);
控制台输出:
30
8.通过反射动态的创建对象
//动态的创建对象,通过反射
public class Test09 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//获得Class对象
Class c1 = Class.forName("com.lcy.reflection.User");
//构造一个对象 此调用必须要有默认构造函数
User user1 = (User) c1.newInstance();
System.out.println(user1); //调用默认构造方法
//通过构造器创建对象
Constructor constructor = c1.getDeclaredConstructor(int.class, String.class, String.class);
User user2 = (User) constructor.newInstance(1, "陈平安", "剑气长城");
System.out.println(user2);
//通过反射调用普通方法
User user3 = (User) c1.newInstance();
//通过反射获取一个方法
Method setName = c1.getDeclaredMethod("setName", String.class);
//invoke :激活的意思 (对象,"方法的值")
setName.invoke(user3,"陆沉");
System.out.println(user3.getName());
//通过反射操作属性
User user4 = (User) c1.newInstance();
Field name = c1.getDeclaredField("name");
//不能直接操作私有属性,关闭安全检测,暴力反射可以提高效率
name.setAccessible(true);
name.set(user4,"宁姚");
System.out.println(user4.getName());
}
}
9.反射操作泛型
泛型是确保数据的安全性和免去强制类型转换问题
/通过反射获取泛型
public class Test11 {
public void test01(Map<String,User> map, List<User> list) {
System.out.println("test01");
}
public Map<String,User> test02() {
System.out.println("test02");
return null;
}
public static void main(String[] args) throws NoSuchMethodException {
/*
#java.util.Map<java.lang.String, com.lcy.reflection.User>
class java.lang.String
class com.lcy.reflection.User
#java.util.List<com.lcy.reflection.User>
class com.lcy.reflection.User
*/
//加载的方法和参数
Method method = Test11.class.getMethod("test01", Map.class, List.class);
//获得泛型的参数类型
Type[] genericParameterTypes = method.getGenericParameterTypes();
for (Type type :genericParameterTypes) { //打印泛型
System.out.println("#"+type);
if (type instanceof ParameterizedType) { //想知道里面的参数类型
//强转获得真实的泛型参数信息
Type[] typeArguments = ((ParameterizedType) type).getActualTypeArguments();
for (Type temp :typeArguments) {
System.out.println(temp);
}
}
}
/*
class java.lang.String
class com.lcy.reflection.User
*/
method = Test11.class.getMethod("test02",null);
//获得返回值类型
Type genericReturnType = method.getGenericReturnType();
if (genericReturnType instanceof ParameterizedType) {
Type[] types = ((ParameterizedType) genericReturnType).getActualTypeArguments();
for (Type temp :types) {
System.out.println(temp);
}
}
}
}
10.反射操作注解
//反射操作注解
public class Test12 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class c1 = Class.forName("com.lcy.reflection.Student");
//通过反射获得注解
Annotation[] annotations = c1.getAnnotations();
for (Annotation annotation :annotations) {
//找到了外面的注解@com.lcy.reflection.TableTemp(value=db_stu)
System.out.println(annotation);
}
//获得注解value的值 db_stu
TableTemp tableTemp = (TableTemp) c1.getAnnotation(TableTemp.class);
String value = tableTemp.value();
System.out.println(value);
/**
* 获得类指定的注解
* db_stu
* db_name
* String
* 10
*/
Field f = c1.getDeclaredField("name"); //name对应表中的字段
FieldTemp annotation = f.getAnnotation(FieldTemp.class);
System.out.println(annotation.columnName());
System.out.println(annotation.type());
System.out.println(annotation.length());
}
}
@TableTemp("db_stu")
class Student{
@FieldTemp(columnName = "db_id",type = "int",length = 10)
private int id;
@FieldTemp(columnName = "db_name",type = "String",length = 10)
private String name;
@FieldTemp(columnName = "db_age",type = "varchar",length = 5)
private int age;
public Student() {
}
public Student(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
//类名的注解
@Target(ElementType.TYPE) //设置作用域
@Retention(RetentionPolicy.RUNTIME) //设置什么级别可以获取
@interface TableTemp{
String value();
}
//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldTemp{
String columnName(); //列名的注解
String type(); //类型
int length(); //长度
}
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
//类名的注解
@Target(ElementType.TYPE) //设置作用域
@Retention(RetentionPolicy.RUNTIME) //设置什么级别可以获取
@interface TableTemp{
String value();
}
//属性的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldTemp{
String columnName(); //列名的注解
String type(); //类型
int length(); //长度
}