阅读 174

注解与反射02-反射

注解与反射02-反射

反射

1 反射基本理解

1.2 反射意义:

1.2 反射机制常用的类:

2 反射的常用使用

2.1 Class三种获得方法

2.2 判断是否为某个类的实例

2.3 创建实例

3 反射深入使用(获取类的运行时结构)

3.1 获取构造方法

3.2 获取类名

3.3 获取成员变量

3.4 获取成员方法

4 主动引用和被动引用

类的主动引用(一定会发生类的初始化)

类的被动调用(不会发生类的初始化)

1 反射基本理解

1.2 反射意义:

1)Java反射机制的核心是在程序运行时动态加载类并获取类的详细信息,从而操作类或对象的属性和方法。本质是JVM得到class对象之后,再通过class对象进行反编译,从而获取对象的各种信息。


(2)Java属于先编译再运行的语言,程序中对象的类型在编译期就确定下来了,而当程序在运行时可能需要动态加载某些类,这些类因为之前用不到,所以没有被加载到JVM。通过反射,可以在运行时动态地创建对象并调用其属性,不需要提前在编译期知道运行的对象是谁。


Class对象的由来是将.class文件读入内存,并为之创建一个Class对象,所以一个类在内存中只存在一个 Class 对象。


反射的用途


1、反编译:.class–>.java

2、通过反射机制访问java对象的属性,方法,构造方法等

3、反射最重要的用途就是开发各种通用框架。比如很多框架(Spring)都是配置化的(比如通过XML文件配置Bean),为了保证框架的通用性,他们可能需要根据配置文件加载不同的类或者对象,调用不同的方法,这个时候就必须使用到反射了,运行时动态加载需要的加载的对象。


例如:Class.forName(“com.mysql.jdbc.Driver”); // 动态加载mysql驱动,就是使用反射机制


1.2 反射机制常用的类:

Java.lang.Class;

Java.lang.reflect.Constructor;

Java.lang.reflect.Field;

Java.lang.reflect.Method;

Java.lang.reflect.Modifier;

2 反射的常用使用

2.1 Class三种获得方法

1 Object–>getClass

2 任何数据类型(包括基本的数据类型)都有一个“静态”的class属性,getClass();

3 通过class类的静态方法:forName(String className)


public class Test {

    public static void main(String[] args) throws ClassNotFoundException {

        //第一种方式获取Class对象

        User user = new User();//new一个 User 对象,一个 Class 对象

        Class c1 = user.getClass();//获取Class对象

System.out.println(c1.getName()); //com.hncj.User

//第二种方式获取Class对象

        Class c2 = User.class;

        System.out.println(c1.getName());//com.hncj.User


//第三种方式获取Class对象

        Class c3 = Class.forName("com.hncj.User");

        System.out.println(c3.getName());//com.hncj.User


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

    }

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

在运行期间,一个类,只有一个Class对象产生,所以打印结果都是true


第一种方式,对象都有了还要反射干什么?

第二种方式,需要导入类包,依赖太强,不导包就抛编译错误。

第三种(常用)方式,一个字符串可以传入也可以写在配置文件中等多种方法。需要抛出异常


2.2 判断是否为某个类的实例

使用instanceof 关键字来判断是否为某个类的实例


public native boolean isInstance(Object obj);

1

2.3 创建实例

通过反射来生成对象主要有两种方法


使用Class对象的newInstance()方法来创建Class对象对应类的实例

Class<?> c = String.class;

Object str = c.newInstance();

1

2

先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建对象,这种方法可以用指定的构造器构造类的实例

//获取Class对象

Class<?> str = String.class;

//通过Class对象获取指定的Constructor构造器对象

Constructor constructor=c.getConstructor(String.class);

//根据构造器创建实例:

Object obj = constructor.newInstance(“hello reflection”);

1

2

3

4

5

6

3 反射深入使用(获取类的运行时结构)

3.1 获取构造方法

1 批量获取

public Constructor[] getConstructors():所有"公有的"构造方法

public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)

 

2 单个获取

public Constructor getConstructor(Class… parameterTypes):获取单个的"公有的"构造方法:

public Constructor getDeclaredConstructor(Class… parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;


调用构造方法:


Constructor–>newInstance(Object… initargs)


Constructor constructor = c1.getDeclaredConstructor(String.class, int.class);

User user2 = (User) constructor.newInstance("李中祥", 23);

System.out.println(user2);

1

2

3

3.2 获取类名

Class c1 = Class.forName("com.hncj.User");

//获取类名

System.out.println(c1.getName()); //获取包名+类名  com.hncj.User

System.out.println(c1.getSimpleName()); //获取类名 User

1

2

3

4

getName() 获取包名+类名

getSimpleName() 获取简单的类名称


3.3 获取成员变量

//批量获取类属性

Field[] fields = c1.getFields(); //获取public属性

for(Field field : fields){

  System.out.println(field);

}

System.out.println("==========");

fields = c1.getDeclaredFields(); //找到全部属性(private,public)

for(Field field : fields){

  System.out.println(field);

}



//单个 获取指定属性的值

Field b = c1.getField("b"); //获取指定字段(private,public)

System.out.println(b);

System.out.println("++++++++++++++++++");


Field b1 = c1.getDeclaredField("b"); //获取指定字段(private,public)

System.out.println(b1);

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

1 批量获取属性

Field[] getFields(); 获取所有public属性

Field[] getDeclaredFields(); 获取所有属性(private.public)

 

2 单个获取属性

Field getField(String fieldName)

Field getDeclaredField(String field) 获取指定字段


3.4 获取成员方法

Method[] methods = c1.getMethods(); //获得本类及其父类所有全部public方法

for(Method method : methods){

    System.out.println("方法:" + method);

}


System.out.println("++++++++++++++++++");

methods = c1.getDeclaredMethods(); //本类所有方法(包含public,private)

for(Method method : methods){

    System.out.println("方法:" + method);

}

1

2

3

4

5

6

7

8

9

10

1.批量的:

Method[] getMethods():获取所有"公有方法";(包含了父类的方法也包含Object类)

Method[] getDeclaredMethods():获取所有的成员方法,包括私有的(不包括继承的)

 

2.获取单个的:

Method getMethod(String name,Class<?>… parameterTypes):

参数:

name : 方法名;

Class … : 形参的Class类型对象

Method getDeclaredMethod(String name,Class<?>… parameterTypes)


 **调用方法**

Method --> public Object invoke(Object obj,Object... args):

参数说明:

obj : 要调用方法的对象;

args:调用方式时所传递的实参;

1

2

3

4

5

4 主动引用和被动引用

类的主动引用(一定会发生类的初始化)

1.当虚拟机启动,先初始化main方法所在的类

2.new一个类的对象

3.调用类的静态成员(除了final常量)和静态方法

4.使用java.lang.reflect包的方法对类进行反射调用

5.当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类

1

2

3

4

5

类的被动调用(不会发生类的初始化)

1.当访问一个静态域时,只有真正申明这个域的类才会被初始化

    (通过子类引用父类的静态变量,不会导致子类初始化)

2.通过数组定义类引用,不会触发此类的初始化

3.引用常量不会触发此类的初始化(常量再连接阶段就存入调用类的常量池了)

————————————————

版权声明:本文为CSDN博主「吴成伟」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/qq_43324779/article/details/115840908


文章分类
后端
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐