反射(reflect)机制的作用
1.反编译:.class--->.java
2.通过反射机制访问java类的属性,方法,构造方法等
获取Class的三种方式
package com.yuijam.reflect; public class Employee { private String name; public Employee(){ } public Employee(String name){ this.name = name; } public void m1(){ } }
package com.yuijam.reflect; public class ReflectTest01 { public static void main(String[] args) throws Exception{ //第一种 Class c1 = Class.forName("com.yuijam.reflect.Employee"); //c1保存内存地址指向堆中的对象,该对象代表的是Employee整个类 //第二种 //Java中任何一个对象都有getClass方法 Class c2 = Employee.class; //第三种 //Java中每个类型都有class属性,注意这里说的是类型不是类,所以可以int.class Employee e = new Employee(); Class c3 = e.getClass(); //因为Employee这个类在JVM中只有一个,所以c1,c2,c3的内存地址是一样的,指向堆中的唯一一个对象 System.out.println(c1==c2); System.out.println(c3 == c2); } }
一个知识点
package com.yuijam.reflect; public class ReflectTest02 { public static void main(String[] args) throws Exception{ //将A.class文件装载到JVM的过程,会执行静态语句块,打印输出 Class c1 = Class.forName("com.yuijam.reflect.A"); //不会执行静态语句块 Class c2 = A.class; } } class A{ static{ System.out.println("A----"); } }
通过Class类对象创建java对象
package com.yuijam.reflect; import java.text.SimpleDateFormat; import java.util.Date; public class ReflectTest03 { public static void main(String[] args) throws Exception{ Class c = Class.forName("com.yuijam.reflect.Employee"); //创建此Class对象所表示的类的一个新实例 Object o = c.newInstance();//调用Employee的无参数构造方法 //如果将Employee的无参数构造方法注释掉,会抛出异常 System.out.println(o); Class d = Class.forName("java.util.Date"); Object o1 = d.newInstance(); if ( o1 instanceof Date){ Date t = (Date)o1; System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss SSS").format(t)); } } }
Employee的无参数构造方法执行!
com.yuijam.reflect.Employee@15db9742
2016-10-23 21:41:20 754
关于Java的可变长参数
package Test; /** * Created by Arenas on 2016/10/24. */ public class ReflectTest04 { //该方法在调用的时候传递的实参可以是0~N个 public static void m1(int... i){ System.out.println("test"); } //如果有可以精确匹配的方法,则调用该方法,而不会调用可变长参数的那个方法 public static void m1(int i){ System.out.println(i); } //可变长参数可以等同看作数组 public static void m2(String... s){ for (String s1 : s) { System.out.println(s1); } } //可变长参数只能出现一次,并且只能出现在参数列表最后一个,下面这样是不行的 // public static void m3(int... i , String s){ // // } //这个是可以的 public static void m3(int s , int... i){ } public static void main(String[] args) { m1(); m1(1); m1(1,2); m1(3,4,5); m2("kobe" , "kg" , "duncan" , "tracy"); } }
test
1
test
test
kobe
kg
duncan
tracy
Properties和IO的使用
首先在D盘新建一个文件info.txt,内容为username=tracy
package Test; import java.io.FileInputStream; import java.util.Properties; /** * Created by Arenas on 2016/10/24. */ public class PropertiesIOTest { public static void main(String[] args) throws Exception{ //创建输入流 FileInputStream fis = new FileInputStream("D:/info.txt"); //创建属性对象,和Map一样,只不过key和value只能是字符串类型 Properties properties = new Properties(); //将file流中的所有数据加载到属性对象中 properties.load(fis); //关闭流 fis.close(); String v = properties.getProperty("username"); System.out.println(v); } }
输出:tracy
info这样的文件通常称为配置文件,配置文件的作用是使程序更加灵活。像info这样一个具有特殊内容的配置文件,通常又称为属性文件。Java规范中要求属性文件以.properites结尾
属性文件的要求:
1.key和value之间可以使用“空格”,“冒号”,“等号”作为分隔符
2.当“空格”,“冒号”,“等号”同时出现时,按最先出现的那个作为分隔符
这里注意一个问题,在info文件中再加一条带中文的,如chinesename=麦迪
输出一个乱码:ÂóµÏ
这个时候进入cmd,输入如下:
再将转换成的unicode码复制到info中替换中文麦迪,即可输出中文麦迪
利用reflect、IO、properties创建Java对象
在D盘新建文件ClassInfo.properites,内容为className=java.util.Date
package Test; import java.io.FileReader; import java.util.Properties; /** * Created by Arenas on 2016/10/24. */ public class ReflectTest05 { public static void main(String[] args)throws Exception{ //创建属性对象 Properties properties = new Properties(); //创建流 FileReader reader = new FileReader("D:/ClassInfo.properites"); //加载 properties.load(reader); //记得关闭流 reader.close(); //通过key获取value String className = properties.getProperty("className"); //创建对象并打印出来 Class c = Class.forName(className); System.out.println(c.newInstance()); } }
输出:Mon Oct 24 19:35:54 CST 2016
反编译某个类的所有Field
新建User
package Test; /** * Created by Arenas on 2016/10/24. */ public class User { private String name; private int age; protected String addr; boolean married; private User(){ } public User(String name , int age){ this.name = name; this.age = age; } public boolean login(String username , String password){ return (username.equals("admin") && password.equals("123456")); } public void loginout(){ System.out.println("login out"); } }
package Test; import java.io.FileReader; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.Properties; /** * Created by Arenas on 2016/10/24. */ public class ReflectTest06 { public static void main(String[] args) throws Exception{ Properties properties = new Properties(); FileReader reader = new FileReader("D:/ClassInfo.properties"); properties.load(reader); reader.close(); String className = properties.getProperty("className"); Class c = Class.forName(className); Field[] fields = c.getDeclaredFields(); for (Field field : fields){ int i = field.getModifiers(); System.out.println(Modifier.toString(i)); Class type = field.getType(); String str = field.getName(); System.out.println(type.getName()); System.out.println(str); } } }
private
java.lang.String
name
public
int
age
protected
java.lang.String
addr
boolean
married
反编译User类
package Test; import java.io.FileReader; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.Properties; /** * Created by Arenas on 2016/10/24. */ public class ReflectTest06 { public static void main(String[] args) throws Exception{ Properties properties = new Properties(); FileReader reader = new FileReader("D:/ClassInfo.properties"); properties.load(reader); reader.close(); String className = properties.getProperty("className"); Class c = Class.forName(className); Field[] fields = c.getDeclaredFields(); StringBuilder builder = new StringBuilder(); builder.append(Modifier.toString(c.getModifiers())); builder.append(" class "); builder.append(c.getSimpleName()); builder.append("{ "); for (Field field : fields){ builder.append(" "); builder.append(Modifier.toString(field.getModifiers())); builder.append(" "); builder.append(field.getType().getSimpleName()); builder.append(" "); builder.append(field.getName()); builder.append("; "); } builder.append("}"); System.out.println(builder.toString()); } }
将User换成java.lang.String等也同样可以顺利打出
获取某个指定的Field
package Test; import java.lang.reflect.Field; /** * Created by Arenas on 2016/10/25. */ public class ReflectTest07 { //获取某个指定的属性 public static void main(String[] args) throws Exception{ Class c = Class.forName("Test.User"); //获取age属性,这里如果用getField只能获取public的属性,如果属性为private会抛出异常 Field field = c.getDeclaredField("age"); //使用反射机制可以打破封装属性,导致了Java对象的属性不安全 //这里如果注释掉这条,对于private属性来说会抛出异常 field.setAccessible(true); Object o = c.newInstance(); //给o对象的age属性赋值110 field.set(o , 110); System.out.println(field.get(o)); } }
获取所有方法
package Test; import java.lang.reflect.Method; import java.lang.reflect.Modifier; /** * Created by Arenas on 2016/10/25. */ public class ReflectTest08 { public static void main(String[] args) throws Exception{ Class c = Class.forName("Test.User"); Method[] methods = c.getDeclaredMethods(); for (Method method : methods){ //获取返回值类型 System.out.println(method.getReturnType().getSimpleName()); System.out.println(Modifier.toString(method.getModifiers())); System.out.println(method.getName()); //获得形参 Class[] paras = method.getParameterTypes(); for (Class para : paras){ System.out.println(para.getSimpleName()); } } } }
boolean
public
login
String
String
void
public
loginout
获取指定方法
package Test; import java.lang.reflect.Method; /** * Created by Arenas on 2016/10/25. */ public class ReflectTest09 { public static void main(String[] args)throws Exception{ Class c = Class.forName("Test.User"); //通过方法名和形参列表确定一个方法 Method method = c.getDeclaredMethod("login" , String.class , String.class); Object o = c.newInstance(); //调用o对象中的method方法,并传入两个参数,获取返回值returnValue Object returnValue = method.invoke(o , "admin" , "123456"); System.out.println(returnValue); } }
true
获取所有构造方法
package Test; import java.lang.reflect.Constructor; import java.lang.reflect.Modifier; /** * Created by Arenas on 2016/10/25. */ public class ReflectTest10 { public static void main(String[] args) throws Exception{ Class c = Class.forName("Test.User"); Constructor[] constructors = c.getDeclaredConstructors(); StringBuilder builder = new StringBuilder(); for (Constructor constructor : constructors){ String modifer = Modifier.toString(constructor.getModifiers()); builder.append(modifer); builder.append(" "); String constructorName = constructor.getName(); builder.append(constructorName);
builder.append(" "); Class[] paras = constructor.getParameterTypes(); for (Class para : paras){ builder.append(para.getSimpleName()); builder.append(","); } builder.append(" "); } System.out.println(builder.toString()); } }
private Test.User
public Test.User String,int,
同理可以根据参数类型来确定特定的构造方法
通过getSuperclass()来获取父类,单继承,所以只有一个父类
通过getInterfaces()获取接口,可以实现多个接口,所以返回一个Class数组
反射的两个缺点
1.性能问题
用反射基本上属于一种解释操作,我们可以告诉JVM,我们希望做什么,并且他满足我们的要求。用字段和方法接入时,反射要远慢与直接代码。性能问题的程度取决于程序是如何使用反射的,如果他作为程序中很少涉及的部分,缓慢的性能将不会是一个问题。大量使用反射要慎重
2.使用反射会模糊程序内部实际要发生的事情,程序员希望在源代码中看到程序的逻辑,反射等绕过了源代码的技术会带来维护问题。反射代码比直接代码更复杂。保守的使用反射,仅在他真正可以增加灵活性的地方使用。