Java反射机制

Java反射机制

一、创建对象(已有Order类)

编译时创建对象

Order o1 = new Order();

运行时创建对象

  • Class.forName ---->加载类型信息(详见第二点)

  • .newInstance ---->创建对象

 String className ="com.xinxin.Order";
 Class c1 = Class.forName(className);
 Order o2 = (Order) c1.newInstance();

二、获取Class类型信息(e.g : String类 3种方式)

  • 通过类名

Class stringClass1 = String.class;
  • 通过class类的forName()方法

Class stringClass2 = Class.forName("java.lang.String");
  • 通过对象调用getClass()方法

Class stringClass3 = "".getClass();

三、Class类型的对象使用场景

  • 将json格式的字符串转为目标类对象,并获取输出

String json = "{\"name\":\"张三\",\"age\":18}";

//此处有Document类,包含name,age属性,并已生成其相关的get、set方法
Document doc = JSON.parseObject(json,Document.class);
System.out.println(doc.getName());
System.out.println(doc.getAge());
  • 通过Class类型的对象获取类名、包名、成员变量、成员方法

//加载类型信息
Class clz = Class.forName("java.util.HashMap");

//获取类名
System.out.println("完全限定类名:"+clz.getName());
System.out.println("简单类名:"+clz.getSimpleName());

//.getPackage 获取包名
System.out.println("package包名:"+clz.getPackage().getName());

//.getDeclaredFields 获取成员变量
Field[] fieldArray = clz.getDeclaredFields();
System.out.println("成员变量(字段):");
for (Field field :fieldArray){
    System.out.println(field);
}

//.getDeclaredMethods 获取成员方法
Method[] methodArray = clz.getDeclaredMethods();
System.out.println("成员方法:");
for(Method method:methodArray){
    System.out.println(method);
}

四、通过反射的方式,创建对象

Class clz = Class.forName("com.xinxin.Document");
//直接通过class对象,调用newInstance()方法
Object objx = clz.newInstance();//相当于在执行无参构造方法

//方式2:通过构造器(构造方法)
//无参构造方法
Constructor constructor1 = clz.getDeclaredConstructor();//获取无参构造方法
System.out.println(constructor1);
Object obj1 = constructor1.newInstance();//执行构造器(构造方法),创建对象

//有参构造方法
Constructor constructor2 = clz.getDeclaredConstructor(String.class);//获取有参构造方法
System.out.println(constructor2);
Object obj2 = constructor2.newInstance("两京十五日");

Constructor constructor3 = clz.getDeclaredConstructor(int.class);//获取有参构造方法
System.out.println(constructor3);
Object obj3 = constructor3.newInstance(32);

Constructor constructor4 = clz.getDeclaredConstructor(String.class, int.class);//获取有参构造方法
System.out.println(constructor4);
Object obj4 = constructor4.newInstance("风起云涌",32);

五、通过构造器创建对象

✔ . getConstructors() -----> 只能获取public修饰的构造方法

✔ . getDeclaredConstructors() -----> 可获取public和private即所有定义的构造方法

上述的两种方法,返回值都是Constructor[]数组。

注意:

//调用私有构造器,必须设置它的访问权限
constructor.setAccessible(true);
//调用构造器,创建对象
Object obj = constructor.newInstance("长安三万里");
System.out.println(obj);

六、通过反射,访问并使用成员变量

意义:在运行时,进行对成员变量的访问和使用

  • 硬编码方式

Document doc1 = new Document();
doc1.name = "" ;
doc1.age =  ;
  • 反射的方式

//反射的方式
Class clz = Class.forName("com.xinxin.Document");//获取类型信息
Object obj = clz.newInstance();//创建对象  //也相当于在执行无参构造方法

//获取指定名称的成员变量
Field nameField = clz.getDeclaredField("name");
//age是private的,所以要使用带Declared的获取
Field ageField = clz.getDeclaredField("age");

//访问私有的成员变量,必须设置权限(否则会报错java.lang.IllegalAccessException)
nameField.setAccessible(true);
ageField.setAccessible(true);

//使用成员变量,将指定数据存入对象中
nameField.set(obj,"长安十二时辰");
ageField.setInt(obj,21);
System.out.println(obj);
//obj此时输出结果: Document{name='长安十二时辰', age=21}

七、通过反射,访问并使用成员方法

  • 硬编码方式

Document doc1 = new Document();
doc1.setName("海底两万里");
doc1.setAge(20000);
  • 反射的方式

Class clz = Class.forName("com.xinxin.Document");//获取类型信息
Object doc1 = clz.newInstance();//创建对象
//doc1此时输出结果: Document{name='null', age=0}

//获取指定名称和参数类型的方法
Method nameMethod = clz.getMethod("setName", String.class);
Method ageMethod = clz.getMethod("setAge", int.class);

//执行方法
//doc1.setName("海底两万里");
nameMethod.invoke(doc1,"海底两万里");
//doc1.setAge(20000);
ageMethod.invoke(doc1,20000);

System.out.println(doc1);
//doc1此时输出结果: Document{name='海底两万里', age=20000}

八、反射方式调用类中静态方法

e.g:String类中的format方法

  • 硬编码方式

String ret1 = String.format("hashMap的默认初始容量是%d,加载因子是%.2f",16,0.75);
System.out.println(ret1);
  • 反射的方式

Class clz = String.class;
Method formatMethod = clz.getMethod("format", String.class, Object[].class);
String ret2 = 
    formatMethod.invoke(null,"hashMap的默认初始容量是%d,加载因子是%.2f",new Object[]{16,0.75}).toString();

System.out.println(ret2);

九、反射方式模拟Mybatis

代码前准备:

1)sql库

2)实体类

config.properties:

sql=select id,title,url,playable,is_new AS isNew,rate,cover,type from subject

sqlHandler:

public class SQLHandler {
    private static final String JDBC_URL = "jdbc:mysql://localhost:3306/mybatis_demo?serverTimezone=GMT";
    private static final String DB_USER = "root";
    private static final String DB_PASS = "20020630";
    //执行
    public static <T>List<T> execute(String sql,Class<T> resultType){
        try {
            //创建Connection连接对象
            Connection con = DriverManager.getConnection(JDBC_URL, DB_USER, DB_PASS);

            //创建PreparedStatement执行对象
            PreparedStatement pst = con.prepareStatement(sql);

            //执行sql语句,获取结果集
            ResultSet rs = pst.executeQuery();

            //获取结果集的字段名称
            ResultSetMetaData resultSetMetaData = rs.getMetaData();

            //创建一个用于保存查询结果的List集合
            List<T> quertList = new ArrayList<T>();

            while (rs.next()){
                //反射加载resultType类的无参构造方法来创建对象实例
               Object resultData = resultType.newInstance();
               //根据结果集的字段名称获取列个数,动态决定 列i的大小
               for(int i = 1 ; i <= resultSetMetaData.getColumnCount(); i++){
                   //根据结果集的字段名称获取字段别名
                   String columnLabel = resultSetMetaData.getColumnLabel(i);
                   //根据创建对象获取成员变量
                   Field field = resultType.getDeclaredField(columnLabel);
                   //设置权限
                   field.setAccessible(true);
                   //根据结果集的字段名称,获取行中数据
                   //根据数据类型分支
                   switch (resultSetMetaData.getColumnType(i)){
                       case Types.INTEGER:
                           field.setInt(resultData,rs.getInt(columnLabel));
                           break;
                       case Types.DOUBLE:
                           field.setDouble(resultData,rs.getDouble(columnLabel));
                           break;
                       default:
                           String value = rs.getString(columnLabel);
                           if("true".equals(value)||"false".equals(value)){
                               field.setBoolean(resultData, Boolean.valueOf(value));
                               break;
                           }else{
                               field.set(resultData,value);
                           }
                   }
               }
                quertList.add((T) resultData);
            }
                return quertList;
        //...对代码异常进行抛出
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值