反射是什么? 是指在程序运行期间,可以动态创建对象。
(1)获得字节码文件对象的三种方法
为什么要获取字节码文件对象,只有这样,才能通过字节码文件对象去创建类的对象,而不是用new,这样方便了程序的修改。直接修改配置文件,便可以更改创建的类。
1.Object类的getclass()方法:同一个类的字节码只被加载一次
2.类.class:任何一个类在生成的.class文件中,会产生一个Class对象,用于表示这个类的类型信息
3.Class.forName(类名):注意类名的写法应该是全路径,包括包名
package demo;
public class test {
public static void main(String[] args) throws ClassNotFoundException {
//1.Object类的getclass() 通过同一个类创建的字节码文件是一样的,只被加载一次
Person p1 = new Person();
Person p2 = new Person();
Class class1= p1.getClass();
Class class2= p2.getClass();
System.out.println(class1);
System.out.println(class2);
System.out.println(class1==class2);
//2.类名.class对象
Class class3= Person.class;
System.out.println(class2==class3);
//3.类型名.forName()
Class class4= Class.forName("demo.Person");//注意是包名.类名
System.out.println(class3==class4);
//结果是:
class demo.Person
class demo.Person
true
true
true
(2)字节码文件对象里面有什么
类 | 字节码文件对象 |
---|---|
构造方法 | 构造方法对象(类型为constructor) |
成员变量 | 成员变量对象(类型为filed) |
成员函数 | 成员函数对象(类型为method) |
(3)用字节码文件对象来创建一个类的对象
------------------------------------------------Person2.java
package demo;
public class Person2 {
public Person2(){};//类的构造方法1
public Person2(String name,int age){//类的构造方法2
super();
this.name=name;
this.age=age;
}
private String name;
private int age;
public void eat(){
System.out.println("吃吃吃222");
}
}
------------------------------------------------test.java
package demo;
public class test {
public static void main(String[] args) {
// Person p=new Person(); 这是传统的创建对象的方法
//读取配置文件中类的信息,想创建什么类就创建什么,可在外部配置文件中修改
FileReader f=new FileReader("aa.txt");
BufferedReader br=new BufferedReader(f);
String str=br.readLine();
System.out.println(str);
//--------------第一步:用Class.forName()来创建字节码文件对象
Class clazz=Class.forName(str);
//--------------第二步:获取类中的构造器对象
//获得Person类的构造方法,用Constructor数组来存储一共有几个(只能得到public的构造方法)
Constructor[] constructors =clazz.getConstructors();
System.out.println(constructors.length);
System.out.println(constructors[0]);//输出构造方法1
System.out.println(constructors[1]);//输出构造方法2
//--------------第三步:选择其中一个,用newInstance()来创建对象
Constructor c=constructors[0];
//返回的是Object类型,再进行类型转换
Object obj=c.newInstance();
//相当于创建了一个Person2类的对象 a ,不是以前传统的用new创建的
Person2 a=(Person2) obj;
a.eat();
}
}
//结果为:2
public demo.Person2()
public demo.Person2(java.lang.String,int)
吃吃吃222
(4)得到字节码文件对象中的成员方法对象Method
1.获取字节码文件对象
2.得到某个特定的方法 【要知道方法名+形参】
3.创建对象【调用的传统方法是对象.方法(对象),但反射里面是:方法.invoke(对象,实参)】
4.反射调用
package demo;
public class Person2 {
Person2(String name){//类的构造方法3
super();
this.name=name;
}
private String name;
public void setName(String name) {
this.name = name;
System.out.println(name);
}
}
package demo;
//-----------------------得到字节码中的成员方法对象 Method
public class test2 {
public static void main(String[] args) {
//--------------第一步:得到字节码文件对象
Class clazz=Class.forName("demo.Person2");
//Method[] methods= clazz.getMethods();//父类继承下来的+自身的+public,才可以显示出来
//增强型的for循环。Method是元素类型,method是每一个元素变量,methods是你要遍历的数组
//for(Method method:methods)
//System.out.println(method);
//--------------第二步:得到特定的方法 要知道方法名+形参。
Method method=clazz.getMethod("setName",String.class);
System.out.println(method);
// Constructor constructor=clazz.getConstructor(); 传统方法是用构造器去创建实例
//Object newInstance=constructor.newInstance();
//--------------第三步:创建方法所在类的对象,是更便捷的方法,但只针对无参数
Object newInstance=clazz.newInstance();
//--------------第四步:反射调用
Object a=method.invoke(newInstance,"haha");
}
}
//结果是:public void demo.Person2.setName(java.lang.String)
haha