java高级之反射

——- android培训java培训、期待与您交流! ———-


java高级之反射



一 反射(类的加载概述和加载时机)

  • A:类的加载概述

    • 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。
    • 加载
      • 就是指将class文件读入内存,并为之创建一个Class对象。任何类被使用时系统都会建立一个Class对象。
    • 连接
      • 验证 是否有正确的内部结构,并和其他类协调一致
      • 准备 负责为类的静态成员分配内存,并设置默认初始化值
      • 解析 将类的二进制数据中的符号引用替换为直接引用
    • 初始化 就是我们以前讲过的初始化步骤
  • B:加载时机
    • 创建类的实例
    • 访问类的静态变量,或者为静态变量赋值
    • 调用类的静态方法
    • 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
    • 初始化某个类的子类
    • 直接使用java.exe命令来运行某个主类


二 反射(类加载器的概述和分类)

  • A:类加载器的概述

    • 负责将.class文件加载到内存中,并为之生成对应的Class对象。虽然我们不需要关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行。
  • B:类加载器的分类
    • Bootstrap ClassLoader 根类加载器
    • Extension ClassLoader 扩展类加载器
    • Sysetm ClassLoader 系统类加载器
  • C:类加载器的作用
    • Bootstrap ClassLoader 根类加载器

      • 也被称为引导类加载器,负责Java核心类的加载
      • 比如System,String等。在JDK中JRE的lib目录下rt.jar文件中
    • Extension ClassLoader 扩展类加载器
      • 负责JRE的扩展目录中jar包的加载。
      • 在JDK中JRE的lib目录下ext目录
    • Sysetm ClassLoader 系统类加载器
      • 负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径


三 反射(反射概述)

  • A:反射概述

    • JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
    • 对于任意一个对象,都能够调用它的任意一个方法和属性;
    • 这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
    • 要想解剖一个类,必须先要获取到该类的字节码文件对象。
    • 而解剖使用的就是Class类中的方法,所以先要获取到每一个字节码文件对应的Class类型的对象。
  • B:三种方式
    • a:Object类的getClass()方法,判断两个对象是否是同一个字节码文件,如 new Date().getClass();
    • b:静态属性class,锁对象
    • c:Class类中静态方法forName(),读取配置文件, 如 Class.forName(“java.util.Date”);
  • C:案例演示
    • 获取class文件对象的三种方式

public class ReflectTest
{
    public static void main(String[] args) throws Exception
    {
        String str = "abc";

        Class cls1 = str.getClass();
        Class cls2 = String.class;
        Class cls3 = Class.forName("java.lang.String");

        //说明他们是同一份字节码
        System.out.println(cls1==cls2);//true
        System.out.println(cls1==cls3);//true

        System.out.println(cls1.isPrimitive());//false
        System.out.println(int.class.isPrimitive());//true
        System.out.println(int.class == Integer.class);//false
        System.out.println(Integer.class.isPrimitive());//false
        System.out.println(int.class == Integer.TYPE);//true

        System.out.println(int[].class.isPrimitive());//false

        System.out.println(int[].class.isArray());//true

运行结果:



注意:

数组类型的Class实例对象

Class.isArray();

  • 总之.只要在源程序中出现的类型,都有各自的Class示例对象 例如 int[] void…


四 反射(Class.forName()读取配置文件举例)

  • 榨汁机(Juicer)榨汁的案例
  • 分别有水果(Fruit)苹果(Apple)香蕉(Banana)桔子(Orange)榨汁(squeeze)
/*
    榨汁机(Juicer)榨汁的按例
    分别有水果(Fruit) 苹果 香蕉 橘子 榨汁

    注: 本例为了突出核心代码,没有进行异常处理
*/
import java.io.*;
public class ReflectDemo
{
    public static void main(String[] args) throws Exception
    {
        //没有用反射  只有多态
//      Juicer j = new Juicer();//买榨汁机
//      j.run(new Apple());//往榨汁机里面扔苹果
//      j.run(new Orange());

        //利用反射和配置文件
        //创建流对象,关联配置文件
        BufferedReader br = new BufferedReader(new FileReader("d:\\config.properties"));
        //,获取该类的字节码对象, 读取配置文件一行内容
        Class clazz = Class.forName(br.readLine());

        //通过字节码对象创建对象实例
        Fruit f = (Fruit)clazz.newInstance();//父类引用指向子类对象  水果的引用指向了苹果对象

        Juicer j = new Juicer();//创建一个榨汁机对象
        j.run(f);

    }
}

interface Fruit
{
    public void squeeze();
}

class Apple implements Fruit
{
    public void squeeze()
    {
        System.out.println("榨苹果汁");
    }
}

class Orange implements Fruit
{
    public void squeeze()
    {
        System.out.println("榨橘子汁");
    }
}

class Juicer
{
    public void run(Fruit f)
    {
        f.squeeze();
    }
}

运行结果:



总结:

通过反射,大大简化了代码的应用场景.在本例中,要改变程序的功能只需要修改相应的配置文件即可,而不用大费周折的修改源码.

从另一方面看, 大大增强了程序的安全性和健壮性.



五 反射(通过反射获取带参构造方法并使用)

  • Constructor

    • Class类的newInstance()方法是使用该类无参的构造函数创建对象, 如果一个类没有无参的构造函数, 就不能这样创建了,可以调用Class类的getConstructor(String.class,int.class)方法获取一个指定的构造函数然后再调用Constructor类的newInstance(“张三”,20)方法创建对象

      示例代码:

/*
    注意: 为了程序简便.本例没有加上Person类.
*/
import java.lang.reflect.*;
class ReflectDemo2
{
    public static void main(String[] args) throws Exception
    {
        Class clazz = Class.forName("Person");
//      Person p = (Person)clazz.newInstance();//通过无参构造对象
//      System.out.println(p);

        //获取有参数构造
        Constructor c = clazz.getConstructor(String.class,int.class);

        //通过有参构造创建对象
        Person p = (Person)c.newInstance("张三",22);
        System.out.println(p);
    }
}

运行结果:




六 反射(通过反射获取成员变量并使用)

  • Field

    • Class.getField(String)方法可以获取类中的指定字段(可见的), 如果是私有的可以用getDeclaedField(“name”)方法获取,通过set(obj, “李四”)方法可以设置指定对象上该字段的值, 如果是私有的需要先调用setAccessible(true)设置访问权限,用获取的指定的字段调用get(obj)可以获取指定对象中该字段的值

代码实现如下:

import java.lang.reflect.*;
class ReflectDemo3
{
    public static void main(String[] args) throws Exception
    {

        Class clazz = Class.forName("Person");
        Constructor c = clazz.getConstructor(String.class,int.class);
        Person p = (Person)c.newInstance("张三",22);

        //因为姓名字段是private的  因此获取不到
        //Field f = clazz.getField("name");//获取姓名字段
        //f.set(p,"李四");//修改姓名

        //通过暴力反射获取字段
        Field f = clazz.getDeclaredField("name");
        f.setAccessible(true);//取出权限
        f.set(p,"李四");

        System.out.println(p);
    }
}

运行结果:





七 反射(通过反射获取方法并使用)

  • Method

    • Class.getMethod(String, Class…) 和 Class.getDeclaredMethod(String, Class…)方法可以获取类中的指定方法,调用invoke(Object, Object…)可以调用该方法,Class.getMethod(“eat”) invoke(obj) Class.getMethod(“eat”,int.class) invoke(obj,10)

示例代码:

import java.lang.reflect.*;
class ReflectDemo4
{
    public static void main(String[] args) throws Exception
    {
        Class clazz = Class.forName("Person");
        Constructor c = clazz.getConstructor(String.class,int.class);
        Person p = (Person)c.newInstance("张三",22);

        Method m = clazz.getMethod("eat"); //获取Method方法
        m.invoke(p);

        Method m2 = clazz.getMethod("eat",int.class);//获取有参的方法
        m2.invoke(p,10);//运行放法
    }
}

运行结果:


八 反射(通过反射越过泛型检查)

  • A:案例演示

    • ArrayList的一个对象,在这个集合中添加一个字符串数据,如何实现呢?
/*
    * A:案例演示  泛型擦除  泛型反射
    * ArrayList<Integer>的一个对象,在这个集合中添加一个字符串数据,如何实现呢?

    泛型只在编译期有效,在运行期会被擦除掉
*/
import java.util.*;
import java.lang.reflect.*;
class ReflectTest1
{
    public static void main(String[] args) throws Exception
    {
        ArrayList<Integer> list = new ArrayList<Integer>();
        list.add(111);
        list.add(222);

        //获取字节码对象
        Class clazz = Class.forName("java.util.ArrayList");
        //获取add方法
        Method m = clazz.getMethod("add",Object.class);

        m.invoke(list,"abc");//运行方法

        System.out.println(list);
    }
}

运行结果:



总结:

泛型只在编译期有效,在运行期会被擦除掉


九 反射(通过反射写一个通用的设置某个对象的某个属性为指定的值)

  • A:案例演示

    • public void setProperty(Object obj, String propertyName, Object value){},此方法可将obj对象中名为propertyName的属性的值设置为value。
import java.lang.reflect.*;
class ReflectTest2
{
    public static void main(String[] args) throws Exception
    {
        //创建Student实例
        Student s = new Student("张三",23);
        System.out.println("修改前的信息: "+s);

        Tool t = new Tool();//创建工具类实例
        t.setProperty(s,"name","李四");
        System.out.println("修改后的信息: "+s);

    }
}
//工具类
class Tool
{
    //此方法可将obj对象中名为propertyName的属性的值设置为value
    public void setProperty(Object obj, String propertyName, Object value)throws Exception
    {
        Class clazz = obj.getClass();//获取字节码对象
        Field f = clazz.getDeclaredField(propertyName);//暴力反射获取字段

        f.setAccessible(true);//取出权限
        f.set(obj,value);

    }
}   

class Student
{
    private String name;
    private int age;

    public Student()//无参构造方法
    {

    }

    public Student(String name,int age)//有参构造方法
    {
        this.name = name;
        this.age = age;
    }

    public String getName()
    {
        return name;
    }

    public int getAge()
    {
        return age;
    }

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

    public void setAge(int age)
    {
        this.age = age;
    }

    public String toString()
    {
        return "name= "+name+", "+"age="+age;
    }
}

运行结果:





十 反射(练习)

  • 已知一个类,定义如下:

    • package cn.itcast.heima;
    • public class DemoClass {

      public void run() {

      System.out.println(“welcome to heima!”);

      }

      }

    • (1) 写一个Properties格式的配置文件,配置类的完整名称。
    • (2) 写一个程序,读取这个Properties配置文件,获得类的完整名称并加载这个类,用反射的方式运行run方法。
import java.io.*;
import java.lang.reflect.*;
class ReflectTest3
{
    public static void main(String[] args) throws Exception
    {
        //创建输入流 关联配置文件
        BufferedReader br = new BufferedReader(new FileReader("D:\\xxx.txt"));
        Class clazz = Class.forName(br.readLine());//读取配置文件中的类名  获取字节码对象

        DemoClass dc = (DemoClass)clazz.newInstance();//通过字节码对象创建对象
        dc.run();
    }
}

class DemoClass
{
    public void run()
    {
        System.out.println("Welcome to heima");
    }
}

运行结果:





十一 反射(动态代理的概述和实现)

  • A:动态代理概述

    • 代理:本来应该自己做的事情,请了别人来做,被请的人就是代理对象。
    • 举例:春节回家买票让人代买
    • 动态代理:在程序运行过程中产生的这个对象,而程序运行过程中产生对象其实就是我们刚才反射讲解的内容,所以,动态代理其实就是通过反射来生成一个代理
    • 在Java中java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口就可以生成动态代理对象。JDK提供的代理只能针对接口做代理。我们有更强大的代理cglib,Proxy类中的方法创建动态代理类对象
    • public static Object newProxyInstance(ClassLoader loader,Class(?)[] interfaces,InvocationHandler h)
    • 最终会调用InvocationHandler的方法
    • InvocationHandler Object invoke(Object proxy,Method method,Object[] args)

——- android培训java培训、期待与您交流! ———-

时间: 2024-10-27 12:23:02

java高级之反射的相关文章

Java高级特性—反射和动态代理

1).反射 通过反射的方式可以获取class对象中的属性.方法.构造函数等,一下是实例: 2).动态代理 使用场景: 在之前的代码调用阶段,我们用action调用service的方法实现业务即可. 由于之前在service中实现的业务可能不能够满足当先客户的要求,需要我们重新修改service中的方法, 但是service的方法不只在我们这个模块使用,在其他模块也在调用,其他模块调用的时候, 现有的service方法已经能够满足业务需求,所以我们不能只为了我们的业务而修改service,导致其他

java进阶之反射:反射基础之如何获取一个类以及如何获取这个类的所有属性和方法(1)

java学习一段时间之后,大家可能经常会听到反射这个词,那么说明java已经学习到一个高一点的层次了.接下来我会一步步和大家一起揭开java高级特性反射的神秘面纱. 首先介绍下类对象这个概念,可能会经常用到这个概念: 类对象:java中有句很经典的话"万事万物皆对象",相信大家都不陌生,这句话告诉了我们java的特征之一,那就是面向对象.java中类的概念我们都很熟悉,既然万事万物皆是对象,那么类是谁的对象呢?<对象的概念:一个类的实例>换句话说,类是谁的实例.如此就有了类

java高级值类反射

 类反射 类反射,这是属于java高级的技术了,如果把这个学好了,那么你的java学习之路就上了一个台阶了. 一.什么是类反射? 1.JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调           用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制. 2.反射(Reflection)是Java程序开发语言的特征之一,它允许运行中的Java程序对自身进行检查, 也称自审,并能直接操作

反射----Java高级开发必须懂的

定义: JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制. 1.在面向对象的世界里,万事万物皆对象. java语言中,静态的成员.普通数据类型是不是对象呢?不是 类是谁的对象呢?类是对象,类是java.lang,Class类的实例对象. 好比,自定义一个student对象,student是Student类的实例对象. 任何一个类,都是Cla

第16篇-JAVA 类加载与反射

第16篇-JAVA 类加载与反射 每篇一句 :敢于弯曲,是为了更坚定的站立 初学心得: 追求远中的欢声笑语,追求远中的结伴同行 (笔者:JEEP/711)[JAVA笔记 | 时间:2017-05-12| JAVA 类加载与反射 ] 1.类加载 类加载器负责将 .class 文件(可能在磁盘上, 也可能在网络上) 加载到内存中, 并为之生成对应的 java.lang.Class 对象 当程序主动使用某个类时,如果该类还未被加载到内存中,系统会通过加载.连接.初始化三个步骤来对该类进行初始化,如果没

Java高级开发工程师面试考纲

如果要应聘高级开发工程师职务,仅仅懂得Java的基础知识是远远不够的,还必须懂得常用数据结构.算法.网络.操作系统等知识.因此本文不会讲解具体的技术,笔者综合自己应聘各大公司的经历,整理了一份大公司对Java高级开发工程师职位的考核纲要,希望可以帮助到需要的人. 当前,市面上有<Java XX宝典>类似的图书,而且图书中的内容都着重在讲解Java最为基础的部分,最严重的是,里面有着大量错误的内容,极具误导性.另外,网上也有各种各样的Java面试题,很多也是着重在Java语言基础上.实际上,如果

问题集录--Java高级软件工程师面试考纲(转)

如果要应聘高级开发工程师职务,仅仅懂得Java的基础知识是远远不够的,还必须懂得常用数据结构.算法.网络.操作系统等知识.因此本文不会讲解具体的技术,笔者综合自己应聘各大公司的经历,整理了一份大公司对Java高级开发工程师职位的考核纲要,希望可以帮助到需要的人. 当前,市面上有<Java XX宝典>类似的图书,而且图书中的内容都着重在讲解Java最为基础的部分,最严重的是,里面有着大量错误的内容,极具误导性.另外,网上也有各种各样的Java面试题,很多也是着重在Java语言基础上.实际上,如果

(转)Java高级开发工程师面试考纲

当前,市面上有<Java XX宝典>类似的图书,而且图书中的内容都着重在讲解Java最为基础的部分,最严重的是,里面有着大量错误的内容,极具误导性.另外,网上也有各种各样的Java面试题,很多也是着重在Java语言基础上.实际上,如果要应聘高级开发工程师职务,仅仅懂得Java的基础知识是远远不够的,还必须懂得常用数据结构.算法.网络.操作系统等知识.因此本文不会讲解具体的技术,笔者综合自己应聘各大公司的经历,整理了一份大公司对Java高级开发工程师职位的考核纲要,希望可以帮助到需要的人. 1

Java学习之反射机制

前段时间在做项目的时候,由于是用的纯Servlet基础框架进行开发的,没有用到那些集成的框架,后来在后台处理表单中的数据的时候,感觉有很多东西都是重复的,比较繁琐,例如获取到前台页面表单中的值之后,要在后台实例化一个对象并且调用定义的setter方法来给对象赋值,由于表单中的数据比较多,然后这个调用setter方法的代码就显得有些重复臃肿,后来网上查资料才了解到可以通过java中的反射机制简化这一操作,并且也知道了很多框架里面也都用到了反射... 一.什么是反射机制 JAVA反射机制是在运行状态