title: Java高级开发必知必会——反射
author: rocklei123
tags:
反射是Java开发中一个非常重要的概念,掌握了反射的知识,才能更好的学习Java高级课程。如Spring框架的核心就是使用Java反射实现的,而且对做一些Java底层的操作会很有帮助。
** 强烈建议大家手动敲一遍,会收获颇丰! **
** 目标:**
(1) 在面向对象的世界里,万事万物皆对象。(java语言中,静态的成员、普通数据类型除外)
** 问题:** 类是不是对象呢?类是(哪个类的对象呢?)谁的对象呢?
** 答: ** 类是对象,类是java.lang.Class类的实例对象(类对象)
(2)这个对象到底如何表示(三种表示方法)
package com.rocklei123.reflect;
public class ClassDemo1 {
public static void main(String[] args) {
//Student的实例对象如何表示
Student stu1 = new Student();
//Student 这个类 也是一个实例对象,Class类的实例对象,如何表示呢
//任何一个类都是Class的实例对象,这个实例对象有三种表示方式
//第一种表示方式--->实际在告诉我们任何一个类都有一个隐含的静态成员变量class
Class c1 = Student.class;
//第二中表达方式 已经知道该类的对象通过getClass方法
Class c2 = stu1.getClass();
//第三种表达方式
Class c3 = null;
try {
c3 = Class.forName("com.rocklei123.reflect.Student");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
//不管c1 or c2 or c3都代表了Student类的类类型,一个类只可能是Class类的一个实例对象.
System.out.println(c1 == c2); //结果True
System.out.println(c2 == c3);//结果True
//我们完全可以通过类的类类型创建该类的对象实例---->通过c1 or c2 or c3创建Student的实例对象
try {
Student stu2 = (Student) c1.newInstance();//需要有无参数的构造方法
stu2.print();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
class Student {
void print() {
System.out.println("I am a student");
}
}
另外Class类对象不可以new 出来,因为它的构造方法为私有的,只有JVM 才可以创建类对象
/*
* Private constructor. Only the Java Virtual Machine creates Class objects.
* This constructor is not used and prevents the default constructor being
* generated.
*/
private Class(ClassLoader loader) {
// Initialize final field for classLoader. The initialization value of non-null
// prevents future JIT optimizations from assuming this final field is null.
classLoader = loader;
}
** 请大家区分编译、运行:** 编译时刻加载类是静态加载类、运行时刻加载类是动态加载类
(1) new 创建的对象,是静态类加载,在编译时刻就需要加载所有的可能使用到的类。
(2)Class.forName(“类的全称”)不仅表示了,类的类类型,还代表了动态加载类,在运行时刻加载。
基本的数据类型、void等关键字等都存在类类型
package com.rocklei123.reflect;
public class ClassDemo2 {
public static void main(String[] args) {
Class c1 = int.class;//int 的类类型
Class c2 = String.class;//String类的类类型 String类字节码(自己发明的)
Class c3 = double.class;
Class c4 = Double.class;
Class c5 = void.class;
Class c6 = Enum.class;
System.out.println(c1.getName());
System.out.println(c2.getName());
System.out.println(c2.getSimpleName());//不包含包名的类的名称
System.out.println(c3.getName());
System.out.println(c4.getName());
System.out.println(c5.getName());
System.out.println(c6.getName());
/**
* 结果:
* c1: int
* c2: java.lang.String
* c2: String
* c3: double
* c4: java.lang.Double
* c5: void
* c6: java.lang.Enum
*/
}
}
实体类信息:
package com.rocklei123.spring.transaction.transferAccount.entity;
/**
* @Title: SpringTransactionTest
* @Description:
* @Author: rocklei123
* @Date: 2018/8/14 14:52
* @Version: 1.0
*/
public class User {
private String username;
private double money;
public User(String username, double money) {
this.username = username;
this.money = money;
}
public User(){
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public double getMoney() {
return money;
}
public void setMoney(double money) {
this.money = money;
}
}
反射ClassUtil打印类的信息,包括类的成员函数、成员变量(只获取成员函数):
package com.rocklei123.reflect;
import com.rocklei123.spring.transaction.transferAccount.entity.User;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* @ClassName: ClassUtil
* @Auther: rocklei123
* @Date: 2018/9/16 09:40
* @Description: 打印类的信息,包括类的成员函数、成员变量(只获取成员函数)
* @Version 1.0
*/
public class ClassUtil {
/**
* 打印类信息
*
* @param object
*/
public static void printClassInfoMessage(Object object) {
Class c = object.getClass();
System.out.println("类加载器为:" + c.getClassLoader());
System.out.println("包名为:" + c.getPackage());
System.out.println("类名称为:" + c.getName());
System.out.println("===========================================");
}
/**
* 打印方法信息
*
* @param object
*/
public static void printClassMethodMessage(Object object) {
Class c = object.getClass();
/*
* Method类,方法对象
* 一个成员方法就是一个Method对象
* getMethods()方法获取的是所有的public的函数,包括父类继承而来的
* getDeclaredMethods()获取的是所有该类自己声明的方法,不问访问权限
*/
Method[] methods = c.getMethods();
for (int i = 0; i < methods.length; i++) {
Method method = methods[i];
System.out.print("方法名称为:" + method.getName() + " ,");
Class returnType = method.getReturnType();
System.out.print(" 方法返回值类型为:" + returnType.getName() + " 方法参数类型(");
Class[] parameterTypes = method.getParameterTypes();
for (int j = 0; j < parameterTypes.length; j++) {
System.out.print(parameterTypes[j].getName());
}
System.out.println(")");
System.out.println("------------------------------------");
}
System.out.println("===========================================");
}
/**
* 打印成员变量信息
*
* @param object
*/
public static void pirntClassFiledsMessage(Object object) {
/*
* 成员变量也是对象
* java.lang.reflect.Field
* Field类封装了关于成员变量的操作
* getFields()方法获取的是所有的public的成员变量的信息
* getDeclaredFields获取的是该类自己声明的成员变量的信息
*/
Class c = object.getClass();
Field[] fields = c.getFields();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
Class fieldType = field.getType();
String fieldName = field.getName();
System.out.print("成员属性类型为:" + fieldType.getName() + ",属性名称为:" + fieldName + " , ");
}
System.out.println("===========================================");
}
/**
* 打印构造方法信息
*
* @param object
*/
public static void printConstructMessage(Object object) {
/*
* 构造函数也是对象
* java.lang. Constructor中封装了构造函数的信息
* getConstructors获取所有的public的构造函数
* getDeclaredConstructors得到所有的构造函数
*/
Class c = object.getClass();
Constructor[] constructors = c.getConstructors();
for (int i = 0; i < constructors.length; i++) {
Constructor cons = constructors[i];
System.out.print("构造方法:" + cons.getName() + "(");
//获取构造函数的参数列表--->得到的是参数列表的类类型
Class[] paramTypes = cons.getParameterTypes();
for (Class class1 : paramTypes) {
System.out.print(class1.getName() + ",");
}
System.out.println(")");
}
System.out.println("===========================================");
}
public static void main(String[] args) {
User user = new User();
ClassUtil.printClassInfoMessage(user);
ClassUtil.printClassMethodMessage(user);
ClassUtil.printConstructMessage(user);
}
}
执行结果:
类加载器为:sun.misc.Launcher$AppClassLoader@4921a90
包名为:package com.rocklei123.spring.transaction.transferAccount.entity
类名称为:com.rocklei123.spring.transaction.transferAccount.entity.User
===========================================
方法名称为:getUsername , 方法返回值类型为:java.lang.String 方法参数类型()
------------------------------------
方法名称为:setUsername , 方法返回值类型为:void 方法参数类型(java.lang.String)
------------------------------------
方法名称为:getMoney , 方法返回值类型为:double 方法参数类型()
------------------------------------
方法名称为:setMoney , 方法返回值类型为:void 方法参数类型(double)
------------------------------------
方法名称为:wait , 方法返回值类型为:void 方法参数类型(longint)
------------------------------------
方法名称为:wait , 方法返回值类型为:void 方法参数类型(long)
------------------------------------
方法名称为:wait , 方法返回值类型为:void 方法参数类型()
------------------------------------
方法名称为:equals , 方法返回值类型为:boolean 方法参数类型(java.lang.Object)
------------------------------------
方法名称为:toString , 方法返回值类型为:java.lang.String 方法参数类型()
------------------------------------
方法名称为:hashCode , 方法返回值类型为:int 方法参数类型()
------------------------------------
方法名称为:getClass , 方法返回值类型为:java.lang.Class 方法参数类型()
------------------------------------
方法名称为:notify , 方法返回值类型为:void 方法参数类型()
------------------------------------
方法名称为:notifyAll , 方法返回值类型为:void 方法参数类型()
===========================================
构造方法:com.rocklei123.spring.transaction.transferAccount.entity.User(java.lang.String,double,)
构造方法:com.rocklei123.spring.transaction.transferAccount.entity.User()
===========================================
1)如何获取某个方法
方法的名称和方法的参数列表才能唯一决定某个方法
2)方法反射的操作
method.invoke(对象,参数列表)
package com.rocklei123.reflect;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* @ClassName: MethodDemo1
* @Auther: rocklei123
* @Date: 2018/9/16 11:11
* @Description: TODO
* @Version 1.0
*/
public class MethodDemo1 {
public static void main(String[] args) {
Demo demo = new Demo();
Class demoClass = demo.getClass();
/*
* 2.获取方法 名称和参数列表来决定
* getMethod获取的是public的方法
* getDelcaredMethod自己声明的方法
*/
try {
//两种获取方式
//Method m = c.getMethod("("", new Class[]{int.class,int.class});
//Method m = c.getMethod("add", int.class, int.class);
Method addMethod = demoClass.getMethod("add", int.class, int.class);
addMethod.invoke(demo, new Object[]{10, 20});
Method printMethod = demoClass.getMethod("print", new Class[]{String.class, String.class});
printMethod.invoke(demo, "hello", "world");
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
/**
* 结果:
* sum=30
* HELLO WORLD !
*/
}
class Demo {
public int add(int a, int b) {
int c = a + b;
System.out.println("sum=" + c);
return c;
}
public void print(String a, String b) {
System.out.println(a.toUpperCase() + " " + b.toUpperCase() + " !");
}
}
package com.rocklei123.reflect;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/**
* @ClassName: MethodDemo2
* @Auther: rocklei123
* @Date: 2018/9/16 12:22
* @Description: TODO
* @Version 1.0
*/
public class MethodDemo2 {
public static void main(String[] args) {
List<Integer> listInt = new ArrayList<Integer>();
List<String> listStr = new ArrayList<String>();
listStr.add("Hello");
Class classListInt = listInt.getClass();
Class classListStr = listStr.getClass();
System.out.println(classListInt == classListStr);
/*
* classListInt == classListStr 结果返回true说明编译之后集合的泛型是去泛型化的
* Java中集合的泛型,是防止错误输入的,只在编译阶段有效,绕过编译就无效了
* 验证:我们可以通过方法的反射来操作,绕过编译
*/
try {
Method method = classListStr.getMethod("add", Object.class);
method.invoke(listStr, 20);
System.out.println("listStr大小:" + listStr.size());
System.out.println("listStr值:" + listStr);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
/**
* 结果:
* true
* listStr大小:2
* listStr值:[Hello, 20]
*/
}
}
慕课网 https://www.imooc.com/learn/199
Java基础之—反射(非常重要) https://blog.csdn.net/sinat_38259539/article/details/71799078
米宝窝 https://rocklei123.github.io/