新手应该了解的反射基本使用
前置了解:泛型
泛型
在Java中的泛型简单来说就是:在创建对象或调用方法的时候才明确下具体的类型
使用泛型的好处就是代码更加简洁(不再需要强制转换),程序更加健壮(在编译期间没有警告,在运行期就不会出现ClassCastException异常)
1、通过反射调接口
Java反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性。
从问题出发:BindBox类里面有有1024个以open开头的函数,每个函数对应返回1~1024的之间的整数且不重复,问哪一个方法返回666?(不可查看源码,源码可能是加密的)
1)、获得类对象,间接通过类对象获得类的相关信息
//拿到所有的公共方法(包括从父类继承过来的方法),返回结果是一个数组
Method[ ] methods = BindBox.class.getMethods();
打印数组
for(Method method : methods) {
System.out.println(method);
}
打印出来的数组:public final int com.ithem.BindBox.open_fhjkalf(long,int)
包括的信息有访问修饰符、final、返回值类型、包名、类名、方法名、抛出异常等
for(Method method : methods) {
System.out.println(method.getName());//只含有方法名
}
for(Method method : methods) {
if(method.getName().startsWith("open")){筛选出open打头的方法名
//进一步处理
System.out.println(method.getName());
}
}
2)、调用每一个open方法,查看返回值等不等于666
method.invoke(null);//执行某个方法,null为能执行的所有方法
for(Method method : methods) {
if(method.getName().startsWith("open")){筛选出open打头的方法名
//进一步处理
if(method.invoke(null).equals.(666)){
System.out.println(method.getName());
}
}
}
①、得到 Class 的三种方式
//1、通过对象调用 getClass() 方法来获取,通常应用在:比如你传过来一个 Object
// 类型的对象,而我不知道你具体是什么类,用这种方法
Person p1 = new Person();
Class c1 = p1.getClass();
//2、直接通过 类名.class 的方式得到,该方法最为安全可靠,程序性能更高
// 这说明任何一个类都有一个隐含的静态成员变量 class
Class c2 = Person.class;
//3、通过 Class 对象的 forName() 静态方法来获取,用的最多,class必须是类全名称,返回Class,需要强转为Class<类型>
// 但可能抛出 ClassNotFoundException 异常
Class c3 = Class.forName("com.ys.reflex.Person");
or Class<?> cls = Class.forName("com.ys.reflex.Person");
②、通过 Class 类获取成员变量、成员方法、接口、超类、构造方法等
查阅 API 可以看到 Class 有很多方法:
getName():获得类的完整名字。
getFields():获得类的public类型的属性。
getDeclaredFields():获得类的所有属性。包括private 声明的和继承类
getMethods():获得类的public类型的方法。
getDeclaredMethods():获得类的所有方法。包括private 声明的和继承类
getMethod(String name, Class[] parameterTypes):获得类的特定方法,name参数指定方法的名字,parameterTypes 参数指定方法的参数类型。
getConstructors():获得类的public类型的构造方法。
getConstructor(Class[] parameterTypes):获得类的特定构造方法,parameterTypes 参数指定构造方法的参数类型。
newInstance():通过类的不带参数的构造方法创建这个类的一个对象。
总结:
Java反射提供了在运行时获取类各个信息的能力,用类加载的方法,把类名、父类、接口、变量、方法、虚方法记录下来。
在编译器写的代码是 .java 文件,经过javac 编译会变成 .class 文件,class 文件会被JVM装载运行(这里就是真正运行着我们所写的代码(虽然是被编译过的),也就所谓的运行时。
反射是直接获取加载了方法区的类模板,所以可以拿到整个类的所有东西,看似是打破了封装特性,但实际上反射的真正作用是为了解偶以及实现动态性,所以框架上不用反射不行,否则达不到那种解偶程度和动态性程度。
要理解反射,需要抛开我们日常写的业务代码。以更高的维度或者说是抽象的思维去看待我们所写的“工具”,所谓的“工具”:在单个系统使用叫做“Utils”、被多个系统使用打成jar包叫做“组件”、组件继续发展壮大就叫做“框架”,一个好用的“工具”是需要兼容各种情况的。
例如SpringMVC 你在方法上写上对象,传入的参数就会帮你封装到对象上,Mybatis可以让我们只写接口,不写实现类,就可以执行SQL。