JAVA 注解和反射(一) 注解 什么是反射机制 得到Class的几种方式

注解

  • 和注释一样,注解不是程序本身,而是对程序作出解释,而注解与注释不同的点在于,注解可以被其他程序比如编译器读取
  • 常见的三个内置注解:
@Override//重写注解
@Deprecated//不推荐使用注解,可以使用但是有风险或者有更好的方式
@SuppressWarnings//“镇压”警告注解

元注解

  • 元注解的作用:解释注解其他注解,Java定义了4个标准的meta-annotation类型,他们被用来提供对其他annotation类型做说明
  • 4个元注解分别为:
    @Target:用于描述注解的使用范围
    @Retention:用于表示需要在什么级别保存注解信息,用于描述注解的声明周期,(SOURCE<CLASS<RUNTIME
    @Documen:说明该注解将被包含在javadoc中
    @Inherite:说明子类可以继承父类中的该注解
  • 测试元注解
//定义一个注解
//Target 表示我们的注解可以用在哪些地方
@Target(value ={ ElementType.METHOD,ElementType.TYPE})
//Retention表示我们的注解在什么地方还有效
@Retention(value = RetentionPolicy.RUNTIME)
//Documented表示是否将我们的注解生成在JAVAdoc文件中
@Documented
//Inherited子类可以继承父类的注解
@Inherited
@interface MyAnnotation{}

自定义注解

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

public class Test03 {
    //注解可以显示赋值,如果没有默认值,我们就必须给注解赋值
    @MyAnnotation2(name = "wang",schools = "西北大学,清华大学")
    public void test(){
    }
    
@MyAnnotation3("li")   //当只有一个参数,且参数名为value时,可以省略value=
    public void test2(){
    }
}

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2{
    //注解的参数: 参数类型 参数名();
    String name() default "";   //默认值为空
    int age() default 0;
    int id() default -1;//如果默认值为-1,代表不存在
    
    String[] schools()default {"北大","清华"};
}

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation3{
    String value();//只有一个参数时,尽量用value命名
}

反射机制

动态语言和静态语言

  • 动态语言:在运行时可以改变其结构:例如新的函数、对象甚至代码可以被引进,已有的函数可以被删除或者是其他结构上的变化。通俗来说就是运行时代码可以根据一些条件来改变自身的结构。
  • 主要动态语言:Object-C、C#、JavaScript、PHP、Python等。
    静态语言:与动态语言相对应的,运行时不能改变其结构,如Java、C、C++
  • Java不是动态语言,但是java可以称为是“准动态语言”。即java有一定的动态性,可以利用反射机制获得类似动态语言的特性。Java的动态性使得编程时更加灵活。
  • JS动态语言实例:
function f() {
      var x="var a=3;var b=5;alert(a+b)";   //运行时x的值变成a+b
      eval(x);
}
  • 反射是Java被视为动态语言的关键,反射机制允许程序在执行期间借助于ReflectionAPI获取任何类的内部信息,并且能够直接操作任意对象的内部属性及方法。
  • 加载完类之后,在堆内存中的方法区中间产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构
  • 反射的优缺点
    优点:实现动态创建对象和编译,有很大灵活性
    缺点:对性能有影响。反射本质上是一种解释操作,即告诉JVM我们希望做什么并且它满足我们的需求。这类操作总是慢于直接执行相同的操作。
//什么叫反射
public class test01 {
    public static void main(String[] args) throws ClassNotFoundException {
        //通过反射获取类的class对象
        Class c1 = Class.forName("com.wang.reflection.User");
        System.out.println(c1);

        Class c2 = Class.forName("com.wang.reflection.User");
        Class c3 = Class.forName("com.wang.reflection.User");
        Class c4 = Class.forName("com.wang.reflection.User");
        Class c5 = Class.forName("com.wang.reflection.User");
//一个类在内存中只有一个Class对象
// 一个类被加载后,类的整个结构都会被封装在Class对象中
        System.out.println(c2.hashCode());
        System.out.println(c3.hashCode());
        System.out.println(c4.hashCode());
        System.out.println(c5.hashCode());
        //hashCode是完全相同的,说明是同一个Class
    }
}
//实体类:pojo  , entity
class User{...}

得到Class的几种方式

class类的常用方法

方法名功能说明
static ClassforName(String name)返回指定类名name的Class对象
Object newInstance()调用缺省构造函数,返回Class对象的一个实例
getName()返回此Class对象所表示的实体(类,接口,数组类或void)的名称
Class getSuperClass()返回当前class对象的父类的class对象
Class[] geiinterfaces()返回当前class对象的接口
ClassLoader getClassLoader()返回该类的类加载器
Constructor[] getConstructors()返回一个包含某些Constructors对象的数组
Method getMethod(String name,Class…T)返回一个Method对象,此对象的形参类型为param Type
Field getDeclaredFields()返回Feild对象的一个数组

获得Class类的实例

  • 如果已有具体的类,通过类的class属性获取,最为安全可靠且性能最高的方法。(Class xxx=XXX.class;)
  • 已知某个类的实例,调用此实例的getClass()方法获取Class对象。(Class xxx=xxx1.getClass();)
  • 已知一个类的全名且在类路径下,可以通过Class类的静态方法forName()获取,需要处理异常ClassNotFoundException(Class xxx=ClassforName(“yyy.XXX”);)
  • 内置基本数据类型可以直接使用类名.Type
  • 还可以用ClassLoader(之后讲解)
//测试class类的创建方式有哪些
public class Test {
    public static void main(String[] args) throws ClassNotFoundException {
        Person person=new Student();
        System.out.println("这个人是"+person.name);//输出  这个人是学生

        //方式1:通过对象获得
        Class c1=person.getClass();
        System.out.println(c1.hashCode()); //输出  1239731077
        System.out.println(c1);         //输出  class com.wang.reflection.Student

        //方式2:通过forname获得
        Class c2 = Class.forName("com.wang.reflection.Student");
        System.out.println(c2.hashCode()); //输出  1239731077

        //方式3:通过类名.class
        Class<Student> c3 = Student.class;
        System.out.println(c3.hashCode());//输出  1239731077

        //方式4:基本内置类型的包装类都有一个Type属性
        Class<Integer> c4 = Integer.TYPE;
        System.out.println(c4);  //输出int

        //获得父类类型
        Class c5 = c1.getSuperclass();
        System.out.println(c5);  //输出 class com.wang.reflection.Person
    }
}
 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 ="老师";
    }

}

哪些类型可以有Class对象?

  • class:外部类、成员(成员内部类、静态内部类),局部内部类,匿名内部类。
  • interface:接口
  • []:数组
  • enum:枚举
  • annotation:注解
  • primitive type:基本数据类型
  • void
public class Test04 {
    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;//基本数据类型
        Class c8 = void.class;//void
        Class c9 = Class.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[1000];
        System.out.println(a.getClass().hashCode());//2083562754
        System.out.println(b.getClass().hashCode());//2083562754
    }
}

  • 注意: 同样是int类型的数组,维度不同Class对象所打印出的hashcode不同,即:数组维度不同对应不同的Class对象。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值