Java反射

反射

反射概念

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

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开始的序号来获取列数据。

  • 27
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值