Java-注解和反射
- 所有的框架的底层
注解(Annotation)
- Annotation不是程序本身,可以对程序做出解释
- 可以被其他程序读取
- 格式:
- 以“@注释名”在代码中存在,还可以添加一些参数值
- “@SuppressWarnings(value=“unchecked”)”
- 可以附加在package、class、method、field、等,给他们添加了额外的辅助信息
- 可以通过反射机制编程实现对这些元数的访问
内置注解
- @Override:声明重写父类中的一个方法,定义在java.lang.Override
- @Deprecated:不鼓励程序员使用的元素,定义在java.lang.Deprecated
- @SuppressWarnings:用来抑制编译时的警告信息,定义在java.lang,SuppressWarnings中
- 需要添加参数:
- @SuppressWarnings(“all”)
- @SuppressWarnings(“unchecked”)
- @SuppressWarnings(value={“unchecked”,“deprecation”})
元注解
- 负责注解其他注解,Java定义四个标准的meta-annotation类型
- 包含在java.lang.annotation:
- @Target:描述注解的使用范围
- @Retention:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(SOURCE<CLASS<RUNTIME)
- @Documented:说明该注解被包含在javadoc中
- @Inherited:说明子类可以继承父类中的该注解
public class testMain {
@myAnnoation(name="huang",school = {"111","222"})
public void test1(){
}
}
//定义一个注解
//表示注解范围
@Target(value = {ElementType.METHOD,ElementType.TYPE})
//表示注解可以用在哪些地方
@Retention(value = RetentionPolicy.RUNTIME)
//表示能否将注解生成在doc中
@Documented
//子类可以继承父类
@Inherited
@interface myAnnoation{
//注解参数:参数类型+参数名();
//default"":表示默认为空
String name()default "";
int age()default 0;
int id()default -1;//-1表示不存在
String[] school()default {"111","222","333"};
}
反射
- Reflection是Java被视为动态语言的关键,反射机制允许程序在执行期借助Reflection API取得任何类的内部信息,能直接操作任意对象的内部属性和方法
- 加载完类后,在堆内存的方法区中就产生一个class对象(一个类只有一个class对象),这个对象就包含了完整的类的结构信息。我们可以通过对象看到类的结构信息。所以形象的称为:反射
- 反射方式:实例化对象----》getClass()方法----》得到完整的包内名称
反射机制提供的功能:
- 运行时判断任意一个对象所属的类
- 运行时构造任意一个类的对象
- 运行时判断任意一个类所具有的成员变量和方法
- 运行时获取泛型信息
- 运行时调用任意一个对象的成员变量和方法
- 运行时处理注解
- 生成动态代理
优点:
- 可以实现动态创建对象和编译,体现很大的灵活性
缺点:
- 对性能有影响,反射基本上是一种解释操作。
相关API:
- java.lang.class:代表一个类
- java,lang.reflect.Method:代表一个类的方法
- java,lang.reflect,Field:代表类的成员变量
- java,lang.reflect.Construction:代表类的构造器
class类:
- 在Object类中定义了以下方法,此方法会被所有子类继承
public final Class getClass()
- 以上方法返回值类型是一个Class类,此类是Java反射的源头
- 可以 通过对象反射求出类的名称
Class类常用对象
public class testReflection {
public static void main(String[] args) throws Exception {
User user=new People(1,2);
System.out.println(user.toString());
//1.通过对象获得
Class c1=user.getClass();
System.out.println(c1.hashCode());
//2.forName获得
Class c2=Class.forName("test01.People");
System.out.println(c2.hashCode());
//3.通过类名获得
Class c3=People.class;
System.out.println(c3.hashCode());
//获得父类类型
Class c4=c1.getSuperclass();
System.out.println(c4);
}
}
//实体类
class User{
private int id;
private String name;
private int age;
public User() {
}
public User(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
class People extends User{
public People() {
}
public People(int id, int age) {
super(id, "xiaowang", age);
}
}
有class对象的类型:
- class:外部类,成员(内部类,静态内部类),局部内部类,匿名内部类
- interface:接口
- []:数组
- enum:枚举
- annotation:注解@interface
- primitive type:基本数据类型
- void
-只要元数类型一样,就是同一个Class
Class a1=Object.class; //类
Class a2=Comparable.class; //接口
Class a3=String[].class; //一维数组
Class a4=int[][].class; //二维数组
Class a5=Override.class; //注解
Class a6= ElementType.class;//枚举
Class a7=Integer.class; //基本数据类型
Class a8=void.class; //void
Class a9=Class.class; //Class
类的加载
- 加载:将class文件字节码内容加载到内存中,并将这些数据转换成方法区的运行时的数据结构,然后生成一个代表这个类的java.lang.Class对象
- 链接:将Java类的二进制代码合并到JVM的运行状态中
- 验证:确保加载的类信息符合JVM规范,没有安全方面的问题
- 准备:正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存都将在方法区中进行分配
- 解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程
- 初始化:
- 执行类构造器()方法的过程
- 初始化一个类时,父类没有初始化,则要先初始化父类
- 虚拟机会保证一个类的()方法在多线程环境中被正确加锁同步
类加载器:
- 将Class文件字节码内容加载到内存中,并将这些数据转换为方法区运行的数据结构,然后在堆中生成一个代表这个类的class对象,作为方法区中类数据的访问入口
- 类缓存:标准的JavaSE类加载器可以按要求查找类,但一旦某个类加载到类加载器中,它将维持加载(缓存)一段时间,不过JVM垃圾回收机制可以收回这些Class对象
动态创建对象
//通过反射,动态创建对象
public class TestClass {
public static void main(String[] args) throws Exception{
//获得Class对象
Class user=Class.forName("test01.User");
//构造对象
User u1=(User) user.newInstance(); //本质上调用了无参构造器
System.out.println(u1);
//通过构造器创建对象
Constructor constructor=user.getConstructor(int.class,String.class,int.class);
User u2=(User) constructor.newInstance(1,"huang",2);
System.out.println(u2);
//通过反射调用普通方法
User u3=(User)user.newInstance();
Method sets = user.getDeclaredMethod("Set",int.class);
//invoke:激活的意思
//(对象,方法值)
sets.invoke(u3,100);
System.out.println(u3);
//通过反射操作属性
User u4=(User)user.newInstance();
Field id = user.getDeclaredField("id");
//不能直接操作私有属性
//要关闭安全检测
id.setAccessible(true);
id.set(u4,18);
System.out.println(u4);
}
}
反射操作注解:
- ORM(Object relationship Mapping)—> 对象关系映射
- 类和表结构对应
- 属性和字段对应
- 对象和记录对应
- 利用注解和反射完成类和表结构的映射关系
例子:
public class TestORM {
public static void main(String[] args) throws Exception {
//获得对象
Class s1=Class.forName("test01.student");
//获得注解
Annotation[] annotations=s1.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
//获得注解的value值
StudentMsg msg=(StudentMsg) s1.getAnnotation(StudentMsg.class);
System.out.println(msg.value());
//获得指定属性注解信息
Field f=s1.getDeclaredField("id");
FieldMsg msg2=(FieldMsg) f.getAnnotation(FieldMsg.class);
System.out.println(msg2.ColName());
}
}
@StudentMsg("db_student")
class student{
@FieldMsg(ColName ="db_id",Type = "int",Length = 10)
private int id;
@FieldMsg(ColName ="db_name",Type = "String",Length = 10)
private String name;
@FieldMsg(ColName ="db_age",Type = "int",Length = 3)
private int age;
public student() {
}
public student(int id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
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;
}
@Override
public String toString() {
return "student{" +
"id=" + id +
", name='" + name + '\'' +
", age=" + age +
'}';
}
}
//类名注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface StudentMsg{
String value();
}
//属性注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@interface FieldMsg{
String ColName();
String Type();
int Length();
}