1、一个类的正常流程:
内存中有很多这在运行的类,比如Person类,Student类等
2、含义
java是面向对象的方法,所以所有的事物都可以看做一个类,那么内存中的那些类都是事物,整体就可以再被认为是一个类,而具体的某一个Person类,或者Student类就可以看作是他的对象
所以java使用了一个类描述内存中正在运行的class对象,这个类是java.lang.class
3、作用
Class类创建了对象Person类,就可以操作内存中的Person.class文件
比如:
获取成员变量 并赋值
成员方法 运行
构造方法 运行
用Class类去操作Person.class的过程叫做反射
4、如何获取运行时类的字节码文件对象
运行时的字节码:在方法区中的Person.class文件
1、Object类的getClass方法
Person p=new Person();
p.getClass();
2、类的静态class属性
Person.class()
3、Class类静态方法 forName(“类名”)
Class.forName(“com.doit.Person”)//Person类太多了,必须具体到哪个包下面的Person
推荐3,因为实现了解耦,将字符串解耦出来
5、完成使用Properties获取className
//创建Properties对象,将里面的设置内容读进来
Properties properties = new Properties();
FileReader fileReader = new FileReader("/Users/Downloads/className.properties");
//在/Users/Downloads/className.properties文件里面设置 className=com.doit.Person
properties.load(fileReader);
System.out.println(properties);
String className=properties.getProperty("className");
//获取字节码文件对象
Class aClass = Class.forName(className);
//所以最后想要获取哪个字节码文件对象,可以直接修改properties里面的calssName内容
6、反射获取构造方法
1、获取字节码文件对象
2、获取构造方法
3、运行构造方法
public class TEST {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//前面4个方法是获取构造方法
method1();
method2();
method3();
method4();
//获取空参构造方法,然后运行空参构造
method5();
//获取带参构造方法,然后运行带参构造
method6();
//获取私有构造方法,然后运行构造方法,暴力方法,了解即可
method7();
}
/*
获取所有的公共的构造方法
Constructor[] getConstructor()此Class对象所表示的类的所有公共构造方法
*/
public static void method1() throws ClassNotFoundException{
Class aClass = Class.forName("test.Person");
Constructor[] cons= aClass.getConstructors();
for(Constructor con:cons){
System.out.println(cons);
}
}
/*
获取所有的构造方法,包括私有
Constructor<T>[] getDeclaredConstructors 此Class对象表示的类声明的所有构造方法
*/
public static void method2() throws ClassNotFoundException{
Class aClass = Class.forName("test.Person");
Constructor[] cons= aClass.getDeclaredConstructors();
for(Constructor con:cons){
System.out.println(cons);
}
}
/*
获取指定的非私有的空参构造方法
Constructor getConstructor()
*/
public static void method3() throws ClassNotFoundException, NoSuchMethodException {
Class aClass = Class.forName("test.Person");
Constructor cons = aClass.getConstructor();
System.out.println(cons);
}
/*
获取指定的非私有的带参构造方法
Constructor getConstructor(Class ... params) 参数是:Class类型的参数
*/
public static void method4() throws ClassNotFoundException, NoSuchMethodException {
Class aClass = Class.forName("test.Person");
Constructor cons = aClass.getConstructor(String.class,int.class);
System.out.println(cons);
}
/*
获取空参构造方法
Constructor getConstructor()
然后运行空参构造方法:
public T newInstance()
*/
public static void method5() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//获取字节码文件对象
Class aClass = Class.forName("test.Person");
//获取空参构造方法
Constructor cons = aClass.getConstructor();
System.out.println(cons);
//运行空参构造
Object o = cons.newInstance(); //相当于Object o =new Person();
//这个方法和一般的new方法的区别在于,这个方法可以通过修改字节码对象来修改创建的对象
System.out.println(o);
}
/*
获取带参构造方法
Constructor getConstructor(参数列表)
然后运行带参构造方法(Constructor下的方法)
public T newInstance(Object...args)运行带参构造,需要制定运行构造方法的实际参数
*/
public static void method6() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//获取字节码文件对象
Class aClass = Class.forName("test.Person");
//获取带参构造方法
Constructor cons = aClass.getConstructor(String.class,int.class);
System.out.println(cons);
//运行带参构造
Object o = cons.newInstance("张三",18); //相当于Object o =new Person();
//这个方法和一般的new方法的区别在于,这个方法可以通过修改字节码对象来修改创建的对象
System.out.println(o);
}
/*
获取私有构造方法(暴力反射 不安全 了解即可)
getDeclaredConstructor(参数列表)
取消反射对象的访问权限检查
方法:
java.lang.reflect.AccessibleObject
void setAccessible(boolean flag) flag为true则取消反射对象的访问权限检查
因为Constructor 继承了AccessibleObject,所以可以直接调用
运行私有构造方法:
public T newInstance(Object...args)
*/
public static void method7() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
//获取字节码对象
Class aClass = Class.forName("test.Person");
//获取当前字节码的私有构造方法
Constructor cons = aClass.getDeclaredConstructor(String.class);
//取消反射对象的访问权限检查,true 取消访问权限检查
cons.setAccessible(true);
//运行私有构造方法
//如果没有上面的取消权限检查这一步会报错。cons可以访问到,但是无法运行,因为获取到的构造方法是私有的
Object o = cons.newInstance("张三");
System.out.println(o);
}
}
/*
* 快捷方式 反射创建对象
* Class 类
* public T newInstance() 通过字节码对象,直接运行空参构造方法
* 使用前提:
* 1、这个类必须具备空参构造
* 2、必须有访问权限
* 对比之前的方法是利用的Constructor 下的 newInstance()方法
* */
public class TEST {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Class aClass = Class.forName("test.Person");
Object o = aClass.newInstance();
System.out.println(o);
}
}
7、反射获取方法
1、获取字节码文件对象
2、获取方法
3、运行方法
//以下内容主要是获取方法,运行方法的内容参考下一段代码
public class TEST {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException {
method1();
method2();
method3();
//重点掌握method4()
method4();
}
/*
* 获取类的所有公共方法,包括继承来的方法
* Class类
* Method[] getMethods()
* */
public static void method1() throws ClassNotFoundException {
//获取字节码文件对象
Class aClass = Class.forName("test.Person");
//调用方法,当前字节码文件对象,所表示类中所有公共的方法,包括继承
Method[] methods = aClass.getMethods();
for (Method method : methods) {
System.out.println(method);
}
}
/*
* 获取类的所有公共方法,包括私有,不包括继承来的方法
* Class类
* Method[] getDeclaredMethods()
* */
public static void method2() throws ClassNotFoundException {
//获取字节码文件对象
Class aClass = Class.forName("test.Person");
//调用方法,当前字节码文件对象,所表示类中公共方法,包括私有,不包括继承
Method[] methods = aClass.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}
}
/*
* 获取类指定的无参数的方法
* Class类
* Method getMethod(String name);
* String name:方法名称
* */
public static void method3() throws ClassNotFoundException, NoSuchMethodException {
//获取字节码文件对象
Class aClass = Class.forName("test.Person");
//调用方法,当前字节码文件对象,所属类的指定的无参数的方法
Method method = aClass.getMethod("eat");
System.out.println(method);
}
/*
* 获取类指定的方法
* Class类
* Method getMethod(String name,Class...params);//获取指定的方法
* String name:方法名称
* Class...params:方法的参数的数据类型
* */
public static void method4() throws ClassNotFoundException, NoSuchMethodException {
//获取字节码文件对象
Class aClass = Class.forName("test.Person");
//调用方法,当前字节码文件对象,所属类的指定的方法
Method method = aClass.getMethod("setName", String.class);
System.out.println(method);
}
}
//重点是运行方法
public class TEST {
public static void main(String[] args) throws Exception {
method();
}
/*
* 1、获取字节码文件对象
* 2、获取类指定的方法
* Class类
* Method getMethod(String name,Class...params);//获取指定的方法
* String name:方法名称
* Class...params:方法的参数的数据类型
*
* 2、运行方法
* public Object invoke(Object obj,Object...args)
* 返回值类型Object:运行方法的返回值,使用Object接收,如果方法没有返回值则返回Null
* 参数Object obj:运行方法需要有对象支持,可以说new对象,但是这种方式不好,没有利用反射解耦
* 所以可以考虑使用快捷方式 创建对象,cons.newInstance()
* 参数Object...args:运行的方法如果有参数,需要给定具体的实际参数 比如setName(String name)
* 就需要一个"张三"。
* */
public static void method() throws Exception{
//获取字节码文件对象
Class aClass = Class.forName("test.Person");
//获取指定的方法setName
Method method = aClass.getMethod("setName", String.class);
//快捷方式创建对象
Object o = aClass.newInstance();
//运行方法
Object obj = method.invoke(o, "张三");
System.out.println(obj);//setName没有返回值,所以这里的obj是null
System.out.println(o);//调用了setName()方法,之后对象o有了name
System.out.println("-----------------------------");
Method getNameMethod = aClass.getMethod("getName");
//运行方法
Object name = getNameMethod.invoke(o);//getName方法没有参数,所以不需要传入具体地址
System.out.println(name);//getName有返回值,返回值为String name
}
}