anno1_注解

1.元注解:负责解释其他注解

​ @Target :用于描述注解的使用范围,即被描述的注解的使用位置

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

//测试元注解
@MyAnnotation
public class Test02 {
    @MyAnnotation
    public void test(){

    }
}
//定义一个注解 @interface是用来定义注解的
// 此时定义的Target在方法和类上有效,如上所示,未报错
@Target({ElementType.METHOD,ElementType.TYPE})
@interface MyAnnotation{

}

​ @Retention:在什么级别保存该注释信息,用于描述注解的生命周期。source<class<runtime

@Retention(value = RetentionPolicy.RUNTIME)  //表示我们的注解在什么地方还有效
@interface MyAnnotation{

}

​ @Document:说明该注解被包含在javadoc中

​ @Inherited:说明子类可以继承父类中的该注解

2.自定义注解
  1. @interface用来定义注解,自动继承 java.lang.annotation.*;接口;

    注解的参数的格式:参数类型+参数名+();

    1. 其中的每一个方法实际上声明了一个配置参数;
  2. 方法的名称就是参数的名称;

  3. 返回值类型就是参数的类型;且返回值类型只能是基本类型class,string,enum;

  4. 可以通过default来申明参数的默认值;

  5. 如果只有一个参数,一般参数名为value;

  6. 注解元素必须要有值,定义注解元素时,经常使用空字符串或者0作为默认。

3.java反射机制reflection
3.1什么时反射

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7k6i38zZ-1629016587633)(C:\Users\56504\AppData\Roaming\Typora\typora-user-images\image-20210811164743148.png)]

package com.yang;

//什么叫反射
public class Test04 {
    public static void main(String[] args) throws ClassNotFoundException {
        Class<?> user = Class.forName("com.yang.User"); //不确定实体类类型,所以用问好代替
        Class<?> user1 = Class.forName("com.yang.User");
        /*打印出来的信息都一样,证明反射出来的时同一个类
        一个类在内存中只有一个class对象
        一个类被加载后,类的整个结构都会被封装在class对象中
        */
        System.out.println(user);
        System.out.println(user1);
        System.out.println(user.hashCode());
        System.out.println(user1.hashCode());
    }
    //通过反射获取类的class对象

}
class User{
}
3.2class类
  • Class对象只能由系统建立对象

  • Class本身也是一个类,是reflection的根源,任何想动态加载运行的类都要先获得对应的class对象

  • 一个加载的类在JVM中只能有一个Class实例

  • 一个class对象对应的是一个加载到JVM中的一个.class文件

    package com.yang;
    
    public class Test05 {
        public static void main(String[] args) throws ClassNotFoundException {
            //正常方式获得
            Person person = new Student();
            System.out.println("这个人是:"+person.name);
            //hashCode比较是不是同一个类
            //方式一:通过对象获得
            Class c1 = person.getClass();
            System.out.println(c1.hashCode());
            //方式二:forname获得
            Class c2 = Class.forName("com.yang.Student");
            System.out.println(c2.hashCode());
            //方式三:类名.class获得
            Class c3 = Student.class;
            System.out.println(c3.hashCode());
            //方式四:只适用于基本类型。基本内置类型的包装类都有个Type属性
            Class type = Integer.TYPE;
            System.out.println(type.hashCode());
            //获得父类
            Class superclass = c2.getSuperclass();
            System.out.println(superclass);
    
        }
    }
    class Person{
        public String name;
        public Person() {
        }
    
        public Person(String name) {
            this.name = name;
        }
        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }
    class Student extends Person{
        public Student(){
            this.name="学生";
        }
    }
    class Teacher extends Person{
        public Teacher(){
            this.name="老师";
        }
    }
    

方式一:通过对象获得

方式二:forname获得

方式三:类名.class获得

3.3哪些类有可以有class对象
package com.yang;
//所有类型的class
public class Test06 {
    public static void main(String[] args) {
        Class c1 = Object.class;   //Object类
        Class c2 = Comparable.class; //接口
        Class c3 = String[].class;   //一维数组
        Class c4 = int[][].class;   //二维数组
        Class c10 = double[][].class;   //二维数组
        Class c5 = Override.class;  //注解
        Class c6 = Integer.class;   //基本类型
        Class c7 = void.class;      //无返回值void
        Class c8 = Enum.class;      //枚举类型
        Class c9 = Class.class;     //Class类


        System.out.println(c1);
        System.out.println(c2);
        System.out.println(c3);
        System.out.println(c4);//打印结果:几个【就代表几维数组,后面的首字母代表类型[[I
        System.out.println(c5);
        System.out.println(c6);
        System.out.println(c7);
        System.out.println(c8);
        System.out.println(c9);
        System.out.println(c10);
//只要元素类型和维度一样,就是同一个class
        int[] a = new int[10];
        int[] b = new int[100];
        System.out.println(a.getClass().hashCode());
        System.out.println(b.getClass().hashCode());
    }
}

结果:
    class java.lang.Object
interface java.lang.Comparable
class [Ljava.lang.String;
class [[I
interface java.lang.Override
class java.lang.Integer
void
class java.lang.Enum
class java.lang.Class
class [[Ljava.lang.Comparable;

4.类的加载与class loader
1.加载

​ 将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行的数据结构,然后生成一个代表这个类的java.lang.Class对象。

2.链接

​ 将Java类的二进制代码合并到jvm的运行状态之中

​ 1.验证:确保加载的类信息符合JVM规范

​ 2.准备:正式为类变量,static分配内存并设置类变量初始值,都在方法区中进行

​ 3.解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程

3.初始化
  • 执行类构造器《clinit()》方法的过程。

  • 初始化一个类时,如果父类没有初始化,先初始化父类。

  • 虚拟机会保证一个类的clinit()方法在多线程的环境中被正确的加载和同步。

    package com.yang;
    
    public class Test07 {
        public static void main(String[] args) {
            A a = new A();
            System.out.println(A.m);
        }
    }
    class A{
        static {
            System.out.println("A类静态代码块初始化");
             m = 100;
        }
        static int m = 300;
        static {
            System.out.println("A类静态代码块初始化2");
            m = 400;
        }
       public A(){
           System.out.println("A类的无参构造初始化");
       }
    
    }
    
    结果:
        A类静态代码块初始化
    A类静态代码块初始化2
    A类的无参构造初始化
    400
    
    
5.什么时候发生类的初始化
##### 5.1类的主动引用

一定会发生类的初始化

  1. 当虚拟机启动时,先初始化main方法所在的类
  2. new一个对象时
  3. 调用类的静态成员和静态方法(final常量除外)
  4. 使用java.lang.reflect包的方法对类进行反射调用
  5. 初始化一个类时,如果父类没有初始化,先初始化父类。
5.2类的被动引用

不会发生类的初始化

1. 访问一个静态域时,只有真正申明这个域的类才会被初始化。如子类引用弗雷德静态变量时,不会导致子类的初始化
2. 通过数组定义类引用,不会发生类的初始化
3. 引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了)
package com.yang;public class Test08 {    static {        System.out.println("main类被加载");    }    public static void main(String[] args) throws ClassNotFoundException {        //1.new一个对象时主动引用       // Son son = new Son();        //2.反射主动引用        Class.forName("com.yang.Son");        //不会产生类的引用的方法        System.out.println(Son.a);//静态代码        Son [] srray = new Son[5];//数组        System.out.println(Son.F);//常量    }}class Father{    static int a = 2;    static {        System.out.println("父类被加载");    }}class Son extends Father{    static {        System.out.println("子类被加载");        m = 300;    }    static int m = 100;    static final int F=4;}
6.类加载器
  • 系统加载器==用户加载器
  • 父类加载器==扩展类加载器
  • 根加载器,C/C++写的,获取不到
package com.yang;public class Test09 {    public static void main(String[] args) throws ClassNotFoundException {        //获取系统类的加载器---》用户加载器        ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();        System.out.println(systemClassLoader);        //获取系统类加载器的父类加载器---》扩展类加载器        ClassLoader parent = systemClassLoader.getParent();        System.out.println(parent);        //获取扩展类加载器的父类加载器--》根加载器(C/C++写的,获取不到)        ClassLoader parent1 = parent.getParent();        System.out.println(parent1);        //测试当前类是哪个加载器加载的        ClassLoader classLoader = Class.forName("com.yang.Test06").getClassLoader();        System.out.println(classLoader); //用户加载器加载的        //测试JDK内置类是哪个加载器加载的        classLoader = Class.forName("java.lang.Object").getClassLoader();        System.out.println(classLoader);//根加载器加载的        //获取系统类加载器的加载路径,即初始化时系统启动的jar包        System.out.println(System.getProperty("java.class.path"));        //双亲委派机制,检测安全性,自己命名的包类名跟系统现有的一样就不会生效。    }}jdk.internal.loader.ClassLoaders$AppClassLoader@2437c6dcjdk.internal.loader.ClassLoaders$PlatformClassLoader@58ceff1nulljdk.internal.loader.ClassLoaders$AppClassLoader@2437c6dcnullC:\Users\56504\IdeaProjects\annotation\target\classes
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值