反射
JAVA 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方
法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以
及动态调用对象的方法的功能称为 java 语言的反射机制。

public class Simple { public static void main(String[] args) { Simple s = new Simple();
//包名.类名 System.out.println(s.getClass().getName()); } }
|
Java 反射机制,可以实现以下功能:
①在运行时判断任意一个对象所属的类;
②在运行时构造任意一个类的对象;
③在运行时判断任意一个类所具有的成员变量和方法;
④在运行时调用任意一个对象的方法;
⑤生成动态代理。
一、获取源头 Class
打开权限:
add.setAccessible(true);
所有类的对象其实都是 Class 的实例。这个 Class 实例可以理解为类的模子,就是包含
了类的结构信息,类似于图纸。
创建对象方法: 序列化:实现 serializable 接口,
反序列化
克隆:实现 cloneable 接口,重写 clone()方法,修改权限为 public
New
反射
获取类的 class 对象,有三种方式可以实现:
①Class.forName(”包名.类名”)//一般尽量采用该形式
②类.class
③对象.getClass()
public class Source { public static void main(String[] args) { //第一种方式 对象.getClass Source s = new Source(); Class<?> c1 = s.getClass(); //第二种方式 类.class Class<?> c2 = Source.class; //第三种方式(推荐使用) Class.forName(”包名.类名”) Class<?> c3 = null; try { c3 = Class.forName(“com.jssh.reflection.Source”); } catch (ClassNotFoundException e) { e.printStackTrace(); } System.out.println(c1.getName()); System.out.println(c2.getName()); System.out.println(c3.getName()); } }
|
二、 构造器
根据 Class 对象,我们可以获得构造器,为实例化对象做准备。调用以下 api 即可

public class GetConstructor { public static void main(String[] args) { try { //获取class对象 Class<?> clz = Class.forName(“com.jssh.reflection.User”); //1.获取所有public权限的构造器 Constructor<?>[] con = clz.getConstructors(); //注意查看构造器顺序 for (Constructor<?> c : con){ System.out.println(c); } //2.获取所有构造器 con= clz.getDeclaredConstructors(); for (Constructor<?> c:con ){ System.out.println(c); } //3.获取指定的构造器(放入具体的类型) Constructor<?> c = clz.getConstructor(String.class); System.out.println(c); //4.非public权限的 c = clz.getDeclaredConstructor(String.class,Integer.class); System.out.println(c); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } } }
|
三、 实例化对象
之前我们讲解过创建对象的方式,有 new 、克隆、反序列化,再加一种,根据 Class 对
象,使用 newInstance() 或者构造器实例化对象。

public class UserImpl { public static void main(String[] args) { Class<?> clz =null; try { //获取源头 clz =Class.forName(“com.jssh.reflection.User”); //第一种:通过newInstance()创建对象 User user = (User) clz.newInstance(); user.setName(“xiaoming”); user.setAge(18); System.out.println(user.getName()+“——–>”+user.getAge()); //第二种:通过getDeclaredConstructors()创建对象,取得全部构造函数(注意顺序) Constructor<?>[] cons = clz.getDeclaredConstructors(); for (Constructor<?> con:cons){ System.out.println(con); } //注意观察上面的输出结果,在实例化,否则参数容易出错 User u1 = (User) cons[0].newInstance(“xxx”,18); User u2 = (User) cons[1].newInstance(“xxx”); User u3 = (User) cons[2].newInstance(); System.out.println(u1.getName()+“——->”+u1.getAge()); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } }
|
注意:newInstance()是调用空构造,如果空构造不存在,会出现异常。由此可知,使
用其他构造器创建对象比较麻烦,使用空构造非常简单。确保空构造存在。
四、 接口与父类
通过 api 获取接口与父类

五、 修饰符
获取修饰符,使用 Modifier 即可

六、 属性
获取所有属性(包括父类或接口) ,使用 Field 即可操作

public class GetField { public static void main(String[] args) throws ClassNotFoundException { Class<?> clz = Class.forName(“com.jssh.reflection.User”); //获取类的全部属性 Field[] fields = clz.getDeclaredFields(); for (int i=0;i<fields.length;i++){ //1.获取权限修饰符 int mo = fields[i].getModifiers(); String s = Modifier.toString(mo); //2.属性类型 Class<?> type = fields[i].getType(); //3.名字 String name = fields[i].getName(); System.out.println(s+“===”+type+“===”+name); } //公开的属性:包括接口或者父类属性 Field[] fields1 = clz.getFields(); for (int i =0;i<fields1.length;i++){ System.out.println(fields1[i]); } } }
|
七、 方法
获取所有方法(包括父类或接口),使用 Method 即可。

八、 数组
操作数组需要借助 Array 类
public class ArrayTest { public static void main(String[] args) { //1.创建数组 Object o = Array.newInstance(int.class, 5); //2.获取大小 if (o.getClass().isArray()){//3、判断是否为数组 System.out.println(Array.getLength(o)); //4.设置值 Array.set(o,0,100); //5.获取值 System.out.println(Array.get(o,0)); } } }
|
九、 类加载器
在 java 中有三种类类加载器:
⑴Bootstrap ClassLoader 此加载器采用 c++编写,一般开发中很少见。
⑵Extension ClassLoader 用来进行扩展类的加载,一般对应的是 jre\lib\ext 目录中的类
⑶AppClassLoader 加载 classpath 指定的类,是最常用的加载器。同时也是 java 中默认
的加载器。 了解即可。
在程序执行中 JVM 通过装载,链接,初始化这 3 个步骤完成。
十、 反射相关操作( 重点)
1、操作属性
//1、获取Class对象
Class<?> clz=Class.forName(“com.shsxt.ref.simple.User”);
//2、获取对象
User u=(User)clz.newInstance();
//3、设置属性
Field field=clz.getDeclaredField(“uname”);
field.setAccessible(true);//打开权限
field.set(u, “0523”);
//4、获取此属性
System.out.println(field.get(u));
|
2 、调用方法
调用方法,都是直接对象.方法([实参]);反射之后,动态调用方法需要使用 invoke 即可。

1)、方法调用
//1、获取Class对象
Class<?> clz=Class.forName(“com.shsxt.ref.simple.User”);
//2、获取对象
User u=(User)clz.newInstance();
//3、获取方法
Method m =clz.getMethod(“coding”, String.class,String.class);
//4、成员方法的调用
m.invoke(u, “反射“,”多个参数“);
//若是静态方法,传递null即可 因为静态方法属性类,不属于对象
m=clz.getMethod(“testStatic”,int.class);
m.invoke(null, 100);//与对象无关
|
2)、操作 setter 与 getter 访问器
3 、利用反射编写简单工厂设计模式
利用反射+配置文件可以实现简单工厂模式。