Java基础——反射 reflect

a { text-decoration: none; color: inherit }
* { margin: 0; padding: 0 }
body { text-indent: 2rem }
.on { margin: 10px 0; cursor: pointer; color: white; text-indent: 2rem }
.on2 { background-color: deeppink; font: bold 24px/50px "" }
.on3 { font: bold 20px/40px ""; background-color: rgb(44, 219, 135) }
p { text-indent: 2rem; font: 20px/34px "" }

什么是反射

(1)Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。

(2)反射(Reflection)是Java程序开发语言的特征之一,它允许运行中的Java程序对自身进行检查, 也称自审,并能直接操作程序的内部属性。例如,使用它能获得Java类中各成员的名称并显示出来。

(3)Java的这一能力在实际应用中应用得很多,在其它的程序语言中根本就不存在这一特性。例如,Pascal、C或者C++中就没有办法在程序中获得函数定义相关的信息。

(4)JavaBean是类反射的实际应用之一,它能让一些工具可视化的操作软件组件。这些工具通过类反射动态的载入并取得Java组件(类)的属性。后面学习的各种框架,基本上都会有反射的使用。

使用反射的基本步骤

用于反射的类,如Method,可以在java.lang.reflect包中找到。使用这些类的时候必须要遵循三个步骤:

第一步:获得你想操作的类的java.lang.Class对象。在运行中的Java程序中,用java.lang.Class类来描述类和接口等。

第二步:调用诸如getDeclaredMethods的方法,取得该类中定义的所有方法的列表。

第三步:使用反射的API来操作这些信息。

认识 java.lang.Class 类

在面向对象的世界里,万事万物皆对象。

那么类(java语言中,静态的成员、普通数据类型除外)是不是对象呢?

类是(哪个类的对象呢?)谁的对象呢?

There is a class named Class .

定义的每一个类都是对象,类是java.lang.Class类的实例对象。

定义一个Foo类

package com.demo.reflect;class Foo{
       public void print(){
             System.out.println("Foo");
    }
 }    

Foo 类的实例对象表示方式:

    Foo f = new Foo();

    //f 就可以表示了 Foo 类的一个对象,这个表示很清晰明了。

定义的 Foo 类也是一个对象,是 java.lang.Class 的对象。

查看源码发现,java.lang.Class类没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的,因此不能显式地声明一个Class对象。

那么问题来了:怎么表示这个对象呢?

在 java 语言中,任何一个类都是Class的实例对象,这个实例对象有三种表示方式。

第一种表示方式: 类.class 告诉我们任何一个类都有一个隐含的静态成员变量class

Class c1 = Foo.class;

第二中表达方式 : 通过该类的对象调用 getClass() 方法

Class c2 = foo1.getClass();

第三种表达方式 : 使用Class类的中静态forName(‘类的全称‘)方法获得与字符串对应的Class对象

Class c3 = Class.forName("com.demo.reflect.Foo");

在java官网中说明:c1 、c2、c3 表示了 Foo类的类类型(class type)。

代码测试c1\c2\c3是否代表同一个对象?

System.out.println(c1==c2);//true

System.out.println(c1==c3);//true

根据输出结果,表示一个类只可能是Class类的一个实例对象。

实际情况下:虚拟机为每种类型管理一个独一无二的Class对象。也就是说,每个类(型)都有一个Class对象。运行程序时,Java虚拟机(JVM)首先检查是否 所要加载的类对应的Class对象是否已经加载。如果没有加载,JVM就会根据类名查找.class文件,并将其Class对象载入。

小结:万事万物皆对象,类也是对象,是Class类的实例对象,这个对象我们称为该类的类类型(不仅仅代表是类或者接口)。

备注:基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也都对应一个 Class 对象。 每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该 Class 对象。

细说:Class.forName(String className)

Class.forName() 不仅表示了类的类类型,还代表了动态加载类。

那什么是静态加载和动态加载?

动态加载:程序在运行时调用相应方法,即使其他方法是错误的,程序依旧会执行。通过动态加载可以让程序的可延长性大大提升,对以后的维护和扩展有重要意义。

静态加载:程序在编译时执行。在执行过程中加载所有可能执行到的程序。在这种加载方式下,只要加载中一个方法出错,程序就不能运行。我们一般写程序默认的是静态加载。

通过下面案例进行分析:

public class Test{
    public static void main(String[] args) {
        // 静态加载。编译时加载,编译时就需要加载全部可能使用到的的类,一个类出错,其他类的功能都不能得到执行
        if ("Word".equals(args[0])) {
            Word Word = new Word();
            System.out.println("Word");
        }
        if ("Excel".equals(args[0])) {
            Excel excel = new Excel();
            System.out.println("Excel");
        }
    }
}

如果你不定义Word类和Excel类,则会出现编译错误。

若你想程序能运行,必须定义Word类和Excel类。

假想如下场景,Test中有100个功能,你只想使用A功能,如果你使用的是静态加载的机制,你必须定义其余的99种功能才能使用A功能,如果使用动态加载机制,不仅不用定义99中功能,通过实现某种标准(继承某个接口),将大大方便了代码的编写。

  创建一个接口:

public interface MyStandard{
    public void print();
  }

新建一个程序入口:

public static void main(String[] args) {

//运行时加载,动态加载类
  Class c1 = Class.forName(args[1]);
  //通过类类型加载对象。
  //返回的是包含N个class的接口,以免程序编译错乱
  RunBetter rb = (RunBetter)c1.newInstance();
  rb.print();
}

实现接口:

class Word implements MyStandard{

  public void print(){
    System.out.println("Word ");
  }
}

class Excel implements MyStandard{

  public void print(){ 
    System.out.println("A"); 
  } 
}

想要使用那个类就传入该类。

得到类的类类型,我们可以干什么呢?

Class 类里面提供了很多解析、操作类的方法,详情可以查看API 文档。最重要的方法:Class.forName(String className)

得到类的构造方法

/**
     * 打印对象的构造函数的信息
     * @param obj
     */
    public static void printConMessage(Object obj){
        Class c = obj.getClass();
        /*
         * 构造函数也是对象
         * java.lang. Constructor中封装了构造函数的信息
         * getConstructors获取所有的public的构造函数
         * getDeclaredConstructors得到所有的构造函数
         */
        //Constructor[] cs = c.getConstructors();
        Constructor[] cs = c.getDeclaredConstructors();
        for (Constructor constructor : cs) {
            System.out.print(constructor.getName()+"(");
            //获取构造函数的参数列表--->得到的是参数列表的类类型
            Class[] paramTypes = constructor.getParameterTypes();
            for (Class class1 : paramTypes) {
                System.out.print(class1.getName()+",");
            }
            System.out.println(")");
        }
    }

得到类的属性

 /**
     * 获取成员变量的信息
     * @param obj
     */
    public static void printFieldMessage(Object obj) {
        Class c = obj.getClass();
        /*
         * 成员变量也是对象
         * java.lang.reflect.Field
         * Field类封装了关于成员变量的操作
         * getFields()方法获取的是所有的public的成员变量的信息
         * getDeclaredFields获取的是该类自己声明的成员变量的信息
         * field.setAccessible(true); 破除封装,属性强制可见
         */
        //Field[] fs = c.getFields();
        Field[] fs = c.getDeclaredFields();
        for (Field field : fs) {
            //得到成员变量的类型的类类型
            Class fieldType = field.getType();
            String typeName = fieldType.getName();
            //得到成员变量的名称
            String fieldName = field.getName();
            System.out.println(typeName+" "+fieldName);
        }
    }

得到类的方法

/*
         * Method类,方法对象
         * 一个成员方法就是一个Method对象
         * getMethods()方法获取的是所有的public的函数,包括父类继承而来的
         * getDeclaredMethods()获取的是所有该类自己声明的方法,不问访问权限
         */
        Method[] ms = c.getMethods();//c.getDeclaredMethods()
        for(int i = 0; i < ms.length;i++){
            //得到方法的返回值类型的类类型
            Class returnType = ms[i].getReturnType();
            System.out.print(returnType.getName()+" ");
            //得到方法的名称
            System.out.print(ms[i].getName()+"(");
            //获取参数类型--->得到的是参数列表的类型的类类型
            Class[] paramTypes = ms[i].getParameterTypes();
            for (Class class1 : paramTypes) {
                System.out.print(class1.getName()+",");
            }
            System.out.println(")");
        }
    }

反射的基本操作

public class Book {

    private String name;
    private double price;

    public void setPrice(double price) {
        this.price = price;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Book(){
        System.out.println("****无参数构造");
    }

    @Override
    public String toString() {
        return "Book [name=" + name + ", price=" + price + "]";
    }

    public Book(String name, double price) {
        super();
        this.name = name;
        this.price = price;
    }
}

Book 类

构造方法反射实例化对象

getConstructor(Class[]) 
返回当前 Class 对象表示的类的指定的公有构造子对象。 
  getConstructors() 
返回当前 Class 对象表示的类的所有公有构造子对象数组。 
  getDeclaredConstructor(Class[]) 
返回当前 Class 对象表示的类的指定已说明的一个构造子对象。 
  getDeclaredConstructors() 
返回当前 Class 对象表示的类的所有已说明的构造子对象数组。

@Test
    public void testBookConstructor() throws Exception{
        Class<?> cs = Class.forName("com.jcy.po.Book");
        //调用类的无参构造器
        Object obj = cs.newInstance();
        Book b = (Book) obj;
        b.setName("无参构造器");
        System.out.println(b);
        //调用类的有参构造器
        Constructor constructor =cs.getConstructor( new Class [] { String.class,double.class});
        //也可以 --> cs.getConstructor( String.class,double.class);
        Book b2 = (Book)constructor.newInstance("有参构造器",100.00);
        System.out.println(b2);
        //输出结果:
        //Book [name=无参构造器, price=0.0]
        //Book [name=有参构造器, price=100.0]
    }

反射操作属性

getDeclaredField(String) 
返回当前 Class 对象表示的类或接口的指定已说明的一个域对象。 
  getDeclaredFields() 
返回当前 Class 对象表示的类或接口的所有已说明的域对象数组。 
  getField(String) 
返回当前 Class 对象表示的类或接口的指定的公有成员域对象。 
  getFields() 
返回当前 Class 对象表示的类或接口的所有可访问的公有域对象数组。

@Test
    public void testBookField() throws Exception{
        Book book = new Book("反射书",10.00);
        Class cs = book.getClass();
        System.out.println(book);
        Field [] fields = cs.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field.getName());
        }
        Field field = cs.getDeclaredField("name");
        //此处报错java.lang.IllegalAccessException
        //私有属性不可以直接访问
        //field.set("name", "强行赋值");
        field.setAccessible(true);//设置该属性为可使用
        field.set(book, "强行赋值");//不报错
        System.out.println(book);
    }//输出结果:

Book [name=反射书, price=10.0]   name   price  Book [name=强行赋值, price=10.0]


方法反射的调用 

getMethod(String, Class[]) 
返回当前 Class 对象表示的类或接口的指定的公有成员方法对象。 
  getMethods() 
返回当前 Class 对象表示的类或接口的所有公有成员方法对象数组,包括已声明的和从父类继承的方法。

getDeclaredMethod(String, Class[]) 
返回当前 Class 对象表示的类或接口的指定已说明的一个方法对象。 
  getDeclaredMethods() 
返回 Class 对象表示的类或接口的所有已说明的方法数组。

@Test
    public void testBookMethod() throws Exception{
        //获得类中的方法
        //getMethod获取的是public的方法,包括继承的方法
        //getDelcaredMethod自己声明的方法
        //getMethod 根据方法名和方法的参数类类型得到对应方法
        Class<?> cs = Class.forName("com.jcy.po.Book");
        Book b = (Book) cs.newInstance();
        //方法的反射操作
        //m.invoke(b,"格林童话");方法的反射操作是用m对象来进行方法调用
        //和b.setName(格林童话);调用的效果完全相同
        //方法如果没有返回值返回null,有返回值返回具体的返回值
        Method m =cs.getMethod("setName", String.class);
        System.out.println(b);
        m.invoke(b,"格林童话");
        System.out.println(b);
        Method[] ms = cs.getMethods();
        for (Method method : ms) {
            System.out.println(method.getName());
        }
        //输出结果:
        /*
         * Book [name=null, price=0.0]
            Book [name=格林童话, price=0.0]
            toString
            setName
            setPrice
            wait
            wait
            wait
            equals
            hashCode
            getClass
            notify
            notifyAll
         *
         */
    }

 

类反射调用图

原文地址:https://www.cnblogs.com/SacredOdysseyHD/p/8353807.html

时间: 2024-10-05 22:04:10

Java基础——反射 reflect的相关文章

黑马程序员——java基础——反射

 黑马程序员--java基础--反射 ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 反射 其实就是动态加载一个指定的类,并获取该类中的所有的内容.而且将字节码文件封装成对象,并将字节码文件中的内容都封装成对象,这样便于操作这些成员. 反射就是把Java类中的各种成分映射成相应的java类. 简单说:反射技术可以对一个类进行解剖. 反射的基石-->Class类 1.java中的类是用来描述一类事物的共性,该类事物有什么属性,没有什么属性

黑马程序员——JAVA基础-反射

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 反射是在运行状态中,对于任意一个类(class文件),都能够知道这个类的所有属性和方法:对于任意一个对象,都只能都调用它的任意一个 方法和属性,这种动态获取的信息一级动态调用对象的方法的功能呢个称为java 的反射机制. 反射其实就是动态加载一个指定的类,并获取该类中的所有的内容.而且将字节码文件封装成对象, 并将字节码文件中的内容都封装成对象,这样便于操作这些成员.就是把JAVA类中的各种成

黑马程序员-java基础-反射基础

------- android培训.java培训.期待与您交流! ---------- java的反射机制是java的特性之一,反射机制是构建框架技术的基础所在,使用反射可以使程序更加灵活,避免将程序写死在代码里.相对于很多初学者只接触过java基础的人,反射还是一个很朦胧难懂的概念,下面我们就来说一下反射的一些应用. java反射机制是指在运行状态中,动态获取信息以及动态调用对象方法的功能.java反射有3个动态性质:1.运行时生成对象实例,2.运行期间调用发放,3.运行时更改属性. 那么反射

一天一个Java基础——反射

1.概念 反射主要是指程序可以访问,检测和修改它本身的状态或行为的一种能力 Java中的反射是一种强大的工具,它能够创建灵活的代码,这些代码可以运行时装配,无须在组件之间进行链接 反射允许在编写与执行时,使程序代码能够接入装载到JVM中的类的内部信息,而不是源代码中选定的类协作的代码 如果使用不当,反射的成本会很高 2.例子 1 package Test; 2 3 import java.lang.reflect.Constructor; 4 import java.lang.reflect.F

黑马程序员——JAVA基础-反射练习

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 1 import java.lang.reflect.*; 2 3 class reflectDemo 4 { 5 public static void main(String[] args) throws Exception 6 { 7 String s="Hello World"; 8 //创建Class对象的三种方式. 9 Class c1=String.class; 10 C

黑马程序员----java基础--反射机制

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 一.反射的基本描述 Java反射机制是在运行状态中,对于任意一个类(class文件),都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象方法的功能称为java语言的反射机制.动态获取类中信息,就是java反射.可以理解为对类的解剖.如果想要对指定名称的字节码文件进行加载并获取其中的内容并调用,这时就使用到了反射技术. 简单一

Java 基础 - 反射

基本概念 Java 反射机制可以让我们在编译期(Compile Time)之外的运行期(Runtime)检查类,接口,变量以及方法的信息. 利用反射,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性. Class 想要获取一个类的信息,首先需要获取类的Class对象. Java中的所有类型包括基本类型(int, long, float等等),即使是数组都有与之关联的Class类的对象. 获取类的对象 //在编译期知道一个类的名字 Class c

黑马程序员-java基础-反射

java.lang.Class类的实例代表java应用程序运行时加载的.class文档. 其构造函数: private Class() {} 说明我们无法创建Class对象,Class对象是有JVM自动产生,每个.class文档加载后,JVM会自动生成对应的Class对象. 什么时候加载.class文件进内存 1,用Class.forName()或者类加载器(Class claz = fu.class 没有执行static{}块??) 2,用 new 生成对象时 注意:用类声明参考名称并不会加载

黑马程序员——Java基础---反射Class类、Constructor类、Field类

------<a href="http://www.itheima.com" target="blank">Java培训.Android培训.iOS培训..Net培训</a>.期待与您交流! ------- 反射的应用场景 一.概述 反射技术: Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类中的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的