注解与反射
注解(Annotation)
-
Annotation是从JDK5.0开始引入的新技术。
元注解
- 元注解得作用就是负责注解其他注解,Java定义了4个标准的meta-annotation类型,他们被用来提供对其他annotation类型作说明
- 这些类型和他们所支持得类在java.lang.annotation包中可以找到。(@Target,@Retention,@Documented,@Inherited)
- @Target:用于描述注解得使用范围(即:被描述得注解用在什么地方)
- @Retention:表示需要在什么级别保存该注释信息,用于描述注解得生命周期
- (SOURCE<CLASS<RUNTIME)
- @Documented:说明该注解被包含在javadoc中
- @Inherited:说明子类可以继承父类中的该注解
反射
-
优点
- 可以实现动态的创建对象和编译,体现出很大的灵活性
-
缺点
- 对性能有影响。使用反射基本上式一种解释操作,我们可以告诉JVM,我们希望做什么并且满足我们的要求。这类操作总是慢于直接执行相同的操作。
反射机制
- Java Reflection
动态创建对象执行方法
package com.yuan.lesson5.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test01 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class c1 = Class.forName("com.yuan.lesson5.reflection.Person");
//获得类的属性
Field field = c1.getField("name");
//构造一个对象
Person person = (Person) c1.newInstance();
System.out.println(person);
//通过构造器创建对象
Constructor constructor = c1.getDeclaredConstructor(String.class);
Person person1 = (Person) constructor.newInstance("职工");
System.out.println(person1);
//通过反射调用普通方法
Person person2 = (Person) c1.newInstance();
//通过反射获取一个方法
Method setName = c1.getDeclaredMethod("setName",String.class);
//invoke:激活的意思
//(对象, ”方法的值“)
setName.invoke(person2,"图书管理员");//激活,执行
System.out.println(person2.getName());
//通过反射获取属性
Person person3 = (Person) c1.newInstance();
Field name = c1.getDeclaredField("name");
//不能直接操作私有属性,我们需要关闭程序的安全检测,属性或者方法的setAccessible()
name.setAccessible(true); //这里我们的时public不用这个也可以访问
name.set(person3,"老师2");
System.out.println(person3.name);
}
}
性能对比分析
-
普通方法 VS 反射方法
-
package com.yuan.lesson5.reflection; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; //分析性能问题 public class Test02 { public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { test01(); test02(); test03(); } //普通方式调用 public static void test01(){ Person person = new Person(); long startTime = System.currentTimeMillis(); for (int i = 0; i < 1000000000; i++) { person.getName(); } long endTime = System.currentTimeMillis(); System.out.println("普通方法执行10亿次"+(endTime-startTime)+"ms"); } //反射方式调用 public static void test02() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { Person person = new Person(); Class c1 = person.getClass(); Method getName = c1.getDeclaredMethod("getName"); long startTime = System.currentTimeMillis(); for (int i = 0; i < 1000000000; i++) { getName.invoke(person,null); } long endTime = System.currentTimeMillis(); System.out.println("反射方法执行10亿次"+(endTime-startTime)+"ms"); } //反射方法,关闭检测 //反射方式调用 public static void test03() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { Person person = new Person(); Class c1 = person.getClass(); Method getName = c1.getDeclaredMethod("getName"); getName.setAccessible(true); //关闭检测 long startTime = System.currentTimeMillis(); for (int i = 0; i < 1000000000; i++) { getName.invoke(person,null); } long endTime = System.currentTimeMillis(); System.out.println("反射方法执行10亿次"+(endTime-startTime)+"ms"); } }
-
练习:ORM
- 了解什么时ORM
- Object relationship Mapping --> 对象关系映射
- 类和表结构对应
- 属性和字段对应
- 对象和记录对应
拓展
静态 VS 动态语言
-
动态语言:
- 是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或者是其它结构上的变化。通俗点说就是在运行时可以根据某些条件改变自身结构
- 主要动态语言:Object-C、C#、JavaScript、PHP、Python等。
-
静态语言
- 与动态语言相对应,运行时结构不可改变的语言就是静态语言。如Java、C、C++.
- Java不是动态语言,但Java可以称之为”准动态语言“。即Java有一定的动态性,我们可以利用反射机制获得类似动态语言的特性。Java的动态性让编程的时候更加灵活!
类的加载与ClassLoader的理解
- 加载:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后生成一个代表这个类的java.lang.Class对象
- 链接:将Java类的二进制代码合并到JVM的运行状态之中的过程。
- 验证:确保加载的类信息符合JVM规范,没有安全方面的问题
- 准备:正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存都将在方法区中进行分配。
- 解析:将虚拟机常量池内的符号引入(常量名)替换为直接引用(地址)的过程。
- 初始化:
- 执行类构造器
()方法的过程。类构造器 ()方法是由编译器自动收集类中的所有类变量的复制动作和静态代码块中的语句合并产生的。(类构造器时构造类信息的,不是构造该类对象的构造器)。 - 当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类的初始化。
- 虚拟机会保证一个类的
()方法在多线程环境中被正确的加锁和同步。
- 执行类构造器