反射作用
1,反编译;2,通过反射机制访问类中的以下几个。
Class
1 | public class Emp{ //Class |
2 | private String name; //Field |
3 | public Emp() {} //Constructor |
4 | public void work(){ //Method |
5 | System.out.println(name+"正在工作。。"); |
6 | } |
7 | } |
获取class类型对象的三种方式
1 | Class c1=Class.forName("com.czw.reflect.Emp"); //第一种 |
2 | //c1引用保存内存地址指向堆中的对象,该对象代表Emp整个类 |
3 | Class c2=Emp.class; //第二种 |
4 | //java中每个类型都有class属性 |
5 | Emp e=new Emp(); |
6 | Class c3=e.getClass(); //第三种,c3是运行时类 |
7 | //java中每个对象都有getClass方法 |
Class.forName(“Emp”);这是将Emp类装载到JVM虚拟机的过程,会执行静态语句块。
而Class c= Emp.class;不会执行。
创建类的对象实例
newInstance()方法
1 | Class c=Class.forName("com.czw.reflect.Emp"); |
2 | Object o=c.newInstance(); //调用的是无参构造方法,Emp必须要有 |
3 | c.getDeclaredConstructor().newInstance();//据说JDK9之后用这个方法 |
反射的使用
反射获取类的属性
1 | Class c=Class.forName("com.czw.reflect.Emp"); |
2 | Field [] fs=c.getFields(); //获取所有public修饰的属性 |
3 | getDeclaredFields() //获取所有属性 |
4 | |
5 | for(Field f:fs){ |
6 | int i=f.getModifiers() //返回属性修饰符(int类型,0-4) |
7 | Modifiler.toString(i) //返回数字所对应的字符(public。。。) |
8 | Class type=f.getType() //获取属性类型 |
9 | type.getName() //获取类型名称(java.lang.String) |
10 | type.getSimpleName() //获取类型名称(String) |
11 | f.getName() //获取属性名字(name) |
12 | } |
综合起来,打印类的结构

1 | Class c=Class.forName("com.czw.reflect.Emp");//获取类 |
2 | Field[] fs= c.getDeclaredFields(); //活获取类的所有属性集合 |
3 | StringBuilder sb=new StringBuilder(); |
4 | sb.append(Modifier.toString(c.getModifiers())+" class "+c.getName()+" {\n"); |
5 | for (Field f:fs){ //遍历所有属性 |
6 | sb.append("\t"+Modifier.toString(f.getModifiers())+" ");//修饰符 |
7 | sb.append(f.getType().getSimpleName()+" "); //属性类型 |
8 | sb.append(f.getName()+";\n"); //属性名 |
9 | } |
10 | sb.append("}"); |
11 | System.out.println(sb); |

结果完美
针对获取某一个属性
1 | Class c=Class.forName("com.czw.reflect.Emp"); |
2 | Field fid=c.getDeclaredField("id"); |
3 | fid.setAccessible(true); //打破封装,使其可以获取私有属性 |
4 | Object o=c.newInstance(); //得到Emp类的实例 |
5 | fid.set(o,100); //给对象o的id属性赋值100 |
6 | System.out.println(fid.get(o)); //获取o的id |
反射获取类的方法
1 | Class c=Class.forName("com.czw.reflect.Emp"); |
2 | Method [] ms=c.getMethods(); //获取所有public修饰的方法 |
3 | getDeclaredMethods() //获取所有方法 |
4 | |
5 | for(Method m:ms){ |
6 | int i=m.getModifiers() //返回方法修饰符(int类型,0-4) |
7 | Modifiler.toString(i) //返回数字所对应的字符(public。。。) |
8 | Class type=m.getReturnType()//获取方法返回值类型 |
9 | type.getName() //获取返回值类型全称(java.lang.String) |
10 | type.getSimpleName() //获取返回值类型名称(String) |
11 | m.getName() //获取方法名字(name) |
12 | } |
13 | |
14 | Class[] pts=getParameterTypes()//获取方法参数列表 |
15 | pts[index].getSimpleName() //获取方法参数类型名称 |
打印类的方法集

1 | Class c=Class.forName("com.czw.reflect.Emp"); |
2 | Method[] ms=c.getDeclaredMethods(); //获取方法集合 |
3 | StringBuilder sb=new StringBuilder(); |
4 | sb.append(Modifier.toString(c.getModifiers())+" class "+c.getSimpleName()+" {\n"); //打印类信息 |
5 | for(Method m:ms){ |
6 | sb.append("\t"+Modifier.toString(m.getModifiers())+" ");//方法修饰符 |
7 | sb.append(m.getReturnType().getSimpleName()+" ");//方法返回值 |
8 | sb.append(m.getName()+"("); //方法名称 |
9 | Class[] pts=m.getParameterTypes(); //获取方法参数列表 |
10 | for(int i=0;i<pts.length;i++){ |
11 | sb.append(pts[i].getSimpleName()); //参数类型 |
12 | if(i!=pts.length-1){ |
13 | sb.append(","); |
14 | } |
15 | } |
16 | sb.append("){}\n"); |
17 | } |
18 | sb.append("}"); |
19 | System.out.println(sb); |

结果同样完美
获取某个特定方法并调用
1 | Class c=Class.forName("com.czw.reflect.Emp"); |
2 | Method m1=c.getDeclaredMethod("work",String.class);//与属性不同,要加参数列表 |
3 | Method m2=c.getDeclaredMethod("say",String.class,int.class); |
4 | m1.setAccessible(true); //打破封装,使其可以获取私有属性 |
5 | Object o=c.newInstance(); //得到Emp类的实例 |
6 | m1.invoke(o,"ccc"); //传入对象和对应参数,无返回值直接使用 |
7 | Object or=m2.invoke(o,"czw",999);//有返回值的用对象接受 |
8 | System.out.println(or); //输出返回值 |
反射获取构造方法

1 | Class c=Class.forName("com.czw.reflect.Emp"); |
2 | Constructor[] cs=c.getConstructors(); |
3 | StringBuilder sb=new StringBuilder(); |
4 | for(Constructor ctr:cs){ |
5 | sb.append(Modifier.toString(ctr.getModifiers())+" "+c.getSimpleName()+"("); |
6 | Class[] cpts=ctr.getParameterTypes(); |
7 | for(int i=0;i<cpts.length;i++){ |
8 | sb.append(cpts[i].getSimpleName()); |
9 | if(i!=cpts.length-1){ |
10 | sb.append(","); |
11 | } |
12 | } |
13 | sb.append("){}\n"); |
14 | } |
15 | System.out.println(sb); |

获取某个特定构造方法并创建对象
1 | Class c=Class.forName("com.czw.reflect.Emp"); |
2 | Constructor ctr=c.getDeclaredConstructor(String.class,int.class,boolean.class);//获取有参构造方法 |
3 | Object oc=ctr.newInstance("ccc",18,true);//这个newInstance属于ctr的有参构造方法 |
4 | System.out.println(oc);//打印对象 |
反射获取父类和实现接口
1 | public class Emp extends Person implements sleep{} |
2 | |
3 | Class sc=c.getSuperclass(); //获取父类 |
4 | System.out.println(sc.getSimpleName()); |
5 | Class[] ics=c.getInterfaces(); //获取接口集合 |
6 | for(Class i:ics){ |
7 | System.out.println(i.getSimpleName()); |
8 | } |
反射的缺点
反射是一种解释操作,性能上是有一定差距的,不如直接new对象。
反射可以获取到私有的属性和方法,所以有一点不安全。
可变长参数
Java中的可变长参数,可以看作数组,如果有精准匹配的,则不会去执行可变长参数方法。
1 | public static void test(int... t){ //参数个数是0-n个,记为方法1 |
2 | System.out.println(t); |
3 | } |
4 | public static void test(int t){ //记为方法2 |
5 | System.out.println("精准匹配"+t); |
6 | } |
7 | |
8 | test();//执行方法1 |
9 | test(1)//此时执行方法2 |
10 | test(1,2,3,4,5);//执行方法1 |
11 | int[] is=[1,2,3] |
12 | test(is);//执行方法1 |
13 | |
14 | //可变长参数只能出现一次,并且必须是最后一位 |
15 | public static void test(int... t,int i){ //不可以 |
16 | System.out.println(t); |
17 | } |
18 | public static void test(String s,int... t){ //可以 |
19 | System.out.println(t); |
20 | } |
配置文件
xxx.properties:每行第一个符号(.不算)前的字符串作为键,之后作为值,键是唯一的。
1 | Properties p = new Properties(); |
2 | FileInputStream fis=new FileInputStream("xxx.properties"); |
3 | p.load(fis); //通过输入流加载出配置文件内容 |
4 | fis.close(); |
5 | String value1=p.getProperty("key1"); //获取每一个键对应的值 |
6 | String value2=p.getProperty("key2"); |
7 | //然后便可以将值用来进行自定义配置 |
这样增强了代码的灵活性,同样的代码,不同的配置,产生不同的效果,比如Spring Boot框架的配置文件就是这样。
注意:在出现中文时,要处理好编码,免得发生乱码。
使用反射+IO+properties配置文件联合应用,可以动态创建对象,在运行时才装载类,更加的灵活,降低了耦合度,增加了扩展性。
总结
头发-1