反射的应用
案例
案例 :美团外卖在线支付:微信,支付宝,银行卡等
/**
* 美团支付公共接口
*/
public interface Meituanwaimai {
void payOnline();
}
/**
* 微信支付
*/
public class WechatPay implements Meituanwaimai{
@Override
public void payOnline() {
System.out.println("用微信支付!");
}
}
/**
* 支付宝支付
*/
public class ZhifubaoPay implements Meituanwaimai{
@Override
public void payOnline() {
System.out.println("用支付宝支付!");
}
}
/**
*某个银行支付
*/
public class BankCardPay implements Meituanwaimai{
@Override
public void payOnline() {
System.out.println("使用招商银行支付!");
}
}
public class Test {
public static void main(String[] args) throws Exception {
//前端传过来的支付方式
String payType = "微信";
// 传统实现:
if ("微信".equals(payType)){ //payType.equals("微信") 避免空指针
pay(new WechatPay()); //控制台输出 用微信支付!
}
if ("支付宝".equals(payType)){
pay(new ZhifubaoPay()); //控制台输出 用支付宝支付!
}
if ("支付宝".equals(payType)){
pay(new BankCardPay()); //使用招商银行支付!
}
//如果要加支付方式,则此处一直要加if 代码,不利于扩展,用反射可以解决该问题
//反射的代码
//前端传过来的支付方式,实际上 是微信类的全限定路径
String paymetch = "com.gy.fx.springtest.reflect.WechatPay";
//拿到Class类 即WechatPay类的字节码信息
Class als = Class.forName(paymetch);
//创建对象: 用Class 初始化对象
Object obj = als.newInstance();
//用Class得到指定方法
Method method = als.getMethod("payOnline");
//执行该对象的该方法
method.invoke(obj); //控制台输出 用微信支付!
}
private static void pay(Meituanwaimai pay){
pay.payOnline();
}
}
反射的定义
JAVA反射机制是在运行状态中,对任意一个类,都能知道这个类的所有属性和方法;对任意一个对象,都能够调用它的任意方法和属性;
这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制
使用
准备数据
/**
* <h5>描述:作为一个父类</h5>
*/
public class Person implements Serializable {
private int age;
public String name;
private void eat(){
System.out.println("private Person eat.....");
}
public void sleep(){
System.out.println("public Person sleep.....");
}
}
package com.gy.fx.springtest.reflect;
/**
* <h5>描述:作为子类</h5>
*/
@MyAnnotation(value = "hello")
public class Student extends Person implements MyInterface{
//属性
private int sno; //私有属性
double height; //默认属性
protected double weight; //保护属性
public double score; //公有属性
//方法
public String show(){
return "Student public show() ";
}
public String show(int a, int b){
return "Student public show(int a, int b) ";
}
private void work(){
System.out.println("Student private work()");
}
void happy(){
System.out.println("Student default work()");
}
protected int getSno(){
return sno;
}
//构造函数
public Student() {
System.out.println("无参构造函数");
}
public Student(int sno, double height, double weight) {
this.sno = sno;
this.height = height;
this.weight = weight;
}
private Student(int sno) {
this.sno = sno;
}
Student(int sno, double height) {
this.sno = sno;
this.height = height;
}
@Override
@MyAnnotation(value = "hi,dowork")
public void dowork() {
System.out.println("自定义接口的方法");
}
@Override
public String toString() {
return "Student{" +
"sno=" + sno +
", height=" + height +
", weight=" + weight +
", score=" + score +
'}';
}
}
四种获取字节码信息的方式 案例:以Person的字节码信息为案例
//方案1:通过getClass() 方法获取 不常用
Person person = new Person();
Class als1 = person.getClass();
System.out.println(als1); //class com.gy.fx.springtest.reflect.Person
//方案2: 通过类名.class 方法获取 不常用
Class als2 = Person.class;
System.out.println(als2); //class com.gy.fx.springtest.reflect.Person
//加载器只加载一次,所以同一个类的 class 肯定是同一个
System.out.println(als1 == als2); //true
//方案3 通过Class.forName 获取, 常用
Class als3 = Class.forName("com.gy.fx.springtest.reflect.Person");
System.out.println(als3); //class com.gy.fx.springtest.reflect.Person
//方案4 利用类加载器 不常用 (前置知识:.java文件,编译成 .class文件, jvm通过类加载器 加载到内存区域)
ClassLoader loader = Demo.class.getClassLoader();
Class als4 = loader.loadClass("com.gy.fx.springtest.reflect.Person");
System.out.println(als4); //class com.gy.fx.springtest.reflect.Person
获取 Class 类的具体实例
/**
* Class 类的具体实例:
* 1.类:外部类,内部类
* 2.接口
* 3.注解
* 4.数组
* 5.基本数据类型
* 6.void
*/
Class c1 = Person.class; //类
Class c2 = Comparable.class; //接口
Class c3 = Override.class; //注解
int[] arr1 = {1, 2, 3}; //数组
Class c4 = arr1.getClass();
int[] arr2 = {4, 5};
Class c5 = arr2.getClass();
System.out.println(c4 == c5); //结果:ture ,同一个维度,同一个元素类型,得到的字节码就是同一个
Class c6 = int.class; //基本数据类型
Class c7 = void.class; //void
获取构造器和创建对象
//获取字节码信息
Class cls = Student.class;
//通过字节码信息可以获取构造器(构造方法) :
// getConstructors() 只能获取当前运行时被public 修饰的构造器
Constructor[] constructors = cls.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor); //public com.gy.fx.springtest.reflect.Student()
}
// getConstructors() 能获取当前运行时所有的构造器
Constructor[] constructors2 = cls.getDeclaredConstructors();
for (Constructor constructor : constructors2) {
System.out.println(constructor); //public com.gy.fx.springtest.reflect.Student() com.gy.fx.springtest.reflect.Student(int,double) private com.gy.fx.springtest.reflect.Student(int)
}
//获取指定的构造器 ,不传参数时,获取的无参构造器 ,不加dec 只能获取pulic 修饰的构造器
Constructor constructor = cls.getConstructor(int.class, double.class, double.class);
//加dec 能获取任何修饰符的构造器
System.out.println(constructor); // public com.gy.fx.springtest.reflect.Student(int,double,double)
Constructor constructor2 = cls.getDeclaredConstructor(int.class); //private com.gy.fx.springtest.reflect.Student(int)
System.out.println(constructor2);
//用构造器创建对象
Object o = constructor.newInstance(1, 2.2, 3.4);
System.out.println(0);
获取属性及属性的具体结构
//获取运行时类的字节码信息
Class clss = Student.class;
//根据字节码信息获取属性
// getFields 获取运行时类和父类被public修饰的属性
Field[] fields = clss.getFields();
for (Field field : fields) {
System.out.println(field);
}
// getDeclaredFields 获取运行时类和父类所有属性
Field[] fields2 = clss.getDeclaredFields();
for (Field field : fields2) {
System.out.println(field);
}
//获取指定属性
//getField 获取public修饰的属性
Field score = clss.getField("score");
System.out.println(score); //public double com.gy.fx.springtest.reflect.Student.score
//getDeclaredField 获取任意修饰符修饰的属性
Field sno = clss.getDeclaredField("sno");
System.out.println(sno); //private int com.gy.fx.springtest.reflect.Student.sno
//属性的具体结构
//属性的修饰符
String s = Modifier.toString(sno.getModifiers());
System.out.println(s); //private
//属性的数据类型
Class type = sno.getType();
System.out.println(type); //int
//属性的名字
String name = sno.getName();
System.out.println(name); //sno
//给属性赋值:给属性设置值,必须要有对象
Field score1 = cls.getField("score");
Object o1 = cls.newInstance(); //调用无参构造函数初始化对象
score1.set(o1, 98); //给obj 这个对象的 score属性设置具体值 ,这个值是98
System.out.println(o1); //Student{sno=0, height=0.0, weight=0.0, score=98.0}
获取方法和调用方法
//获取字节码信息
Class classs = Student.class;
//获取方法
// getMethods() 获取 运行时类 中被public 修饰的方法和 父类中被public修饰的的方法
Method[] methods = classs.getMethods();
for (Method method : methods) {
System.out.println(method);
}
// getDeclaredMethods() 获取 运行时类的所有方法和 父类的所有方法
Method[] methods2 = classs.getDeclaredMethods();
for (Method method : methods2) {
System.out.println(method);
}
//获取指定方法
//getMethod()获取public 修饰的方法
Method show = classs.getMethod("show");
System.out.println(show); //public java.lang.String com.gy.fx.springtest.reflect.Student.show()
Method show2 = classs.getMethod("show", int.class, int.class);
System.out.println(show2); //public java.lang.String com.gy.fx.springtest.reflect.Student.show(int,int)
//getDeclaredMethod()获取任意修饰符修饰的方法
Method show3 = classs.getDeclaredMethod("work");
System.out.println(show3); //private void com.gy.fx.springtest.reflect.Student.work()
//获取方法的具体结构:@注解,修饰符,返回值类型,方法名,参数列表,抛出的异常,注解 等
//方法名
String name1 = show.getName();
System.out.println(name1);
//修饰符
int modifiers = show.getModifiers();
System.out.println(Modifier.toString(modifiers));
//返回值类型
Class returnType = show.getReturnType();
System.out.println(returnType); //class java.lang.String
//参数列表
Class[] parameterTypes = show.getParameterTypes();
for (Class aClass : parameterTypes) {
System.out.println(aClass);
}
//获取注解 注意 只能获取到声明周期是运行时 @Retention(RetentionPolicy.RUNTIME) 的注解
Method dowork = classs.getMethod("dowork");
Annotation[] annotations = dowork.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
//调用方法
Object o2 = classs.newInstance();
dowork.invoke(o2); //调用o2对象的dowork 方法
show2.invoke(o2,1,2); //调用o2对象的show(int,int) 方法
获取 类的接口,包,注解等
//获取运行时类的接口
Class clsss = Student.class;
Class[] interfaces = clsss.getInterfaces();
for (Class anInterface : interfaces) {
System.out.println(anInterface); //interface com.gy.fx.springtest.reflect.MyInterface
}
//得到父类的接口:1.先获取父类的字节码信息,2.在获取接口
Class superclass = clsss.getSuperclass();
Class[] interfaces1 = superclass.getInterfaces();
for (Class aClass : interfaces1) {
System.out.println(aClass); //interface java.io.Serializable
}
//获取运行时类所在的包
Package aPackage = clsss.getPackage();
System.out.println(aPackage); // package com.gy.fx.springtest.reflect
System.out.println(aPackage.getName()); // com.gy.fx.springtest.reflect
//获取运行时类的注解
Annotation[] annotations1 = clsss.getAnnotations();
for (Annotation annotation : annotations1) {
System.out.println(annotation); //@com.gy.fx.springtest.reflect.MyAnnotation(value=hello)
}