反射机制:动态获取类中的信息。可以理解为对类的解剖

(104)反射:获取Class的对象、构造函数、字段、方法。反射实例练习_配置文件

在一个已经做好的应用程序中,没有源码,只有对外提供的接口,所以不能创建新的对象。

在反射机制中,只要实现接口,然后在配置文件中写注明该类,在应用程序中就能自动加载

(104)反射:获取Class的对象、构造函数、字段、方法。反射实例练习_配置文件_02

一、获取Class对象的方式:

方式1,Object类中的getClass()方法,想要用这种方式,必须要明确具体的类,并创建对象

        car c=new car();
Class clazz=c.getClass();
car c1=new car();
Class clazz=c1.getClass();

Class clazz1=c1.getClass();//返回运行时类
System.out.println(clazz1==clazz);//true


方式2,任何数据类型都具有一个静态的属性:.class来获取其对应的Class对象(相对简单,但是还要明确类中用到的静态成员,不够扩展)

        Class clazz=car.class;
Class clazz1=car.class;
System.out.println(clazz1==clazz);//true


方式3,只要通过给定的类的字符串名称就可以获取该类,扩展性强

可以用Class类中方法来完成:forName,只要指定名称即可

        String className="com.Car.car";//必须指定包名的类,
Class clazz=Class.forName(className);//该方法抛异常
System.out.println(clazz);


二、获取Class中的构造函数

       //早期:new 时,先根据被new的类的名称找到该类的字节码文件,加载进内存并创建该字节码文件对象,然后创建该字节码文件对应的person对象
//com.Car.person p=new com.Car.person();
//现在:
String className="com.Car.person";
Class clazz=Class.forName(className);//获取到了class字节码文件对象
//Object obj=clazz.newInstance(); //创建该字节码文件对应的person对象,获取的是无参的构造函数对应的对象
Constructor constructor=clazz.getConstructor(String.class,int.class);//创建该字节码对应的person对象,获取含参的构造函数对象
//通过该构造器的newInstance创建person对象含参的实例
constructor.newInstance("张三",15);


三、获取Class中的字段

//创建对象
Class clazz=Class.forName("com.Car.person");
Object obj=clazz.newInstance();

//获取公共字段
Field f=clazz.getField("sex");//只能获取公共字段
System.out.println(f);//public java.lang.String com.Car.person.sex
//获取指定字段属性的值
Object objField=f.get(obj);
System.out.println(objField);

//获取任Object何权限的字段
Field f1=clazz.getDeclaredField("age");
System.out.println(f1);//private int com.Car.person.age
//获取特定对象的该字段值
//Object objField1=f1.get(obj);//java.lang.IllegalAccessException私有字段,不能访问java.lang.IllegalAccessException

//若非要访问,则可以通过父类继承过来的方法,对私有字段的访问权限取消检查(暴力访问)
f1.setAccessible(true);
Object objField1=f1.get(obj);
System.out.println(objField);

//设置字段的值
f1.set(obj, 60);//在指定对象上字段设置值
System.out.println(f1.get(obj));


四、获取Class中的方法

Class clazz=Class.forName("com.Car.person");
//Object obj=clazz.newInstance();
//获取包括父类的所有公共方法
Method [] method=clazz.getMethods();
for(Method m:method)
{
//System.out.println(m);
}

//获取本类中写的所有方法,不包含父类继承
Method[] method1=clazz.getDeclaredMethods();
for(Method m:method1)
{
//System.out.println(m);
}


//获取一个方法(无参)
Method method2=clazz.getMethod("run", null);
//System.out.println(method2);//public void com.Car.person.run()
//想要让run中的值是某个对象的值
Constructor construct=clazz.getConstructor(String.class,int.class);
Object obj=construct.newInstance("小强",20);

//想要运行这个方法
method2.invoke(obj, null);//没返回值,直接在方法中输出了

//获取一个方法含参
Method method3=clazz.getMethod("show", int.class,int.class);
method3.invoke(obj,80,63);


五、反射练习

在主板中可以有声卡等插件,在以前的学习中的做法是如下这样的:

package com.Car1;
public class mainBoard {

public void run()
{
System.out.println("main.......run");
}
public void useSoundCard(soundCard sc)
{
sc.open();
sc.close();
}

public static void main(String[] args) {

mainBoard mb=new mainBoard();
mb.useSoundCard(new soundCard());
//这样做法的坏处就是要加网卡的话,还要修改网卡的代码,扩展性差

}
}

package com.Car1;

public class soundCard {

public void open()
{
System.out.println("sound...open");
}
public void close()
{
System.out.println("sound...close");
}
}


利用反射实现:

1)主板可以插入声卡网卡等,声卡等要实现个接口(PCI),这个接口是和主板关联的,比如主板中有public void usePCI(PCI p)方法,那么这个方法就能实现PCI中的功能(为简单起见,这个接口只有open、close功能)。

2)需要读配置文件用Properties类中的load方法加载文件到集合中,配置文件中放的是设备:类名,这样就可以通过遍历这个集合,将类名取出,利用类名创建对象p,然后再用主板的usePIC(p),就可以将这个设备运行起来了。

特别提示:若配置文件为空,则集合.size()==-1,则主板上没有可运行的,只能运行主板或者其他的接口。若需要添加PCI设备,只需要在配置文件中加入类名即可,不用修改主板代码(因为集合长度+1了),提高了程序的扩展性

package com.Car1;
import java.io.*;
import java.util.*;
public class mainBoard {

public void run()
{
System.out.println("main.......run");
}
public void usePCI(PCI p)//无论是插入什么设备,只要是设备符合PCI这个接口,都有两个方法可用
{
p.open();
p.close();
}

public static void main(String[] args)throws Exception {

mainBoard mb=new mainBoard();
mb.run();
FileInputStream fis=new FileInputStream("e:\\pci.prop");//配置文件,格式是设备:类名
Properties prop=new Properties();

prop.load(fis);//将流中对象加载进集合
for(int x=0;x<prop.size();x++)
{
String className=prop.getProperty("pci"+(x+1));//获取类名
Class clazz=Class.forName(className);
PCI p=(PCI)clazz.newInstance();
mb.usePCI(p);

}
fis.close();

}
}

package com.Car1;

public interface PCI {
public void open() ;
public void close();

}

package com.Car1;

public class soundCard implements PCI{

public void open()
{
System.out.println("sound...open");
}
public void close()
{
System.out.println("sound...close");
}

}

package com.Car1;

public class netBoard implements PCI {

public void open()
{
System.out.println("net...open");
}
public void close()
{
System.out.println("net...close");
}



}