标签:const tcl exce java 继承性 test 堆内存 div dha
注解就是源代码的元数据,通熟的讲就是代码中的标签。注解就有如下的特点:
注解是一个附属品,依赖于其他元素(包、类、方法、属性等等)存在。
注解本身没有作用,在恰当的时候由外部程序进行解析才会发生作用。
按来源分
JDK 自带注解,例如:@Override, @Deprecated, @SuppressWornings 。
第三方注解。
自定义注解。
按生命周期划分
SOURCE:只存在于源代码中,编译成 class 文件就不存在了。
Class:存在于源代码中和 class 文件中。
RUNTIME:注解保留到运行时。
元注解指的是用于修饰注解的注解,包括如下几个:
@Retention:指明 Annotation 的生命周期,传入的值是一个枚举类型,可选值为:
RetentionPolicy.SOURCE
RetentionPolicy.CLASS
RetentionPolicy.RUNTIME
@Target:指明 Annotation 可以修饰程序哪些元素,传入的值为ElemetType[] 类型,值可为:
ElementType.CONSTRUCTOR
:构造器
ElementType.FIELD
:属性
ElementType.LOCAL_VARIABLE
:局部变量
ElementType.METHOD
:方法
ElementType.PACKAGE
:包
ElementType.PARAMETER
:参数
ElementType.TYPE
:类、接口(包括注解类型和 enum 声明)
@Documented:使用此修饰的注解将会被 javadoc 工具提取成文档,使用此注解,其 @Retention 必须被设置为 RetentionPolicy.RUNTIME
。
@Inherited:具有继承性。
自定义注解需要注意的问题:
使用 @interface 关键字定义。
自动继承 java.lang.annotation.Annotation
接口。
配置参数的类型只能是八大基本类型、String、Class、enum、Annotation 和对应的数组类型。
配置参数声明的语法格式如下([] 表示可省略):
类型 变量名() [default 默认值];
如果只有一个配置参数,其参数名必须为 value。
如果定义的注解含有配置参数,那在使用注解时,必须指定参数值,指定形式为:“参数名=参数值”。如果只有一个参数,直接写参数值即可,定义中指定了默认值的参数可以不指定值,但没有的一定要指定值。
没有成员的注解为标记,包含成员的称为元数据。
参考代码:
(1)Info.java
1 package com.hkl; 2 ? 3 import java.lang.annotation.ElementType; 4 import java.lang.annotation.Retention; 5 import java.lang.annotation.RetentionPolicy; 6 import java.lang.annotation.Target; 7 ? 8 /** 9 * 注解 10 */ 11 @Retention(RetentionPolicy.RUNTIME) 12 @Target({ElementType.TYPE, ElementType.METHOD}) 13 public @interface Info { 14 String info(); 15 String birthday(); 16 int age() default 0; 17 } 18 ? 19 @Retention(RetentionPolicy.RUNTIME) 20 @Target({ElementType.TYPE, ElementType.METHOD}) 21 @interface Desc{ 22 String value(); 23 }
(2)App.java
1 package com.hkl; 2 ? 3 import java.lang.reflect.Method; 4 ? 5 /** 6 * Hello world! 7 * 8 */ 9 @Info(info = "hkl", birthday = "2019/7/20") 10 @Desc("这是一个类") 11 public class App 12 { 13 @Info(info = "hkl", birthday = "2019/7/20", age = 22) 14 @Desc("这是一个方法") 15 public static void main( String[] args ) 16 { 17 // 解析注解 18 try { 19 Class clazz = Class.forName("com.hkl.App"); 20 ? 21 // 获取类修饰的注解 22 System.out.println("---------类中的注解---------"); 23 if(clazz.isAnnotationPresent(Info.class)){ 24 Info classInfo = (Info) clazz.getAnnotation(Info.class); 25 System.out.println(classInfo.info()); 26 System.out.println(classInfo.birthday()); 27 System.out.println(classInfo.age()); 28 } 29 ? 30 if(clazz.isAnnotationPresent(Desc.class)){ 31 Desc classDesc = (Desc)clazz.getAnnotation(Desc.class); 32 System.out.println(classDesc.value()); 33 } 34 ? 35 // 获取方法修饰的注解 36 Method[] methods = clazz.getMethods(); 37 ? 38 System.out.println("---------方法中的注解解析---------"); 39 for(Method method : methods){ 40 if(method.isAnnotationPresent(Desc.class)){ 41 Desc methodDesc = (Desc)method.getAnnotation(Desc.class); 42 System.out.println(methodDesc.value()); 43 } 44 ? 45 if(method.isAnnotationPresent(Info.class)){ 46 Info methodInfo = (Info)method.getAnnotation(Info.class); 47 System.out.println(methodInfo.info()); 48 System.out.println(methodInfo.birthday()); 49 System.out.println(methodInfo.age()); 50 } 51 ? 52 } 53 } catch (ClassNotFoundException e) { 54 e.printStackTrace(); 55 } 56 } 57 }
反射指的是程序在运行期间借助反射 API 取得任何类的内部信息,并通过这些内部信息去操作对应对象的内部属性和方法。
任何一个类,在第一次使用时,就会被 JVM 加载到堆内存的方法区中。JVM 加载类成功后,就会在方法区中产生一个对应的 Class 对象(一个类只要一个 Class 对象),这个 Class 对象包含被加载类的全部结构信息。
(1)类的 class 属性
每一个类,都有一个 class 静态属性,这个静态属性就是类对应的 Class 对象。
1 Class<Person> cl1 = Person.class;
(2)Object 对象 的 getClass() 方法
1 Person p1 = new Person(); 2 Class<Person> cl2 = (Class<Person>) p1.getClass();
(3)通过 Class 类的 forName() 方法(最常用)
1 try { 2 Class cl3 = Class.forName("com.llm.hkl.Person"); 3 } catch (ClassNotFoundException e) { 4 e.printStackTrace(); 5 }
(4)通过 ClassLoader 类(不常用)
1 ClassLoader cl = Person.class.getClassLoader(); 2 try { 3 Class cl4 = cl.loadClass("com.llm.hkl.Person"); 4 } catch (ClassNotFoundException e) { 5 e.printStackTrace(); 6 }
反射的基本使用包括创建对象,设置属性和调用方法。Class 对象中大多数 get 方法有 Declared 和无 Declared,他们的区别是:
无 Declared:只能获取到 public 修饰的,包括当前类和所有父类。
有 Declared:获取到当前类所有的(含有 private),但不包括其父类。
Person 类:
1 public class Person { 2 private String name; 3 private int age; 4 public String habbit; 5 ? 6 public Person() { 7 } 8 ? 9 public Person(String name, int age) { 10 this.name = name; 11 this.age = age; 12 } 13 ? 14 private Person(String name, int age, String habbit) { 15 this.name = name; 16 this.age = age; 17 this.habbit = habbit; 18 } 19 ? 20 public String getName() { 21 return name; 22 } 23 ? 24 public void setName(String name) { 25 this.name = name; 26 } 27 ? 28 public int getAge() { 29 return age; 30 } 31 ? 32 public void setAge(int age) { 33 this.age = age; 34 } 35 ? 36 public String getHabbit() { 37 return habbit; 38 } 39 ? 40 public void setHabbit(String habbit) { 41 this.habbit = habbit; 42 } 43 ? 44 private String say(String str){ 45 String str1 = name+"说:"+str; 46 System.out.println(str1); 47 return str1; 48 } 49 ? 50 public void eat(String food){ 51 System.out.println(name+"吃"+food); 52 } 53 ? 54 @Override 55 public String toString() { 56 return "["+name+","+age+","+habbit+"]"; 57 } 58 }
测试方法:
1 public class PersonTest { 2 @Test 3 public void ReflexTest() throws Exception{ 4 System.out.println("---------- new 方式创建对象 ----------"); 5 // 普通方式创建 Person 对象 6 Person p1 = new Person("hkl", 22); 7 ? 8 // 直接设置属性 9 p1.habbit = "编程"; 10 // 调用方法 11 System.out.println(p1); 12 ? 13 //无法直接设置私有属性和调用私有方法 14 //p1.name = "hkl"; 15 //p1.say(""Hello); 16 ? 17 //反射方式创建对象 18 System.out.println("---------- 反射方式创建对象 ----------"); 19 Class<Person> clazz = Person.class; 20 ? 21 // 调用无参构造器参加对象 22 Constructor<Person> constructor1 = clazz.getConstructor(); 23 Person p2 = constructor1.newInstance(); 24 System.out.println(p2); 25 ? 26 // 通过有参构造器 27 Constructor<Person> constructor2 = clazz.getConstructor(String.class, int.class); 28 Person p3 = constructor2.newInstance("hkl", 22); 29 System.out.println(p3); 30 ? 31 // 通过私有的构造器 32 Constructor<Person> constructor3 = clazz.getDeclaredConstructor(String.class, int.class, String.class); 33 constructor3.setAccessible(true); 34 Person p4 = constructor3.newInstance("hkl", 22, "编程"); 35 System.out.println(p4); 36 ? 37 //通过反射设置公有属性 38 Field personFeildHabbit = clazz.getDeclaredField("habbit"); 39 personFeildHabbit.set(p2, "编程"); 40 ? 41 //通过反射设置私有属性 42 Field personFeildAge = clazz.getDeclaredField("age"); 43 personFeildAge.setAccessible(true); 44 personFeildAge.set(p2, 18); 45 ? 46 //通过反射调用方法 47 Method personMethodToString = clazz.getDeclaredMethod("toString"); 48 // 方法的返回值为调用方法的返回值 49 String str = (String)personMethodToString.invoke(p2); 50 System.out.println(str); 51 ? 52 // 通过反射调用私有方法 53 Method personMethodSay = clazz.getDeclaredMethod("say", String.class); 54 personMethodSay.setAccessible(true); 55 String str2 = (String)personMethodSay.invoke(p2, "Hello"); 56 System.out.println(str2); 57 } 58 }
使用一个代理对象将原始对象包装起来, 然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理对象,代理对象决定是否以及何时将方法调用转到原始对象上。
代理类和原始对象在编译期间就确定下来了,不利于程序的扩展,且每一个代理只能为一个接口服务,这就会在开发的过程中产生多大的代理类。
静态代理的实现:
代理类和原始对象实现相同的接口。
代理类保持原始对象的引用。
代理类里调用原始对象的方法。
ClothFactory 接口:
1 package com.hkl.proxy; 2 ? 3 ? 4 public interface ClothFactory { 5 String producer(); 6 }
ClothFactoryProxy 类:
1 package com.hkl.proxy; 2 ? 3 public class ClothFactoryProxy implements ClothFactory{ 4 private ClothFactory clothFactory; 5 ? 6 public ClothFactoryProxy(ClothFactory clothFactory) { 7 this.clothFactory = clothFactory; 8 } 9 ? 10 @Override 11 public String producer() { 12 System.out.println("代理对象做一些准备"); 13 clothFactory.producer(); 14 System.out.println("代理对象做一些收尾工作"); 15 ? 16 return null; 17 } 18 }
NikeFactory 类:
1 package com.hkl.proxy; 2 ? 3 public class NikeFactory implements ClothFactory{ 4 ? 5 public NikeFactory() { 6 } 7 ? 8 @Override 9 public String producer() { 10 System.out.println("Nike 正在生产衣服"); 11 return null; 12 } 13 }
测试方法:
1 @Test 2 public void staticProxyTest(){ 3 // 创建被代理对象 4 NikeFactory nikeFactory = new NikeFactory(); 5 ? 6 // 创建代理对象 7 ClothFactoryProxy clothFactoryProxy = new ClothFactoryProxy(nikeFactory); 8 ? 9 // 通过代理对象调用被代理对象的方法 10 clothFactoryProxy.producer(); 11 }
动态代理是通过 Java 的反射机制实现的。通过动态代理,只需一个代理对象就可以代理所有的对象。
Humen :接口
1 package com.llm.proxy; 2 public interface Human { 3 String belief(); 4 void eat(String food); 5 }
SuperMan:类
1 package com.hkl.proxy; 2 ? 3 public class SuperMan implements Human { 4 @Override 5 public String belief() { 6 return "我相信,我能行!"; 7 } 8 ? 9 @Override 10 public void eat(String food) { 11 System.out.println("正在吃"+food); 12 } 13 }
动态代理类:
1 package com.hkl.proxy; 2 ? 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 import java.lang.reflect.Proxy; 6 ? 7 ? 8 public class DynamicProxy { 9 // 获取代理对象 10 public static Object getInstance(Object obj){ 11 MyInvocation h = new MyInvocation(); 12 h.bind(obj); 13 // 动态的创建对象 14 return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), h); 15 } 16 } 17 ? 18 class MyInvocation implements InvocationHandler{ 19 private Object obj; 20 ? 21 /** 22 * 绑定被代理对象 23 * @param obj 24 */ 25 public void bind(Object obj){ 26 this.obj = obj; 27 } 28 ? 29 @Override 30 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 31 // 代理对象调用被代理对象的方法 32 Object ret = method.invoke(obj, args); 33 return ret; 34 } 35 }
测试方法:
1 @Test 2 public void dynamicProxyTest(){ 3 SuperMan sm = new SuperMan(); 4 Human h = (Human)DynamicProxy.getInstance(sm); 5 System.out.println(h.belief());; 6 h.eat("麻辣烫"); 7 ? 8 NikeFactory nikeFactory = new NikeFactory(); 9 ClothFactory clothFactory = (ClothFactory) DynamicProxy.getInstance(nikeFactory); 10 clothFactory.producer(); 11 }
标签:const tcl exce java 继承性 test 堆内存 div dha
原文地址:https://www.cnblogs.com/opendragonhuang/p/11225026.html