0.1java反射机制概述
反射被视为动态语言的关键,反射机制允许程序在运行期借助反射API取得类的内部信息,并能直接操作对象的内部属性及方法。
反射相关的主要API:
java.lang.Class:代表一个类
java.lang.reflect.Method:代表类的方法
java.lang.reflect.Field:代表类的成员变量
java.lang.reflect.Constructor:代表类的构造器
不使用反射,对于Person类的操作:
//1.创建Person类的对象
Person p1=new Person("Tom",12)
//2.通过对象,调用其内部的属性、方法
p1.age=10;
pl.show()
//在Person类外部,不可以通过Person类的对象调用其内部私有结构
使用反射之后,对于Person类的操作:
Class clazz=Person.class;
//1.通过反射创建Person类的对象
Constructor cons=class.getConstructor(String.class,int.class); //--------------
Object obj=cons.newInstance("Tom",12); //Object本质上还是Person
Person p=(Person) obj;
//2.通过反射,调用对象指定的属性、方法
//调属性
Field age=clazz.getDeclaredField("age"); //age是属性名 ------------------
age.set(p,10);
//调方法
Method show=clazz.getDeclaredMethod("show"); //show是方法名 --------------
show.invoke(p);
//通过反射,可以调用Person类的私有结构。私有构造器、方法、属性
//私有构造器
Constructor cons1=clazz.getDeclaredConstructor(String.class); //------------------
cons1.setAccessible(true);
Object obj1=cons1.newInstance("jerry");
Person p1=(Person)obj1;
//私有属性
Field name=clazz.getDeclaredField("name"); //属性名 --------------------
name.setAccessible(true);
name.set(p1,"HanMeimei");
//私有方法
Method showNation=clazz.getDeclaredMethod("showNation",String.class); //方法名,第一个参数是对应的类型 --------------
showNation.setAccessible(true);
String nation=(String)showNation.invoke(p1,"中国"); nation就是该Person类的showNation()的返回值
0.2理解Class类并获取Class实例
1.类的加载过程:
(1)程序经过javac.exe命令以后,会生成一个或多个字节码文件(.class结尾)。接着我们使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中。此过程就称为类的加载。
(2)加载到内存中的类,我们就称为运行时类,此运行时类,就作为Class的一个实例。我们可以通过不同的方式来获取此运行时类
2.获取Cass实例的4种方式
方式一:通过运行时类的class属性
Class<Person> c1=Person.class;
方式二:通过运行时类对象的getClass()
Person p1=new Person();
Class c2=p1.getClass(); //所有对象都有这个方法,因为这个方法是Object的
方式三:调用Class的forName(String classPath)
Class c3=Class.forName("com.atguigu.java.Person");
方式四:使用当前类的加载器ClassLoader
ClassLoader classLoader=当前类.class.getClassLoader();
Class c4=classLoader.loadClass("com.atguigu.java.Person");
0.3创建运行时类的对象
使用newInstance():调用此方法,会创建对应的运行时类的对象,内部调用无参构造器,该构造器不能是私有的,通常为public
Class lazz = Person.class;
Person obj = (Person)clazz.newInstance();
说明:在javabean中要求提供一个public的无参构造器。原因:
1.便于通过反射,创建运行时类的对象
2.便于子类实例化时,会默认调用父类的无参构造器
0.4调用运行时类的指定结构
1.调用运行时类的属性(getField()、getDeclaredField())
Class clazz=Person.class;
Person p=(Person)clazz.newInstance();
Field id=clazz.getField("id"); //id属性名,该方法获取的属性必须为public
Field age=clazz.getDeclaredField("age");//age属性名,该方法可以获取私有的属性
id.setAccessible(true); //表示当前属性是可访问的。set私有属性前必须使用该方法
id.set(p,1001); //设置id的值。参数1:要设置哪个对象的id属性;参数2:将此id属性值设置为多少。对于静态属性,参数1就为Person.class或null
id.get(p); //获取id的值。参数1:获取哪个对象的id属性
2.调用运行时类的方法(getDeclaredMethod())
Class clazz=Person.class;
Person p=(Person)clazz.newInstance();
Method show=clazz.getDeclaredMethod("show",String.class);//show方法名,参数2指明获取的方法参数形参列表。可以获取私有方法
show.setAccessible(true); //表示当前方法是可访问的。执行私有方法前必须使用该方法
Object obj=show.invoke(p,"Tom"); //执行方法。参数1:执行哪个对象的show方法,参数2:根据上面的形参列表类型赋值。invoke()的返回值即为show()方法的返回值,可以强转
//如果invoke()要执行的是静态方法,那么参数就为Person.class或null
3.调用运行时类的构造器
Class clazz=Person.class;
Constructor constructor=clazz.getDeclaredConstructor(String.class); //形参列表
constructor.setAccessible(true); //表示当前构造器是可访问的。执行私有构造器前必须使用该方法
Person per=(Person)constructor.newInstance("Tom");//根据上面的形参列表赋值
//或
Person p=(Person)clazz.newInstance(); //内部会调用无参构造器