Java-注解和反射-03

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

类的加载

2345

1234

  1. 加载:将class文件字节码内容加载到内存中,并将这些数据转换成方法区的运行时的数据结构,然后生成一个代表这个类的java.lang.Class对象
  2. 链接:将Java类的二进制代码合并到JVM的运行状态中
  • 验证:确保加载的类信息符合JVM规范,没有安全方面的问题
  • 准备:正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存都将在方法区中进行分配
  • 解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程
  1. 初始化:
  • 执行类构造器()方法的过程
  • 初始化一个类时,父类没有初始化,则要先初始化父类
  • 虚拟机会保证一个类的()方法在多线程环境中被正确加锁同步

类加载器:

  • 将Class文件字节码内容加载到内存中,并将这些数据转换为方法区运行的数据结构,然后在堆中生成一个代表这个类的class对象,作为方法区中类数据的访问入口
  • 类缓存:标准的JavaSE类加载器可以按要求查找类,但一旦某个类加载到类加载器中,它将维持加载(缓存)一段时间,不过JVM垃圾回收机制可以收回这些Class对象
    134

动态创建对象


//通过反射,动态创建对象
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);
    }
}

234

234
反射操作注解:

  • 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();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值