Java反射

Java反射机制允许程序在运行时获取类的内部信息并操作对象。通过Class对象,可以创建运行时类的对象,获取类的完整结构,并调用指定的方法和属性。反射在ORM、动态代理等方面有广泛应用,但也存在性能影响。动态代理利用Java的Proxy类和InvocationHandler接口实现接口方法的统一处理。
摘要由CSDN通过智能技术生成

Java反射

反射机制的概述

Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期 借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内 部属性及方法。

加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个 类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可 以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射。

正常方式:引入需要的“包类”名称----》通过new实例化----》取得实例化对象

反射方式:实例化对象----》getClass()方法-----》得到完整的包类名称

Java反射机制提供的功能

  • 在运行时判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象
  • 在运行时判断任意一个类所具有的成员变量和方法
  • 在运行时获取泛型信息
  • 在运行时调用任意一个对象的成员变量和方法 在运行时处理注解
  • 生成动态代理

Java反射的优点与缺点

优点:可以实现动态创建对象和编译,体现出很大的灵活性

缺点:对性能有影响。使用反射基本是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于直接执行相同的操作

反射相关的主要API

java.lang.Class代表一个类

java.lang.reflect.Method代表类的方法

java.lang.reflect.Field:代表类的成员变量

java.lang.reflect.Constructor:代表类的构造器

Class 类

在Object类中定义了以下的方法,此方法 将被所有子类继承:public final Class getClass()

以上的方法返回值的类型是一个Class类, 此类是Java反射的源头,实际上所谓反射 从程序的运行结果来看也很好理解,即: 可以通过对象反射求出类的名称。

  • Class本身也是一个类
  • Class 对象只能由系统建立对象
  • 一个加载的类在 JVM 中只会有一个Class实例
  • 一个Class对象对应的是一个加载到JVM中的一个.class文件
  • 每个类的实例都会记得自己是由哪个 Class 实例所生成
  • 通过Class可以完整地得到一个类中的所有被加载的结构
  • Class类是Reflection的根源,针对任何你想动态加载、运行的类,唯有先获得相应的 Class对象
常用方法
方法名 功能说明
static Class forName(String name) 返回指定类名 name 的 Class 对象
Object newInstance() 调用缺省构造函数,返回该Class对象的一个实例;创建对应的运行时类的对象
getName() 返回此Class对象所表示的实体(类、接口、数组类、基本类型 或void)名称
Class getSuperClass() 返回当前Class对象的父类的Class对象
Class [] getInterfaces() 获取当前Class对象的接口
ClassLoader getClassLoader() 返回该类的类加载器
Class getSuperclass() 返回表示此Class所表示的实体的超类的Class
Constructor[] getConstructors() 返回一个包含某些Constructor对象的数组
Field[] getDeclaredFields() 返回Field对象的一个数组
Method getMethod(String name,Class … paramTypes) 返回一个Method对象,此对象的形参类型为paramType

反射的应用举例

String str = "test4.Person";
Class clazz = Class.forName(str);
Object obj = clazz.newInstance(); 
Field field = clazz.getField("name"); 
field.set(obj, "Peter");Object name = field.get(obj);
System.out.println(name);

test4.Person是test4包下的Person
获取Class类的实例(四种方法)
  • 前提:若已知具体的类,通过类的class属性获取,该方法最为安全可靠, 程序性能最高
    • 实例:Class clazz = String.class;
  • 前提:已知某个类的实例,调用该实例的getClass()方法获取Class对象
    • 实例:Class clazz = “dwdwq”.getClass();
  • 前提:已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException
    • 实例:Class clazz = Class.forName(“java.lang.String”);
  • 其他方式(不做要求)
    • ClassLoader cl = this.getClass().getClassLoader();
    • Class clazz4 = cl.loadClass(“类的全类名”);
package com.shao.reflection;
public class Test2 {
   
    public static void main(String[] args) throws ClassNotFoundException {
   
        Person person = new Student();
        System.out.println(person.name);
        // 方式1:通过对象获得
        Class c1 = person.getClass();
        System.out.println(c1.hashCode()); // 356573597
        // 方式2:forname获得
        Class c2 = Class.forName("com.shao.reflection.Student");
        System.out.println(c2.hashCode()); // 356573597
        // 方式3:通过类名.class获得
        Class c3 = Student.class;
        System.out.println(c3.hashCode()); // 356573597
        // 方式4:基本内置类型的包装类都有一个Type属性
        Class c4 = Integer.TYPE;
        System.out.println(c4); // int
        // 获得父类类型
        Class c5 = c1.getSuperclass();
        System.out.println(c5); // class com.shao.reflection.Person
    }
}
class Person {
   
    String name;
    // 有参、无参、toString
}
class Student extends Person{
   
    public Student(){
   
        this.name = "学生";
    }
}
哪些类型可以有Class对象?
  • class: 外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类
  • interface:接口
  • []:数组
  • enum:枚举
  • annotation:注解@interface
  • primitive type:基本数据类型
  • void
Class c1 = Object.class; // 类
Class c2 = Comparable.class; // 接口
Class c3 = String[].class;  // 一维数组
Class c4 = int[][].class;	// 二维数组
Class c5 = ElementType.class;  // 枚举
Class c6 = Override.class;  // 注解
Class c7 = int.class;
Class c8 = void.class;	 // void
Class c9 = Class.class;	 // class
int[] a = new int[10]; 
int[] b = new int[100];
Class c10 = a.getClass();
Class c11 = b.getClass();
// 只要元素类型与维度一样,就是同一个Class
System.out.println(c10 == c11);
类的加载与ClassLoader的理解
  • 加载:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时 数据结构,然后生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问 入口(即引用地址)。所有需要访问和使用类数据只能通过这个Class对象。这个加载的过程需要类加载器参与。
  • 链接:将Java类的二进制代码合并到JVM的运行状态之中的过程。
    • 验证:确保加载的类信息符合JVM规范,例如:以cafe开头,没有安全方面的问题
    • 准备:正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存 都将在方法区中进行分配。
    • 解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程。
  • 初始化:
    • 执行类构造器()方法的过程。类构造器()方法是由编译期自动收集类中 所有类变量的赋值动作和静态代码块中的语句合并产生的。(类构造器是构造类信 息的,不是构造该类对象的构造器)。
    • 当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类 的初始化。
    • 虚拟机会保证一个类的()方法在多线程环境中被正确加锁和同步。
public class ClassLoadingTest {
   
	public static void main(String[] args) {
   
        A a = new A();
		System.out.println(A.m);// 100
	}
}
class A {
   
	static {
   
        System.out.println(A类静态代码块初始化”);
		m = 300;
	}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操作数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表中的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库中的映射。 通过 ORM,开发者可以像操作 Python 对象一样操作数据库,这大大简化了数据库操作的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建、使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工作单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操作时执行额外的逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值