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;
//...对代码异常进行抛出
}