反射
1.反射的介绍
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制,很多优秀的开源框架都是通过反射完成的。
Java反射机制,可以实现以下功能:
①在运行时判断任意一个对象所属的类;
②在运行时构造任意一个类的对象;
③在运行时判断任意一个类所具有的成员变量和方法;
④在运行时调用任意一个对象的方法;
⑤生成动态代理;
2.获取Class对象
Class 对象
在类加载到内容中时就有了表示这个类型的Class对象
Class对象是唯一的,不会改变的
private int a; private String Uname; private String Upwd; public Demo(){ } public Demo(double a){ } public int getA() { return a; } public void setA(int a) { this.a = a; } @Override public String toString() { return "Demo{" + "a=" + a + ", Uname='" + Uname + '\'' + ", Upwd='" + Upwd + '\'' + '}'; } private Demo(int a){ this.a=a; } public Demo(String a){ } public Demo(String uname, String upwd) { Uname = uname; Upwd = upwd; } public String getUname() { return Uname; } public void setUname(String uname) { Uname = uname; } public String getUpwd() { return Upwd; } public void setUpwd(String upwd) { Upwd = upwd; } public void a(){ System.out.println("你好"); } public void b(){ System.out.println("世界"); } private void c(){ System.out.println("哈哈"); }
2.1:对象.class
Demo demo=new Demo(); Class<?> c1=demo.getClass(); System.out.println(c1.getName());
2.2:类.class
Class<?> c2=Demo.class; System.out.println(c2.getName());
2.3:Class.forName()-->推荐使用这种方式
Class<?> c3=Class.forName("com.zh.reflect"); System.out.println(c3.getName());
2.4根据子类的对象获取父类
Class c4=c3.getSuperclass(); System.out.println(c4.getName());
2.5基本数据类型与包装类的对比
//基本数据类型的Class对象 System.out.println(int.class); //基本数据类型的包装类都有一个TYPE System.out.println(Integer.TYPE); System.out.println(Integer.TYPE==int.class);
可以说明Class的对象是唯一的,不会改变
3.获得修饰符
返回此类或接口的Java语言修饰符,以整数编码。
Class<?> clz=Class.forName("com.zh.reflect.Demo"); int n=clz.getModifiers(); System.out.println(Modifier.toString(n));
4.创建对象
4.1获得构造器
根据Class对象,我们可以获得构造器,为实例化对象做准备。
getConstructor()--->获得public权限的构造器 返回一个Constructor对象
getConstructors()--->获得所有public权限的构造器,返回一个Constructor数组
getDeclaredConstructor()--->获得所有权限的构造器 返回一个Constructor对象
getDeclaredConstructors()--->获得所有权限的构造器 返回一个Constructor数组
Constructor<?> constructor = clz.getConstructor();//不给参数,默认调用参数空的构造器,如果没有,会报异常 System.out.println(constructor); constructor=clz.getConstructor(String.class);--->获得一个带(String)的构造器 System.out.println(constructor); Constructor<?>[] constructors=clz.getConstructors(); for(Constructor<?> c:constructors){ System.out.println(c); } Constructor<?> declaredConstructor = clz.getDeclaredConstructor(int.class);//获得所有权限的带int参数的构造器 System.out.println(declaredConstructor); Constructor<?>[] constructors=clz.getDeclaredConstructors();//获得所有权限的所有构造器 for(Constructor<?> c:constructors){ System.out.println(c); }
4.2实例化对象
4.2.1使用newInstance()
Class类中newInstance方法 内部创建对象时候默认调用空构造,没有空构造方法则抛出异常InstantiationException
Class<?> c= Class.forName("com.zh.reflect.Demo"); Demo demo = (Demo) c.newInstance();//实例化一个Demo类的对象 demo.setA(1); demo.setUname("aaa"); demo.setUpwd("bbb"); System.out.println(demo);
4.2.2获取构造器,在调用构造器的newInstance()方法,并赋实参。
如果遇到private权限的构造器,使用constructor.setAccessible(true)方法忽略权限
Constructor constructor=c.getConstructor(String.class,String.class);//获取构造器 Demo demo=(Demo)constructor.newInstance("aaaa","cccc");//创建对象 指定使用这种构造器 赋初值 System.out.println(demo); Constructor<?> constructor = c.getDeclaredConstructor(int.class);//获得带int类型参数的构造器 int modifiers = constructor.getModifiers(); System.out.println(Modifier.toString(modifiers));//输出修饰符 constructor.setAccessible(true);//如果是私有的内容,使用前忽略权限 Demo demo = (Demo)constructor.newInstance(3); System.out.println(demo);
5.获得方法
getMethod(...)-->获得指定名字的公有方法 返回Method
getMethods()-->获得所有公有方法 返回Method [ ]数组
getDeclaredMethod(...)-->获得指定名字的所有修饰符的方法 返回Method
getDeclaredMethods()-->获得所有方法 返回Method [ ]数组
Demo demo=new Demo(); Class<?> classz=Class.forName("com.zh.reflect.Demo"); Method a = classz.getMethod("a");//获得叫 a的公有方法 System.out.println(a.getName());//获得方法名
调用方法 Object invoke(Object obj, Object... args)
成员方法 ->对象
静态方法 ->对象|类
a.invoke(demo);
如果是调用私有方法,一定也得调用a.setAccessible(true),忽略方法权限
Demo demo=new Demo(); Class<?> classz=Class.forName("com.zh.reflect.Demo"); Method c = classz.getDeclaredMethod("c"); c.setAccessible(true); c.invoke(demo);
6.获得属性
getField(....)-->获得指定的公有属性 返回Field
getFields()-->获得所有的公有属性 返回Field [ ] 数组
getDeclaredField(...)-->获得指定所有修饰符的属性 返回 Field
getDeclaredFields(...)-->获得所有属性 返回 Field [ ] 数组
与方法类似 访问私有属性时 也要调用setAccessible()方法 忽略权限
Class classz=Class.forName("com.zh.reflect.Demo"); Demo demo =(Demo) classz.getConstructor(String.class, String.class).newInstance("aaa", "bbb"); Field uname = classz.getDeclaredField("Uname"); uname.setAccessible(true);//忽略权限 uname.set(demo,"aaa");//设置属性 System.out.println(uname.get(demo));//输出这个对象的所获得的这个属性的值
7.数组
操作数组需要借助Array类
String[] arr = (String[]) Array.newInstance(String.class,5); System.out.println(arr.getClass().isArray()); //设置值 Array.set(arr,0,"胡歌"); //获取值 System.out.println(Array.get(arr,0)); System.out.println(Arrays.toString(arr));