java之反射一文详解

使用Spring需要用到反射知识,故整理

反射是框架设计的灵魂

(使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码))

一、反射的概述

1.1 反射机制的概念:

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

要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.

所谓反射其实是获取类的字节码文件,也就是.class文件,那么我们就可以通过Class这个对象进行获取。

1.2 反射的应用场合

在Java程序中许多对象在运行是都会出现两种类型:编译时类型和运行时类型。
编译时的类型由声明对象时实用的类型来决定,运行时的类型由实际赋值给对象的类型决定

Person p=new Student();//其中编译时类型为Person,运行时类型为Student。

除此之外,程序在运行时还可能接收到外部传入的对象,该对象的编译时类型为Object,但是程序有需要调用该对象的运行时类型的方法。为了解决这些问题,程序需要在运行时发现对象和类的真实信息。然而,如果编译时根本无法预知该对象和类属于哪些类,程序只能依靠运行时信息来发现该对象和类的真实信息,此时就必须使用到反射了。

总结:
反射就是把java类中的各种成分映射成一个个的Java对象
例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。
(其实:一个类中这些成员方法、构造方法、在加入类中都有一个类来描述)

1.3 反射的原理

Class对象的由来是将class文件读入内存,并为之创建一个Class对象。

img

二、JAVA反射的涉及的类

反射API用来生成JVM中的类、接口或则对象的信息。

类名用途
Class类代表类的实体,在运行的Java应用程序中表示类和接口。反射的核心类,可以获取类的属性,方法等信息。
Field类Java.lang.reflec包中的类,表示类的成员变量,可以用来获取和设置类之中的属性值。
Method类Java.lang.reflec包中的类,表示类的方法,它可以用来获取类中的方法信息或者执行方法。
Constructor类Java.lang.reflec包中的类,表示类的构造方法。

注意区分:我们自己创建的类是继承Object的。而反射使用最多的是Class对象,是系统里的另外一个类。

速查表:

Class类-获得类相关方法用途
asSubclass(Class clazz)把传递的类的对象转换成代表其子类的对象
Cast把对象转换成代表类或是接口的对象
getClassLoader()获得类的加载器
getClasses()返回一个数组,数组中包含该类中所有公共类和接口类的对象
getDeclaredClasses()返回一个数组,数组中包含该类中所有类和接口类的对象
forName(String className)根据类名返回类的对象
getName()获得类的完整路径名字
newInstance()创建类的实例
getPackage()获得类的包
getSimpleName()获得类的名字
getSuperclass()获得当前类继承的父类的名字
getInterfaces()获得当前类实现的类或是接口
Class类-获得类属性方法用途
getField(String name)获得某个公有的属性对象
getFields()获得所有公有的属性对象
getDeclaredField(String name)获得某个属性对象
getDeclaredFields()获得所有属性对象
Class类-获得类中注解方法(可以先不用掌握)用途
getAnnotation(Class annotationClass)返回该类中与参数类型匹配的公有注解对象
getAnnotations()返回该类所有的公有注解对象
getDeclaredAnnotation(Class annotationClass)返回该类中与参数类型匹配的所有注解对象
getDeclaredAnnotations()返回该类所有的注解对象
Class类-获得构造函数方法用途
getConstructor(Class…<?> parameterTypes)获得该类中与参数类型匹配的公有构造方法
getConstructors()获得该类的所有公有构造方法
getDeclaredConstructor(Class…<?> parameterTypes)获得该类中与参数类型匹配的构造方法
getDeclaredConstructors()获得该类所有构造方法
Class类-获得类中方法的方法用途
getMethod(String name, Class…<?> parameterTypes)获得该类某个公有的方法
getMethods()获得该类所有公有的方法
getDeclaredMethod(String name, Class…<?> parameterTypes)获得该类某个方法
getDeclaredMethods()获得该类所有方法
Field类方法用途
equals(Object obj)属性与obj相等则返回true
get(Object obj)获得obj中对应的属性值
set(Object obj, Object value)设置obj中对应属性值
Method类方法用途
invoke(Object obj, Object… args)传递object对象及参数调用该对象对应的方法
Constructor类方法用途
newInstance(Object… initargs)根据传递的参数创建类的对象

三、反射的使用

前备知识:Person类

public class Person {
    private int age;
    private String name;
    private int testint;

    public Person() {//无参构造
    }
    
    public Person(int age) {//有参构造、public
        this.age = age;
    }
    
    private Person(String name) {//有参构造、private
        this.name = name;
    }
    
    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }

3.1、创建Class对象的三种方式

Class类是我们没学过的一个类,创建Class对象可以通过下面三种方法:

方法解释使用情形例子
1对于Object类对象,可以调用getClass()方法。有了类对象,获取其类。stu1.getClass();
2任何数据类型(包括基本数据类型)都有一个“静态”的class属性:已经要有的数据类型,只是想转为Classint.class;或Person.class.TYPE
3通过Class类的静态方法(常用):只知道其全类名Class.className("全类名");
 实例:
//方法一
String name = "HHH";
Class c1 = name.getClass();
System.out.println(c1.getName());  //java.lang.String

//方法三
Class c1 = Boolean.TYPE;
Class c2 = Byte.TYPE;
Class c3 = Float.TYPE;
Class c4 = Double.TYPE;

//方法三
String name = "java.lang.String";//全类名
Class c1 = null;
try {//因为我们传的这个字符串可能不合法,字符串合法命名是类的命名空间和类的名称组成
    c1 = Class.forName(name);
    System.out.println(c1.getName());//java.lang.String
} catch (ClassNotFoundException e) {
}    

3.2、反射构造方法

可以一下获取全部的构造方法,也可以获取指定形参列表的构造方法

1).批量的方法:
public Constructor[] getConstructors():所有"公有的"构造方法
public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
注意返回值是类型是数组,Constructor为返回值类型

提前总结:反射,在Class中,类的私有属性和方法都是可以获取到的。

实例:获取所有构造方法以及每个构造方法的参数类型
涉及知识:
通过getDeclaredConstructors可以返回类的所有构造方法,返回的是一个数组因为构造方法可能不止一个,通过
getModifiers可以得到构造方法的类型;//如public//private
getParameterTypes可以得到构造方法的所有参数,返回的是一个Class数组

Person person1 = new Person();
Class c4 = person1.getClass();
Constructor[] constructors ;
constructors = c4.getDeclaredConstructors(); 

for (int i = 0; i < constructors.length; i++) {
    System.out.print(Modifier.toString(constructors[i].getModifiers()) + "参数:");

    Class[] parametertypes = constructors[i].getParameterTypes();
    for (int j = 0; j < parametertypes.length; j++) {
        System.out.print(parametertypes[j].getName() + " ");
        //输出全类名//如int//如java.lang.String
    }
    System.out.println("");
}
2).获取单个的方法,并调用:
获取单个的"公有的"构造方法:
public Constructor getConstructor(Class... parameterTypes)
    
获取"某个构造方法"可以是私有的,或受保护、默认、公有;
public Constructor getDeclaredConstructor(Class... parameterTypes)

注意:没有s,返回的是单个Constructor类对象。

同样需要进行异常捕获,因为可能不存在对应的构造方法

Class[] p = {int.class,String.class};//指定形参列表
try {
    获取指定的构造函数
    constructor1 = c4.getDeclaredConstructor(p);// 可以为空
    System.out.print(Modifier.toString(constructor1.getModifiers()) + "参数:"  );//打印构造函数类型
    Class[] parametertypes = constructor1.getParameterTypes();//参数列表也通过Class类获取
    for (int j = 0; j < parametertypes.length; j++) {
        System.out.print(parametertypes[j].getName() + " ");//打印形参全类名//如`java.lang.String`
    }
} catch (NoSuchMethodException e) {
    e.printStackTrace();
}

3.3、通过反射New对象

两种方法:

  • 通过Class类
  • 通过Constructor
1) 通过Class类的对象.NewInstance()

前面我们提到了Class类不是我们所理解的Object类。在反射中,因为Class类的对象已经包含了我们指定的类的信息,所以New对象可以通过Class类的对象(如class1)的方法来New出来的。

实例
Class class1=Class.forName("com.hhh.Person"); 
class1.NewInstance();//等价于Person person1=New Person();

注意:如上,我们并没有传参数,所以New对象是使用的无参构造函数,所以这种方法要求Person类有默认的空构造器。(注意如果重写了构造函数,要把无参构造函数也写进去,不然有参的会屏蔽无参的)

2) 通过Constructor的cons对象.newInstance()

通过3.2的内容先获取构造器,再new对象

Class class1=Class.forName("com.hhh.Person"); 
Class[] p = {int.class,String.class};
Constructor c=class1.getDeclaredConstructor(p);
Person p1=(Person)c.newInstance("李四","男",20);//等价于Person person1=New Person()

调用私有构造函数的方法

Class[] p = {String.class};
constructor1 = c4.getDeclaredConstructor(p);
constructor1.setAccessible(true);//设置位可访问
constructor1.newInstance("HuangLinqing");

3.4 反射对象的属性(成员变量)

1.获取全部属性
1).Field[] getFields():获取所有的"公有字段"
2).Field[] getDeclaredFields():获取所有字段,包括:私有、受保护、默认、公有;  

2.获取指定属性
获取某个"公有的"字段;
public Field getField(String fieldName属性名)

获取某个字段(可以是私有的)
public Field getDeclaredField(String fieldName属性名)

3.设置属性值
Field --> public void set(Object obj对象,Object value字段属性名):

 例:
Field field1 = c4.getDeclaredField("name");
field1.setAccessible(true);
field1.set(对象,"123123"); 

3.5 反射对象的方法

获取全部方法
Method[] getMethods();//获取公有的
Method[] getDeclaredMethods();//获取全部的

获取指定的方法
Method getMethod(方法名,形参类型);;//获取指定公有
Method getDeclaredMethod(方法名,形参类型)//获取指定(含私有)

 例:
Class[] p4 = {String.class};
Method method1 = c4.getDeclaredMethod("welcome",p4);//因为方法也可能重载,只指定方法名不够
method1.setAccessible(true);//可以设置私有方法为可访问
Object arg1s[] = {"123123"};
method1.invoke(person,arg1s);//(类的实例,实参)

================================================================

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值