反射技术中,最重要的一点:先获取到那个类。如何获取那个类呢?这是最重要的一步操作。
反射技术:动态的获取类以及类中的成员,并可以调用该类成员,以前是有什么类,就new什么类,现在是没有类,给什么类就new什么对象。
无论new 什么对象,都需要先获取字节码文件,如何获取呢?发现java已对字节码文件进行了描述,用的是Class类完成的(首字母大写)。
每一个class文件都有可能生产一个Class对象,可以这么去理解:一个Person类,可以new出很多人,例如person1, person2等等,这里一个class类就好比是一个人,Class好比是Person类。
反射里最常用的找类方法:通过给定的类名称,找到对应的类
但是获取名称肯定还还不够,如何通过找到的这个类建立它的对象呢?
问题来了:如果构造方法中没有空参数怎么办呢?例如:public Person(String Name, Int age){ …… }
反射技术:动态的获取类以及类中的成员,并可以调用该类成员,以前是有什么类,就new什么类,现在是没有类,给什么类就new什么对象。
无论new 什么对象,都需要先获取字节码文件,如何获取呢?发现java已对字节码文件进行了描述,用的是Class类完成的(首字母大写)。
每一个class文件都有可能生产一个Class对象,可以这么去理解:一个Person类,可以new出很多人,例如person1, person2等等,这里一个class类就好比是一个人,Class好比是Person类。
如何获取一个字节码文字的对象呢?
1、假设存在一个Person类,以获取Person类为例
public class Person{
String Name = "";
Int age = "";
public Person(){
System.out.println("this is person");
}
}
2、主函数调用一个获取类名称的方法
public class refectDemo{
public static void main(String args[]){
method();
}
}
3、获取类的操作如下
反射里最常用的找类方法:通过给定的类名称,找到对应的类
public static void method() throws ClassNotFoundException{
String className ="";
Class clazz = Class.forName(className);
System.out.println(clazz);
}
forName方法:通过给定的类名,找到对应的类,找到之后自动加载这个类进内存。例如传入类名:com.study.Person ,找到对应的com.study.Person.class文件,加载并封装成一个Class对象。
但是获取名称肯定还还不够,如何通过找到的这个类建立它的对象呢?
public class ReflectDemo2{
public static void main(String args[]){
getObject();
}
public staic void getObject() throws ClassNotFoundException{
//1、根据给定的类名获取大Class对象
String className = "com.study.Person";
Class clazz = class.forName(className);
<strong><span style="color:#ff0000;">Object obj = clazz.newInstance();</span></strong>
<span style="color:#ff0000;"><strong>//动态创建一个Person对象,默认调用其空参数构造方法
//不能使用 Person p = new Person()方法,因为不知道具体的类是什么
常见异常:java.lang.InstantiationException: 没有调用与之对应的构造函数
记住:一般被反射的类通常都有空参数的构造方法</strong></span>
}
}
这时候可以看到会自动调用Person里的无参构造方法,输出一串字符: this is a person
问题来了:如果构造方法中没有空参数怎么办呢?例如:public Person(String Name, Int age){ …… }
需求:万一给定类中没有空参数呢?可以先获取指定的构造函数,再通过该构造函数进行实例化。
1、通过大Class获取指定的构造函数:class 文件中的构造函数,也被封装成一个对象,万物皆对象。
Constructor cons = clazz.getConstructor(String.class,int.class);这里传入的是类型对象
2、通过指定的构造器对象进行对象的初始化
Object obj = cons.newInstances("lisi",23);
public static void getObject2()throws ClassNotFoundException{
String className = "com.study.Person";
Class clazz = calss.forName(className);
Constructor cons = clazz.getConstrctor(String.class, int.class);
Object obj = cons.newInstances("lisi",23);
}
反射技术,可以简单的理解成对类的解剖,通过得到了类,可以想拿啥就拿啥。
4、获取类的字段
例如获取类中的age属性,并对其操作
public static void getFileDemo() throws Exception{
String className = "com.study.Person";
Class clazz = Class.forName(className);
//获取指定的age字段
//Field field = clazz.getField("age");该方法只获取公有的
Filed field = clazz.getDeclaredField("age");
//要对非静态的字段操作必须有对象
Object obj = clazz.newInstance();
//使用父类的方法,将访问权限检查能力取消(如果定义的private,就不能访问)
field.setAccessible(true);//暴力访问私有
field.set(obj, 40);
system.out.println(field.get(obj));
}
//反射方法,非静态,无参数
public static void getMethodDemo() throws Exception{
String className = "com.study.Person";
Class clazz = Class.forName(className);
Method method = clazz.getMethod("show",null);//show是方法名
Object obj = clazz.newInstance();
method.invoke(obj,null);
}
//反射方法,静态,无参数
public static void getMethodDemo2 thorws Exception{
String className = "com.study.Person";
Class clazz = Class.forName(className);
Method method = clazz.getMethod("staticshow",null);
//静态方法不需要对象也可以调用
nethod.invoke(null,null);
}
//反射方法:非静态,有参数
public static void getMethodDemo3 throws Exception{
String className = "com.study.Person";
Class clazz = Class.forName(className);
Method method = clazz.getMethod("show2", String.class,int.class);
//上行代码的意思是,我要反射的是show2方法,携带的是String 和int两个类型的参数
Object obj = clazz.newInstance();
method.invoke(obj,"小强",20);
}