反射

1.反射机制:

java运行期间动态的加载一些不确定的类的对象。大多数的情况下我们使用的是一个确定的类,通过在内存中的加载,再使用。
反射机制提供的功能

  • 加载运行时才能确定的数据类型
  • 解析类的结构,获取其内部信息
  • 能够访问属性,调用方法,创建新的对象。

1.1 动态加载类

image.png

通过以上的代码可以总结使用Reflection.需要如下几步:

  1. 获取目标对象的Class对象
  2. 调用Class对象内省方法获取目标对类成员信息
  3. 调用目标的成员属性

1.2 解析类的结构

1.2.1 定义一个Teacher的类

public class Teacher {
private String name;
    private  int age;
    private  static  int total;
    public Teacher(String name, int age) {
        this.name = name;
        this.age = age;
        total++;
    }
    public Teacher() {
       total++;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public static int getTotal() {
        return total;
    }
    public static void setTotal(int total) {
        Teacher.total = total;}
    @Override
    public String toString() {
        return "Teacher{" + "name='" + name + '\'' + ", age=" + age + '}';
    }
}

1.2.2 对Teacher进行解析

  public class RflectionTeacher {
    private  final  static  String TEACHER_CLASS="reflection.Teacher";
    public static void main(String[] args) {
        try {
            Class<?> clazz = Class.forName(TEACHER_CLASS);
            Field[] fields = clazz.getDeclaredFields();//获取该类中的属性属性成员
            Method[] methods = clazz.getDeclaredMethods();//获取该类的成员方法
            Constructor<?>[] constructors = clazz.getConstructors();//获取该类的所有的构造方法
            System.out.println("------打印成员属性-------");
            for(Field field:fields){
                System.out.println("属性 :"+field);
                System.out.println("名称 :"+field.getName());
                System.out.println("修饰符 :"+ Modifier.toString(field.getModifiers()));
                System.out.println("--------------------------------------------------");
            }
            for (Method method:methods){
                System.out.println("方法 :"+method.toString());
                System.out.println("方法名称 :"+method.getName());
                System.out.println("方法修饰符 :"+Modifier.toString(method.getModifiers()));
                System.out.println("------方法参数列表------");
                Class<?>[] types = method.getParameterTypes();
                System.out.println(types.length!=0?"有参数":"无参数:");
                for (Class c:types){
                    System.out.println(c.getName()+"类型\t");
                }
                System.out.println("\n方法返回类 型 :"+method.getReturnType().getName());
                System.out.println("=====================================");
            }
            System.out.println("***************打印构造方法 ***************");
            for(Constructor constructor:constructors){
                System.out.println("构造方法 :"+constructor.toString());
                System.out.println("构造方法名 :"+constructor.getName());
                System.out.println("构造方法修饰符 :"+Modifier.toString(constructor.getModifiers()));
                Class[] mClass=constructor.getParameterTypes();
                System.out.print(mClass.length!=0?"有参数:":"无参数:");
                for(Class c:mClass){
                    System.out.print(c.getName()+"类型\t");
                }
                System.out.println("\n=====================================");
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

1.2.3 输出结果

------打印成员属性-------
属性 :private java.lang.String reflection.Teacher.name
名称 :name
修饰符 :private
--------------------------------------------------
属性 :private int reflection.Teacher.age
名称 :age
修饰符 :private
--------------------------------------------------
属性 :private static int reflection.Teacher.total
名称 :total
修饰符 :private static
--------------------------------------------------
方法 :public java.lang.String reflection.Teacher.toString()
方法名称 :toString
方法修饰符 :public
------方法参数列表------
无参数:

方法返回类 型 :java.lang.String
=====================================
方法 :public java.lang.String reflection.Teacher.getName()
方法名称 :getName
方法修饰符 :public
------方法参数列表------
无参数:

方法返回类 型 :java.lang.String
=====================================
方法 :public void reflection.Teacher.setName(java.lang.String)
方法名称 :setName
方法修饰符 :public
------方法参数列表------
有参数
java.lang.String类型  

方法返回类 型 :void
=====================================
方法 :public static int reflection.Teacher.getTotal()
方法名称 :getTotal
方法修饰符 :public static
------方法参数列表------
无参数:

方法返回类 型 :int
=====================================
方法 :public int reflection.Teacher.getAge()
方法名称 :getAge
方法修饰符 :public
------方法参数列表------
无参数:

方法返回类 型 :int
=====================================
方法 :public void reflection.Teacher.setAge(int)
方法名称 :setAge
方法修饰符 :public
------方法参数列表------
有参数
int类型   

方法返回类 型 :void
=====================================
方法 :public static void reflection.Teacher.setTotal(int)
方法名称 :setTotal
方法修饰符 :public static
------方法参数列表------
有参数
int类型   

方法返回类 型 :void
=====================================
***************打印构造方法 ***************
构造方法 :public reflection.Teacher(java.lang.String,int)
构造方法名 :reflection.Teacher
构造方法修饰符 :public
有参数:java.lang.String类型  int类型   
=====================================
构造方法 :public reflection.Teacher()
构造方法名 :reflection.Teacher
构造方法修饰符 :public
无参数:
=====================================

1.3 访问类的属性和方法

1.3.1 Student类

public class Student {
private String name;
    private static  int count=100;
    public Student() {
    }
    public Student(String name) {
        this.name = name;
    }
    public void setValue(String name){
        this.name = name;
    }
    public void showCount(){
        System.out.println("Student对象被实例化了"+count+"次");
    }
    public String toString(){
        return "Name:"+this.name+",调用次数:"+count;
    }
}

1.3.2 访问 name 属性的操作方法:

public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
         //访问name属性的操作方法
        Student student = new Student("zhangsan");
        Class<? extends Student> claszz = student.getClass();
        Field field = claszz.getField("name");
        Object o = field.get(student);
        System.out.println("修改前 "+ field.getName()+" 的值 "+o);
        field.set(student,"李思");
        o=field.get(student);
        System.out.println("修改后:"+field.getName()+"的值:"+o);
    }

1.3.3 访问 setValue 方法的操作方法

 public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        //访问 setValue 方法的操作方法
        Student student = new Student("zhangsan");
        Class<? extends Student> claszz = student.getClass();
        Method m = claszz.getMethod("setValue", new Class[]{String.class});
        m.invoke(student, new Object[]{"张三"});
        System.out.println(student.toString());

    }

1.3.4 访问类的有参构造方法

 public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //访问类的有参构造方法
        Class<?> clazz = Class.forName("reflection.Student");
        Constructor<?> constructor = clazz.getConstructor(new Class[]{String.class});
        Student student= (Student)constructor.newInstance(new Object[]{"陈飞"});
        System.out.println("----->>>>-----"+student);
    }

1.4 如何使用反射机制

使用反射机制,就是因为不知道运行的时候不知道使用哪一个类,所以就需要运行的时候动态加载。先加载动态的类,然后再解析类。最后使用反射API对类的成员信息进行访问。

1.5 静态代理

若代理类在程序运行前就已经存在,那么这种代理方式被成为 静态代理 ,这种情况下的代理类通常都是我们在Java代码中定义的。 通常情况下, 静态代理中的代理类和委托类会实现同一接口或是派生自相同的父类

public interface Subject {
    public  int add(int a ,int b);
}
public class ReadSubject implements  Subject {
    @Override
    public int add(int a, int b) {
        return a+b;
    }
}
public class Proxy implements Subject {

    private Subject subject=null;

    public Proxy(Subject subject) {
        this.subject = subject;
    }

    @Override
    public int add(int arg1, int arg2) {
        System.out.println("被加数为:"+arg1);
        System.out.println("加数为:"+arg2);
        return subject.add(arg1, arg2);
    }
}
public class ProxyTest {
    public static void main(String[] args) {
        Subject subject = new Proxy(new ReadSubject());
        int resulr=subject.add(1,4);
        System.out.println(resulr);
    }
}

1.6动态代理

静态代理解决了业务逻辑与日志信息脱耦的一种设计, 但是又带来其他的问题, 也就是
说我们有 100 个目标对象,就需要设计 100 个代理,这样会引起类爆炸(类非常多) 。
代理类在程序运行时创建的代理方式被成为 动态代理。 也就是说,这种情况下,代理类并不是在Java代码中定义的,而是在运行时根据我们在Java代码中的“指示”动态生成的。相比于静态代理, 动态代理的优势在于可以很方便的对代理类的函数进行统一的处理,而不用修改每个代理类的函数。

public class DynamicProxy implements InvocationHandler {
    private  Object object=null;
     public Object biding(Object object){
         this.object=object;
         return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);
     }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result=null;
        for (Object o:args){
            System.out.println(o);
        }
        result=method.invoke(object,args);
        return result;
    }
}
public class DymicProxyTest {
    public static void main(String[] args) {
        DynamicProxy dynamicProxy = new DynamicProxy();
        Subject biding = (Subject)dynamicProxy.biding(new ReadSubject());
        int resultt=biding.add(1,6);
        System.out.println(resultt);
    }
}

1.7 创建对象的几种方式

  • 使用new关键字:这是我们最常见的也是最简单的创建对象的方式,通过这种方式我们还可以调用任意的够赞函数(无参的和有参的)。比如:Student student = new Student()

  • 使用Class类的newInstance方法:我们也可以使用Class类的newInstance方法创建对象,这个newInstance方法调用无参的构造器创建对象,如:Student student2 = (Student)Class.forName("根路径.Student").newInstance(); 或者:Student stu = Student.class.newInstance();

  • 使用Constructor类的newInstance方法:本方法和Class类的newInstance方法很像,java.lang.relect.Constructor类里也有一个newInstance方法可以创建对象。我们可以通过这个newInstance方法调用有参数的和私有的构造函数。如: Constructor<Student> constructor = Student.class.getInstance(); Student stu = constructor.newInstance(); 这两种newInstance的方法就是大家所说的反射,事实上Class的newInstance方法内部调用Constructor的newInstance方法。这也是众多框架Spring、Hibernate、Struts等使用后者的原因。

  • 使用Clone的方法:无论何时我们调用一个对象的clone方法,JVM就会创建一个新的对象,将前面的对象的内容全部拷贝进去,用clone方法创建对象并不会调用任何构造函数。要使用clone方法,我们必须先实现Cloneable接口并实现其定义的clone方法。如:Student stu2 = <Student>stu.clone();这也是原型模式的应用。

  • 使用反序列化:当我们序列化和反序列化一个对象,JVM会给我们创建一个单独的对象,在反序列化时,JVM创建对象并不会调用任何构造函数。为了反序列化一个对象,我们需要让我们的类实现Serializable接口。如:ObjectInputStream in = new ObjectInputStream (new FileInputStream("data.obj")); Student stu3 = (Student)in.readObject();

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,236评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,867评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,715评论 0 340
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,899评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,895评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,733评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,085评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,722评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,025评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,696评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,816评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,447评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,057评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,254评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,204评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,561评论 2 343

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,577评论 18 399
  • 一. Java基础部分.................................................
    wy_sure阅读 3,789评论 0 11
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,598评论 18 139
  • 德泰能源邓总、左副总及其他诸君: 今日偶知德泰即将迎来五周年庆典,实在是可喜可贺!作为免费用了不少德泰充电宝的用户...
    平选2015阅读 221评论 0 0
  • 这部分内容只是对四层进行发现,发现主机是否在线。后期会针对端口进行探测。 四层发现比二层,三层更加精确。 这里要注...
    FKTX阅读 328评论 0 0