知识点
类是用来描述对象的,而反射就可以理解为是用来描述类的。
类中的属性包括:
- Class 类本身
- Package 类所在的包
- Field 类中的属性
- Method 类中的方法
- Constructor 类中的构造方法
- Annotation 类中的注解
如何获取Class
1.Class的静态方法,forName("全类名")
2.类.class关键字
3.对象引用.getClass()方法 Object中的方法
Class中的常用方法
/* 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(); } } }
利用反射修改String类型的值
/* 注意只能是绕过private去修改属性的值,而不能去修改属性的长度,因为是final修饰的。 String的不可变指的是长度+值的不可变 */ public class ChangeString { public static void main(String[] args) { try { String str = new String("abc"); System.out.println(str); //1、利用反射技术获取String的Class Class clazz = str.getClass(); //2、获取属性 Field f = clazz.getDeclaredField("value"); //3、设置可以修改属性的值 f.setAccessible(true); //4、获取属性的值 char[] newChar = (char[])f.get(str); //5、修改属性的值 newChar[0] = 'xu'; newChar[1] = 'Li'; newChar[2] = 'Li'; System.out.println(str); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } }
利用反射调用类中的方法
可以获取共有的方法,包括自己类的以及父类的
可以找到私有的方法,但是要通过setAccessible(true)方法来执行私有的方法。
/** * 测试使用反射获取类中的方法 */ public class TestMethod { public static void main(String[] args) { try { //1、获取People类对应的Class Class clazz = People.class; //2、获取对象 People p = (People) clazz.newInstance(); //3、通过clazz获取其中的方法,通过方法名以及方法的参数类型来定位方法。 Method m = clazz.getMethod("eat", String.class); //4、调用方法,第一个参数是要执行方法的对象,第二个则是传进去的参数列表 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 { //1、获取People对应的Class Class<People> clazz = People.class; //2、获取People中的构造方法,其中省去了构造方法的名称,因为是与类同名 //无参的就是调用的无参数的构造方法 //有参数的就是传的构造方法中形参的类型.class Constructor<People> constructor = clazz.getConstructor(String.class); //3、执行构造方法,同理参数就是要传参数的实参 People people = constructor.newInstance("哈哈哈哈哈"); System.out.println(people); } catch (Exception e) { e.printStackTrace(); } } }
设计一个小工具
这个小工具可以代替我们自己创建对象的功能,通过传递一个字符串,来帮我们创建一个对象,同时还能将对象内的所有属性赋值。
其实这就是简单的模拟了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 { //1、获取该路径下对应的Class Class clazz = Class.forName(classPath); //2、创建一个对象 obj = clazz.newInstance(); //使用set方法对对象的属性进行赋值,找到每一个不同对象对应的set方法。 //也就是字符串set+属性的名字 //3、获取类中的属性 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); //4、获取属性的类型 Class fieldType = field.getType(); //5、获取方法 Method method = clazz.getMethod(methodName.toString(), fieldType); //接收实参 System.out.println("请给"+ fieldName +"属性赋值"); String value = scanner.nextLine(); /*为了解决参数类型不一致的问题,可以将参数的类型都设置未相应的包装类, 并且将它们都转换成String的类型,除了Char类型之外需要另外的判断。 可以利用其它包装类带String类型的构造方法进行处理。 */ Constructor con = fieldType.getConstructor(String.class); //6、执行方法 method.invoke(obj, con.newInstance(value)); } } catch (Exception e) { e.printStackTrace(); } return obj; } }
© 著作权归作者所有
举报
发表评论
0/200