Java 反射机制
1.Class 类
所有的类都是java.lang.Class类的实例。 通过a1,a2,a3,a4四种方式获得Class类实例。
通过已知不同的条件,或者为类名A,可通过Class a1 = A.class方式获取类,如果知道实例可以通过Class a2 = a.getClass();效果一样。
public class AboutClass { public static void main(String[] args) { A a = new A(); Class a1 = A.class; //任何事物皆是对象,类A是Class类的对象 Class a2 = a.getClass(); //a1,a2 表示了A类的类类型 System.out.println("a1=a2是"+(a1==a2)); try{ Class a3 = Class.forName("com.project.reflect.A"); //全路径 System.out.println("a1=a3是"+(a1==a3)); }catch(Exception e){ e.printStackTrace(); } try { A a4 = (A) a1.newInstance(); //A必须有无参构造方法 a4.print(); } catch (Exception e) { e.printStackTrace(); } } } class A{ public A(){ }; public void print(){ System.out.println("this is A"); } }
运行结果为:
2、静态加载&动态加载
静态加载类:编译时加载,指的是通过new创建的对象,在编译时加载所有可能用到的类。
动态加载类:运行时加载类。 Class.forName("类的全称")
例子:
如果在记事本上,编写一个类如下:
public class Test{ public static void main(String args[]){ if("Word".equals(args[0])){ Word.start(); } else if("Excel".equals(args[0])){ Excel.start(); } } }
通过cmd命令行,编译javac时,会报错,找不到Word类、找不到start()方法、Excel类、找不到start()方法,四个错误。
假如我们已经有了一个Word类,Word类中存在start()方法,并且已经编译过。则仍然报错找不到Excel类、找不到start()方法,两个错误。
这就造成了,本来是运行word,却因为excel报错而无法运行。
然后,我们对程序做如下修改:
1.创建一个OfficeRef接口
public interface OfficeRef{ public void start(); }
2.创建Word类继承OfficeRef接口
public class Word implements OfficeRef{ public void start(){ System.out.println("word starting..."); } }
3.将Test类做如下修改
public class Test{ public static void main(String args[]){ if("Word".equals(args[0])){ try{ Class c = Class.forName(args[0]); //动态加载类,通过类类型创建Class对象(全路径) OfficeRef off = (OfficeRef)c.newInstance(); //根据实例创建类 off.start(); }catch(Exception e){ e.printStackTrace(); } } } }
在cmd命令下,首先编译OfficeRef,然后word,然后编译Test类,最后运行 java Test Word 发现可以成功运行。
此处Word换成excel依然可以。这就是动态加载类的好处。
功能性的类使用动态加载。
3.反射--获取方法的信息
public class ReflectClass{ public static void main(String[] args) { Class c1 = int.class; //int的类类型 Class c2 = String.class; Class c3 = double.class; Class c4 = Double.class; Class c5 = void.class; //所有类中的元素,都含有类类型 System.out.println(c1.getName()); System.out.println(c2.getName()); } }
public class ClassUtil { public static void getMethodRef(Object obj){ Class c = obj.getClass(); c.getName(); Method[] ms = c.getMethods(); //获取的是所有的public类型的,包括从父类中继承的方法 Method [] mms = c.getDeclaredMethods();//获取的是所有的自己类声明的方法; for(int i=0;i<ms.length;i++){ System.out.println(ms[i].getName()); Class returnType = ms[i].getReturnType(); //返回的是返回类型的类类型 System.out.println(returnType.getName()); Class []paraType=ms[i].getParameterTypes(); //参数类型的类类型 for(Class param:paraType){ System.out.print(param.getName()+","); } } } }
public class Demo { public static void main(String[] args) { String s ="Hello"; ClassUtil.getMethodRef(s); } }
4.获取成员变量构造函数信息
成员变量也是对象,是java.lang.reflect.Filed Filed类获得了封装关于成员变量的操作
Filed fs[] =c.getFileds()