java----反射
动态语言
首先java不是一个动态语言,但是java具有一定的动态性,这个动态性实现方式之一:反射
String str = "xx"; Class<?> aClass = Class.forName(str); //根据字符串的不同,动态编译不同的类对象
反射的强大之处
指的是可以运行时加载、探知、使用编译期间完全未知的类。
程序在运行状态中,可以动态加载一个只有名称的类,对于任意一个已加载的类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;
获取Class对象的三种方法
package com.first; public class Demo { public static void main(String[] args) { Dog dog = new Dog("花花",10); //方式一,通过对象获取class对象 Class<? extends Dog> aClass = dog.getClass(); //方式二,通过类来获取 Class<Dog> dogClass = Dog.class; //方式三,通过Class.forName;(好处在于类不存在再编译期不会报错) try { Class.forName("com.first.Dog"); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } class Dog{ private String name; private int age; public Dog(String name, int age) { this.name = name; this.age = age; } }
一个类只有一个class对象
public class Test1 { public static void main(String[] args) throws ClassNotFoundException { Class<?> aClass1 = Class.forName("com.zy.Dog"); Class<?> aClass2 = Class.forName("com.zy.Dog"); Dog dog = new Dog(); Class<? extends Dog> aClass3 = dog.getClass(); Class<Dog> aClass4 = Dog.class; System.out.println(aClass1.hashCode()==aClass2.hashCode()); //true System.out.println(aClass2.hashCode()==aClass3.hashCode()); //true System.out.println(aClass3.hashCode()==aClass4.hashCode()); //true } }
Class类的使用(通过反射,任何封装都可以被访问到)
通过反射实例化对象,实例化对象的类必须设置相应的构造方法;
import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; public class Demo { public static void main(String[] args) { //test1(); //实例化对象 //test2(); //获取类对象的属性(字段) test3(); //方法的调用; } public static void test1(){ Class<Dog> dogClass = Dog.class; try { //通过Class实例化对象,默认调用对象的无参构造方法;(jdk9不推荐使用) Dog dog = dogClass.newInstance(); //实例化对象,调用有参构造方法; Constructor<Dog> constructor = dogClass.getConstructor(String.class, int.class); //dogClass.getConstructors() 获取所有的构造方法,生成一个[],列表 Dog dog1 = constructor.newInstance("花花",10); } catch (InstantiationException|IllegalAccessException|NoSuchMethodException|InvocationTargetException e) { e.printStackTrace(); } } public static void test2(){ Class<Dog> dogClass = Dog.class; System.out.println(dogClass.getFields().length); //获取所有的公有属性,静态属性,私有属性获取不到 System.out.println(dogClass.getDeclaredFields().length);//获取所有的属性,(包括静态和私有) for (int i = 0; i <dogClass.getDeclaredFields().length ; i++) { System.out.println(Modifier.toString(dogClass.getDeclaredFields()[i].getModifiers())+" "+dogClass.getDeclaredFields()[i].getType()+" "+dogClass.getDeclaredFields()[i].getName()); } } public static void test3(){ Class<Dog> dogClass = Dog.class; //System.out.println(dogClass.getPackage()); //获取包名 //访问公有的方法(包括继承的父类的方法) for (int i = 0; i < dogClass.getMethods().length; i++) { if (dogClass.getMethods()[i].getName().equals("toString")){ try { //通过invoke调用方法,第一个参数传对象,第二个参数传参数的形参(没有就不用填) String str = (String) dogClass.getMethods()[i].invoke(new Dog("花花",10)); System.out.println(str); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } } //访问包括私有方法的所有的方法(不继承父类的任何一个方法) Method[] methods = dogClass.getDeclaredMethods(); Method method = dogClass.getDeclaredMethod("setName",String.class); //获取指定的方法,但是如果方法有参数,右面需要填写参数的class对象,如果没有,传null for (int i = 0; i < methods.length; i++) { if (methods[i].getName().equals("test")){ //设置私有方法可以被访问 methods[i].setAccessible(true); //不能这样设置(没有效果,可能这种执行方法是没有保存数据):dogClass.getDeclaredMthods[i].setAccessible(true); try { methods[i].invoke(new Dog("花花",10)); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } } } } class Dog{ static String t1; public String t2; private String name; private int age; public Dog(){} public Dog(String name, int age) { this.name = name; this.age = age; } private void test(){ System.out.println("我是私有方法"); } @Override public String toString() { return "Dog{" + "t2='" + t2 + '\'' + ", name='" + name + '\'' + ", age=" + age + '}'; } }
利用反射来操作对象
首先通过三种方式的一种获取Class对象;
可以找到class对象的方法、属性等,传入我们实例化的对象,就可以进行操作了
public class Test1 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { Dog dog = new Dog(); dog.setName("嘿嘿"); Class<Dog> dogClass = Dog.class; Field name = dogClass.getDeclaredField("name"); name.setAccessible(true); String o = (String) name.get(dog); System.out.println(o); name.set(dog,"大大"); String o1 = (String) name.get(dog); System.out.println(o1); } } class Dog{ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }
反射机制性能问题
public class Test1 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException { Dog dog = new Dog(); //普通方法调用 long l = System.currentTimeMillis(); for (int i = 0; i < 10000000; i++) { dog.test(); } long l2 = System.currentTimeMillis(); System.out.println(l2-l); //反射:不跳过安全检查 //检查就是为了不然我们执行private方法 Class<? extends Dog> aClass = dog.getClass(); Method test = aClass.getDeclaredMethod("test"); for (int i = 0; i < 10000000; i++) { test.invoke(dog); } long l3 = System.currentTimeMillis(); System.out.println(l3-l2); //反射:跳过安全检查 //即使我们知道这是一个public方法,我们也设置setAccessible(true),可以加快执行效率 test.setAccessible(true); for (int i = 0; i < 10000000; i++) { test.invoke(dog); } long l4 = System.currentTimeMillis(); System.out.println(l4-l3); } } class Dog{ public void test(){ } }