浅谈java反射机制-------反射机制的由来(8.26更新)

问题提出

一个公司要开发本公司APP,某程序员在支付功能处给出了两种解决方案-----
第一种---------
利用多态来完成

第二种--------
是利用反射机制完成

代码实现

代码实现----多态

 class AlipayM  implements WoerMa{
    @Override
    public void payOnline() {
        System.out.println("阿里支付");
    }
}
class WechatPayM implements WoerMa {
    @Override
    public void payOnline() {
        System.out.println("微信支付");
    }
}
class WoermaCard implements WoerMa {
    @Override
    public void payOnline() {
        System.out.println("沃尔玛钱包");
    }
}
public class ZhaoHang implements WoerMa{
    @Override
    public void payOnline() {
        System.out.println("招行支付");
    }
}

测试方法-----


public class WoermaTest {
    public static void main(String[] args) {
        String string= "微信";
        switch(string){
            case "招行" :
                pay(new ZhaoHang());
                break;
            case "阿里":
                pay(new AlipayM());
                break;
            case "微信":
                pay(new WechatPayM());
                break;
            default:
                pay(new WoermaCard());
        }

    }
    public  static void pay(WoerMa woerMa){
        woerMa.payOnline();
    }

}

以上方式虽然用了多态的方式(参数为接口,传入的为参数的实现类)解决了一些问题,但仍然会有维护起来比较繁琐的问题既要维护实现类,又要维护测试类.

代码实现----反射

需要修改测试类即可,

以后再次添加支付方式时只需要维护该实现类即可;


public class WoermaTest {
    public static void main(String[] args) {
        String string= "com.woerma.client.ZhaoHang";
        try {
            Class client=Class.forName(string);//通过路径来获得类
          
            Object obj= client.newInstance();
 //在最新版本中通过newInstance()方法直接获得实例已被弃用;
 //此种方式要求的是类中有无参的构造
            Method method=client.getMethod("payOnline");
       method.invoke(obj);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

可以通过获得构造方法来间接获得实例;
通过获得构造方法来间接获得实例适用于有参和无参的构造;


public class WoermaTest {
    public static void main(String[] args) {
        String string= "com.woerma.client.ZhaoHang";
        try {
            Class client=Class.forName(string);//通过路径来获得类
            Constructor constructor = client.getConstructor();
            Object obj = constructor.newInstance();
           
            Method method=client.getMethod("payOnline");
       method.invoke(obj);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }


}

创建对象的方式:

1、使用Class对象的newInstance()方法创建该Class对象的实例,此时该Class对象必须要有无参数的构造方法,在最新的JDK版本中这种方式已被弃用;

2、使用Class对象获取指定的Constructor对象,再调用Constructor的newInstance()方法创建对象类的实例,此时可以选择使用某个构造方法。如果这个构造方法被私有化起来,那么必须先申请访问,将可以访问设置为true;

类中有无参构造-----


class Alibaba{

    public Alibaba() {
        System.out.println("创建对象成功");
    }
}
public class reflecTest {
    public static void main(String[] args) throws ClassNotFoundException {
        //创建对象
        //传统方式
        new Alibaba();
        //反射方式
        Class Ali=Class.forName("com.woerma.client.Alibaba");
         Ali.newInstance();
    }
}

在这里插入图片描述以上通过无参来直接获得类的实例的方式在新版本种已被废弃;

类中没有无参构造------

如果依旧是上面的代码----会出现错误,
在这里插入图片描述


class Alibaba{
String name;
int productNum;

    public Alibaba(String name, int productNum) {
        this.name = name;
        this.productNum = productNum;
        System.out.println(name+"------"+productNum);
        System.out.println("创建有参对象成功");

    }


}
public class reflecTest {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        //创建对象
        //传统方式
        new Alibaba("圆珠笔",100);
        //反射方式
        Class Ali=Class.forName("com.woerma.client.Alibaba");
        Constructor constructor = Ali.getConstructor(String.class,int.class);//参数类型
       /*或者这个方法----   Constructor constructor = Ali.getDeclaredConstructor(String.class,int.class);*/
        Object o = constructor.newInstance("圆珠笔",100);
      

    }
}

在这里插入图片描述
接下来看构造方法私有化的情况下


class Alibaba{
private String name;
private int productNum;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getProductNum() {
        return productNum;
    }

    public void setProductNum(int productNum) {
        this.productNum = productNum;
    }

    private Alibaba(String name, int productNum) {
        this.name = name;
        this.productNum = productNum;
        System.out.println(name+"------"+productNum);
        System.out.println("创建有参对象成功");

    }
   static Alibaba alibaba= new Alibaba("圆珠笔",100);
public static Alibaba getInstance(){
return alibaba;
}
}
public class reflecTest {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
        //创建对象
        //传统方式
       Alibaba.getInstance();//单例设计
        //反射方式
        Class Ali=Class.forName("com.woerma.client.Alibaba");
     // Constructor constructor = Ali.getConstructor(String.class,int.class);//参数类型
        Constructor constructor = Ali.getDeclaredConstructor(String.class,int.class);
        constructor.setAccessible(true);//获得访问权限
        Object o = constructor.newInstance("圆珠笔",100);


    }
}

在这里插入图片描述

getDeclaredConstructor()与getConstructor()的区别

从代码中观察----

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

class A{
    String name;
    public A() {
        System.out.println("获得了无参实例");
    }
   private A(String name){
        System.out.println("获得了有参实例");
    }

}
public class ReflectTest0001 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class cla=Class.forName("com.woerma.client.A");
        Constructor constructor = cla.getConstructor(String.class);
        Constructor declaredConstructor = cla.getDeclaredConstructor(String.class);
        constructor.setAccessible(true);
        constructor.newInstance("李四");
        declaredConstructor.setAccessible(true);
        declaredConstructor.newInstance("张三");
    }
}

在访问公有构造器时两者都可以,但是当用getConstructor()访问私有构造器时取出现了----错误
在这里插入图片描述所以两者区别如下----
getConstructor()返回指定参数类型public的构造器。
getDeclaredConstructor()返回指定参数类型的private和public构造器。

同时要注意在访问私有构造时要先设定方位权限为true,不然getDeclaredConstructor()也不能访问;

由此来看单例设计也并不安全,

来看枚举类中的反射情况-----


enum  ThreeColor{
   RED("红"),
    GREEN("绿"),
     YELLOW("黄");
  String desc;
    ThreeColor(String desc){
       this.desc=desc;
   }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }
}
public class ReflectTest0001 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class cla=Class.forName("com.woerma.client.ThreeColor");
        Constructor declaredConstructor = cla.getDeclaredConstructor(String.class);
        declaredConstructor.setAccessible(true);
        declaredConstructor.newInstance("红");
    }
}

对枚举而言,连构造器都获得不了,所以没法获得实例,所以对于实例个数限定的可以用枚举来以确保内存的安全性

同理就可以理解 对应其他的getDeclaredxxx()方法和getxxx()方法的区别

创建对象之前的工作----加载类的字节码信息

四种方式可以加载类的字节码信息-----


class Student{}

public class Person {
    public static void main(String[] args) throws ClassNotFoundException {
        //方式一----直接通过系统内置类加载器获得
        Class aClass = Student.class;
        //方式二----通过调用对象的getClass()方法获得
        Student per= new Student();
        Class aClass1 = per.getClass();
        System.out.println(aClass);
        //方式三---
        Class aClass2=Class.forName("com.gavin.flect.Student");
        //方式四-----
        ClassLoader classLoader=Person.class.getClassLoader();//获得来的加载器
        Class aClass3 = classLoader.loadClass("com.gavin.flect.Student");//通过类加载器来完成字节码信息的加载
        System.out.println(aClass==aClass1);
        System.out.println(aClass1==aClass2);
        System.out.println(aClass2==aClass3);
    }
}

最常用的为第三种;

通过反射还能获取啥信息?

简单地说是能获取该类在运行时所有的信息-----属性,方法等;
也能获得父类的一些信息;

获得属性,方法,注解------

通过反射获得属性(包括修饰符,属性名)和方法(包括参数类型,返回值)----

package com.gavin.flect;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

/**
 * @author : Gavin
 * @date: 2021/8/26 - 08 - 26 - 15:47
 * @Description: com.gavin.flect
 * @version: 1.0
 */

 class FatherTest {
    @MySon(name="李二狗他爸",age=48)
    void eat(String food){//default
        System.out.println("我爱吃----"+food);
    }
}
class SonTest extends FatherTest{
     //属性区
     public static String name;
     private int age;
     String gender;
//构造方法区

    public SonTest(String name, int age) {
        this.name = name;
        this.age = age;
    }

    private SonTest(String name) {
        this.name = name;
    }

    //方法区
    @MySon(name="李二狗",age=18)
     void eat(String food){//default
         System.out.println("我爱吃----"+food);
     }
     public String show(String show,int age){
         return "我"+age+"岁就会表演---"+show;
     }
     protected int getAge(){
         return 19;
     }

     private static void call(){
         System.out.println("有事给我打电话");
     }
}

测试代码---------------获取属性相关信息


class Test{
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
       Class cla=Class.forName("com.gavin.flect.SonTest") ;
       //获得属性
        Field name = cla.getField("name");//getField()只能获得public修饰的属性
        System.out.println(name);
        System.out.println(name.getName());//获取属性名
        int modifiers = name.getModifiers();//获取属性修饰符
        System.out.println(Modifier.toString(modifiers));//打印修饰符
        System.out.println("1-----------------");
        Field[] shuxing = cla.getDeclaredFields();//getDeclaredFields可获得所有
        for ( Field f:shuxing
             ) {
            System.out.println(f.toString());
        }    
    }
}


在这里插入图片描述

测试代码---------------获取方法相关信息


class Test{
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
       Class cla=Class.forName("com.gavin.flect.SonTest") ;

        //获取方法
        Method[] dMethods = cla.getMethods();//获取当前类中的所有被public修饰的方法包括父类中的被public修饰的
        for (Method d:dMethods
             ) {
            System.out.println(d);
        }
        System.out.println("1----------------------");
        Method show = cla.getMethod("show", String.class, int.class);//getMethod只能获得public修饰的方法
        System.out.println(show);
        int modifiers = show.getModifiers();//获得方法的修饰符
        System.out.println(Modifier.toString(modifiers));//打印修饰符
        System.out.println("2----------------------");
        Class cla1=Class.forName("com.gavin.flect.SonTest") ;
        Method[] declaredMethods1 = cla1.getDeclaredMethods();//获得当前类中的所有方法---不包括父类
        for (Method d :
                declaredMethods1) {
            System.out.println(d);
        }

    }
}

在这里插入图片描述

测试代码---------------获取注解相关信息


class Test {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        Class cla = Class.forName("com.gavin.flect.SonTest");

        Method eat = cla.getDeclaredMethod("eat", String.class);
        Annotation[] declaredAnnotations = eat.getDeclaredAnnotations();//得到该方法上的所有注解----RetentionPolicy.RUNTIME条件下的
        for (Annotation an :
                declaredAnnotations) {
            System.out.println(an);
        }
        Annotation annotation = eat.getAnnotation(MySon.class);
        System.out.println(annotation);
       
        }
    }
}

在这里插入图片描述
在SonTest类中补充方法funmethod()----获取参数的注解----

 private void funmethod(@MySon int a,@Myfather(height = 188.8) double b){

    }

测试类—

class Test {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        Class cla = Class.forName("com.gavin.flect.SonTest");
        Method funmethod = cla.getDeclaredMethod("funmethod", int.class, double.class);
        Annotation[][] parameterAnnotations = funmethod.getParameterAnnotations();
        for (Annotation [] p:parameterAnnotations
             ) {
            for (Annotation pp:p
                 ) {
                System.out.println(pp);
            }
        }

    }
}

在这里插入图片描述

通过反射调用方法-----


class Test {
    public static void main(String[] args) throws Exception {
        Class cla = Class.forName("com.gavin.flect.SonTest");//加载类字节码信息
        Constructor de = cla.getDeclaredConstructor(String.class);//获得构造方法
        de.setAccessible(true);//私有构造要设置权限可访问
        Object o = de.newInstance("李二狗");//实例化----可以转型也可以不转
        Method eat=cla.getDeclaredMethod("eat", String.class);//获得方法
      eat.invoke(o,"鱼");//运行方法----invoke(对象,方法参数)

    }
}

在这里插入图片描述
未完待续…21.8.26

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CodeMartain

祝:生活蒸蒸日上!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值