1. 反射机制介绍_Class对象获取
反射机制是 Java 的动态性之一
动态语言:在程序运行时,可以改变程序的结构或变量的 类型。
反射机制的常见作用
- 动态的加载类、动态的获取类的信息(属性,方法,构造 器)
- 动态构造对象
- 动态调用类和对象的任意方法、构造器
- 动态调用和处理属性
- 获取泛型信息
- 处理注解
java.lang.Class类 :表示正在运行的Java应用程序中的类和接口
获取Class对象的方式
- Class.forName(全限定类名);全限定类名==>包名+类名
- 类名.class
- 对象名.getClass()
练习代码
public class Test {public static void main(String[] args) {//获取Class对象try {//方法1:Class.forName("包名+类名")Class clazz=Class.forName("com.sxt.reflect.User");//方法2:类名.clazz
// Class clazz=User.class;//方法3:通过调用 对象名.getClass()方法获取该类的Class信息
// User user=new User();
// Class clazz=user.getClass();String name=clazz.getName(); //获取类或接口的名称System.out.println("名称:"+name);String simpleName=clazz.getSimpleName();System.out.println("简单类名:"+simpleName);//获取声明的属性信息System.out.println("*****************属性信息******************");Field[] fields=clazz.getDeclaredFields(); //Field类封装了属性信息for (Field field : fields) {int fieldModifier=field.getModifiers();//获取修饰符 0:默认 1:private 2:public 4:protectedClass fieldType=field.getType();//获取类型String fieldName=field.getName();//获取名称System.out.println(fieldModifier+"----"+fieldType+"----"+fieldName); }//获取构造方法System.out.println("**************构造方法****************");Constructor[] constructors=clazz.getDeclaredConstructors(); //获取构造器for (Constructor constructor : constructors) {int cModifier=constructor.getModifiers(); //获取构造器的修饰符String cName=constructor.getName();Class[] cs=constructor.getParameterTypes();System.out.println(cModifier+"---"+cName+"---"+Arrays.toString(cs)); }//获取方法信息System.out.println("***************方法信息***************");Method[] methods=clazz.getDeclaredMethods();for (Method method : methods) {int mModifier=method.getModifiers();Class returnType=method.getReturnType(); //获取返回值类型String mName=method.getName(); //获取方法名Class[] cs=method.getParameterTypes();System.out.println(mModifier+"---"+returnType+"---"+mName+"---"+Arrays.toString(cs));}} catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}
运行结果
2 反射机制动态操作方法_属性_构造器
获取类的名字的方法
- String getName() 获得全限定类名 包名+类名
- String getSimpleName() 获得简单类名
获得类的属性的方法
- Field getField(String fieldName) 得到公共的属性 对象
- Field getDeclareField(String fieldName) 得到指定名称的 属性对象
- Field []c.getDeclaredFields() 得到所有的属性 对象
获得类的方法
- Method[] getDeclaredMethods() 得到所有声明的公共的方法对象
- Method[] c.getMethods() 得到父类及本类中的公共的方法对象
- Method getDeclaredMethod(String methodName, Class …type) 得到指定名称的 本类中公共的方法
- Method getMethod(String methodName, Class type) 得到本类或父类中的公共的方法对象
获得构造方法
- Constructor[] getDeclaredConstructors() 得到所有声明的公共的构造方法的对象
- Constructor[] getConstructors() 得到公共的构造方法对象
- Constructor getDeclaredConstructor(Class...type) 得到指定参数的公共的构造方法对象
练习代码
public class Test {public static void main(String[] args) throws Exception {String path="com.sxt.demo.User";//1.获取类的名称Class c=Class.forName(path);System.out.println("类的全名称:"+c.getName());System.out.println("类的名称:"+c.getSimpleName());//获取父类的Class对象Class cSuper=c.getSuperclass();System.out.println(cSuper.getName());System.out.println(cSuper.getSimpleName());//3.获取类的属性信息
// Field f=c.getField("userId"); // 报错 只能获取公开的属性
// System.out.println(f);Field[] fields=c.getFields(); //只能获取公开的属性System.out.println(fields.length);Field[] fields2=c.getDeclaredFields();System.out.println(fields2.length);for (Field field : fields2) {
// System.out.println(field); //调用了toString()方法System.out.println(field.getModifiers()+"t"+field.getType()+"t"+field.getName());}//3.获取类的方法信息Method[] methods=c.getDeclaredMethods(); //本类中的公共的方法对象System.out.println(methods.length);for (Method method : methods) {
// System.out.println(method);System.out.println("访问权限:"+method.getModifiers());System.out.println("返回值类型:"+method.getReturnType());System.out.println("方法的名称:"+method.getName());//获取方法的参数Class[] cPara=method.getParameterTypes();for (Class c1 : cPara) {System.out.println(c1.getTypeName()+"t");}System.out.println("--------------------------");}System.out.println("========================");//4.获取类的构造器Constructor[] cons=c.getConstructors();for (Constructor constructor : cons) {System.out.println(constructor);}System.out.println("====================================");//根据参数获取指定的构造方法Constructor con=c.getConstructor(null);System.out.println(con);System.out.println("====================================");Constructor con2=c.getConstructor(int.class,String.class,String.class);System.out.println(con2);}
}
运行结果
练习代码
public class Test2 {public static void main(String[] args) {Class clazz;try {//如何动态创建对象clazz = Class.forName("com.sxt.reflect.User");Object object=clazz.newInstance();//通过反射动态创建对象System.out.println(object);System.out.println("------------访问属性---------------");Field userId=clazz.getDeclaredField("userId"); //获取指定的属性信息userId.setAccessible(true);userId.set(object, 1);//回调指定属性的赋值---->user.userId=1Object value=userId.get(object);//回调指定属性的getter方法进行赋值System.out.println("userId="+value);System.out.println("----------------回调方法---------------------");Method setUserName=clazz.getDeclaredMethod("setUserName", String.class);setUserName.invoke(object, "zhangsan"); //user.setUserName("zhangsan")Method getUserName=clazz.getDeclaredMethod("getUserName");//获取getUserName方法Object returnValue=getUserName.invoke(object); //user.getUserName()System.out.println(returnValue);} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}}
运行结果
3 提高反射效率
通过 setAccessible 提高性能
a) setAccessible 启用和禁用访问安全检查的开关,值为 true 则指示反射的对象在使用时应该取消 Java 语言访 问检查,值为 false 则指示反射的对象不实施 Java 语 言访问检查,并不是为 true 就能访问为 false 就不能访问
b) 禁止安全检查,可以提高反射的运行速度
练习代码
public class Test3 {//方法的直接调用public static void test(){Object obj=new Object();long startTime=System.currentTimeMillis();for(int i=0;i<1000000000L;i++){obj.hashCode();}long endTime=System.currentTimeMillis();System.out.println("直接调用 用时:"+(endTime-startTime));}//未优化 使用反射机制回调public static void test2() throws Exception{Object obj=new Object();Class clazz=obj.getClass();Method method=clazz.getDeclaredMethod("hashCode");long startTime=System.currentTimeMillis();for(int i=0;i<1000000000L;i++){method.invoke(obj);}long endTime=System.currentTimeMillis();System.out.println("未优化 使用反射机制回调 用时:"+(endTime-startTime));}//优化 使用反射机制回调public static void test3() throws Exception{Object obj=new Object();Class clazz=obj.getClass();Method method=clazz.getDeclaredMethod("hashCode");long startTime=System.currentTimeMillis();method.setAccessible(true);for(int i=0;i<1000000000L;i++){method.invoke(obj);}long endTime=System.currentTimeMillis();System.out.println("优化 使用反射机制回调 用时:"+(endTime-startTime));}public static void main(String[] args) throws Exception {test();test2();test3();}}
运行结果
4 反射操作泛型
Java 中的泛型仅仅是给编译器 javac 使用的,确保数据的安全性和免去强制类型转换的麻烦,但是一旦编译完成,所 有与泛型有关的类型全部擦除。
使用泛型直接读取泛型,是读取不到的,因为反射是操作 加载以后的类的。
Java新增的数据类型有
- ParameterizedType: 表 示 一 种 参 数 化 的 类 型 ,比 如 Collection<String>,可以获取 String 信息
- GenericArrayType:泛型数组类型
- TypeVariable:各种类型变量的公共父接口
- WildcardType:代表一种通配符类型表达式, 比如? extends Number,? super Integer (Wildcard 是一个单词,就是通配符)
练习代码
public class TestGeneric {public void test01(Map<String,User>map,List<User>list,String s){System.out.println("TestGeneric.test01");}public Map<Integer,User> test02(){System.out.println("TestGeneric.test01");return null;}public void test03(){System.out.println("TestGeneric.test01");}public static void main(String[] args) throws Exception {//获取test01方法的泛型参数信息NoSuchMethodExceptionClass c=TestGeneric.class;Method test01=c.getDeclaredMethod("test01", Map.class,List.class,String.class);//获取带泛型参数的类型Type[] types=test01.getGenericParameterTypes();System.out.println(types.length);for (Type type : types) {if(type instanceof ParameterizedType){ParameterizedType parameterizedType=(ParameterizedType) type;//ParameterizedType表示一个参数化类型Type[] genricType=parameterizedType.getActualTypeArguments();//返回一个表示此类型的实际类型参数的数组Type对象//遍历每一个泛型参数中的泛型的类型for (Type genType : genricType) {System.out.println("泛型类型:"+genType);}System.out.println("-------------------");}}System.out.println("-------------------------");//获取test01方法返回值的泛型信息Method test02=c.getDeclaredMethod("test02", null);Type returnType=test02.getGenericReturnType();//判断是否带有泛型if(returnType instanceof ParameterizedType){Type[] types2=((ParameterizedType)returnType).getActualTypeArguments();for (Type type : types2) {System.out.println("返回值的泛值类型:"+type);}}System.out.println("----------------------------");Method test03=c.getMethod("test03", null);Type returnType3=test03.getGenericReturnType();System.out.println(returnType3 instanceof ParameterizedType);}
}
运行结果
5 注解
注解的作用
不是程序本身,可以对程序作出解释。(这一点跟注释没 什么区别)
可以被其他程序(比如:编译器等)读取。(注解信息处理流程,是注解和注释的重大区别,如果没有注解信息处理流 程,则注解毫无意义)
注解的格式:注解是以”@注释名”在代码中存在,还可以添加一些参数 值,例如@SuppressWarnings(value=”unchecked”)。
注解可以附加在 package,class,method,field 等上面,相当于给它们添加了额外的辅助信息,我们可以通过反射机制编程 实现对这些元素的访问。
内置的注解
- @Override :标识方法是重写的方法
- @Deprecated :标识的方法不建议使用
- @SuppressWarnings:用来抑制编译时的警告信息
- @SuppressWarinings 需要提供参数才能正常使用,这些参数 都是已经定义好的,我们只需要选择就可以了。
- @SuppressWarnings("unchecked") @SuppressWarnings(value={"unchecked","deprecation"})