反射基础
类模板类,字段类,方法类,构造器
1 package testPart1; 2 3 import org.w3c.dom.ls.LSOutput; 4 5 import java.io.InputStream; 6 import java.lang.reflect.*; 7 import java.util.Arrays; 8 9 /** 10 * 类模板类 Class<T> 11 * Class构建T这个类型的模板 12 * Class<T> 说明了T类型对应的类 ,T就是解剖类 13 * Class<T>类是反射的核心 14 * 1.通过模板处理所有类, 15 * 获得类的模板类对象--就是类似import 导入文件的对象 16 * 常用方法 17 * 1.public native boolean isInstance(Object obj) 比较 模板类是否是obj的类的子类 18 * 2.public boolean equals(Object obj) 判断是否是同一个模板类 通过各种方式创建的模板类都一样 19 * 3.public String getName() 获得模板类的类全限定名 20 * 4.public Field getField(String name) 只能获得public修饰的字段 21 * 5.public Field getDeclaredField(String name) 获得任何权限修饰的字段 22 * 6.public Method getMethod(String name, Class<?>... parameterTypes) 只能获得public修饰的方法 23 * 7.public Method getDeclaredMethod(String name, Class<?>... parameterTypes) 获得任何权限修饰的方法 24 * 字段类,Field 25 * 可以处理模板类对象的对应字段 26 * 修改,查看某个对象的字段 27 * 相应方法 28 * 1.解析类的字段操作 29 * public String getName() 获得字段名 30 * public Class<?> getType() 获得字段的模板类 31 * public int getModifiers() 获得字段修饰符的数值和,所有修饰符 32 * 2.对象属性值相关 33 * public void set(Object obj, Object value) 修改obj对象的相应属性值为value 34 * public Object get(Object obj) 得到obj对象的相应属性值 35 * 36 * Modifier类,类型 37 * 相应方法 38 * public static String toString(int ) 39 * 可以将修饰符数值转为字符串 40 * 41 * Method类 42 * 相应方法、 43 * 1.解析类的方法属性 44 * public String getName() 得到方法名 45 * public Class<?> getReturnType() 得到方法模板类 46 * public int getParameterCount() 得到方法参数数量 47 * public Class<?>[] getParameterTypes() 得到方法参数类型数值 48 * public Object invoke(Object obj, Object... args) 执行某个对象的方法 49 * 50 * 注意点 51 * 权限相关 52 * getDeclaredField 53 * getDeclaredMethod 54 * 55 */ 56 57 public class Test1 { 58 59 public static void test(){ 60 /** 61 * 1.获取目标类型的类类型(模板类)---这是使用反射的基础 62 * 要想使用Class<T>,首先就是将对象的类模板获得到, 63 * 方式一 class关键字+类名获取,特点就是直接返回了确定类型,耦合度高 64 * 方式二 forName静态方法+类的全限定名获取 65 * 方式三 对象的getClass()方法 66 * 考虑点 是否需要确定泛型类型,是谁在用, 67 * 1.用户使用,就确定类型 68 * 2.开发者最好不确定类型 69 */ 70 Class<String> c1 = String.class; 71 try { 72 Class<?> c2 = Class.forName("java.lang.String"); 73 } catch (ClassNotFoundException e) { 74 throw new RuntimeException(e); 75 } 76 String name = "刘"; 77 Class<?> c3 = name.getClass(); 78 79 /** 80 * 2.获取目标解析类的字段 81 * 默认获取解析类的public字段信息 82 * getField只能获得类中是public的 83 * 获得一个解析类的所有的字段信息 84 */ 85 User u = new User(); 86 Class c = u.getClass(); 87 try { 88 Field age = c.getField("age"); 89 System.out.println("字段名称:"+age.getName()); 90 System.out.println("字段类型:"+age.getType().getName()); 91 System.out.println("修饰符的值:"+age.getModifiers()); 92 System.out.println("修饰符是:"+ Modifier.toString(age.getModifiers())); 93 User tmp = (User)c.newInstance(); 94 System.out.println("设置对象的字段值"); 95 age.set(tmp,23); 96 System.out.println(tmp.age); 97 System.out.println(age.get(tmp)); 98 Field[] files = c.getFields(); 99 Arrays.stream(files).forEach((f)->{ 100 System.out.println("字段名:"+f.getName()+",字段类型"+f.getType().getName()+",字段修饰符"+Modifier.toString(f.getModifiers())); 101 }); 102 } catch (NoSuchFieldException e) { 103 throw new RuntimeException(e); 104 } catch (InstantiationException e) { 105 throw new RuntimeException(e); 106 } catch (IllegalAccessException e) { 107 throw new RuntimeException(e); 108 } 109 try { 110 Field name1 = c.getDeclaredField("name"); 111 Field[] names = c.getDeclaredFields(); 112 for (int i = 0,len = names.length;i<len;i++){ 113 System.out.println("字段修饰符:"+Modifier.toString(names[i].getModifiers())+"字段类型:"+names[i].getType().getName()+"字段名:"+names[i].getName()); 114 } 115 User tmp = (User)c.newInstance(); 116 System.out.println("设置对象的字段值"); 117 name1.set(tmp,"张三"); 118 System.out.println(tmp.name); 119 System.out.println(name1.get(tmp)); 120 } catch (NoSuchFieldException e) { 121 throw new RuntimeException(e); 122 } catch (InstantiationException e) { 123 throw new RuntimeException(e); 124 } catch (IllegalAccessException e) { 125 throw new RuntimeException(e); 126 } 127 } 128 /** 129 * 易错点 130 * 1.找不到指定类异常 相应.class文件找不到, 131 * 错误代码: 132 * Class.forName("张三"); Class.forName("String"); 133 * 错误原因: 参数字符串里面应该是类的全限定名(包名+类名).1不能是类名2.也不能理解是普通字符串对象 134 * 拓展,这个就相当于导包的时候import里面的值;同时需要考虑classpath正确。 135 * 2.解剖权限不足 136 * 错误代码 String.class.getField("hash"); User.class.getField("name"); 137 * 错误原因: 权限不够, 1.默认只能解剖public的成员.就理解是public默认允许解剖 138 * 拓展,权限修饰符 -> 其它作用 139 * 3.修改获得字段值需要先实例化对象(本质是修改一个对象的属性值) 140 * 字段可以单独读,但是修改值是修改某个对象的相应字段值。 141 * 特殊,属于类的属性也需要通过对象修改,age.set(User,23);错误的 142 */ 143 144 /** 145 * 3.获得解析类的方法,执行对象的方法 146 */ 147 public static void test2() { 148 User user = new User(); 149 Class c = user.getClass(); 150 try { 151 // c.getMethod("方法名","参数类型的解析类".getClass()); 152 Method info = c.getMethod("info"); 153 System.out.println("名称:"+info.getName()); 154 System.out.println("返回类型"+info.getReturnType().getName()); 155 System.out.println("修饰符:"+Modifier.toString(info.getModifiers())); 156 System.out.println("参数数量:"+info.getParameterCount()); 157 158 //执行方法 159 //调用对象,方法参数 160 try { 161 info.invoke(user); 162 } catch (IllegalAccessException e) { 163 throw new RuntimeException(e); 164 } catch (InvocationTargetException e) { 165 throw new RuntimeException(e); 166 } 167 168 info = c.getMethod("setAge", int.class); 169 c.getDeclaredMethod("setAge",int.class); 170 // info = c.getMethod("setAge", Integer.class);//不能这样写 171 System.out.println("名称:"+info.getName()); 172 System.out.println("返回类型"+info.getReturnType().getName()); 173 System.out.println("修饰符:"+Modifier.toString(info.getModifiers())); 174 System.out.println("参数数量:"+info.getParameterCount()); 175 System.out.println("第一个参数类型:"+info.getParameterTypes()[0].getName()); 176 177 try { 178 info.invoke(user,20); 179 } catch (IllegalAccessException e) { 180 throw new RuntimeException(e); 181 } catch (InvocationTargetException e) { 182 throw new RuntimeException(e); 183 } 184 user.info(); 185 } catch (NoSuchMethodException e) { 186 throw new RuntimeException(e); 187 } 188 } 189 190 /** 191 * 4.通过反射创建对象 192 * 获得对象的构造器对象 193 * java默认的构造方法类型 194 */ 195 public static void test3() { 196 User u = new User(); 197 Class c = u.getClass(); 198 Constructor con =null; 199 try { 200 con = c.getConstructor(); 201 } catch (NoSuchMethodException e) { 202 throw new RuntimeException(e); 203 } 204 //获得构造方法属性 205 206 //构造方法权限 207 System.out.println("构造方法权限为:"+Modifier.toString(con.getModifiers())); 208 209 //打印参数类型 210 Class[] para = con.getParameterTypes(); 211 if (null!=para){ 212 for (int i = 0,len=para.length;i<len;i++){ 213 System.out.println(para[i].getTypeName()); 214 } 215 } 216 //执行构造方法 217 try { 218 User user = (User)con.newInstance(); 219 user.setAge(20); 220 System.out.println(user.getAge()); 221 } catch (InstantiationException e) { 222 throw new RuntimeException(e); 223 } catch (IllegalAccessException e) { 224 throw new RuntimeException(e); 225 } catch (InvocationTargetException e) { 226 throw new RuntimeException(e); 227 } 228 229 try { 230 con = c.getConstructor(String.class,int.class); 231 } catch (NoSuchMethodException e) { 232 throw new RuntimeException(e); 233 } 234 //获得构造方法属性 235 236 //构造方法权限 237 System.out.println("构造方法权限为:"+Modifier.toString(con.getModifiers())); 238 239 System.out.println("参数列表为:"); 240 //打印参数类型 241 para = con.getParameterTypes(); 242 if (null!=para){ 243 for (int i = 0,len=para.length;i<len;i++){ 244 System.out.print(para[i].getTypeName()+","); 245 } 246 } 247 } 248 /** 249 * 5.类模板其它方法 250 */ 251 252 public static void main(String[] args) { 253 /** 254 * 类模板的路径 255 * getResource(""),得到模板类的绝对路径,其实就是.class文件的父目录--路径中可以包含包 256 * getSimpleName(),得到模板类的名字,不带包名,区别getName()获得类的全限定名 257 */ 258 259 Class u = User.class; 260 Class s = Student.class; 261 Student student = new Student(); 262 User user = new User(); 263 System.out.println(u.getResource("")); 264 System.out.println(u.getSimpleName()); 265 266 /** 267 * equals(Object )和isInstance(Object )方法 268 * equals用于比较两个模板类是否相等 1.实际是判断的地址2.一个类的模板类只有一个地址 269 * isInstance用于模板类和非模板类的比较, 可类比instanceof 270 * 1.判断模板类是否是对象父(爷爷,祖先)类的模板类和是对象的模板类, 271 * 反过来理解对象是否是模板类处理的类的子类,或者本身,或者孙子,或者后代。 272 * 2.可以替代 instanceof 273 * 274 */ 275 276 System.out.println(u.equals(user));//false 277 System.out.println(s.equals(student));//false 278 279 System.out.println(u.equals(user.getClass()));//true 280 System.out.println(user.getClass().equals(u));//true 281 282 System.out.println(u.equals(s));//false 283 System.out.println(s.equals(u));//false 284 285 System.out.println(s.isInstance(u));//false 286 System.out.println(u.isInstance(s));//false 287 288 System.out.println(s.isInstance(user));//false 289 System.out.println(s.isInstance(student));//true 290 291 System.out.println(u.isInstance(user));//true 292 System.out.println(u.isInstance(student));//true 293 294 Class o = Object.class; 295 System.out.println(o.isInstance(user));//true 296 System.out.println(o.isInstance(student));//true 297 298 System.out.println(user instanceof User);//true 299 System.out.println(user instanceof Student);//false 300 301 System.out.println(student instanceof Student);//true 302 System.out.println(student instanceof User);//true 303 System.out.println(student instanceof Object);//true 304 } 305 }
2022/9/13
反射和类构造
通过反射可以得到类模板,在创建类模板的时候会实例化类的静态方法,初始化静态成员,执行静态代码块的代码
案例就是:注册 jdbc驱动的时候只需要写
Class.forName("com.mysql.cj.jdbc.Driver");
然后会自动把类构造出来,就能注册驱动。

浙公网安备 33010602011771号