注解与反射02-反射

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
    }
}

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

第一种方式,对象都有了还要反射干什么?
第二种方式,需要导入类包,依赖太强,不导包就抛编译错误。
第三种(常用)方式,一个字符串可以传入也可以写在配置文件中等多种方法。需要抛出异常

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

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

public native boolean isInstance(Object obj);

2.3 创建实例

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

  1. 使用Class对象的newInstance()方法来创建Class对象对应类的实例
Class<?> c = String.class;
Object str = c.newInstance();
  1. 先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建对象,这种方法可以用指定的构造器构造类的实例
//获取Class对象
Class<?> str = String.class;
//通过Class对象获取指定的Constructor构造器对象
Constructor constructor=c.getConstructor(String.class);
//根据构造器创建实例:
Object obj = constructor.newInstance(“hello reflection”);

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);

3.2 获取类名

Class c1 = Class.forName("com.hncj.User");
//获取类名
System.out.println(c1.getName()); //获取包名+类名  com.hncj.User
System.out.println(c1.getSimpleName()); //获取类名 User

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 批量获取属性
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.批量的:
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:调用方式时所传递的实参;

4 主动引用和被动引用

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

1.当虚拟机启动,先初始化main方法所在的类
2.new一个类的对象
3.调用类的静态成员(除了final常量)和静态方法
4.使用java.lang.reflect包的方法对类进行反射调用
5.当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类

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

1.当访问一个静态域时,只有真正申明这个域的类才会被初始化
    (通过子类引用父类的静态变量,不会导致子类初始化)
2.通过数组定义类引用,不会触发此类的初始化
3.引用常量不会触发此类的初始化(常量再连接阶段就存入调用类的常量池了)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值