0
点赞
收藏
分享

微信扫一扫

【JAVA SE】——注解和反射

芷兮离离 2022-04-08 阅读 42
java

文章目录

注解(Java.Annotation)

1. 作用

可以被其他程序(比如:编译器)读取

2. 内置注解

//Override 表示:重写
@Override 

//Deprecated 表示:不推荐使用
@Deprecated


//SuppressWarnings 表示:抑制编译器警告
@SuppressWarnings("rawtypes") 
@SuppressWarnings(value={"unchecked", "rawtypes"})  
@SuppressWarnings("all") 

3. 元注解

注解其他注解

//保留期,能设定注解的存活时间
//RUNTIME > CLASS > SOURCE
@Retention(RententionPolicy:SOURCE)
RententionPolicy:SOURCE //源代码阶段
RententionPolicy:CLASS //到编译阶段
RententionPolicy:RUNTIME //到运行阶段
    
//将注解中的元素包含到Javadoc中
@Documented

//限定注解能运用的地方
@Target(ElementType.ANNOTATION_TYPE)
ElementType.ANNOTATION_TYPE //注解
ElementType.COUNSTRUCTOR //构造方法
ElementType.FIELD //属性
ElementType.METHOD //属性

//标明注解是能被继承的,例如B继承了A,A添加了注解,那么B也会继承同样的注解
@Inherited

4. 自定义注解

语法: public @interface xxx{}

使用:@xxx

注解只有成员变量,没有方法

public @interface MyAnnotation{
  //注解的参数:参数类型+参数名
  String name();
  int age() default 0; //默认值    
}
//使用
@MyAnnotation(name="hh")

反射(Java.Reflection)

1. 概述

  • 动态和静态语言

    动态语言:运行时才确定数据类型的语言,变量在使用之前无需申明类型,通常变量的值是被赋值的那个值的类型。比如Php、Asp、JavaScript、Python、Perl等等。

    静态语言:是编译时变量的数据类型就可以确定的语言,大多数静态语言要求在使用变量之前必须生命数据类型。比如Java、C、C++、C#等。

  • Reflection(反射)是java被视为动态语言的关键,允许程序在执行器利用Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性和方法。

  • 注意:

    一个类在内存中只有一个Class对象

    一个类被加载后,类的整个结构都会被封装在Class对象中

2. 理解class类并获取Class实例

  • 正常:引入需要的“包类”、new实例化、取得实例化对象

    反射:实例化对象、getClass()方法、得到完整的“包类”

  • 反射主要API

Java.lang.Class代表一个类
java.lang.reflect.Method代表类的方法
java.lang.reflect.Field代表类的成员变量
java.lang.reflect.Constructor代表类的构造器
  • Class类常用方法

    Class.forName(“ClassName”) 返回类名name的Class对象

    Class.newInstance() 调用缺省构造函数,返回Class对象的一个实例。(有点像new)

    Class.getName() 返回Class对象所表示的实体的,名称(类、接口);

    Class.CanonicalName() 返回不包含包名的全限定名;

    Class.getSimpleName() 返回不包含包名的类名;
    Class.getInterface() 返回Class对象,表示在感兴趣的Class对象中所包含的接口;

    Class.getSuperclass() 返回所选类基类;

    ClassLoader getClassLoader() :返回该类的加载器

  • 获取Class实例的创建方式

    – 通过类名获得(推荐):Class cl = User.class;

    – 通过对象获得:Class cl = user.getClass();

    – Class cl = Class.forName(“com.JAVASE.User”);

    //什么是反射
    public class TestReflection extends Object{
        public static void main(String[] args) throws ClassNotFoundException {
            //通过反射获取类的Class对象
            Class c1 = Class.forName("com.JAVASE.User");
            System.out.println(c1);
    
            Class c2 = Class.forName("com.JAVASE.User");
            Class c3 = Class.forName("com.JAVASE.User");
            Class c4 = Class.forName("com.JAVASE.User");
            //hashcode一样
            //一个类在内存中只有一个Class对象
            //一个类被加载后,类的整个结构都会被封装在Class对象中
            System.out.println(c2.hashCode());
            System.out.println(c3.hashCode());
            System.out.println(c4.hashCode());
        }
    }
    
  • 包含Class对象的类型

    class、interface、数组、枚举、注解、基本数据类型、void

3. JAVA内存分析

  • java内存分析

在这里插入图片描述
方法区是特殊的堆

  • 类的初始化过程
    在这里插入图片描述

    • 加载:class文件字节码内容加载到内存中,将静态数据转换为运行时数据结构,然后生成一个代码这个类的java.lang.Class对象
    • 链接:将java类的二进制代码合并到JVM的运行状态之中【验证(是否符合JVM规范)、准备(为类变量分配内存并设置类变量默认初始值)、解析(符号引用替换为直接引用)】
    • 初始化:JVM执行类构造器()方法

4. 类的加载

  • 代码演示

    public class TestClassLoad {
        public static void main(String[] args) {
            A a = new A();
            System.out.println(A.m);
    
            /*
            1. 加载到内存,会产生一个类对应Class对象
            2. 链接,链接结束后m = 0(默认值)
            3. 初始化
                <clinit>(){
                    System.out.println("A类静态代码块初始化");
                    m = 300;
                    m = 100;
                }
    
                 m = 100;
            */
        }
    }
    
    class A{
        //静态代码在类的初始化阶段被初始化
        //非静态代码在类的使用阶段被初始化
        //静态方法在内存中只有一份
        static{
            System.out.println("A类静态代码块初始化");
            m = 300;
        }
        static int m = 100;
    
        public A(){
            System.out.println("A类无参构造初始化");
        }
    }
    

5. 类的初始化

  • 发生条件:

    类的主动引用会产生初始化【new、调用类的静态成员和方法、反射、父类没有被初始化会先初始化父类】

    类的被动引用不会引发类的初始化【通过子类引用父类的静态变量、数组定义类引用、常量(在链接阶段)】

  • 代码演示

    public class TestInit {
        static{
            System.out.println("main类被加载");
        }
    
        public static void main(String[] args) throws ClassNotFoundException {
            //1. new主动引用
    //        Son son = new Son();
    
            //反射产生的主动引用
    //        Class.forName("com.JAVASE.Son");
    
            //不会产生类的引用的方法(main father)
    //        System.out.println(Son.b);
            //(main)
    //        Son[] array = new Son[5];
            //(main)
            System.out.println(Son.M);
        }
    }
    
    class Father{
        static int b = 2;
        static{
            System.out.println("父类被加载");
        }
    }
    
    class Son extends Father{
        static {
            System.out.println("子类被加载");
            m = 300;
        }
    
        static int m = 100;
        static final int M = 1;
    }
    

6. 类加载器(ClassLoader)

  • 作用:ClassLoader负责通过各种方式将Class信息的二进制数据流读入JVM内部,转换为一个于目标类对应的java.lang.Class对象实例。

  • 分类:

    – 启动类加载器(JAVA_HOME/jre/lib/rt.jar或sun.boot.class.path路径下的内容)
    – 扩展类加载器(父类加载器为启动类加载器)
    – 系统类加载器(父类加载器为启动类加载器,它负责加载环境变量classpath或系统属性java.class.path指定路径下的类库)

  • 代码

    public class TestLoader {
        public static void main(String[] args) throws ClassNotFoundException {
            //获得系统类的加载器
            ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
            System.out.println(systemClassLoader);
    
            //获得系统类加载器的父类加载器--》扩展类加载器
            ClassLoader parent = systemClassLoader.getParent();
            System.out.println(parent);
    
            //获取扩展类加载器的父类加载器--》根加载器
            ClassLoader parent1 = parent.getParent();
            System.out.println(parent1);
    
            //测试当前类是哪个加载器加载的
            ClassLoader classLoader = Class.forName("com.JAVASE.TestLoader").getClassLoader();
            System.out.println(classLoader);
    
            //测试jDK内置的类是谁加载的
            classLoader = Class.forName("java.lang.Object").getClassLoader();
            System.out.println(classLoader);
    
            //如何获得系统类加载器可以加载的路径
            System.out.println(System.getProperty("java.class.path"));
    
            //双亲委派机制:存在原来的包会用原来的包
                //java.lang.String
        }
    }
    

7. 获取类的运行时结构

获取类的属性、方法、构造器、修饰符、注解

public class TestClassInformation {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException {
        Class c1 = Class.forName("com.JAVASE.User");

//        User user = new User();
//        Class c1 = user.getClass();

        //获得类的名字
        System.out.println(c1.getName()); //获得包名+类名
        System.out.println(c1.getSimpleName()); //获得类名

        //获得类的属性
        Field[] fields = c1.getFields();//只能都找到public 属性
        for (Field field : fields) { //可以找到全部属性
            System.out.println(field);
        }

        //获得指定属性的值
        Field name = c1.getDeclaredField("name");
        System.out.println(name);

        //获得类的方法
        System.out.println("====");
        //获得奔雷及其父类的全部public方法
        Method[] methods = c1.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }

        //获得本类的所有方法,包含private
        Method[] declaredMethods = c1.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }

        //获得指定方法
        //重载
        Method getName = c1.getMethod("getName",null);
        Method setName = c1.getMethod("setName",String.class);
        System.out.println(getName);
        System.out.println(setName);

        //获得指定构造器
        Constructor[] constructors = c1.getConstructors();
        for (Constructor constructor : constructors) {
            System.out.println(constructor);
        }
        Constructor[] declaredConstructors = c1.getDeclaredConstructors();
        for (Constructor constructor : declaredConstructors) {
            System.out.println(constructor);
        }

        //获得指定构造器
        Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
        System.out.println(declaredConstructor);

    }
}

8. 动态创建对象执行方法

public class TestObject {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
        //获得class对象
        Class c1 = Class.forName("com.JAVASE.User");

        //构造一个对象
        User user = (User)c1.newInstance(); //本质调用了类的无参构造器
        System.out.println(user);

        //通过构造器创建对象,有参数通过这种方式进行创建
        Constructor declaredConstructor = c1.getDeclaredConstructor(String.class, int.class, int.class);
        User user2 = (User)declaredConstructor.newInstance("xrz",001,18);
        System.out.println(user2);

        //通过反射调用普通方法
        User user3 = (User)c1.newInstance();
        //通过反射获取方法
        Method setName = c1.getDeclaredMethod("setName", String.class);
        //激活(对象,方法的值),相当于执行
        //调用指定的方法
        setName.invoke(user3,"xrz");
        System.out.println(user3.getName());

        //通过反射操作属性
        //这样方法获取不到,权限不够,因为name是private
//        User user4 = (User)c1.newInstance();
//        Field name = c1.getDeclaredField("name");
//        name.set(user4,"xrz2");
//        System.out.println(user4.getName());

        //取消安全检测就可以访问私有属性
        User user5 = (User)c1.newInstance();
        Field name5 = c1.getDeclaredField("name");
        name5.setAccessible(true);
        name5.set(user5,"xrz2");
        System.out.println(user5.getName());
    }
}

注意:

取消安全检测就可以访问私有属性setAccessible(true);

调用指定的方法:setName.invoke(user3,“xrz”);

9. 反射操作泛型

  • ParameterizedType:表示一种参数化类型,比如Collection

    GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型

    TypeVariable:是各种类型变量的公共父接口

    WildcardType:代表一种通配符类型表达式

10. 反射操作注解

  • ORM对象关系映射

  • 代码:利用注解和反射完成类和表结构的映射关系

    //练习反射操作注解
    public class TestFAndA {
        public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
            Class c1 = Class.forName("com.JAVASE.Student");
    
            //通过反射获得注解
            Annotation[] annotations = c1.getAnnotations();
            for (Annotation annotation : annotations) {
                System.out.println(annotation);
            }
            
            //获得注解的value的值
            Table table = (Table)c1.getAnnotation(Table.class);
            String value = table.value();
            System.out.println(value);
            
            //获得类指定的注解
            Field f = c1.getDeclaredField("name");
            FieldTable annotation = f.getAnnotation(FieldTable.class);
            System.out.println(annotation.columnName());
            System.out.println(annotation.type());
            System.out.println(annotation.length());
        }
    }
    
    @Table("db_stu")
    class Student{
    
        @FieldTable(columnName = "db_id",type="int",length=10)
        private int id;
        @FieldTable(columnName = "db_age",type="int",length=10)
        private int age;
        @FieldTable(columnName = "db_name",type="int",length=3)
        private String name;
    
        public Student() {
        }
    
        public Student(int id, int age, String name) {
            this.id = id;
            this.age = age;
            this.name = name;
        }
    
        public int getId() {
            return id;
        }
    
        public void setId(int id) {
            this.id = id;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "id=" + id +
                    ", age=" + age +
                    ", name='" + name + '\'' +
                    '}';
        }
    }
    
    //类名的注解
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    @interface Table{
        String value();
    }
    
    //属性的注解
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    @interface FieldTable{
        String columnName();
        String type();
        int length();
    
    }
    

``
本文是参考B站遇见狂神说的相关视频进行学习记录的,如有问题也欢迎大家一起交流~

举报

相关推荐

0 条评论