JAVA学习笔记——注解与反射

1.什么是注解?

1.Annotation 是从JDK 5.0开始引入的新技术

2.Annotation的作用:
1.可以对程序作出解释,这个作用与我们在程序写的注释的作用类似
2.可以其他程序(如编译器)读取,一般通过反射来实现

3.Annotation 的格式
注解是以“@注释名”在代码中存储在的,还可以添加一些参数值,例
如果:@SuppressWarnings(value=“unchecked”)

4.Annotation 在哪里使用?
注解可以附加在package 、class、method、field 等上面,相当于给这些数据添加了额外的辅助信息。此外,我们还可以通过注解以及反射机制实现对这些元数据的访问。

2.内置注解

1.@Override:
@Override定义在java.lang.Override 中,此注解只能附加在方法上,表示此方法重写父类的中的方法

2.@Deprecated:
@Deprecated定义在java.lang.Deprecated中,此注解可以附加在方法、属性以及类上,表示不鼓励程序员使用这样的元素,同时是因为该元素很危险或者存在更好的选择。(一般来说表示废弃了的方法、或者类等等)

3.@SuppressWarnings:
@SuppressWarnings定义在java.lang.SuppressWarings 中,用来抑制编译时的警告信息,该注解与前两个注解有所不同,需要添加一个参数才能正确使用,而这些参数都是已经定义好了的,如:
@SuppressWarnings(“all”),表示抑制所有警告信息
@SuppressWarnings(“unchecked”),表示抑制未检查警告信息
@SuppressWarnings(value={“unchecked”,“deprecation”}),表示抑制未检查以及废弃警告信息

3.元注解

元注解的作用就是定义其他注解,Java定义了四个标准的meta-annotation类型,它们被用来提供对其他annotation 类型做说明。
1.@Target:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
2.@Retention:表示注解在哪个级别中有效。SOURCE代表源代码级别,CLASS代表字节码级别, RUNTIEM代表运行级别。
3.@Document:说明该注解将被包含在javadoc中
4.@Inherited:说明该注解可以被子类继承

4.自定义注解

使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口。

分析:
  1.@interface用来声明一个注解,格式:“public @interface 注解名{ 定义内容 }”
  2.定义内容中的每一个方法实际上是声明了一个属性
  3.方法的名称就是属性的名称
  4.方法的返回值类型就是属性的类型(方法的返回值只能是基本类型,Class,String,enum)。
  5.可以通过default 来声明属性的默认值
  6.如果只有一个属性,则属性名一般为value
  7.使用自定义注解时,若注解中声明了属性且无默认值,则使用时必须定义属性值;若有默认值,则可以不显式定义值。

自定义注解如下图所示:
在这里插入图片描述
从图中可以看出,定义了一个名为MyAnnotation的注解,该注解可以作用于方法以及类上。此外,该注解在运行时也起作用、可以被子类继承以及该注解会被包含在javadoc文档中。而在定义内容中,该注解声明了一个属性,该属性名为name,属性类型为String,且没有设置默认值。

自定义注解测试如下图所示:
在这里插入图片描述
从图中可以看出,自定义的注解作用在方法上,编译器报错的原因是因为我们在注解的定义内容中声明了一个名为name的属性,而且并没有为该属性设置默认值。
解决方法:
1.使用注解的时候加上属性值
在这里插入图片描述

2.声明属性时设置默认值
在这里插入图片描述

5.反射概述

5.1 动态语言与静态语言
动态语言是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。通俗点说就是在运行时代码可以根据某些条件改变自身结构。主要动态语言:Object-C、C#、JavaScript、PHP、Python等。

静态语言与动态语言相对应的,运行时结构不可变的语言就是静态语言。如Java、C、C++。Java不是动态语言,但Java可以称之为“准动态语言”。即Java有一定的动态性,我们可以利用反射机制获得类似动态语言的特性。Java的动态性让编程的时候更加灵活!

5.2 Java Reflection
Java Reflection是Java被视为动态语言的关键,反射机制允许程序在运行期间借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。

能这样做的主要原因:在Java源代码编译成class文件字节码文件之后,首先便会进行类加载。在类加载的过程中,会将class文件字节码内容加载到内存中,并将类的这些静态数据转换成方法区(方法区其实是一个特殊的堆)运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。反射机制主要是依靠这个Class类型的对象来实现的。

那么问题就来了,为什么类在堆中生成的是Class类型对象呢?原因就是:我们所创建的所有的类都属于Class类型 如下图所示:
在这里插入图片描述
假如我们创建了一个对象张三,这个对象属于Person类型,而Person类又属于Class类型,所有由此可得张三也属于Class类型,因此我们也可以通过类对象来获得类对应的Class类型对象。

5.3 如何得到Class类型对象?

public class Person {
    String name;
    int age;
    String sex;
}

 public static void main(String[] args) throws ClassNotFoundException {
 
        Person person = new Person();
        
        //方式1:通过类对象.getClass()方法获得
        Class c1 = person .getClass();
        System.out.println(c1.hashCode());

        //方式2:Class.forName()方法获得
        Class c2 = Class.forName("pojo.Person ");
        System.out.println(c2.hashCode());

        //方式3. 通过类名.class 获得
        Class c3 = Person .class;
        System.out.println(c3.hashCode());

        //方式4:基本内置类型的包装类都有一个Type 属性,所以内置类型可以通过TYPE属性获得对应的Class类型对象
        Class<Integer> c4 = Integer.TYPE;
        System.out.println(c4);
    }

对于上面的方法4,那么拥有class对象的类型为:
1.class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类。
2.interface:接口
3.[ ] :数组
4.enum:枚举
5.annotation:注解 @interface
6.primitive type :基本数据类型
7.void
示例代码如下:

//测试所有类型的Class
public class Test {
    public static void main(String[] args) {
        //类
        Class c1 = Object.class;
        //接口
        Class c2 = Comparable.class;
        //一维数组
        Class c3 = String[].class;
        //二维数组
        Class c4 = int[][].class;
        //注解
        Class c5 = Override.class;
        //枚举
        Class c6 = ElementType.class;
        //基本类型
        Class c7 = Integer.class;
        //void
        Class c8 = void.class;
        // Class
        Class c9 = Class.class;

        System.out.println(c1);
        System.out.println(c2);
        System.out.println(c3);
        System.out.println(c4);
        System.out.println(c5);
        System.out.println(c6);
        System.out.println(c7);
        System.out.println(c8);
        System.out.println(c9);

        //只要元素类型与维度一样,就是同Class
        int[]  a = new int[10];
        int[]  b = new int[100];
        System.out.println(a.getClass().hashCode());
        System.out.println(b.getClass().hashCode());
    }
}

5.4 获得Class对象后能实现的功能
获得类对应的Class类型对象后,能实现的功能有:
1.在运行时判断任意一个对象所属的类
2.在运行时构造任意一个类的对象
3.在运行时判断任意一个类所具有的成员变量和方法
4.在运行时获取泛型信息
5.在运行时调用任意一个对象的成员变量和方法
6.在运行时处理注解
7.生成动态代理

实现代码如下:

注解:

//自定义的注解,作用于类
@Target(value = {ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface AnnotationForClass {
    String value() default "class";
}
//自定义的注解,作用于方法
@Target(value = {ElementType.METHOD})
@Retention(value = RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface AnnotationForMethod {
    String value() default "method";
}

//自定义的注解,作用于属性
@Target(value = {ElementType.FIELD})
@Retention(value = RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface AnnotationForField {
    String value() default "field";
}

实体类:

//Person实体类
public class Person {
    public String name;
    public int age;
    public String sex;

    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;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
}

//Studnet实体类
import annotation.AnnotationForClass;
import annotation.AnnotationForField;
import annotation.AnnotationForMethod;

@AnnotationForClass("class")
public class Student extends Person {

    @AnnotationForField("no")
    private String no;
    @AnnotationForField("grade")
    public String grade;

    public Student(){

    }

    public Student(String no, String grade) {
        this.no = no;
        this.grade = grade;
    }
    
    @AnnotationForMethod("getNo")
    public String getNo() {
        return no;
    }
    @AnnotationForMethod("setNo")
    public void setNo(String no) {
        this.no = no;
    }

    public String getGrade() {
        return grade;
    }

    public void setGrade(String grade) {
        this.grade = grade;
    }

    @Override
    public String toString() {
        return "Student{" +
                "no='" + no + '\'' +
                ", grade='" + grade + '\'' +
                "} " + super.toString();
    }
}

测试类:

//测试类代码
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
        //获得Student对应的class对象
        Class<?> c1 = Class.forName("reflect.pojo.Student");

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

        //获得类的属性
        System.out.println("============本类与父类中所有用public修饰的属性==============");
        Field[] fields = c1.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        System.out.println("============本类中所有的属性==============");
        fields = c1.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field);
        }

        //获取指定属性的值
        //Field name = c1.getField("no");报错,因为getField方法只能获取public修饰的属性
        System.out.println("============获取指定属性的值==============");
        Field name = c1.getDeclaredField("no");
        System.out.println(name);

        //获得类的方法
        System.out.println("============获取本类及父类所有用public修饰的方法==============");
        Method[] methods = c1.getMethods();
        for (Method method : methods) {
            System.out.println("getMethods():"+method);
        }
        System.out.println("============获取本类的所有方法==============");
        methods = c1.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println("getDeclaredMethods():"+method);
        }
        System.out.println("=============根据方法名称获取指定方法=============");
        Method getNo = c1.getMethod("getNo");
        System.out.println(getNo);
        Method setNo = c1.getMethod("setNo", String.class);
        System.out.println(setNo);

        System.out.println("===========获取本类中所有用public修饰的构造方法===============");
        Constructor<?>[] constructors = c1.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println("getConstructors: "+constructor);
        }

        System.out.println("=============获取本类中所有的构造方法===============");
        constructors = c1.getDeclaredConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println("getDeclaredConstructors():"+constructor);
        }


        System.out.println("=============根据构造器的参数类型获取指定构造方法===============");
        Constructor<?> declaredConstructor = c1.getDeclaredConstructor(String.class, String.class);
        System.out.println("指定: "+declaredConstructor);

        System.out.println("=============通过无参构造方法创建对象===============");
        Student student1 = (Student) c1.newInstance();
        System.out.println(student1);

        System.out.println("=============通过有参构造方法创建对象===============");
        Student student2 = (Student) declaredConstructor.newInstance("2","二年级");
        System.out.println(student2);

        System.out.println("=============获取并调用指定方法===============");
        Method method1 = c1.getDeclaredMethod("setNo", String.class);
        Method method2 = c1.getDeclaredMethod("setGrade", String.class);
        System.out.println("=============获调用指定方法===============");
        method1.invoke(student1,"1");
        method2.invoke(student1,"一年级");
        System.out.println(student1);

        System.out.println("=============获取所有注解===============");
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation annotation : annotations){
            System.out.println(annotation);
        }

        System.out.println("=============根据注解名获取作用在类上的注解并输出该注解的值===============");
        AnnotationForClass annotationForClass = c1.getAnnotation(AnnotationForClass.class);
        System.out.println(annotationForClass.value());

        System.out.println("=============根据注解名获取作用在属性上的注解并输出该注解的值===============");
        Field field = c1.getDeclaredField("no");
        AnnotationForField annotationForField = field.getAnnotation(AnnotationForField.class);
        System.out.println(annotationForField.value());

        System.out.println("=============根据注解名获取作用在方法上的注解并输出该注解的值===============");
        Method method = c1.getDeclaredMethod("setNo", String.class);
        AnnotationForMethod annotationForMethod = method.getAnnotation(AnnotationForMethod.class);
        System.out.println(annotationForMethod.value());
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Xulidanga

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值