反射:
程序运行过程中,可以获取到类的构造方法,成员变量(包括私有的)方法,对象使用类成员,我们把获取类成员和对象调用类成员机制,叫反射。
Class:封装了大量的方法,通过方法可以获取到构造方法,方法,成员变量
Class类的对象——.class文件 只加载一次 唯一的标识:包名.类名
获取Class类的对象3种方法:
-
对象.getClass()
-
类名.class
-
forName(“包名.类名”)
//获取Class类的对象3种方法
public static void test1() throws ClassNotFoundException {
//通过 对象.getClass()
Class<? extends Student> clazz=new Student().getClass();
//通过 类名.class
Class<Student> clazz1=Student.class;
System.out.println(clazz==clazz1);
//forame(”包名+类名“)
Class clazz3=Class.forName("day_18.Student");
System.out.println(clazz==clazz3);
}
结果:
true
true
由上面的运行结果可以看出,内存中加载的字节码文件只有一个,所以获取的Class对象都是同一个。
获取和使用构造方法:
//获取和使用构造方法
public static void test2() {
Class<Student> clazz1=Student.class;
@SuppressWarnings("rawtypes")
Constructor[] constructors=clazz1.getDeclaredConstructors();
for(Constructor<?> construct : constructors) {
//1 - public
//获取访问修饰符
System.out.println(construct.getModifiers()+"->"+Modifier.toString(construct.getModifiers()));
System.out.println(construct.getName());
//返回参数列表的Class类型的数组
Class[] pClazz=construct.getParameterTypes();
for(Class c:pClazz) {
System.out.println(c.getName());
}
System.out.println("=============");
}
}
public class Student {
public String name;
private int age;
public Student() {
}
public Student(String name) {
this.name=name;
}
private Student(String name,int age) {//String.class,Integer.class
this.name=name;
this.age=age;
}
public void eat(String food) {
System.out.println(name+"吃"+food);
}
public void sleep() {
System.out.println("睡觉");
}
private int getAge() {
return age;
}
private void setAge() {
this.age=age;
}
}
结果:
2->private
day_18.Student
java.lang.String
int
=============
1->public
day_18.Student
java.lang.String
=============
1->public
day_18.Student
=============
获取无参的构造方法,创建对象:
//获取无参的构造方法,创建对象
public static void test2_1() throws Exception {
Class clazz=Student.class;
//得到无参的构造方法对象
//Constructor con=clazz.getDeclaredConstructor();
//使用无参构造方法的对象创建对象
//Student stu=(Student) con.newInstance();//new Student();
//调用无参的构造方法创建对象,不用获取Constructor对象,可以使用下面的
//方式直接由Class类型的对象调用
Student stu=(Student) clazz.newInstance();
stu.name="张三";
stu.eat("饺子");
}
结果:
张三吃饺子
获取带参的构造方法,创建对象
//获取带参的构造方法,创建对象
public static void test2_2() throws Exception {
Class<Student> clazz=Student.class;
//获取带String类型参数的构造方法的对象
Constructor construct=clazz.getDeclaredConstructor(new Class[]{String.class});
//使用构造方法创建对象
Student stu =(Student) construct.newInstance(new Object[]{"李四"});
stu.eat("芒果");
}
//获取私有带参的构造方法,创建对象
public static void test2_3() throws Exception {
Class<Student> clazz=Student.class;
//获取带2个参数的构造方法的对象
Constructor construct=clazz.getDeclaredConstructor(new Class[]{String.class,int.class});
//设置私有的构造方法的可访问性
construct.setAccessible(true);
//使用构造方法创建对象
Student stu =(Student) construct.newInstance(new Object[]{"李四",18});
stu.eat("芒果");
}
李四吃芒果
工具方法
Method[] getDeclaredMethods();获取本类的所有的方法
Method[] getMethods():获取非私有的方法(父类)
获取和使用功能方法(返回的是非私有的方法)
//getDeclaredMethods获取本类的方法
//getMethods()获取本类及父类的非私有的方法
public static void test3(){
Class<Student> clazz = Student.class;
//Method[] methods = clazz.getDeclaredMethods();
//getDeclaredMethods()获取本类的所有方法
Method[] methods = clazz.getMethods();
for(Method m : methods){
System.out.println(m.getName());
System.out.println(m.getReturnType());
System.out.println("=======================");
}
}
public static void test3_1() throws Exception{
Class<Student> clazz = Student.class;
Student stu = clazz.newInstance();
//获取sleep方法对象(无参)
Method method = clazz.getDeclaredMethod("sleep");
//使用方法
method.invoke(stu);//stu.sleep();
//练习:获取eat方法,并调用(有参)
Method methodEat = clazz.getDeclaredMethod("eat",
new Class[]{String.class});
methodEat.invoke(stu,new Object[]{"馒头"});
// 获取setAge/getAge方法并调用(私有)
Method methodSet = clazz.getDeclaredMethod("setAge",
new Class[]{int.class});
methodSet.setAccessible(true);
methodSet.invoke(stu,new Object[]{18});
Method methodGet = clazz.getDeclaredMethod("getAge");
methodGet.setAccessible(true);
System.out.println(methodGet.invoke(stu));
}
获取和使用成员变量
//4.获取和使用成员变量
public static void test4() throws Exception{
Class<Student> clazz = Student.class;
Student stu = clazz.newInstance();
Field[] fields = clazz.getDeclaredFields();
for(Field f : fields){
System.out.println(f.getName());
}
}
public static void test4_1()throws Exception{
Class<Student> clazz = Student.class;
Student stu = clazz.newInstance();
Field field = clazz.getDeclaredField("name");
field.set(stu, "王五");//stu.name = "wangwu"
System.out.println(field.get(stu)); //stu.name
//练习:age成员变量赋值(私有)
Field f2=clazz.getDeclaredField("age");
f2.setAccessible(true);
f2.set(stu, 12);
System.out.println(f2.get(stu));
}
练习:
public class GJC {
public void zuo() {
System.out.println("看风景");
}
}
public class DDC {
public void qi() {
System.out.println("兜风hhhhh");
}
}
test.properties
className=day_18.GJC
methodName=zuo
Properties p=new Properties();
p.load(new FileInputStream("test.properties"));
String className=p.getProperty("className");
String methodName=p.getProperty("methodName");
Class clazz=Class.forName(className);
Object obj=clazz.newInstance();
Method method=clazz.getDeclaredMethod(methodName);
method.invoke(obj);