java8-初识注解和反射
转载:https://www.cnblogs.com/opendragonhuang/p/11225026.html
一、注解
1、注解的定义
注解就是源代码的元数据,通熟的讲就是代码中的标签。注解就有如下的特点:
(1)注解是一个附属品,依赖于其他元素(包、类、方法、属性等等)存在。
(2)注解本身没有作用,在恰当的时候由外部程序进行解析才会发生作用。
2、注解的分类
(1)按来源分
- JDK 自带注解,例如:@Override, @Deprecated, @SuppressWornings 。
- 第三方注解。
- 自定义注解。
(2)按生命周期划分
- SOURCE:只存在于源代码中,编译成 class 文件就不存在了。
- Class:存在于源代码中和 class 文件中。
- RUNTIME:注解保留到运行时。
3、元注解
元注解指的是用于修饰注解的注解,包括如下几个:
(1)@Retention:指明 Annotation 的生命周期,传入的值是一个枚举类型,可选值为
RetentionPolicy.SOURCE
RetentionPolicy.CLASS
RetentionPolicy.RUNTIME
(2)@Target:指明 Annotation 可以修饰程序哪些元素,传入的值为ElemetType[] 类型,值可为:
ElementType.CONSTRUCTOR:构造器
ElementType.FIELD:属性
ElementType.LOCAL_VARIABLE:局部变量
ElementType.METHOD:方法
ElementType.PACKAGE:包
ElementType.PARAMETER:参数
ElementType.TYPE:类、接口(包括注解类型和 enum 声明)
(3)@Documented:使用此修饰的注解将会被 javadoc 工具提取成文档,使用此注解,其 @Retention 必须被设置为 RetentionPolicy.RUNTIME 。
(4)@Inherited:具有继承性。
4、自定义注解
自定义注解需要注意的问题:
(1)使用 @interface 关键字定义。
(2)自动继承 java.lang.annotation.Annotation 接口。
(3)配置参数的类型只能是八大基本类型、String、Class、enum、Annotation 和对应的数组类型。
(4)配置参数声明的语法格式如下([] 表示可省略):
(5)类型 变量名() [default 默认值];
(6)如果只有一个配置参数,其参数名必须为 value。
(7)如果定义的注解含有配置参数,那在使用注解时,必须指定参数值,指定形式为:“参数名=参数值”。如果只有一个参数,直接写参数值即可,定义中指定了默认值的参数可以不指定值,但没有的一定要指定值。
(8)没有成员的注解为标记,包含成员的称为元数据。
二、反射
1、什么是反射
反射指的是程序在运行期间借助反射 API 取得任何类的内部信息,并通过这些内部信息去操作对应对象的内部属性和方法。
任何一个类,在第一次使用时,就会被 JVM 加载到堆内存的方法区中。JVM 加载类成功后,就会在方法区中产生一个对应的 Class 对象(一个类只要一个 Class 对象),这个 Class 对象包含被加载类的全部结构信息。
2、获取class对象的常用方式
(1)类的属性
每一个类都有一个class静态属性,这个class静态属性就是类对应的class对象
Class<Person> cl1 = Person.class;
(2)Object对象的getClass()方法
Person p1 = new Person(); Class<Person> class = (Class<Person>) p1.getClass();
(3)通过forName()方法获取class对象(常用)
try { Class class = Class.forName("com.adf.ccxx.Person"); } catch (ClassNotFoundException e) { e.printStackTrace(); }
(4)通过ClassLoader类(不常用)
ClassLoader cl = Person.class.getClassLoader(); try { Class class = cl.loadClass("com.adf.ccxx.Person"); } catch (ClassNotFoundException e) { e.printStackTrace(); }
3、反射的基本使用
反射的基本使用包括创建对象,设置属性和调用方法。Class 对象中大多数 get 方法有 Declared 和无 Declared,他们的区别是:
(1)方法名中有Declared:获取到当前类所有的(含有 private),但不包括其父类。
(2)方法命中没有Declared:只能获取到 public 修饰的,包括当前类和所有父类。
基本用法:
//Person public class Person { private String name; private int age; public String habbit; public Person() { } public Person(String name, int age) { this.name = name; this.age = age; } private Person(String name, int age, String habbit) { this.name = name; this.age = age; this.habbit = habbit; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getHabbit() { return habbit; } public void setHabbit(String habbit) { this.habbit = habbit; } private String say(String str){ String str1 = name+"说:"+str; System.out.println(str1); return str1; } public void eat(String food){ System.out.println(name+"吃"+food); } @Override public String toString() { return "["+name+","+age+","+habbit+"]"; } }
//测试 public class PersonTest { @Test public void ReflexTest() throws Exception{ System.out.println("---------- new 方式创建对象 ----------"); // 普通方式创建 Person 对象 Person p1 = new Person("adf", 22); // 直接设置属性 p1.habbit = "编程"; // 调用方法 System.out.println(p1); //无法直接设置私有属性和调用私有方法 //p1.name = "adf"; //p1.say(""Hello); //反射方式创建对象 System.out.println("---------- 反射方式创建对象 ----------"); Class<Person> clazz = Person.class; // 调用无参构造器参加对象 Constructor<Person> constructor1 = clazz.getConstructor(); Person p2 = constructor1.newInstance(); System.out.println(p2); // 通过有参构造器 Constructor<Person> constructor2 = clazz.getConstructor(String.class, int.class); Person p3 = constructor2.newInstance("adf", 22); System.out.println(p3); // 通过私有的构造器 Constructor<Person> constructor3 = clazz.getDeclaredConstructor(String.class, int.class, String.class); constructor3.setAccessible(true); Person p4 = constructor3.newInstance("adf", 22, "编程"); System.out.println(p4); //通过反射设置公有属性 Field personFeildHabbit = clazz.getDeclaredField("habbit"); personFeildHabbit.set(p2, "编程"); //通过反射设置私有属性 Field personFeildAge = clazz.getDeclaredField("age"); personFeildAge.setAccessible(true); personFeildAge.set(p2, 18); //通过反射调用方法 Method personMethodToString = clazz.getDeclaredMethod("toString"); // 方法的返回值为调用方法的返回值 String str = (String)personMethodToString.invoke(p2); System.out.println(str); // 通过反射调用私有方法 Method personMethodSay = clazz.getDeclaredMethod("say", String.class); personMethodSay.setAccessible(true); String str2 = (String)personMethodSay.invoke(p2, "Hello"); System.out.println(str2); } }
4、设计模式:代理模式
使用一个代理对象将原始对象包装起来, 然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理对象,代理对象决定是否以及何时将方法调用转到原始对象上。
(1)静态代理
代理类和原始对象在编译期间就确定下来了,不利于程序的扩展,且每一个代理只能为一个接口服务,这就会在开发的过程中产生多大的代理类。
静态代理的实现:
- 代理类和原始对象实现相同的接口。
- 代理类保持原始对象的引用。
- 代理类里调用原始对象的方法。
//ClothFactory public interface ClothFactory { String producer(); }
//ClothFactoryProxy public class ClothFactoryProxy implements ClothFactory{ private ClothFactory clothFactory; public ClothFactoryProxy(ClothFactory clothFactory) { this.clothFactory = clothFactory; } @Override public String producer() { System.out.println("代理对象做一些准备"); clothFactory.producer(); System.out.println("代理对象做一些收尾工作"); return null; } }
//NikeFactory public class NikeFactory implements ClothFactory{ public NikeFactory() { } @Override public String producer() { System.out.println("Nike 正在生产衣服"); return null; } }
//测试 @Test public void staticProxyTest(){ // 创建被代理对象 NikeFactory nikeFactory = new NikeFactory(); // 创建代理对象 ClothFactoryProxy clothFactoryProxy = new ClothFactoryProxy(nikeFactory); // 通过代理对象调用被代理对象的方法 clothFactoryProxy.producer(); }
(2)动态代理模式
动态代理是通过 Java 的反射机制实现的。通过动态代理,只需一个代理对象就可以代理所有的对象。
//Humen public interface Human { String belief(); void eat(String food); }
//SuperMan public class SuperMan implements Human { @Override public String belief() { return "我相信,我能行!"; } @Override public void eat(String food) { System.out.println("正在吃"+food); } }
//DynamicProxy import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class DynamicProxy { // 获取代理对象 public static Object getInstance(Object obj){ MyInvocation h = new MyInvocation(); h.bind(obj); // 动态的创建对象 return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), h); } } class MyInvocation implements InvocationHandler{ private Object obj; /** * 绑定被代理对象 * @param obj */ public void bind(Object obj){ this.obj = obj; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 代理对象调用被代理对象的方法 Object ret = method.invoke(obj, args); return ret; } }
//测试 @Test public void dynamicProxyTest(){ SuperMan sm = new SuperMan(); Human h = (Human)DynamicProxy.getInstance(sm); System.out.println(h.belief());; h.eat("麻辣烫"); NikeFactory nikeFactory = new NikeFactory(); ClothFactory clothFactory = (ClothFactory) DynamicProxy.getInstance(nikeFactory); clothFactory.producer(); }
三、使用注解与反射小练习
//自定义注解 @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface DriveAccess { public boolean canDrive() default false; }
//实体类 public class Tesla extends Car implements Runnable { public Tesla(int velocity) { this.velocity = velocity; } @Override public String getName() { return "Tesla"; } @Override @DriveAccess(canDrive = true) public void run() { String simpleName = this.getClass().getSimpleName(); System.out.println(simpleName + " run " + velocity + "km/h"); } }
public class CarFactory { public static void test(String car) throws Exception { //获取class对象 Class<?> name = Class.forName(car); //获取class对象中的方法 for (Method method : name.getDeclaredMethods()) { //判断方法是否被DriveAccess注解标记 if (method.isAnnotationPresent(DriveAccess.class)) { //返回方法上被标记的DriveAccess注解 DriveAccess annotation = method.getAnnotation(DriveAccess.class); //获取方法的全名 String methodName = method.toGenericString(); if (annotation.canDrive()) { System.out.println(methodName + " method can be accessed... "); //获取类实例对象 Object c = name.getDeclaredConstructor(int.class).newInstance(100); //调用方法 method.invoke(c); } else { System.out.println(methodName + " method can not be accessed... "); } } else { System.out.println(method.toGenericString() + " don't have DriveAccess Annotation..."); } } } }
浙公网安备 33010602011771号