-
反射:
Class 类的实例表示正在运行的 Java 应用程序中的类和接口;
枚举是一种类,注解(指的是注解Annotation)是一种接口;
每个数组都是 Class字节码类中的一个具体 对象
基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void 也表示为 Class 对象;
注意 :
1、 Class类 和它的实例的产生: Class的对象是已经存在的类型,
所以不能够直接new一个Class对象出来,是通过Class类中的一个方法获取到的。
例如:通过全限定路径类名2、同一种类型不管通过什么方式得到Class的实例都是相等的;一个类型的字节码对象只有一份,在元空间。 3、Class的实例就看成是Java中我们学过的所有的数据类型在JVM中存在的一种状态(字节码对象) String.class int.class List.class int[].class 1.概念:通过一个全限定类名,获取字节码文件 2.作用: 1. 提高开发灵活度,提高程序的扩展性 2. 框架(提高开发效率的别人封装好的代码)底层都是使用反射技术。例如:Tomcat、Spring... 3. 缺点:破坏封装性,性能低下(以后,能不用反射技术就不用) 3. 使用:(重点) 1. 获取字节码文件 1. 1.1 Class clazz = Class.forName(全限定路径名) (最多使用)默认就是调用下面的方法 1.2 static 类<?> forName(String name, boolean initialize, ClassLoader loader) name:全限定路径名 initialize:表示是否初始化,默认是false loader:可以指定一个类加载器加载字节码文件 2. 全限定类名.class 3. 对象名.getClass() Class类中方法newInstance():创建当前字节码对象(只能调用无参且是public修饰的构造方法) 2. 根据字节码文件获取构造方法、普通方法、字段等 构造方法 Constructor[] constructors = clazz.getConstructors() 获取public修饰的构造方法数组 Constructor[] constructors = clazz.getDeclaredConstructors() 获取任意权限的所有造方法数组 Constructor constructor = clazz.getConstructor(Class 参数字节码)根据参数类型获取public修饰的指定的的构造方法 Constructor constructor = clazz.getDeclearConstructor(Class 参数字节码) 获取任意访问权限指定的构造方法 //通过构造方法对象去用构造方法创建对象 => 相当于new 一个对象 Object instance = constructor.newInstance(Object 实参);//可以创建任意访问权限的有参或者无参构造 普通方法 Method[] methods = clazz.getMethods() 获取public修饰的构造方法数组,有父类中的方法 Method[] methods = clazz.getDeclaredMethods() 获取任意访问权限所有造方法数组,并且都是自己的方法 Method method = clazz.getMethod(String methodName,Class... 参数字节码)根据方法名和参数类型获取指定的的方法 methodName:方法名 Class:形参类型。如果方法没有形参,则Class可变参数不用写 Method method = clazz.getDeclaredMethod(String methodName,Class... 参数字节码)根据方法名和参数类型获取指定的的方法 methodName:方法名 Class:形参类型。如果方法没有形参,则Class可变参数不用写 //通过普通方法对象调用执行方法 method.invoke(Object obj,Object... args); obj:对象。如果是对象的方法,就传入一个当前字节码创建的对象,如果是static方法,则写null args:就是具体实参 字段 Field[] fields = clazz.getFields() 获取public修饰的字段 Field[] fields = clazz.getDeclaredFields() 获取任意权限所有字段 Field field = clazz.getDeclaredField(String fieldName) 根据字段名获取任意访问权限的指定字段 Field field = clazz.Field(String fieldName)根据字段名获取public的指定字段 //通过当前的字段对象,给某一个字段赋值取值 field.get(Object obj);//如果是属于非static,就传入一个对象,如果是静态的,就传入null obj:对象 field.set(Object obj, Object value);//如果是属于非static,就传入一个对象,如果是静态的,就传入null obj:对象 value:值 String getName() 获取全限定类名(全限定,包含包名) Class类中方法 String getSimpleName() 获取类名简称 Class类中方法 Package getPackage() 获取包名 Class类中方法 T newInstance() 根据当前字节码创建对应的对象 Class类中方法 注意: 1. Class类中方法newInstance():创建当前字节码对象(只能调用无参且是public修饰的构造方法) 2. Constructor类中方法newInstance(Object 实参);//可以创建任意访问权限的有参或者无参构造 3. 私有化方法、字段、构造方法都必须破坏封装才能使用: public void setAccessible(boolean flag) true表示破坏封装,false是不破坏 是哪个private修饰的方法、字段、构造方法需要执行,就需要用这个对象破坏哪一个的封装 例如: //获取cn.itsource.reflect.User字节码文件 Class<?> clazz = Class.forName("cn.itsource.reflect.User"); //获取User的有String参构造 Constructor<?> constructor = clazz.getConstructor(String.class); //调用有参String构造,创建一个User对象 Object newInstance = constructor.newInstance("某文"); //获取private修饰的方法:testPrivate Method method2 = clazz.getDeclaredMethod("testPrivate"); method2.setAccessible(true);//破坏普通方法Method封装 //破坏封装后就可以执行了 Object invoke2 = method2.invoke(newInstance);//没有形参就不用写 System.out.println(invoke2); 4. 调用static方法、字段: 例如: Field field = clazz.getDeclaredField("country");//获取任意访问权限静态变量country field.set(null, "中国");//因为字段country是static修饰,所以不用对象调用,就传入null。字段country赋值:中文 Object object = field.get(null);//字段country取值 System.out.println(object);
-
注解:
1.概念: 就是一个标签,有标签后,就具有某一些标签的特性。
本质就是跟类、接口、枚举平级的新结构
2.作用:
1. 帮助程序员校验代码
2. 可以提高开发效率和程序的扩展性
@Test
@Before
@After3. 可以生成文档说明 api 操作步骤: 1.选中项目/代码,右键选中Export 2.输入Javadoc 3.第一个next(可以设置生成文档注释的目录),第二个next,设置字符集 如果是UTF-8编码,且有中文,请输入-encoding UTF-8 -charset UTF-8 4. 勾选一个生成完毕后,直接通过浏览器打开的选项 5. finish 3.使用:(重点) 1. 使用jdk或者别人定义好的标签 @ + 注解的名称 -- 比如@Override ->注解 2. 使用自定义的标签 1.JDK的元注解:就是专门用来声明其他注解的注解 作用:通过元注解了解其他注解的使用特点,还可以自定义注解 2.元注解: 1. @Target @Target 作用 用来限制被修饰注解的使用范围,即注解可以在类的哪些成员上使用 @Target 取值使用ElementType.() 1. CONSTRUCTOR:可以在构造器上使用注解 2. FIELD:可以在字段上使用注解 3. LOCAL_VARIABLE:可以在局部变量上使用注解 4. METHOD:可以在普通方法上使用注解 5. PACKAGE:可以在包上使用注解 6. PARAMETER:可以在参数列表上使用注解 7. TYPE:可以在类、接口(包括注解类型) 或enum上使用注解 例如:@Target(ElementType.METHOD)//意味着@Override只能在普通方法上使用 public @interface Override { } 2. @Retention @Retention 作用 限制注解的作用时间 注解的生命周期和三个阶段有关:源代码阶段、CLASS文件中有效、运行时有效, 故其取值也就三个值,分别代表着三个阶段 @Retention RetentionPolicy.(枚举) 1. SOURCE:在源文件中有效(即源文件保留),这个一般用来校验代码 2. CLASS:在class文件中有效(在源文件和字节码文件时有作用) 3. RUNTIME:在运行时有效(在源文件、字节码文件、运行的时候起作用) 一般是通过反射技术使用,通过程序的扩展性 例如:@Retention(RetentionPolicy.SOURCE)//编译期有效,主要用来校验代码 public @interface Override { } 3. @Documented @Documented 作用:文档注解,可以使用javadoc生成文档注释 Documented是一个标记注解,没有成员。 4. @Inherited @Inherited 作用:从该类的子类上可以继承父类的注解 假设一个注解在定义时,使用了@Inherited,然后该注解在一个类上使用, 如果这个类有子类,那么通过反射我们可以从类的子类上获取到同样的注解 自定义注解声明步骤: 1. 创建一个注解类@Annotation: 2. 在类上用元注解修饰(注意,根据情况,决定写几个) @Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited 3. 描述注解的取值(声明一些属性) 语法: @4大元注解 public @interface 注解名{ 类型 属性名() default 默认值; //default表示一个默认取值,可以不写 } 数据类型支持:数组、String、8个基本类型、枚举 属性名:见名知意,小驼峰,如果只有一个属性,建议声明为:value 因为使用的时候,value可以省略。 使用注解 @注解名(属性名=值)//类型要一致 @注解名(属性名={值1,值2}) //注解类型为数组,如果属性名是value可以省略 例如: 声明自定义注解: //@Target(value=ElementType.TYPE)//value可以省略 //只有一个属性名的时候且名字是value的时候,value可以省略。因为Target注解,取值的数据类型是数组,所以,多个值用{}括起来 @Target({ElementType.TYPE,ElementType.METHOD})//表示,只能在类和普通方法上使用 @Retention(RetentionPolicy.RUNTIME)//在运行期一直发生作用 @Documented //表示使用Vip注解后,可以生成文档说明 @Inherited //表示如果一个类A使用了注解@Vip,则A类的子类,会继承到该注解@Vip public @interface Vip { / 类型 属性名() default 默认值; //default表示一个默认取值,可以不写 数据类型只能有:数组、String、8个基本类型、枚举 属性名:见名知意,小驼峰,如果只有一个属性,建议声明为:value 因为使用的时候,value可以省略。 枚举类型比较符合Vip取值 / // Level value();//可以不写default,写就表示有默认值 // String test() default "test";//这里可以写多个 属性 // int test2();//这里可以写多个 属性 Level value() default Level.ONE;//表示vip默认级别是ONE } 使用自定义注解: //@Vip(value=Level.FIVE) //表示每一个User对象都有一个Vip注解,可以不用默认值 @Vip //表示每一个User对象都有一个Vip注解,且默认值都是 Level.ONE public class User {} 4. 四大内置注解(了解,掌握@Override) @Override 注解用于标识方法重写,帮助我们校验代码 @Deprecated 注解用于标识方法已过时,只要是在版本迭代中使用。 以下作为了解 @SuppressWarnings 注解用于抑制编译器警告,直白的讲就是消除Eclipse上那条黄色警告线, 但编译器里关于这条警告的信息还在。没什么用 代码示例 List list=null; @SafeVarargs 抑制堆污染警告(单独警告),直白的讲就是使用泛型和可变参数搭配使用将会产生的 编译器警告,可以使用@SuppressWarnings消除警告,后来在Java7引入了新的注解, 就是@SafeVarargs,如果开发人员确信某个使用了可变参数的方法, 在与泛型类一起使用时不会出现类型安全问题,就可以用这个注解进行声明,这样编译器就不会报警告。
扩展:
用反射优化简单工厂模式