精选文章 java基础学习笔记(七)-反射--注解

java基础学习笔记(七)-反射--注解

作者:m0_47419463 时间: 2021-02-05 09:43:15
m0_47419463 2021-02-05 09:43:15
【摘要】反射机制介绍
 _Class 
 对象获取
 

  
 
反射机制是 Java 的动态性之一  动态语言 : 在程序运行时,可以改变程序的结构或变量的类型。 
    典型的动态语言 ”Python 、 ruby 、 JavaScripC,C++, Java  不是动态语言,但具有一定的动态性,可以称为” 准动态语言 ”, 具备类似动态语言的特性。传一块代码来动态的执行,动态的处理,Jav...
反射机制介绍 _Class 对象获取
  1. 反射机制是 Java 的动态性之一
    动态语言 : 在程序运行时,可以改变程序的结构或变量的类型。
    典型的动态语言 ”Python ruby JavaScripC,C++, Java 不是动态语言,但具有一定的动态性,可以称为” 准动态语言 ”, 具备类似动态语言的特性。传一块代码来动态的执行,动态的处理,Java 也能做,可以利用反射来实现类似的功能。
    Java 的动态性让编程变得更加的灵活,功能就更加的强大。
  2. 反射机制
    程序在运行的过程中加载一些“只知道相关名字”的类,
    以下代码,在程序运行时加载 User 类。
    Class c=Class.forName("com.zb.reflect.User");
    一个类被加载后, JVM 会创建一个对应类的 Class 对象,
    类的整个结构信息会被放到 Class 对象中。
    这个 Class 对象就像镜子一样,通过这面镜子,可以得到对应类的全部信息。
  3. 反射机制的常见作用
    1) 动态的加载类、动态的获取类的信息 ( 属性,方法,构造器)
    2) 动态构造对象
    3) 动态调用类和对象的任意方法、构造器
    4) 动态调用和处理属性
    5) 获取泛型信息
    6) 处理注解
  4. 获取 Class 对象的方式
    1) 通过字节码文件
    2) 对象的 getClass() 方法 3) Class 类的静态方法 forName(….)
  5. public class Test1 { public static void main(String[] args) throws ClassNotFoundException { System.out.println(Integer.class); System.out.println(int.class); System.out.println(void.class); //维数相同和类型相同的数组共享同一个Class对象 int [] array=new int[10]; int [] array2=new int[30]; System.out.println(array.getClass()==array2.getClass()); //同一个类的N多对象,共享同一个Class对象 User u1=new User(); User u2=new User(); System.out.println(u1.getClass()==u2.getClass()); //获取Class对象的三种方法 Class c1=u1.getClass(); Class c2=User.class; Class c3=Class.forName("day07.reflect.User"); }
    }

     


反射机制动态操作 _ 方法 _ 属性 _ 构造器
  1. 获取类的名字
    方法描述
    String getName()
    获得包名 + 类名
    String getSimpleName()
    获得类的名字
  2. 获得类的属性
    方法描述
    Field getField(String fieldName)
    得到公共的属性对象
    Field getDeclareField(String fieldName)
    得到指定名称的属性对象
    Field []c.getDeclaredFields()
    得到所有的属性对象
  3. 获得类的方法
    方法描述
    Method[] getDeclaredMethods()
    得到公共的方法对象
    Method[] c.getMethods()
    得到父类及本类中的公共的方法对象
    Method getDeclaredMethod(String methodName, Class …type)
    得到指定名称的本类中公共的方法
    Method getMethod(String methodName, Class type)
    得到本类或父类中的公共的方法对象
  4. 获得构造方法
    方法描述
    Constructor[] getDeclaredConstructors()
    得到公共的构造方法的对象
    Constructor [] getConstructors()
    得到公共的构造方法对象
    Constructor getDeclaredConstructor(Class...type)
    得到指定参数的公共的构造方法对象
  5. 动态的操作属性、方法、构造方法
  6. public class Test03 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException { Class c=Class.forName("day07.reflect.User"); System.out.println(c.getName());//包名 System.out.println(c.getSimpleName());//类名 Class cSuper=c.getSuperclass();//得到父类 Field [] fields1=c.getFields();//只能获取公共属性 Field [] fields2=c.getDeclaredFields();//获取所有属性 for(Field field:fields2){ System.out.println(field); //访问权限 类型 方法名称 System.out.println(field.getModifiers()+"\t"+field.getType()+"\t"+field.getName()); } Method [] methods=c.getDeclaredMethods(); for(Method m1:methods){ System.out.println(m1); System.out.println(m1.getModifiers()+"\t"+m1.getReturnType()+"\t"+m1.getName()); Class [] aPara=m1.getParameterTypes();//获取方法的参数也是Class类型 for(Class cs:aPara){ System.out.println(cs.getTypeName()); } Constructor [] constructors=c.getConstructors(); c.getConstructor();//获取指定的构造方法 } }
    }
    public class Test3 { public static void main(String[] args) throws Exception  { Class c= Class.forName("day07.reflect.User"); //得到无参构造方法的对象 Constructor con=c.getConstructor(null); User user=(User) con.newInstance(); //动态操作属性 Field field = c.getDeclaredField("userid"); field.setAccessible(true);//这个属性不做安全检查,直接访问 field.set(user,1001); System.out.println(field.get(user)); //动态操作方法 Method m= c.getDeclaredMethod("setUsername", String.class); m.invoke(user,"张三"); Method m2= c.getDeclaredMethod("getUsername",null); System.out.println(m2.invoke(user)); }
    }
    

     


提高反射效率
反射机制对程序的运行在性能上有一定的影响,速度慢
如何提高反射的性能
1) 通过 setAccessible 提高性能
a) setAccessible 启用和禁用访问安全检查的开关,值为true 则指示反射的对象在使用时应该取消 Java 语言访问检查,值为 false 则指示反射的对象不实施 Java 语言访问检查,并不是为 true 就能访问为 false 就不能访问
b) 禁止安全检查,可以提高反射的运行速度
public class Test01 { public static void test01(){ Object o=new Object(); long starttime=System.currentTimeMillis(); for(int i=0;i<1000000000L;i++){ o.hashCode(); } long endtime=System.currentTimeMillis(); System.out.println("普通方法执行时间为:"+(endtime-starttime)); } public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { Object o=new Object(); Class c=o.getClass(); Method method=c.getDeclaredMethod("hashCode",null); long starttime=System.currentTimeMillis(); for(int i=0;i<1000000000L;i++){ method.invoke(o,null); } long endtime=System.currentTimeMillis(); System.out.println("反射方法执行时间为:"+(endtime-starttime)); } public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { Object o = new Object(); Class c = o.getClass(); Method method = c.getDeclaredMethod("hashCode", null); method.setAccessible(true); long time1 = System.currentTimeMillis(); for(int i=0;i<1000000000L;i++) { method.invoke(o, null); } long time2=System.currentTimeMillis(); System.out.println("禁用安全检查反射方法执行时间为:"+(time2-time1)); } public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { test01(); test02(); test03(); }
}

反射操作泛型
  1. 泛型
    Java 中的泛型仅仅是给编译器 javac 使用的,确保数据的安全性和免去强制类型转换的麻烦,但是一旦编译完成,所有与泛型有关的类型全部擦除。使用反射直接读取泛型,是读取不到的,因为反射是操作加载以后的类的。
  2. Java 新增的数据类型
    为了通过反射操作这些类型以迎合实际开发的需要
    1) ParameterizedType : 表示一种参数化的类型 , 比 如Collection,可以获取 String 信息
    2) GenericArrayType :泛型数组类型
    3) TypeVariable :各种类型变量的公共父接口
    4) WildcardType :代表一种通配符类型表达式,比如? extends Number,? super Integer(Wildcard 是一个单词,就是通配符 )
    public class Test02 { public void test01(Map map,List list,String s){ System.out.println("test01"); } public Map test02(){ System.out.println("test02"); return null; } public String test03(){ System.out.println("test03"); return null; } public static void main(String[] args) throws NoSuchMethodException { //获取test01方法的泛型参数信息 Class c1=Test02.class; Method test01= c1.getMethod("test01",Map.class,List.class,String.class); //获取泛型参数的类型 Type[] types=test01.getGenericParameterTypes(); System.out.println(types.length);//3 for(Type type:types){ //System.out.println("#"+type); if(type instanceof ParameterizedType){//只获取带有泛型的参数 Type[] g=((ParameterizedType) type).getActualTypeArguments(); for(Type t:g){ //遍历每一个泛型参数中泛型的类型 System.out.println(t);//class java.lang.String  class day07.reflect.User } System.out.println("------------"); } } System.out.println("test02方法返回值的泛型信息"); Method me=c1.getMethod("test02",null); Type returnType=me.getGenericReturnType(); //是否带有泛型 if(returnType instanceof ParameterizedType){ //返回值的泛型类型 Type[] types1=((ParameterizedType) returnType).getActualTypeArguments(); for(Type t:types1){ System.out.println("返回值的泛型类型:"+t); } } System.out.println("test03"); Method m=c1.getMethod("test03",null); Type returnType1 = m.getGenericReturnType(); System.out.println(returnType1 instanceof ParameterizedType); }
    }

     


注解
  1. 注解的作用
    1) 不是程序本身,可以对程序作出解释。(这一点跟注释没什么区别)
    2) 可以被其他程序(比如:编译器等)读取。 ( 注解信息处理流程,是注解和注释的重大区别,如果没有注解信息处理流程,则注解毫无意义)
  2. 注解的格式
    1) 注解是以 ”@ 注释名 在代码中存在,还可以添加一些参数值,例如@SuppressWarnings(value=”unchecked”)
  3. 注解在哪里使用
    1) 可以附加在 package,class,method,field 等上面,相当于给它们添加了额外的辅助信息,我们可以通过反射机制编程
    实现对这些元素的访问。
  4. 内置的注解
    1) @Override : 标识方法是重写的方法
    2) @Deprecated :标识的方法不建议使用
    3) @SuppressWarnings :用来抑制编译时的警告信息 @SuppressWarinings 需要提供参数才能正常使用,这些参数都是已经定义好的,我们只需要选择就可以了。

自定义注解
  1. 自定义注解的语法
    使 用 @interface 定义自定义注解时,自动继承了 java.lang.annotation.Annotation 接口
    1) @interface 用来声明一个注解
    2) 其中的每一个方法实际上是声明了一个配置参数
    a) 方法的名称就是参数的名称
    b) 返回值类型就是参数类型 ( 返回值类型只能是基本类型、Class String enum)
    c) 可以通过 default 来声明参数的默认值
    d) 如果只有一个成员,一般参数名为 value
    注意事项:注解元素必须要有值。我们定义注解元素时,经常使用空字符串,0 作为默认值。也经常使用负数( 比如 -1) 表示不存在的含义
  2. 元注解
    元注解的作用就是负责注解其他注解。在 Java 中定义了 4个标准的 meta-annotation 类型,它们被用来提供对其它 annotation 类型作说明这些类型和它们所支持的类在 java.lang.annotation 包中可以找到
  3. @Target
    用于描述注解的使用范围 ( 即被描述的注解可以用在什么地方)
    所修饰范围
    取值 ElementType
    package 包 PACKAGE
    PACKAGE
    类、接口、枚举、 Annotation 类型
    TYPE
    类型成员(方法、构造方法、 成员变量、枚举值)
    CONSTRUCTOR: 用于描述构造器
    CONSTRUCTOR: 用于描述构造器
    FIELD: 用于描述域
    METHOD: 用于描述方法
    方法参数和本地变量
    LOCAL_VARIABLE: 用于描述局部变量
    PARAMETER: 用于描述参数
    @Target(value=ElementType.TYPE)
  4. @Retention
    表示需要在什么级别保存该注解信息 , 用于描述注解的生命周期
    取值作用
    SOURCE
    在源文件中有效 ( 即源文件中保留)
    CLASS
    class 文件中有效 ( class保留)
    RUNTIME
    在运行时有效 ( 即运行时保留), 被加载到程序中,可以被反射机制读取
    @Target(ElementType.METHOD)//使用范围在方法上
    @Retention(RetentionPolicy.RUNTIME)//注解的生命周期运行时有效,可以被反射机制读取
    public @interface MyAnnotation { //方法的名称就是参数名称,返回值类型就是参数类型,default声明参数的默认值 String name() default ""; int age() default 0; String[] schoolName() default {"山西大学","太原理工大学"};
    }
    public class Test04 { @MyAnnotation(name="weiwei",age=20,schoolName = {"山西大学","太原理工大学"}) public static void test01(){ }
    }

     


反射读取注解信息
  1. ORM (Object Relationship Mapping)
    1) 类与表结构对应
    2) 属性和字段对应
    3) 对象和记录对应
    使用注解完成类和表结构的映射关系
  2. 功能描述
    Java 中的 Student 类使用第三方程序通过读取注解生成数据库中的表
  3. 实现步骤 1) 编写 Student
    2) 编写注解
    3) 在类中使用注解
    4) 通过解析程序将注解读取出来 ( 通过框架解析 )
    5) 拼接 SQL 语句,使用 JDBC 到数据库中执行创建表
  4. @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface sxtTable { String value();
    }
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface sxtField { String conlumeName(); String type(); int length();
    }
    @sxtTable("table_student")
    public class Student { @sxtField(conlumeName = "name",type="char",length=10) private String name; @sxtField(conlumeName = "age",type="int",length=10) private int age;
    }
    public class Test05 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException { Class c=Class.forName("day07.reflect.Student"); System.out.println("获取类的注解"); Annotation[] a=c.getDeclaredAnnotations(); for(Annotation a1:a){ System.out.println(a1);//@day07.reflect.sxtTable(value=table_student) } System.out.println("获取指定的注解"); sxtTable sxtTable =(sxtTable)c.getDeclaredAnnotation(sxtTable.class); System.out.println(sxtTable);//@day07.reflect.sxtTable(value=table_student) System.out.println("获取属性的注解"); Field field=c.getDeclaredField("name"); //   SxtField s =field.getDeclaredAnnotations(SxtField.class); //  System.out.println(s); }
    }

     

分享文章到微博
分享文章到朋友圈

上一篇:编程小白的毕设开发教程-filter实战

下一篇:使用webpack打包多页面

CSDN

CSDN

中国开发者社区CSDN (Chinese Software Developer Network) 创立于1999年,致力为中国开发者提供知识传播、在线学习、职业发展等全生命周期服务。
java基础学习笔记(七)-反射--注解介绍:华为云为您免费提供java基础学习笔记(七)-反射--注解在博客、论坛、帮助中心等栏目的相关文章,同时还可以通过 站内搜索 查询更多java基础学习笔记(七)-反射--注解的相关内容。| 移动地址: java基础学习笔记(七)-反射--注解 | 写博客