注解与反射机制
注解与反射
注解【1.可以对程序作出解释;2.可以被其他程序读取】
1. 格式:@注释名2.分类:
名称 | 表示 1 | 表示2 | 表示3 | 表示4 |
---|---|---|---|---|
内置注解 | @Override [表示一个类声明打算重写超类中的另一个方法声明] | @Deprecated [表示不鼓励程序员使用这样的元素] | @SuppressWarnings [用来抑制编译时的警告信息有参数:all/unchecked/value=("unchecked","deprecation")] | 内置注解 |
元注解 | @Taget [用于描述注解的使用范围] | @Retention [表示需要什么级别保存注释信息,用于描述注解的生命周期(source<class<runtime)] | @Document [说明该注解将被包含在javadoc中] | @Inherited[说明子类可以继承父类中的该注解] |
3.如何自定义注解:
- 使用@interface自定义注解,自动继承java.lang.annotation.Annotation接口,格式:public @interface 注释名
- 其中每一个方法实际上是声明了一个配置参数;方法的名称就是参数的名称;返回值类型【只有class、string、enum】就是参数的类型;可以通过default来声明参数的默认值;如果只有一个参数成员,一般参数名为value;注解元素必须有值,我们定义注解元素时,经常使用空字符串.0作为默认值
反射机制
1.反射的引入:当编译时不知道类或者对象的具体信息时,我们无法创建对象/操作属性/执行方法,这时就需要使用反射。
2.通过类实现JAVA反射机制:-
Class类:代表一个类
-
Constructor类:代表类的构造方法
-
Field类:代表类的成员变量(属性)
-
Method类:代表类的成员方法
3.反射的入口【Class类】:
-
获取一个类的类对象的多种方法:
1. class.forName()--------------使用的前提:编译/编码时不知道类和对象的具体信息,此时只能使用该方法。 Class clazz = Class.forName("com.ll.Cat"); 2.类名.class Class clazz = Cat.class; 3.对象名.getClass()--------------使用的前提:编译/编码时已经知道类和对象的具体信息 Cat cat = new Cat(); Class clazz = cat.getClass(); 4.获得父类的类对象 Class clazz = cat.getClass().getSuperclass(); 5.仅针对包装类,得到的是包装的基本数据类型的类对象 Class clazz = Integer.class;
-
类加载过程:
加载-->{验证-->准备-->解析}(链接)-->初始化
4.利用反射创建对象:
-
通过无参数构造方法创建对象:
* 方法1:调用Class的newInstance方法 //1.获取类的完整路径字符串 String className = "com.ll.Cat"; //2.根据类的完整路径字符串获取类的对象 Class clazz = Class.forName(className); //3. Object o = clazz.newInstance(); //已经不建议使用 * 方法2:调用Constructor的newInstance方法 //1.获取类的完整路径字符串 String className = "com.ll.Cat"; //2.根据类的完整路径字符串获取类的对象 Class clazz = Class.forName(className); //3.从类对象中获取无参构造方法 Constructor con = clazz.getConstructor(); //4.使用反射调用Constructor的newInstance方法创建对象 Animal animal = (Animal)con.newInstance();
-
通过无参数构造方法创建对象:
* 方法1:调用Constructor的newInstance方法 //1.获取类的完整路径字符串 String className = "com.ll.Cat"; //2.根据类的完整路径字符串获取类的对象 Class clazz = Class.forName(className); //3.从类对象中获取有参构造方法 Constructor con = clazz.getDeclaredConstructor(String.class,int.class,String.class); con.setAccessible(true); //突破封装性的限制,即使private也可以调用 //4.使用反射调用Constructor的newInstance方法创建对象 Object obj = con.newInstance("迷糊",1,"蓝猫");
5.利用反射操作属性:
-
操作属性----------------实际中使用很少
* 操作属性 //1.获取类的完整路径字符串 String className = "com.ll.Cat"; //2.根据类的完整路径字符串获取类的对象 Class clazz = Class.forName(className); //3.从类对象中获取有参构造方法 Object obj = clazz.getConstructor().newInstance(); //相当于 Dog d = new Dog(); //4.从类对象中获取指定Field Field f1 = clazz.getSupperclass().getDeclaredField("nickname"); //5.使用反射操作属性 f1.setAccessible(true); //突破封装性的限制,即使private也可以调用 f1.set(obj,"迷糊"); //相当于 dog.nickName = "迷糊"
6.利用反射执行方法
-
执行方法
* 执行方法 //1.获取类的完整路径字符串 String className = "com.ll.Cat"; //2.根据类的完整路径字符串获取类的对象 Class clazz = Class.forName(className); //3.根据反射创建对象 Constructor con = clazz.getConstructor(String class,int class,String class); Object obj = clazz.getConstructor().newInstance(); //4.从类对象中获取指定方法 Method m1 = clazz.geyMethod("shout"); Method m2 = clazz.geyMethod("add",int class,int class); //5.使用反射执行方法 m1.invoke(obj); Object result = m2.invoke(obj,10,20);
7.使用反射获取参数类型的泛型信息
- 认识泛型扩充的数据类型:
类型 | 例子 |
---|---|
parameterized types【参数化类型】 | 如:List |
type variables【类型变量】 | 如:List |
array types【数组类型】 | 并不是通常所用的数组String[]、byte[],而是如:List |
WildcardType【通配符类型】 | 如:List<? extends Number> |
-
获取泛型信息
//1.得到类对象 Class clazz = TestGeneric.class; //2.获取method Method m1 = clazz.getMethod("method1",Map.class,List.class,String.class); //3.获取方法参数上的泛型类型:无法获取 Class<?>[] parameterType = m1.getParameterTypes(); for(Class parameterType : parameterTypes){ System.out.println(parameterType); } //4.获取方法参数上的泛型类型 Type[] genericParameterType = m1.getGenericParameterType(); for(Type genericParameterType:generaticParameterTypes){ Type[] actualTypeArguments = ((ParameterizedType)genericParameterType).getActualTyoeArguments; for(Type actualTypeArguments:actualTypeArguments){ System.out.println("\t\t"+actualTypeArgument); } }