类是用来描述对象的,而反射就能够理解为是用来描述类的。java
类中的属性包括:app
1.Class的静态方法,forName("全类名")工具
2.类.class关键字测试
3.对象引用.getClass()方法 Object中的方法ui
/* 0--默认不写 1--public 2--private 4--protected 8--static 16--final 32--synchronized 64--volatile 128--transient 256--native 512--interface 1024--abstract */ int = getModifiers(); //获取类的修饰符(权限+特征) String = getName(); //获取类的全类名 String = getSimpleName(); //获取简单名(只有类名 ) Class = getSuperClass(); //获取当前父类的对应Class Class[] = getInterfaces(); //获取当前父类的接口 Package p = getPackage(); //获取当前类所在的包 p.getName(); //获取包的名字 Class[] = getClasses(); //获取类中的内部类 Object = newInstance(); //获取当前类的对象(至关于调用了类中的无参数的构造方法)若是类中不存在无参数的构造方法,就会抛出NoSuchMethodException异常 Field = getField("属性名"); //获取类中的属性(公有的 本身类+父类) Field[] = getFields(); //获取类中的所有属性(公有的 本身类+父类) Field = getDeclaredField("属性名") //获取当前类的属性(公有 + 私有 本身类) Field = getDeclaredFields() //获取当前类的所有属性(公有 + 私有 本身类) 若是想修改私有的属性则须要设置属性能够被操做 setAccessible()
public class TestMain { public static void main(String[] args) { try { Class<?> clazz = Class.forName("com.lili.reflect.People"); Package aPackage = clazz.getPackage(); int modifiers = clazz.getModifiers(); System.out.println(modifiers); Method[] methods = clazz.getMethods(); for (Method method : methods) { System.out.println(method.getName()); } System.out.println(aPackage); Class<?>[] interfaces = clazz.getInterfaces(); for (Class c : interfaces) { System.out.println(c.getName()); } ArrayList<String> list = new ArrayList<>(); Class c = ArrayList.class; Class superclass = c.getSuperclass(); while (superclass != null) { System.out.println(superclass.getName()); superclass = superclass.getSuperclass(); } } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
/* 注意只能是绕过private去修改属性的值,而不能去修改属性的长度,由于是final修饰的。 String的不可变指的是长度+值的不可变 */ public class ChangeString { public static void main(String[] args) { try { String str = new String("abc"); System.out.println(str); //一、利用反射技术获取String的Class Class clazz = str.getClass(); //二、获取属性 Field f = clazz.getDeclaredField("value"); //三、设置能够修改属性的值 f.setAccessible(true); //四、获取属性的值 char[] newChar = (char[])f.get(str); //五、修改属性的值 newChar[0] = 'xu'; newChar[1] = 'Li'; newChar[2] = 'Li'; System.out.println(str); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } }
能够获取共有的方法,包括本身类的以及父类的spa
能够找到私有的方法,可是要经过setAccessible(true)
方法来执行私有的方法。设计
/** * 测试使用反射获取类中的方法 */ public class TestMethod { public static void main(String[] args) { try { //一、获取People类对应的Class Class clazz = People.class; //二、获取对象 People p = (People) clazz.newInstance(); //三、经过clazz获取其中的方法,经过方法名以及方法的参数类型来定位方法。 Method m = clazz.getMethod("eat", String.class); //四、调用方法,第一个参数是要执行方法的对象,第二个则是传进去的参数列表 String n = (String) m.invoke(p, "lili要开始吃饭啦"); System.out.println(n); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } }
/** * 利用反射执行构造方法 */ public class TestConstructor { public static void main(String[] args) { try { //一、获取People对应的Class Class<People> clazz = People.class; //二、获取People中的构造方法,其中省去了构造方法的名称,由于是与类同名 //无参的就是调用的无参数的构造方法 //有参数的就是传的构造方法中形参的类型.class Constructor<People> constructor = clazz.getConstructor(String.class); //三、执行构造方法,同理参数就是要传参数的实参 People people = constructor.newInstance("哈哈哈哈哈"); System.out.println(people); } catch (Exception e) { e.printStackTrace(); } } }
这个小工具能够代替咱们本身建立对象的功能,经过传递一个字符串,来帮咱们建立一个对象,同时还能将对象内的全部属性赋值。code
其实这就是简单的模拟了Spring中IOC思想的原理,IOC(Inversion Of Control)控制反转:将对象的控制权反转,交给Spring容器去处理;DI(Dependency Injection)依赖注入:Spring容器建立对象的同时帮咱们自动的注入属性的值。对象
public class MySpring { //设计一个方法,将咱们建立对象的过程交给该方法去执行。 //参数String类型的全类名 //返回值 建立出来的对象 Object类型--->再添加上DI依赖注入 public Object getBean(String classPath) { Object obj = null; //模拟输入的实参 Scanner scanner = new Scanner(System.in); System.out.println("请给"+ classPath +"的属性赋值"); try { //一、获取该路径下对应的Class Class clazz = Class.forName(classPath); //二、建立一个对象 obj = clazz.newInstance(); //使用set方法对对象的属性进行赋值,找到每个不一样对象对应的set方法。 //也就是字符串set+属性的名字 //三、获取类中的属性 Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { //获取属性的名称 String fieldName = field.getName(); //改变属性名中第一个字母的大小写 String first = fieldName.substring(0, 1).toUpperCase(); //获取属性名中除开第一个字母的字段 String last = fieldName.substring(1); //拼接set方法 StringBuilder methodName = new StringBuilder("set"); methodName.append(first); methodName.append(last); //四、获取属性的类型 Class fieldType = field.getType(); //五、获取方法 Method method = clazz.getMethod(methodName.toString(), fieldType); //接收实参 System.out.println("请给"+ fieldName +"属性赋值"); String value = scanner.nextLine(); /*为了解决参数类型不一致的问题,能够将参数的类型都设置未相应的包装类, 而且将它们都转换成String的类型,除了Char类型以外须要另外的判断。 能够利用其它包装类带String类型的构造方法进行处理。 */ Constructor con = fieldType.getConstructor(String.class); //六、执行方法 method.invoke(obj, con.newInstance(value)); } } catch (Exception e) { e.printStackTrace(); } return obj; } }