Java反射
1、何为反射? 简而言之: 加载类,并解剖出类的各个组成部分。根据java语言的这一特性,可将Java视为一种动态语言。更好的理解反射机制有助于我们深层次的理解spring框架。
2、Class类 代表了一个类的字节码。 在 java.lang包中可以找到。
加载字节码的方法:
1 Class.forName("全类名"); Class.forName("com.mysql.jdbc.Driver");
该方法的作用是,加载某个类的字节码到内存中,并使用class对象进行封装。
3、如何获取class对象?下面用Demos.java来举例
1 package org.reflect.test; 2 3 public class Demos implements Serializable { 4 5 public String demoName0; 6 public String demoName2; 7 public String demoName3; 8 private String demotype0; 9 private String demotype1; 10 private String demotype2; 11 12 public Demos(){} 13 14 //构造函数 15 public Demos(String name, String type) { 16 17 } 18 19 //私有方法 20 private void getDemoName0(){ 21 22 23 } 24 private void setDemoName1(){ 25 26 27 } 28 private void setDemoName2(){ 29 30 31 } 32 33 //共有方法 34 public void getDemoType0(){ 35 36 37 } 38 public void getDemoType1(){ 39 40 41 } 42 public void getDemoType2(){ 43 44 45 } 46 47 //测试方法 48 public void sayHello(String s){ 49 50 System.out.println("Public Hello"+s); 51 } 52 53 //测试方法 54 private void sayPrivateHello(String s){ 55 56 System.out.println("Private Hello"+s); 57 } 58 59 }
获取方式:
1 //获取class类方式1 2 Class clazz1=Class.forName("org.reflect.test.Demos"); 3 //方式2 4 Class clazz2=Demos.class; 5 //方式3 6 Class clazz3=new Demos().getClass();
4、获取包名,全类名,类的修饰符,父类,接口名,构造方法
1 //获取包名包名 2 String package1=clazz1.getPackage().getName(); 3 String package2=clazz2.getPackage().getName(); 4 5 System.out.println("包名1 :"+package1+"---包名2 :"+package2); 6 7 //获取类全名 8 String name1=clazz1.getName(); 9 String name2=clazz2.getName(); 10 System.out.println("类名1 :"+name1+"---类名2 :"+name2); 11 12 //获取类的修饰符 13 int mod=clazz1.getModifiers(); 14 System.out.println("该类的修饰符 :"+Modifier.toString(mod)); 15 16 //获取该类的父类 17 Class supercla=clazz1.getSuperclass(); 18 System.out.println("父类 :"+supercla); 19 20 //获得该类的接口 21 Class []interfaces=clazz1.getInterfaces(); 22 for (Class i:interfaces) { 23 System.out.println("接口名 :" + i.getName()); 24 } 25 26 27 //获取该类的构造方法 28 Constructor []con=clazz1.getConstructors(); 29 for (Constructor c :con) { 30 System.out.println("构造函数名 :"+c.getName()); 31 } 32
输出结果:
5、获取该类的字段的两种方法:
getFields();
getDeclaredFields();
1 //获取该类的字段 ,只限public修饰符修饰的 2 Field[]fils=clazz1.getFields(); 3 for (Field f :fils) { 4 System.out.println("fieldsName :"+f.getName()); 5 } 6 //获取该类的所有的字段,public, protected, default(package) access, and private fields 7 //不包括继承来的属性 8 Field []filss=clazz1.getDeclaredFields(); 9 for (Field f :filss) { 10 System.out.println("DeclaredFields :"+f.getName()); 11 }
说明:getFields();该方法只获取本类中public修饰的属性,
getDeclaredFileds();该方法获取该类中所有的属性,包括私有,但是不包括继承来的属性。
输出结果:
6、获取该类的方法的两种方法:
getMethods();
getDeclaredMethods();
1 //获取该类的特定的方法 public,包括父类的以及接口实现的 2 Method[]methods=clazz1.getMethods(); 3 for(Method m:methods){ 4 System.out.println("Methods :"+m.getName()); 5 } 6 7 //获取所有的方法,public private 仅限当前类,不包括父类 8 Method []method3=clazz1.getDeclaredMethods(); 9 for(Method m : method3){ 10 System.out.println("DeclaredMethods :"+m.getName()); 11 }
说明:getMethods();获取该类public修饰的方法,包括父类及接口实现的
getDeclaredMethods();只获取本类中的所有方法,包括private修饰的
输出结果:
7、通过反射调用Demos类中的方法
1 //获得该类的一个实例 2 Demos c=(Demos) clazz2.newInstance(); 3 Method method=clazz2.getMethod("sayHello", String.class); 4 method.invoke(c, "World!!!"); 5 6 //getDeclaredMethod能获取到所有定义的方法。setAccessible方法为true 则可以访问到私有的方法 7 Demos c2=(Demos) clazz1.newInstance(); 8 Method method2=clazz1.getDeclaredMethod("sayPrivateHello", String.class); 9 method2.setAccessible(true); 10 method2.invoke(c2, "World!!!!");
说明:getMethod("arg0","arg1"); arg0代表方法的名称,arg1代表参数的类型。
getDeclaredMethod("arg2","arg3"); arg2,arg3的含义同getMethod方法。
输出结果:
这里有一个小插曲,都知道私有的方法只能供本类使用,属于本类私有,但是这里我们可以看到利用反射可以访问到Demos类中的私有方法,所以下次面试遇到private修饰的方法能被其他类调用吗?就可以说利用反射是可以的 0.0