反射
反射的基石:Clasee类
- JAVA程序中的各个Java类属于同一类事物,描述这类事物的Java类名即使Class 。
- 一个Java被加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,不同的类字节码不相同,所以他们在内存中的内容是不相同的,这一个个的空间分别用一个Class对象来表示,这些对象显然具有相同的类型,这个类型就是Class。
- 如何得到一个字节码对应的实例对象
类名.class ,例如System.class.
对象.getClass() ,例如:new Date().getClass() .
Class.forName("类的完整名称,加包名") , 例如:Class.forName("java.util.Date") 。
- 九个预定义Class对象:8个基本数据类型,和void。
public class ReflectTest {
public static void main(String[] args)throws Exception {
String srt = "abc" ;
//Class对象的第一种获取方法:类名.calss
Class class1 = String.class;
//Class对象的第二种获取方法:对象.getClass();
Class class2 = srt.getClass();
//Class对象的第三种获取方法:Class.forName();
//class的获得过程:当虚拟机中还没有这个对象的字节码时,通过类加载器从文件中加载,并缓存起来。
//当再次来去这个对象的字节码时直接返回,缓存起来的字节码对象。
Class class3 = Class.forName("java.lang.String");
//类的字节码只有一份,所以都想等
System.out.println(class1==class2);
System.out.println(class1==class3);
System.out.println(class1.isPrimitive());
System.out.println(int.class.isPrimitive());
//int的字节码是预定义的,integer是包装类,不相等。
System.out.println(int.class==Integer.class);
//Integer.TYPE是返回的int类型,所以相等。
System.out.println(int.class==Integer.TYPE);
}
}
反射就是将Java类中的各种成分映射成相应的java类。例如,类中的组成成分:成员变量、构造方法、方法、包信息等分别对应Field、Constructor、Method、Package等。
Constructor类
- Constructor类代表某个类中的构造方法
- 一个类中的构造方法可能有很多,我们可以根据参数列表进行区分。
- 得到某个类中的构造方法:根据参数类型进行区分。将参数类型的字节码传进去,就可以得到相应的方法。
public class ReflactTest2 {
public static void main(String[] args)throws Exception {
Class c =Class.forName("Person");
//调用默认的构造函数
Person p = (Person)c.newInstance();
//默认的构造方法,参数为空
Constructor cons = c.getConstructor(null);
Person p1 =(Person)cons.newInstance();
//通过参数类型,获得一个构造方法对象
//调用构造方法对象的newInstance()方法,将实际参数传递进去
Constructor cons2 = c.getConstructor(String.class,int.class) ;
Person p2 =(Person)cons2.newInstance("andy",12);
}
}
class Person{
private int age ;
private String name ;
public Person(){
System.out.println("Person run.."+this.name+":"+this.age);
}
public Person(String name,int age){
this.age = age ;
this.name = name ;
System.out.println("Person run.."+this.name+":"+this.age);
}
}
Field类
- Field类代表了某个类中的属性
- 通过属性名字来区分。
public class ReflactTest2 {
public static void main(String[] args)throws Exception {
Class c =Class.forName("Person");
//调用默认的构造函数
Person p = (Person)c.newInstance();
//获得Field对象,是属于字节码的。对于private的属性要使用getDeclaredFile才可以看见。
Field age = c.getDeclaredField("age");
//对于private的变量,要通过下面的方法暴力反射才可以修改
age.setAccessible(true);
//调用Field对象的set方法设置具体person对象的age
age.set(p, 10);
Field name = c.getDeclaredField("name");
name.setAccessible(true);
name.set(p, "zhangsan");
//不是private的属性使用getField就可以拿到。
Field address = c.getField("address");
address.set(p, "beijing");
System.out.println(p.toString());
}
}
class Person{
private int age ;
private String name ;
public String address;<pre name="code" class="java">class Person{
private int age ;
private String name ;
public String address;
public Person(){
System.out.println("Person run.."+this.name+":"+this.age);
}
public void show(){
System.out.println("Pserson show ...");
}
public void show(String p){
System.out.println("Pserson show ..."+"String:"+p);
}
private void show(int i){
System.out.println("private method show ..."+"String:"+i);
}
}
Method类
- Method类代表某个类中的一个成员方法
- 要得到一个方法,要知道方法名和参数类型,还有类的字节码
public class Reflact3 {
public static void main(String[] args)throws Exception{
Class c = Class.forName("Person");
Object p = c.newInstance();
//获得一个方法要 方法名、方法的参数列表
Method m1 = c.getMethod("show", null);
m1.invoke(p, args);
Method m2 = c.getMethod("show", String.class);
m2.invoke(p, "nihao");
//私有方法直接使用getMethos获取会报java.lang.NoSuchMethodException:
//
Method m3 = c.getDeclaredMethod("show", int.class) ;
//不设置accessible为true会报下面的错误。
//can not access a member of class Person with modifiers "private"
m3.setAccessible(true);
m3.invoke(p, 1) ;
}
}
Peson类:
class Person{
private int age ;
private String name ;
public String address;
public Person(){
System.out.println("Person run.."+this.name+":"+this.age);
}
public void show(){
System.out.println("Pserson show ...");
}
public void show(String p){
System.out.println("Pserson show ..."+"String:"+p);
}
private void show(int i){
System.out.println("private method show ..."+"String:"+i);
}
}
反射的作用:实现框架功能
- java框架就是一些类和接口的集合,通过这些类和接口协调来完成一系列的程序实现。
- 框架在开发时,无法知道后来开发要调用的类名,所以无法直接通过new某个对象,而是通过反射来创建对象。
public class ReflactTest {
public static void main(String[] args)throws Exception {
//加载配置文件
Properties proper = new Properties();
InputStream is = new FileInputStream("G:\\eclipse\\Reflect\\src\\init.property");
proper.load(is);
//拿到配置文件中,对应的类名
String soundcard = proper.getProperty("soundCard");
String netcard = proper.getProperty("netCard") ;
//根据上面的类名,通过反射获得类的对象
pci p1 = (pci)Class.forName(soundcard).newInstance();
pci p2 = (pci)Class.forName(netcard).newInstance() ;
//调用对象的方法
p1.run();
p2.run();
}
}
class SoundCart implements pci{
public void start(){
System.out.println("Sound is start");
}
public void close(){
System.out.println("Sound is close");
}
public void run(){
start();
close();
}
}
class netCard implements pci{
@Override
public void start() {
System.out.println("netCard is start");
}
@Override
public void close() {
System.out.println("netCard is start");
}
public void run(){
start();
close();
}
}