Java反射

2023-12-14 02:59:00

反射

反射概念

反射: 加载类,反射出类的各个组成部分 构造方法,属性(非静态属性和静态属性),方法(非静态方法,静态方法)

java 反射机制: 是在运行状态中(Class对象), 对于任何类,都能能够知道这个类的所有的属性和方法; 对于任意一个对象,能够调用它的任意属性和方法;这种动态获取信息的方式,就称之反射.

类加载

当程序要使用某个类时,如果这个类还没有加载内存中,则系统会通过加载,连接,初始化三个步骤来实现对这个类的初始化。

加载 :

将class 文件加载到内存中,并为之创建一个Class对象(将class文件的内容放到一个对象中,而对象的名字刚好就是Class)

任何类被使用时,系统都会建立一个Class对象.

连接

验证: 是否有正确的内部结构 ,并和其它协调一致

准备 : 负责为类的静态成员分配内存,并设置默认初始化值

解析: 将类的二进制数据中的符号引用替换成直接引用

初始化

就是之前的初始化步骤

类加载的时机

  1. 创建类的实例

  2. 访问类的静态变量或给静态变量赋值

  3. 调用类的静态方法

  4. 初始化某个类的子类

  5. java命令,运行某个类

  6. 使用反射方式强制创建某个类或接口对应的Class对象

类加载器

负责将class 文件加载到内存中,并为之创建一个Class对象,如果了解类加载器的机制,可以的更好的理解程序的运行

类加载器的组成:

根类加载器: bootstrap classLoader

也被称为引导类加载类,负责Java核心类的加载

比如: System, String 等,在 JDK 中的JRE 中 lib 中的 rt.jar文件中

扩展类加载器: extension classLoader

负责jre的扩展目录中的jar的加载

系统类加载器: System classLoader

负责在JVM启动时加载来自java 命令的class文件

获取Class对象的方式

开发: 使用第三种.

为什么? 因为第三种是一个字符 串,而不是具体类名,这种的话就可以将这个值放到配置文件中,方便对它修改.

//方法1:
        Person p = new Person();
        Class c = p.getClass();

        Person p1 = new Person();
        Class c1 = p.getClass();

        System.out.println(p==p1);  //false
        System.out.println(c==c1);  //true
        //方法2:
        Class c2 = Person.class;
        System.out.println(c == c2); //true

        // 方法3
        // Class对象中的静态方法
        //ClassNotFoundException  必须写包名

        Class c3 = Class.forName("com.demo1.Person");

        System.out.println(c==c3);

获取类的加载器

//1. 如何获取 类的加载器
? ? ? ? //1.1 首先得到Class对象
? ? ? ? Class c = Person.class;
? ? ? ? //1.2 获取类的加载器
? ? ? ? ClassLoader classLoader = c.getClassLoader();
? ? ? ? System.out.println(classLoader);

?

使用类加载器加载其它的文件

注:小心路径问题,最好是将方法放到 resource 目录下

?

 Class c = User.class;
 ? ? ? ?//1.2 获取类的加载器
 ? ? ? ?ClassLoader classLoader = c.getClassLoader();
 ? ? ? ?System.out.println(classLoader);
 ? ? ? ?// 类加载器加载其它的文件
 ? ? ? ?InputStream in = classLoader.getResourceAsStream("jdbc.properties");
 ? ? ? ?System.out.println(in);

?

类加载的原理

反射构造器

反射构造器: 通过Class对象,获取构造方法

?

?Class c = Person.class;
? ? ? ? ?//获取构造方法
? ? ? ? // Constructor<?>[] getConstructors() : 返回所有的构造方法 Constructor 类的对象 ?只能获取 public修饰的构造方法
? ? ? ? //返回包含一个数组 Constructor对象反射由此表示的类的所有公共构造 类对象。
// ? ? ? ?Constructor[] constructors = c.getConstructors();
? ? ? ? //c.getDeclaredConstructors(); 获取 所有构造方法
// ? ? ? ?Constructor[] constructors = c.getDeclaredConstructors();
// ? ? ? ?for(Constructor constructor:constructors){
// ? ? ? ? ? ?System.out.println(constructor);
// ? ? ? ?}

? ? ? ? //获取单个构造方法
? ? ? ? // getConstructor(类<?>... parameterTypes): 只能得到public修饰
// ? ? ? ?Constructor constructor = c.getConstructor(String.class);
? ? ? ? Constructor constructor = c.getDeclaredConstructor(String.class);
? ? ? ? System.out.println(constructor);


? ? ? ? //Constructor<T> getConstructor(类<?>... parameterTypes)
? ? ? ? //返回一个 Constructor对象,该对象反映 Constructor对象表示的类的指定的公共 类函数。

? ? ? ? // 根据构造方法,创建实例对象
? ? ? ? //java.lang.IllegalAccessException 构造方法是私有的,创建实现,会报非法异常
? ? ? ? // 解决方案:
? ? ? ? constructor.setAccessible(true); //跳过java语法检查
? ? ? ? Object obj = constructor.newInstance("张三");
? ? ? ? System.out.println(obj);

?

反射属性

反射构造器: 通过Class对象,获取成员属性

 ? public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
 ? ? ? ?Class c = Person.class;
 ? ? ? ?//public Field[] getFields() 返回包含一个数组Field对象反射由此表示的类或接口的所有可访问的公共字段类对象。
// ? ? ?  Field[] fields = c.getFields();
// ? ? ?  for(Field field : fields){
// ? ? ? ? ?  System.out.println(field);
// ? ? ?  }
?
 ? ? ? ?//public Field[] getDeclaredFields() : 获取所有属性
// ? ? ?  Field[] fields = c.getDeclaredFields();
// ? ? ?  for(Field field : fields){
// ? ? ? ? ?  System.out.println(field);
// ? ? ?  }
 ? ? //NoSuchFieldException
// ? ? ?  Field field= c.getField("name");
// ? ? ?  System.out.println(field);
?
// ? ? ?  Field field= c.getDeclaredField("name");
// ? ? ?  System.out.println(field);
?
 ? ? ? ?// 没有对象就没有属性
 ? ? ? ?// 要使用属性,必须 要有对象
 ? ? ? ?Constructor constructor = c.getDeclaredConstructor();
 ? ? ? ?Object obj = constructor.newInstance(); //创建对应的对象
?
 ? ? ? ?Field namefield = c.getDeclaredField("name");
 ? ? ? ?Field agefield = c.getDeclaredField("age");
 ? ? ? ?Field addressfield = c.getDeclaredField("address");
?
 ? ? ? ?//IllegalAccessException
 ? ? ? ?namefield.setAccessible(true);
 ? ? ? ?namefield.set(obj,"zhangsan");
 ? ? ? ?agefield.set(obj,18);
 ? ? ? ?addressfield.set(obj,"成都");
 ? ? ? ?System.out.println(obj);
 ?  }

反射方法

反射构造器: 通过Class对象,获取成员方法

?public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
? ? ? ?Class c = Person.class;
? ? ? //c.getMethods(); 得到所有公共的方法,包括父类的
// ? ? ? Method[] methods = c.getMethods();
// ? ? ? for(Method method:methods){
// ? ? ? ? ? System.out.println(method);
// ? ? ? }
? ? ? ?//c.getDeclaredMethods(); 获取自身的所有方法
// ? ? ? ?Method[] methods = c.getDeclaredMethods();
// ? ? ? ?for(Method method:methods){
// ? ? ? ? ? ?System.out.println(method);
// ? ? ? ?}

// ? ? ? ?Method method = c.getMethod("show");
// ? ? ? ?System.out.println(method);
// ? ? ? ?Method method = c.getDeclaredMethod("function");
// ? ? ? ?// 方法和字段 都必须 由对象去调用,虽然写法不一样,必须 将对象传递
// ? ? ? ?System.out.println(method);
// ? ? ? ?Constructor constructor = c.getDeclaredConstructor();
// ? ? ? ?Object obj = constructor.newInstance();
// ? ? ? ?method.setAccessible(true);
// ? ? ? ?method.invoke(obj); //invoke :调用


// ? ? ? ?Method method = c.getDeclaredMethod("method", String.class);
// ? ? ? ?// 方法和字段 都必须 由对象去调用,虽然写法不一样,必须 将对象传递
// ? ? ? ?System.out.println(method);
// ? ? ? ?Constructor constructor = c.getDeclaredConstructor();
// ? ? ? ?Object obj = constructor.newInstance();
// ? ? ? ?method.setAccessible(true);
// ? ? ? ?method.invoke(obj,"good"); //invoke :调用

? ? ? ? Method method = c.getDeclaredMethod("getString", String.class, int.class);
? ? ? ? // 方法和字段 都必须 由对象去调用,虽然写法不一样,必须 将对象传递
? ? ? ? System.out.println(method);
? ? ? ? Constructor constructor = c.getDeclaredConstructor();
? ? ? ? Object obj = constructor.newInstance();
? ? ? ? method.setAccessible(true);
? ? ? ? String str = (String)method.invoke(obj,"good",666); //invoke :调用
? ? ? ? System.out.println(str);
? ? }
}
?

?

面试题

面试题

第一题:JDBC操作数据库的步骤 ?

1)注册数据库驱动。

2)建立数据库连接。

3)创建一个Statement。

4)执行SQL语句。

5)处理结果集。

6)关闭数据库连接

第二题:JDBC中的Statement 和PreparedStatement,CallableStatement的区别?

1)PreparedStatement是预编译的SQL语句,效率高于Statement。

2)PreparedStatement支持?操作符,相对于Statement更加灵活。

3)PreparedStatement可以防止SQL注入,安全性高于Statement。

4)CallableStatement适用于执行存储过程。

第三题:execute,executeQuery,executeUpdate的区别是什么?

· Statement的execute(String query)方法用来执行任意的SQL查询,如果查询的结果是一个ResultSet,这个方法就返回true。如果结果不是ResultSet,比如insert或者update查询,它就会返回false。我们可以通过它的getResultSet方法来获取ResultSet,或者通过getUpdateCount()方法来获取更新的记录条数。

· Statement的executeQuery(String query)接口用来执行select查询,并且返回ResultSet。即使查询不到记录返回的ResultSet也不会为null。我们通常使用executeQuery来执行查询语句,这样的话如果传进来的是insert或者update语句的话,它会抛出错误信息为 “executeQuery method can not be used for update”的java.util.SQLException。

· Statement的executeUpdate(String query)方法用来执行insert或者update/delete(DML)语句,或者 什么也不返回DDL语句。返回值是int类型,如果是DML语句的话,它就是更新的条数,如果是DDL的话,就返回0。

· 只有当你不确定是什么语句的时候才应该使用execute()方法,否则应该使用executeQuery或者executeUpdate方法。

第四题:PreparedStatement的缺点是什么,怎么解决这个问题?

PreparedStatement的一个缺点是,我们不能直接用它来执行in条件语句;需要执行IN条件语句的话,下面有一些解决方案:

1)分别进行单条查询——这样做性能很差,不推荐。

2)使用存储过程——这取决于数据库的实现,不是所有数据库都支持。

3)动态生成PreparedStatement——这是个好办法,但是不能享受PreparedStatement的缓存带来的好处了。

4)在PreparedStatement查询中使用NULL值——如果你知道输入变量的最大个数的话,这是个不错的办法,扩展一下还可以支持无限参数。

第五题:JDBC的ResultSet是什么?

在查询数据库后会返回一个ResultSet,它就像是查询结果集的一张数据表。

ResultSet对象维护了一个游标,指向当前的数据行。开始的时候这个游标指向的是第一行。如果调用了ResultSet的next()方法游标会下移一行,如果没有更多的数据了,next()方法会返回false。可以在for循环中用它来遍历数据集。

默认的ResultSet是不能更新的,游标也只能往下移。也就是说你只能从第一行到最后一行遍历一遍。不过也可以创建可以回滚或者可更新的ResultSet。

当生成ResultSet的Statement对象要关闭或者重新执行或是获取下一个ResultSet的时候,ResultSet对象也会自动关闭。

可以通过ResultSet的getter方法,传入列名或者从1开始的序号来获取列数据。

文章来源:https://blog.csdn.net/qq_59048453/article/details/134850732
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。