Java反射机制基础

Java反射机制

在这里插入图片描述

前言:反射是框架的基础

一.反射机制

若有db文件:

classfullPath=Mysourses.cat
method=cat

通过反射机制,可以得到该类的实例化对象,并调用方法

//加载类,返回Class类型的对象cls
Class cls=Class.forName(classfullPath);
//通过cls得到你加载类的实例化对象
Object o=cls.newInstance();
//万物皆对象,将method方法也视为对象,通过cls得到
Method method01=cls.getMethod(method);
//通过方法对象调用方法
method01.invoke(o);

在这里插入图片描述

反射即是从Class类阶段拿到Class类对象,然后去创建对象,调用方法。

2.反射主要类

java.lang.reflection.*;//包括以下类

java.lang.Class  //Class对象表示某个类加载后在堆中的对象
java.lang.reflect.Method  //代表类的方法
java.lang.reflect.Field //属性
java.lang.reflect.Constructor //构造器

Method使用参考上文

Field使用

Field nameField=cls.getField("age");//得到成员变量名
System.out.print(nameField.get(o));//调用方法得到o对象中的成员变量

Constructor

Constructor constructor=cls.getConstructor();//返回无参构造器
Constructor constructor=cls.getConstructor(String Class);//有参构造器
System.out.print(constructor); //public Mysourses.cat()或public Mysourses.cat(java.lang.String)

3.反射优缺点

优点:动态的创建对象和使用方法(框架底层的核心),使用灵活。

缺点:使用反射基本是解释执行,影响执行速度

优化:关掉检查

method.setAccessible(true);

二.Class类

  1. Class也是类,所以继承了Object类
  2. Class不是new出来的,是系统创建的
  3. 对于某个类的Class对象,在内存中只加载一次地址相同
  4. 类的实例对象知道自己从哪个Class而来
  5. Class对象存放在堆中
  6. 通过Class对象可以得到类的完整结构

1.常用方法

有前置类car

public class car {
    public int money=10000;
    car(){}
    public void m1(){
        System.out.println("我是小猫咪");
    }
    @Override
    public String toString() {
        return "小车价值:"+money;
    }
}

常用方法

String classAllPath="test.car";
//得到Car类的class对象
Class cls = Class.forName(classAllPath);
System.out.println(cls);//显示的是哪个类的class对象 class test.car
System.out.println(cls.getClass());//输出cls运行类型 class java.lang.Class
System.out.println(cls.getPackage().getName()); //得到包名 test
System.out.println(cls.getName()); //test.car
//创建对象实例
Object o=cls.newInstance();
System.out.println(o);//重写toString()方法
//获取成员变量 属性brand
Field brand= cls.getField("money");
System.out.println(brand.get(o));
//通过反射改变成员变量数值
brand.set(o,-100);
System.out.println(brand.get(o));
//通过反射使用成员函数
Method method01=cls.getMethod("m1");
method01.invoke(o);

2.获取Class对象的六种方式

由上图可知,大体有4种方式,

//1.从配置文件中获取
String classAllPath="test.car";
Class<?> cls1 = Class.forName(classAllPath);
System.out.println(cls1);
//2.类名.class,用于参数传递
Class cls2=car.class;
System.out.println(cls2);
//3.通过已知实例化对象,得到类
car car01=new car();
Class cls3 = car01.getClass();
System.out.println(cls3);
//4.通过类加载器获得类的Class对象
//得到类加载器
ClassLoader classLoader=car01.getClass().getClassLoader();
//通过类加载器得到Class
Class cls4 = classLoader.loadClass(classAllPath);
System.out.println(cls4);

其实是同一个对象,在四个不同的阶段去获得Class对象

另外两种:
//5.基本数据类型可以获得自己的Class类对象
Class<Integer> integerClass = int.class;  //int
Class<Character> characterClass = char.class;  //char
Class<Boolean> booleanClass = boolean.class;   //boolean
//6.基本数据类型对应的包装类,通过.TYPE 得到Class类对象
Class<Integer> type = Integer.TYPE; //int

而这两种得到Class对象的哈希值相同,说明底层对象相同,不过进行了装箱拆箱。

三.类加载

1.静态加载与动态加载

  • 静态加载:编译时加载相关的类,如果没有则报错,依赖性太强
  • 动态加载:运行时加载相关的类,用哪再加载哪,不用就不加载。即使不存在该类都不会报错,依赖性降低

静态加载时机:

  1. new一个对象时
  2. 子类被加载,父类也被加载
  3. 调用类中的静态成员

动态加载时机:

  • 通过反射调用

2.类加载流程

  • 加载:

    JVM将字节码从不同的数据源中转化成二进制字节流读入内存,并创建一个java.lang.Class对象

  • 连接:将类的二进制数据合并到jre中
    1.验证:

    目的:为了确保字节流中包含的信息符合要求并,没有危害性

    包括字节码验证,文件格式验证,元数据验证等。

    2.准备

    JVM会对静态变量分配内存并初始化

    class A{
        public int n1=10;  //常量,不分配内存
        public static n2=20;  //静态变量,分配内存但值为默认值--0
        public static final int n3=30;  //final修饰的静态变量,是常量,不分配内存  
    }
    
    3.解析

    将符号引用替换成直接引用的过程

  • 初始化:JVM负责初始化,主要指的是静态成员
    1. 执行()方法的过程
    2. 按照语句在源文件中出现的顺序,依次收集所有的静态对象的复制动作和静态代码块语句进行合并。
    3. 虚拟机会保证一个类的()方法在多线程环境中被正确地加锁同步。如果多个线程去初始化一个类,那么只会有一个

线程去执行,其他都堵塞住。

四.反射获取类的信息

需要哪个上网查对应的api即可

五.通过反射创建对象

两种方法

  • 调用类中public修饰的无参构造器
  • 调用指定的构造器

class类相关方法

newInstance 调用无参构造器
getConstructor(Class..):根据参数列表,获取相应的public构造器对象
getDecalaredConstructor(Class...):获取所有的构造器对象

Constructor类相关方法

setAccessible 暴破
newInstance(Object...) 调用构造器    

实例:

//先获得Class类对象
Class cls = Class.forName(classAllPath);
//1.通过public的无参构造器创建实例
Object o=userClass.newInstance();
//2.通过public的有参构造器创建实例
Constructor constructor1=userClass.getConstructor(String.Class);
Object o1=constructor1.newInstance("石头");
//3.1 通过非public的有参构造器创建实例
Constructor constructor2=userClass.getDecalaredConstructor(String.Class,int.class);
//3.2 暴破获取private构造器/属性/方法
constructor2.setAccessible(true);
Object o1=constructor.newInstance("石头1","1000");
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值