一。反射入门案例
目录
提出一个问题,如何修改外部的配置文件,来操控java内部代码的执行逻辑。
反射类
ReflectionQuestion
package com.hspaidu.reflection.qusetion;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;
public class ReflectionQuestion {
public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
// 使用properties类可以引入外部文件
Properties properties = new Properties();
properties.load(new FileInputStream("src\\re.properties"));
// 获得class的全部路径
String classfullpath = properties.get("classfullpath").toString();
// 得到对象的方法
String method = properties.get("method").toString();
System.out.println("method = "+method);
System.out.println("classfullpath = " + classfullpath);
// 返回了一个class类的类对象
Class cls = Class.forName(classfullpath);
// 通过cls得到对象的实例 可以不用强转也是cat类型
Object o = cls.newInstance();
System.out.println("o的运行类型 = "+o.getClass());
// 得到类当中cls的方法的对象 方法也是对象
Method method1 = cls.getMethod(method);
// 通过方法的对象来调用类实例当中的方法
method1.invoke(o); // 方法.invoke(对象)
}
}
运行结果
method = hi
classfullpath = com.hspaidu.Cat
o的运行类型 = class com.hspaidu.Cat
Hi 招财猫
被操作的类
Cat
package com.hspaidu;
public class Cat {
private String name = "招财猫";
public void hi(){
System.out.println("Hi "+name);
}
public void cry(){
System.out.println(name+" 在cry");
}
}
配置文件
re.properties
classfullpath = com.hspaidu.Cat
method = hi
修改外部文件
classfullpath = com.hspaidu.Cat
method = cry
反射类输出结果
method = cry
classfullpath = com.hspaidu.Cat
o的运行类型 = class com.hspaidu.Cat
招财猫 在cry
二。反射的机制
1.反射的原理
Class当中有一些api可以获取类相关的一些信息,比如实例,方法,全类名等。
所有的类在堆中都有一个复制体,我们可以通过操作这个复制体,来使用这个类。
原理图
描述:Java程序加载有三个阶段
编译阶段:类有属性和方法,构造器。Cat有hi方法,源代码当中会体现,经过Javac的编译,得到一个Cat.class字节码文件,会有属性,方法,构造器等等,
类的加载阶段:字节码文件会加载到加载区域。将class类对象放到堆当中。字节码文件到堆当中是使用了类加载器的classLoader的,类加载器就体现了反射机制。在底层,已经将放在堆当中对象的属性看成可以操作的对象了。类加载完之后生成对象。该对象知道他是属于那个class对象的。得到class对象之后,就可以对对象进行操作了。
运行阶段:调用Cat cat = new Cat(); cat.hi() 会导致类的加载
2.反射相关的类
代码演示
package com.hspaidu.reflection;
import java.io.FileInputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Properties;
public class Reflection01 {
public static void main(String[] args) throws Exception {
Properties properties = new Properties();
properties.load(new FileInputStream("src\\re.properties"));
String classfullpath = properties.get("classfullpath").toString();
String method = properties.get("method").toString();
System.out.println("method = "+method);
System.out.println("classfullpath = " + classfullpath);
// 关于Class对象
Class cls = Class.forName(classfullpath);
//并没有进行类型的强转
Object o = cls.newInstance();
System.out.println(o.getClass());
// 关于方法
Method method1 = cls.getMethod(method);
method1.invoke(o);
// 关于属性
Field age = cls.getField("age"); //不能得到私有的属性
System.out.println("年龄"+age.get(o)); //反射反射,反过来的: 成员变量对象.get(对象)
// 关于构造器
Constructor constructor = cls.getConstructor(); //后边没有参数,返回的是无参的构造器
System.out.println(constructor); //没有形参的构造器
Constructor constructor1 = cls.getConstructor(String.class); //传入的是String的Class对象
System.out.println(constructor1); //有形参的构造器
}
}
结果
method = cry
classfullpath = com.hspaidu.Cat
class com.hspaidu.Cat
招财猫 在cry
年龄10
public com.hspaidu.Cat()
public com.hspaidu.Cat(java.lang.String)
3.反射的优点和缺点
实例
Reflection02
package com.hspaidu.reflection;
import com.hspaidu.Cat;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Reflection02 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
m1();
m2();
}
// 传统的方法来调用hi方法
public static void m1(){
Cat cat = new Cat();
long start = System.currentTimeMillis();
for (int i=0;i<9000000;i++){
cat.hi();
}
long end = System.currentTimeMillis();
System.out.println("传统方法调用 hi 耗时 = "+(end-start));
}
// 反射机制调用
public static void m2() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
Class aClass = Class.forName("com.hspaidu.Cat");
Method hi = aClass.getMethod("hi");
Object o = aClass.newInstance();
long start = System.currentTimeMillis();
for (int i=0;i<9000000;i++){
hi.invoke(o);
}
long end = System.currentTimeMillis();
System.out.println("反射方法调用 hi 耗时 = "+(end-start));
}
}
记得把控制台输出语句关了,太耗时间。
结果
传统方法调用 hi 耗时 = 3
反射方法调用 hi 耗时 = 20
进行优化
Reflection02类
package com.hspaidu.reflection;
import com.hspaidu.Cat;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Reflection02 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
m1();
m2();
m3();
}
// 传统的方法来调用hi方法
public static void m1() {
Cat cat = new Cat();
long start = System.currentTimeMillis();
for (int i = 0; i < 9000000; i++) {
cat.hi();
}
long end = System.currentTimeMillis();
System.out.println("传统方法调用 hi 耗时 = " + (end - start));
}
// 反射机制调用
public static void m2() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
Class aClass = Class.forName("com.hspaidu.Cat");
Method hi = aClass.getMethod("hi");
Object o = aClass.newInstance();
long start = System.currentTimeMillis();
for (int i = 0; i < 9000000; i++) {
hi.invoke(o);
}
long end = System.currentTimeMillis();
System.out.println("反射方法调用 hi 耗时 = " + (end - start));
}
// 反射优化,取消访问机制
public static void m3() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
Class aClass = Class.forName("com.hspaidu.Cat");
Method hi = aClass.getMethod("hi");
hi.setAccessible(true);
Object o = aClass.newInstance();
long start = System.currentTimeMillis();
for (int i = 0; i < 9000000; i++) {
hi.invoke(o);
}
long end = System.currentTimeMillis();
System.out.println("优化后反射方法调用 hi 耗时 = " + (end - start));
}
}
优化结果
传统方法调用 hi 耗时 = 3
反射方法调用 hi 耗时 = 24
优化后反射方法调用 hi 耗时 = 17
优化的幅度并不大
三。Class类详解
1.Class类的特征
类图
Class是被系统创建出来的。
相同的类,只有一个class对象
public class Class01 {
public static void main(String[] args) throws ClassNotFoundException {
// 对于相同的Class,在内存中只有一份
Class cls1 = Class.forName("com.hspaidu.Cat");
Class cls2 = Class.forName("com.hspaidu.Cat");
System.out.println("哈希值 :"+cls1.hashCode());
System.out.println("哈希值 :"+cls2.hashCode());
Class cls3 = Class.forName("com.hspaidu.Dog");
System.out.println("dog哈希值:"+cls3.hashCode());
// 对象实例知道自己是那个class类对象的实现
}
}
运行结果
哈希值 :1735600054
哈希值 :1735600054
dog哈希值:21685669
对象实例知道自己是那个class类对象的实现
2.Class的常用方法
Class02类
package com.hspaidu.reflection.class_;
import com.hspaidu.Car;
import java.lang.reflect.Field;
public class Class02 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
// 获取到了Car类的Class对象,根据全路径
String classAllPath = "com.hspaidu.Car";
// <?>不知道属于哪个类
Class<?> aClass = Class.forName(classAllPath);
System.out.println(aClass); //是属于那个类的class对象
System.out.println(aClass.getClass()); //输出他的运行类型
System.out.println(aClass.getPackage().getName()); //z得到类对象包的名字
System.out.println(aClass.getName()); //得到一个全类名
//对象
Car car = (Car)aClass.newInstance(); //创建一个对象实例
System.out.println(car);
//创建一个属性实例 获得字段的值 但不能是私有的属性
Field brand = aClass.getField("brand");
System.out.println(brand.get(car));
//修改指定对象的属性值
brand.set(car,"奔驰");
System.out.println(brand.get(car));
System.out.println(brand.getName());
System.out.println();
//获取所有字段的名称
Field[] fields = aClass.getFields();
for (Field a: fields){
System.out.println(a.getName());
}
}
}
运行结果
class com.hspaidu.Car
class java.lang.Class
com.hspaidu
com.hspaidu.Car
Car{brand='宝马', price=50, color='red'}
宝马
奔驰
brandbrand
price
color
3.获取Class对象的六种方法
在程序的不同阶段可以用不同的方式得到Class的类对象,编译阶段,类加载阶段,运行阶段,在类加载器处获得。
代码
package com.hspaidu.reflection.class_;
import com.hspaidu.Car;
public class GetClass {
public static void main(String[] args) throws ClassNotFoundException {
// 编译阶段获得 多用于配置文件的到类的全路径使用 xml文件 框架的底层使用
String classAllPath = "com.hspaidu.Car";
Class<?> cls1= Class.forName(classAllPath);
System.out.println(cls1);
// 类加载阶段获得 类名.class
// 多用于参数的传递
// Constructor constructor1 = cls.getConstructor(String.class); 例如这行代码
Class cls2 = Car.class;
System.out.println(cls2);
// 运行阶段获得 对象.class 所以说每一个对象知道他的Class类是什么
Car car = new Car();
Class cls3 = car.getClass();
System.out.println(cls3);
// 通过类加载器获得 有四种类加载器 JVM会讲
ClassLoader classLoader = car.getClass().getClassLoader();
Class cls4 = classLoader.loadClass(classAllPath);
System.out.println(cls4);
System.out.println(cls1.hashCode());
System.out.println(cls2.hashCode());
System.out.println(cls3.hashCode());
System.out.println(cls4.hashCode());
// 基本类的封装
Class<Integer> integerClass = int.class;
Class<Double> doubleClass = double.class;
Class<Character> characterClass = char.class;
System.out.println(integerClass); //输出int 有一个自动装箱和一个自动拆箱的过程
// 基本类型的TYPE属性的到
Class<Integer> type = Integer.TYPE;
Class<Character> type1 = Character.TYPE;
Class<Double> type2 = Double.TYPE;
System.out.println(type);
// 两种方式获得的基本类型的Class是同一个
System.out.println(integerClass.hashCode());
System.out.println(type.hashCode());
}
}
运行结果
class com.hspaidu.Car
class com.hspaidu.Car
class com.hspaidu.Car
class com.hspaidu.Car
1735600054
1735600054
1735600054
1735600054
int
int
21685669
21685669
4.那些类型有Class对象
代码
package com.hspaidu.reflection.class_;
import java.io.Serializable;
public class AllTypeClass {
public static void main(String[] args) {
Class<String> cls = String.class;//外部类
Class<Serializable> cls1 = Serializable.class;//接口
Class<Integer[]> cls2 = Integer[].class;//数组
Class<Integer[][]> cls3 = Integer[][].class;//二维数组
Class<Deprecated> cls4 = Deprecated.class;//注解
Class<Thread.State> cls5 = Thread.State.class; //枚举
Class<Long> cls6 = long.class; //基本数据类型
Class<Void> cls7 = void.class; //返回类型
Class<Class> cls8 = Class.class;
System.out.println(cls);
System.out.println(cls1);
System.out.println(cls2);
System.out.println(cls3);
System.out.println(cls4);
System.out.println(cls5);
System.out.println(cls6);
System.out.println(cls7);
System.out.println(cls8);
}
}
运行结果
class java.lang.String
interface java.io.Serializable
class [Ljava.lang.Integer;
class [[Ljava.lang.Integer;
interface java.lang.Deprecated
class java.lang.Thread$State
long
void
class java.lang.Class
四。类加载
1.动态加载和静态加载
静态加载:编译时会校验所有的类,动态加载:在运行的时候,没有运行这个类就不会报错
反射是动态加载,执行到的时候才会报错。直接new是静态加载,直接在编译时期就会检测你类的合法性。
错误是一直存在的,就是有没有发现,不过静态加载生成不了class文件,过不了编译,动态可以。
2.类的加载流程
流程图
加载
将class文件读入内存,并创建一个Class对象
链接
分为三部分,验证,准备,解析。
初始化
可以由程序员控制前两个是JVM自动完成的。主要是静态成员,与对象无关,是类的加载阶段,而不是对象创建阶段。
类加载的五个阶段
加载
讲二进制放到方法区,并生成Class类。
验证
准备
举例
package com.hspaidu.reflection.classload;
public class ClassLoad02 {
public static void main(String[] args) {
}
}
class A{
//属性-字段-成员变量
// n1是实例变量,在准备的时候不会进行处理,
public int n1 = 10;
// n2是静态变量,分配内存,但是默认初始化,值为0
public static int n2 = 20;
// 是常量,不是静态变量,一旦赋值就不会改变,所以会赋值为20
public static final int n3 = 30;
}
解析
加载的时候,还没有真正的放在内存当中,按符号来记录。常量池内的符号引用,就像是你的小名,只有你的家人朋友会使用,适合小范围索引。直接引用为你具体的名字,在哪里都是通过用的,适合在大的范围当中索引。
一个是A类B类,相对位置表示,一个是经纬度表示。
仍然是处理静态代码块,而不是具体的实例。
在进行类加载的时候,因为这个机制,才能保证某个类在内存中只有一份Class对象。
再进行深入就是JVM的底层了
3.获取类的结构信息
第一组
7.不返回父类的构造器
第二组
第三组
第四组
api的代码
package com.hspaidu.reflection.qusetion;
import org.junit.Test;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
//演示如何通过Api获得类的结构信息。 如果你可以拿到一个类的Class对象,你基本上就可以得到该类所有的对象信息了
public class ReflectionUtils {
public static void main(String[] args) {
}
@Test
public void api_01() throws ClassNotFoundException, NoSuchMethodException {
// 得到Class的对象
Class<?> aClass = Class.forName("com.hspaidu.reflection.qusetion.Person");
// getName() 获得类的全类名
System.out.println(aClass.getName());
// getSimpleName() 获取简单类名
System.out.println(aClass.getSimpleName());
// getFields()获得所有的本类及父类的属性 只能达到公开的
Field[] fields = aClass.getFields();
for (Field field : fields) {
System.out.println("本类及父类的属性 = " + field.getName());
}
// getDeclaredFields() 公开的私有的都可以的到
Field[] declaredFields = aClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println("所有的详细的属性 = " + declaredField.getName());
}
// getMethods() 获得本类和父类的方法 只得到公开的 父类的父类也可以
Method[] methods = aClass.getMethods();
for (Method method : methods) {
System.out.println("父类及子类的方法名 = " + method.getName()); //得到的事公开的方法
}
// 获得本类当中所有的方法
Method[] declaredMethod = aClass.getDeclaredMethods();
for (Method method : declaredMethod) {
System.out.println("所有的方法 = " + method.getName());//只有类的
}
// getConstructors() 公开的 得到本类当中的构造方法
Constructor<?>[] constructor = aClass.getConstructors();
for (Constructor<?> constructor1 : constructor) {
System.out.println("本类及父类的构造方法" + constructor1);
}
// 得到本类所有的构造器名称,包括私有的
Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println("输出构造器的名字" + declaredConstructor.getName()); //这里只是输出名字
}
}
// 字段当中包含的方法
@Test
public void api_02() throws ClassNotFoundException {
Class<?> aClass = Class.forName("com.hspaidu.reflection.qusetion.Person");
// getDeclaredFields() 本类及父类的属性
Field[] declaredFields = aClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println("所有的详细的属性 = " + declaredField.getName() + "所有属性类型的值为 = " + declaredField.getModifiers()
+ "该属性的类型 = " + declaredField.getType());
}
// 获得本类当中所有的
Method[] declaredMethod = aClass.getDeclaredMethods();
for (Method method : declaredMethod) {
System.out.println("该方法的方法名 = " + method.getName() + "该方法修饰符的值为 = " + method.getModifiers()
+ "该方法的返回值类型 = " + method.getReturnType());//只有类的
// 获得所有方法的参数类型
Class<?>[] parameterTypes = method.getParameterTypes();
for (Class<?> parameterType : parameterTypes) {
System.out.println("参数类型为" + parameterType);
}
}
// 返回一个父类的全路径
System.out.println(aClass.getSuperclass());
// 获得接口的信息
Class<?>[] interfaces = aClass.getInterfaces();
for (Class<?> anInterface : interfaces) {
System.out.println("接口的信息 " + anInterface);
}
// 获得注解的信息
Annotation[] annotations = aClass.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println("注解信息 " + annotation);
}
Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println("构造方法的名字 "+declaredConstructor.getName());
Class<?>[] parameterTypes = declaredConstructor.getParameterTypes();
for (Class<?> parameterType : parameterTypes) {
System.out.println("改构造器的形参类型 "+parameterType);
}
}
}
}
class A {
public String hobby;
public void hi() {
}
}
interface IA {
}
interface IB {
}
@Deprecated
class Person extends A implements IA, IB {
// 不同访问权限的属性
public String name;
protected int age;
String job;
private static double sal;
public Person() {
}
public Person(int age) {
this.age = age;
}
public Person(int age, String job) {
this.age = age;
this.job = job;
}
// 不同访问权限的方法
public void m1(String name, String job, int age) {
}
private void m2() {
}
protected void m3() {
}
void m4() {
}
}
运行的结果 api_01
com.hspaidu.reflection.qusetion.Person
Person
本类及父类的属性 = name
本类及父类的属性 = hobby
所有的详细的属性 = name
所有的详细的属性 = age
所有的详细的属性 = job
所有的详细的属性 = sal
父类及子类的方法名 = m1
父类及子类的方法名 = hi
父类及子类的方法名 = wait
父类及子类的方法名 = wait
父类及子类的方法名 = wait
父类及子类的方法名 = equals
父类及子类的方法名 = toString
父类及子类的方法名 = hashCode
父类及子类的方法名 = getClass
父类及子类的方法名 = notify
父类及子类的方法名 = notifyAll
所有的方法 = m1
所有的方法 = m2
所有的方法 = m4
所有的方法 = m3
本类及父类的构造方法public com.hspaidu.reflection.qusetion.Person(int,java.lang.String)
本类及父类的构造方法public com.hspaidu.reflection.qusetion.Person(int)
本类及父类的构造方法public com.hspaidu.reflection.qusetion.Person()
输出构造器的名字com.hspaidu.reflection.qusetion.Person
输出构造器的名字com.hspaidu.reflection.qusetion.Person
输出构造器的名字com.hspaidu.reflection.qusetion.Person
运行的结果 api_02
所有的详细的属性 = name所有属性类型的值为 = 1该属性的类型 = class java.lang.String
所有的详细的属性 = age所有属性类型的值为 = 4该属性的类型 = int
所有的详细的属性 = job所有属性类型的值为 = 0该属性的类型 = class java.lang.String
所有的详细的属性 = sal所有属性类型的值为 = 10该属性的类型 = double
该方法的方法名 = m1该方法修饰符的值为 = 1该方法的返回值类型 = void
参数类型为class java.lang.String
参数类型为class java.lang.String
参数类型为int
该方法的方法名 = m2该方法修饰符的值为 = 2该方法的返回值类型 = void
该方法的方法名 = m4该方法修饰符的值为 = 0该方法的返回值类型 = void
该方法的方法名 = m3该方法修饰符的值为 = 4该方法的返回值类型 = void
class com.hspaidu.reflection.qusetion.A
接口的信息 interface com.hspaidu.reflection.qusetion.IA
接口的信息 interface com.hspaidu.reflection.qusetion.IB
注解信息 @java.lang.Deprecated()
构造方法的名字 com.hspaidu.reflection.qusetion.Person
改构造器的形参类型 int
改构造器的形参类型 class java.lang.String
构造方法的名字 com.hspaidu.reflection.qusetion.Person
改构造器的形参类型 int
构造方法的名字 com.hspaidu.reflection.qusetion.Person
4.反射爆破
案例
爆破创建实例
代码
package com.hspaidu.reflection.qusetion;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class ReflectCreateInstance {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
// 得到Class对象
Class<?> aClass = Class.forName("com.hspaidu.reflection.qusetion.User");
//调用的是无参的构造器 创建实例
Object o = aClass.newInstance();
System.out.println(o);
//调用的是带有一个参数的构造器 getConstructor创建的是公开的构造器方法
Constructor<?> constructor = aClass.getConstructor(String.class);
// 先得到相应的构造器,再传入相应的实参
Object hsp = constructor.newInstance("hsp");
System.out.println("hsp = "+hsp);
//得到私有的构造器对象
Constructor<?> constructor1 = aClass.getDeclaredConstructor(int.class,String.class);
// 进行爆破访问私有的构造器 可以访问私有的构造方法 在反射面前一切都是纸老虎,留的一个后门
constructor1.setAccessible(true);
Object xiaowang = constructor1.newInstance(100, "小王");
//破坏了数据的封装性
System.out.println(xiaowang);
}
}
class User{
private int age = 20;
private String name = "韩顺平教育";
public User(){}
public User(String name) {
this.name = name;
} //public的有参构造器
private User(int age, String name) { //private的有参构造器
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "User{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
运行结果
User{age=20, name='韩顺平教育'}
hsp = User{age=20, name='hsp'}
User{age=100, name='小王'}
访问对象的成员
代码
package com.hspaidu.reflection.qusetion;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public class ReflectAccessProperty {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException, NoSuchMethodException {
// 得到类对应的Class对象
Class<?> aClass = Class.forName("com.hspaidu.reflection.qusetion.Student");
Object o = aClass.newInstance();
System.out.println(o.getClass());
// 创建字段对象
Field age = aClass.getField("age");
age.set(o,88); //通过反射来得到他的属性
System.out.println(o);
System.out.println(age.get(o));
// 操作私有的静态属性
Field name = aClass.getDeclaredField("name");
// 进行强制爆破,操纵私有的属性
name.setAccessible(true);
name.set(null,"老汉"); //因为name是静态的所以可以是null,算是所有对象的
System.out.println(o);
System.out.println(name.get(null));
}
}
class Student{
public int age;
private static String name;
public Student(){}
@Override
public String toString() {
return "Student{" +
"age=" + age +" name = "+name+
'}';
}
}
运行结果
class com.hspaidu.reflection.qusetion.Student
Student{age=88 name = null}
88
Student{age=88 name = 老汉}
老汉
访问方法
代码
package com.hspaidu.reflection.qusetion;
import javax.print.DocFlavor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ReflectAccessMethod {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
// 得到Class
Class<?> aClass = Class.forName("com.hspaidu.reflection.qusetion.Boos");
// 创建对象
Object o = aClass.newInstance();
// 得到方法的对象
Method hi = aClass.getMethod("hi",String.class);
// 调用方法
hi.invoke(o,"韩顺平将java");
// 方法的属性当中并没有定义方法返回值的类型 可以拿到私有的方法
Method say = aClass.getDeclaredMethod("say", int.class, String.class, char.class);
// 这样就可以操作私有的方法了
say.setAccessible(true);
System.out.println(say.invoke(o,100,"小明",'A'));
System.out.println(say.invoke(o,200,"李四",'B'));
// 在编译阶段是Object 在返回的时候运行类型为String 接受的时候不知道的 编译的时候才判定
Object invoke = say.invoke(o, 200, "李四", 'B');
System.out.println(invoke.getClass());
}
}
class Boos{
public int age;
private static String name;
public Boos() {
}
private static String say(int n,String s,char c){
return n+" "+s+" "+c;
}
public void hi(String s){
System.out.println("hi"+s);
}
}
结果
hi韩顺平将java
100 小明 A
200 李四 B
class java.lang.String
五。课后的作业
1.课后作业1
代码
package com.hspaidu.homework;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class HomeWork01 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
// 得到类对应的Class对象
Class<?> aClass = Class.forName("com.hspaidu.homework.PrivateTest");
// 创建一个对象的实例
Object o = aClass.newInstance();
// 创建一个私有字段的实例
Field name = aClass.getDeclaredField("name");
// 进行爆破
name.setAccessible(true);
// 修改私有属性的值
name.set(o,"中国");
// System.out.println(o);
// 得到私有方法的对象
Method getName = aClass.getDeclaredMethod("getName");
// 直接调用方法
System.out.println("name属性的值 "+getName.invoke(o));
}
}
class PrivateTest{
private String name = "弯弯";
public String getName(){
return name;
}
@Override
public String toString() {
return "PrivateTest{" +
"name='" + name + '\'' +
'}';
}
}
结果
中国
2.课后作业2
代码
package com.hspaidu.homework;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class HomeWork02 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
// 得到file类对象
Class<?> aClass = Class.forName("java.io.File");
// 得到所有的构造方法
Constructor<?>[] declaredConstructor = aClass.getDeclaredConstructors();
for (Constructor<?> constructor : declaredConstructor) {
System.out.println("File的构造器"+constructor);
}
// 得到形参为string的构造器
Constructor<?> declaredConstructor1 = aClass.getDeclaredConstructor(String.class);
// 写入文件的地址
String fileAllPath = "d:\\mynew.txt";
// 创建文件对象 这是一个返回值 还在内存当中
Object file = declaredConstructor1.newInstance(fileAllPath);
// 得到方法的对象
Method createNewFile = aClass.getMethod("createNewFile");
createNewFile.invoke(file);//引用文件创建方法
System.out.println(file.getClass());
System.out.println("创建文件成功 "+ fileAllPath);
}
}
运行结果
File的构造器public java.io.File(java.lang.String,java.lang.String)
File的构造器public java.io.File(java.lang.String)
File的构造器private java.io.File(java.lang.String,java.io.File)
File的构造器public java.io.File(java.io.File,java.lang.String)
File的构造器public java.io.File(java.net.URI)
File的构造器private java.io.File(java.lang.String,int)
class java.io.File
创建文件成功 d:\mynew.txt
四。其他知识点
反射在泛型当中的应用
代码
package com.map_;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
List<Integer> list = new ArrayList<>();
list.add(12);
Method method = list.getClass().getDeclaredMethod("add", Object.class);
method.invoke(list, "abc");
System.out.println(list);
}
}
运行结果
[12, abc]