反射:
动态获取字节码文件对象(Person.class),并对其成员进行运行。
动态获取字节码文件对象的方式:
1:任何一个对象都是由字节码文件对象创建的,所以任何一个对象都可以得到自己的字节码文件对象
那么这个功能应该定义在Object中,所以使用 getClass()
需要先new对象
2:每种数据类型都有一个 静态的class 属性,通过该属性可以得到字节码文件对象
不需要new对象,但是需要Person类存在
3:Class类提供了一个静态的forName(String str)方法
只需要提供字符串形式的包名+类名
1.
Person person1 = new Person();//先加载Person.class到方法区
Class<? extends Person> claz1 = person1.getClass();//得到了Person.class
Person person2 = new Person();
Class<? extends Person> claz2 = person2.getClass();//得到了 Person.class
System.out.println(claz1==claz2);//true
---->字节码文件只加载一次到方法区,所以两次得到的是同一个
2.
Class<Person> claz1 = Person.class;
3.
Class<?> claz1 = Class.forName("com.reflect.Person");
动态获取字节码文件对象,并创建对象:
1)调用无参构造方法创建对象
//当无参的构造方法不存在时,会发生InstantiationException
//当构造方法的权限过低时,会发生IllegalAccessException
public static void createObj1() throws ClassNotFoundException, InstantiationException, IllegalAccessException
{
//Person person = new Person();
//获取字节码文件对象---Person.class
Class<?> claz = Class.forName("com.reflect.Person");
//使用Class提供的newInstance()方法创建Person类型的对象
Object obj = claz.newInstance();//使用无参的构造方法创建对象
Person person = (Person)obj;
System.out.println(person);
}
2)使用有参数的构造方法创建对象
public static void createObj2() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
{ //Person person = new Person("小红",20);
//获取字节码文件对象---Person.class
Class<?> claz = Class.forName("com.reflect.Person");
//得到构造方法所属的Constructor类型的对象
Constructor<?> constructor = claz.getConstructor(String.class,int.class);
//使用构造方法创建对象--使用Constructor提供的创建对象的功能
Person person =(Person)constructor.newInstance("小红",20);
System.out.println(person);
}
3)动态创建对象并给属性赋值
Class<?> claz = Class.forName("com.reflect.Person");
//得到属性name所属的 Field类型的对象
//Field field = claz.getField("name");//只能获取权限是public 的属性
//System.out.println(field);//NoSuchFieldException
Field field = claz.getDeclaredField("name");
//因为name是非静态属性,所以必须通过对象访问,所以先创建对象
Object obj = claz.newInstance();
//设置name属性为可访问的
field.setAccessible(true);// 该方法是从父类中继承的
//使用Field类提供的赋值功能,给属性赋值
field.set(obj, "小红");
System.out.println(obj);
4)调用静态方法
public static void method3() throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
{
//获取字节码文件对象---Person.class
Class<?> claz = Class.forName("com.reflect.Person");
///获取被调用的方法所属的 Method类型的对象
Method method = claz.getMethod("function", null);
//执行方法
method.invoke(null, null);
}
5)通过对象调用无参方法
public static void method1() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
{
// Person person = new Person();person.show();
//获取字节码文件对象---Person.class
Class<?> claz = Class.forName("com.reflect.Person");
//获取被调用的方法所属的 Method类型的对象
Method method = claz.getMethod("show", null);
//show()属于非静态方式,需要对象去调用
Object obj = claz.newInstance();
//执行方法
method.invoke(obj, null);
}
6)通过对象调用有参方法
//调用带参的方法
public static void method2() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
{
//获取字节码文件对象---Person.class
Class<?> claz = Class.forName("com.reflect.Person");
//获取被调用的方法所属的 Method类型的对象
Method method = claz.getMethod("fun", String.class);
//fun()属于非静态方式,需要对象去调用
Object obj = claz.newInstance();
//执行方法
method.invoke(obj, "hello");
}
反射应用:
这里有一台笔记本,刚开始只有外设鼠标。后来增加键盘、摄像头等等。
笔记本有running方法和use方法.外设都有open和close方法
public class NoteBook {
public void runing(){
System.out.println("电脑运行");
}
public void useKeyBoard(KeyBoard kb){
if(kb!=null){
kb.open();
kb.close();
}
}
}
调用:
NoteBook noteBook = new NoteBook();
noteBook.runing();
KeyBoard keyBoard = new KeyBoard ();
noteBook.use(keyBoard );
如果添加外设鼠标呢?
NoteBook又得添加一个useMouse(Mouse mouse){..}方法,如果再添加外设的话,还得添加相应的方法。
当然,这里很容易解决,定义一个借口Usb.
interface Usb {
public void open();
public void close();
}
然后让外设去实现这个接口,
在NoteBook里面只用定义一个
useUsb(Usb usb){
usb.open();
usb.close();
}
在主程里调用:
Usb keyBoard = new KeyBoard ();
noteBook.useUsb(keyBoard );
Usb mouse = new Mouse();
noteBook.useUsb(mouse);
如果还要添加外设,只用添加相应的类并实现Usb接口即可,那么问题来了,主程序里面又得new新的对象,调用相同的语句。
解决方法就可以用反射了:
1.把所有的外设添加到一个配置文件中
usb1=com.reflect.test.KeyBoard
usb2=com.reflect.test.Mouse
2.主程序里调用
Properties properties = new Properties();
FileInputStream fileInputStream = new FileInputStream("config\\config.properties");
properties.load(fileInputStream);
for(int i=1;i<=properties.size();i++)
{
String value properties.getProperty("usb"+i);
Class<?> claz = Class.forName(value);
Object obj = claz.newInstance();
Usb usb = (Usb)obj;
noteBook.useUsb(usb);
}
–>添加外设只用在配置文件中添加,主程序调用不用修改
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-09-29 22:03:46