反射背景:
学习重点:
1)创建对应的运行时类的对象
2)调用对应的运行时类的指定的结构(属性、方法、构造器)
定义:
Reflection(反射)是被视为动态语言的关键,
反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,
并能直接操作任意对象的内部属性及方法
好处:
1)大大提高了程序的扩展性
2)类不确定的情况下,都会用到反射
应用场景: 大多为加载配置文件
实例化Class类对象(四种方法)
1)前提:若已知具体的类,通过类的class属性获取,该方法 最为安全可靠,程序性能最高 实例:Class clazz = String.class;
2)前提:已知某个类的实例,调用该实例的getClass()方法获 取Class对象 实例:Class clazz = “www.atguigu.com”.getClass();
3)前提:已知一个类的全类名,且该类在类路径下,可通过 Class类的静态方法forName()获取,可能抛出ClassNotFoundException 实例:Class clazz = Class.forName(“java.lang.String”);
4)其他方式(不做要求) ClassLoader cl = this.getClass().getClassLoader(); Class clazz4 = cl.loadClass(“类的全类名”);
调用对应的运行时类的指定的结构(属性、方法、构造器)
1)获取对应的运行时类的属性
package com.atguigu.java; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import org.junit.Test; public class TestField { //获取对应的运行时类的属性 @Test public void test1(){ Class clazz = Person.class; //1.getFields():只能获取到运行时类中及其父类中声明为public的属性 Field[] fields = clazz.getFields(); for(int i = 0;i < fields.length;i++){ System.out.println(fields[i]); } System.out.println(); //2.getDeclaredFields():获取运行时类本身声明的所有的属性 Field[] fields1 = clazz.getDeclaredFields(); for(Field f : fields1){ System.out.println(f.getName()); } } //权限修饰符 变量类型 变量名 //获取属性的各个部分的内容 @Test public void test2(){ Class clazz = Person.class; Field[] fields1 = clazz.getDeclaredFields(); for(Field f : fields1){ //1.获取每个属性的权限修饰符 int i = f.getModifiers(); String str1 = Modifier.toString(i); System.out.print(str1 + " "); //2.获取属性的类型 Class type = f.getType(); System.out.print(type.getName() + " "); //3.获取属性名 System.out.print(f.getName()); System.out.println(); } } //调用运行时类中指定的属性 @Test public void test3() throws Exception{ Class clazz = Person.class; //1.获取指定的属性 //getField(String fieldName):获取运行时类中声明为public的指定属性名为fieldName的属性 Field name = clazz.getField("name"); //2.创建运行时类的对象 Person p = (Person)clazz.newInstance(); System.out.println(p); //3.将运行时类的指定的属性赋值 name.set(p,"Jerry"); System.out.println(p); System.out.println("%"+name.get(p)); System.out.println(); //getDeclaredField(String fieldName):获取运行时类中指定的名为fieldName的属性 Field age = clazz.getDeclaredField("age"); //由于属性权限修饰符的限制,为了保证可以给属性赋值,需要在操作前使得此属性可被操作。 age.setAccessible(true); age.set(p,10); System.out.println(p); // Field id = clazz.getField("id"); } }
2)获取运行时类的方法
package com.atguigu.java; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import org.junit.Test; public class TestMethod { //1.获取运行时类的方法 @Test public void test1(){ Class clazz = Person.class; //1.getMethods():获取运行时类及其父类中所有的声明为public的方法 Method[] m1 = clazz.getMethods(); for(Method m : m1){ System.out.println(m); } System.out.println(); //2.getDeclaredMethods():获取运行时类本身声明的所有的方法 Method[] m2 = clazz.getDeclaredMethods(); for(Method m : m2){ System.out.println(m); } } //注解 权限修饰符 返回值类型 方法名 形参列表 异常 @Test public void test2(){ Class clazz = Person.class; Method[] m2 = clazz.getDeclaredMethods(); for(Method m : m2){ //1.注解 Annotation[] ann = m.getAnnotations(); for(Annotation a : ann){ System.out.println(a); } //2.权限修饰符 String str = Modifier.toString(m.getModifiers()); System.out.print(str + " "); //3.返回值类型 Class returnType = m.getReturnType(); System.out.print(returnType.getName() + " "); //4.方法名 System.out.print(m.getName() + " "); //5.形参列表 System.out.print("("); Class[] params = m.getParameterTypes(); for(int i = 0;i < params.length;i++){ System.out.print(params[i].getName() + " args-" + i + " "); } System.out.print(")"); //6.异常类型 Class[] exps = m.getExceptionTypes(); if(exps.length != 0){ System.out.print("throws "); } for(int i = 0;i < exps.length;i++){ System.out.print(exps[i].getName() + " "); } System.out.println(); } } //调用运行时类中指定的方法 @Test public void test3() throws Exception{ Class clazz = Person.class; //getMethod(String methodName,Class ... params):获取运行时类中声明为public的指定的方法 Method m1 = clazz.getMethod("show"); Person p = (Person)clazz.newInstance(); //调用指定的方法:Object invoke(Object obj,Object ... obj) Object returnVal = m1.invoke(p);//我是一个人 System.out.println(returnVal);//null Method m2 = clazz.getMethod("toString"); Object returnVal1 = m2.invoke(p); System.out.println(returnVal1);//Person [name=null, age=0] //对于运行时类中静态方法的调用 Method m3 = clazz.getMethod("info"); m3.invoke(Person.class); //getDeclaredMethod(String methodName,Class ... params):获取运行时类中声明了的指定的方法 Method m4 = clazz.getDeclaredMethod("display",String.class,Integer.class); m4.setAccessible(true); Object value = m4.invoke(p,"CHN",10);//我的国籍是:CHN System.out.println(value);//10 } }
3)调用指定的构造器,创建运行时类的对象
package com.atguigu.java; import java.lang.reflect.Constructor; import org.junit.Test; public class TestConstructor { @Test public void test1() throws Exception{ String className = "com.atguigu.java.Person"; Class clazz = Class.forName(className); //创建对应的运行时类的对象。使用newInstance(),实际上就是调用了运行时类的空参的构造器。 //要想能够创建成功:①要求对应的运行时类要有空参的构造器。②构造器的权限修饰符的权限要足够。 Object obj = clazz.newInstance(); Person p = (Person)obj; System.out.println(p); } @Test public void test2() throws ClassNotFoundException{ String className = "com.atguigu.java.Person"; Class clazz = Class.forName(className); Constructor[] cons = clazz.getDeclaredConstructors(); for(Constructor c : cons){ System.out.println(c); } } //调用指定的构造器,创建运行时类的对象 @Test public void test3() throws Exception{ String className = "com.atguigu.java.Person"; Class clazz = Class.forName(className); Constructor cons = clazz.getDeclaredConstructor(String.class,int.class); cons.setAccessible(true); Person p = (Person)cons.newInstance("罗伟",20); System.out.println(p); } }
反射的应用场景(以下代码均是)
NoteBookMain.java
package cn.itcast.reflect.test; import java.io.File; import java.io.FileReader; import java.util.Properties; public class NoteBookMain { /** * @param args * @throws Exception */ public static void main(String[] args) throws Exception { /* * 案例一: * 阶段一:笔记电脑运行。NoteBook run(); * 阶段二:想要使用一些外围设备,比如鼠标,键盘...... * 为了提高了笔记本的扩展性,应该降低这些设备和笔记本的耦合性。 * 需要接口。 * 只需要在设计之初,定义一个接口。而且笔记本在使用这个接口。 * * 后期有了usb的设备后,需要不断的new对象才可以用。每一次都要修改代码。 * * 能不能不修改这代码。就可以使用后期的设备呢? * 设备不明确的,而前期还要对其进行对象的建立。需要反射技术。 * 对外提供一个配置文件。 */ NoteBook book = new NoteBook(); book.run(); // book.useUSB(null); // book.useUSB(new MouseByUSB()); //通过反射的方法重新设计应用程序,以提高更好的扩展性。 File configFile = new File("tempfile\usb.properties"); if(!configFile.exists()){ configFile.createNewFile(); } //2,读取配置文件。 FileReader fr = new FileReader(configFile); //3,为了获取其中的键值信息方便,建立Properties。 Properties prop = new Properties(); prop.load(fr); for(int x = 1; x<=prop.size(); x++){ String className = prop.getProperty("usb"+x); //反射。 Class clazz = Class.forName(className); USB usb = (USB)clazz.newInstance(); book.useUSB(usb); } fr.close(); } }
NoteBook.java
package cn.itcast.reflect.test; public class NoteBook { /** * 运行 */ public void run(){ System.out.println("notebook run"); } /** * 使用usb的设备。 */ public void useUSB(USB usb){//多态 if(usb!=null){ usb.open(); usb.close(); } } }
USB.java
package cn.itcast.reflect.test; public interface USB { /** * 开启。 * */ void open(); /** * 关闭。 */ void close(); }
KeyByUSB.java
package cn.itcast.reflect.test; public class KeyByUSB implements USB { @Override public void open() { System.out.println("key open"); } @Override public void close() { System.out.println("key close"); } }
MouseByUSB.java
package cn.itcast.reflect.test; public class MouseByUSB implements USB { @Override public void open() { System.out.println("mouse open"); } @Override public void close() { System.out.println("mouse close"); } }