Java的注解与反射(框架底层学习的基础):

Java的注解与反射-框架底层学习的基础:

1.注解(Annotation):

1.1功能

  • 不是程序本身,可以对程序做出解释(这一点和注释comment没有区别);
  • 可以被其他的程序(比如编译器)读取;
  • 检查与约束

1.2分类

1.2.1内置注解:

(最常用的三种方法,在Java帮助文档可以查阅)

  • @Override:重写方法
  • @Deprecated:表示不鼓励程序员使用
  • SuppressWarnings:镇压警告,镇压在编译过程中出现的警告,放在类上就镇压类的警告,放在方法上镇压方法的警告

1.2.2元注解(meta-annotation):

可以注解其他的注解,理解为注解的注解。

  • @Target:用于描述注解的适用范围:
  • @Retention:在什么级别保存该注释,描述注解的生命周期(source<class<runtime(默认))
  • @Documented:说明该注解将被包含在javadoc中
  • @Inherited:说明子类可以继承父类中的该注解

例:定义元注解

//测试元注解
public class Test03{
    
}
//定义注解的生命周期在源码级别,即在源码上还有效,一般默认为runtime
@Retention(RetentionPolicy.SOURCE)
//定义一个元注解,作用域为方法上
@Target(value = ElementType.METHOD)
//表示是否将我们的注解生成在Javadoc中
@Documented
//子类可以继承父类的注解
@Inherited
//定义一个注解
@interface MyAnnotation{
    
}

1.3自定义注解

1.3.1格式:

  • (public)@interface 注解名 {定义内容}
  • 其中的每个方法实际上是声明了一个配置参数.
  • 方法的名称就是参数的名称.
  • 返回值类型就是参数的类型(返回值只能是基本类型,Class,String,enum)
  • 可以通过default来声明参数的默认值
  • 如果只有一个参数成员,一般参数名为value
  • 注解元素必须要有值,我们定义注解元素时,经常使用空字符串,0作为默认值.

例:

public class Tset{
    //如果没有默认值,则必须给注解赋值
    @MyAnnotation(name = "爱玛",schools = {"你好","哈哈哈"})
    @MyAnnotation("爱玛")
    public void test(){}
}
@Target({ElementType.TYPE,ElementType.METHOD})//作用在类和方法上
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation02{
    //注解的参数:参数类型+参数名();
    String name() default "";
    int id() default -1;//如果默认值为-1,则代表找不到
    String[] schools();
    
}
@interface MyAnnotation3{
    String value();//使用value参数的时候没有默认值时,不需要显示的写出参数名
}

2.反射(重点)

2.1重要性

1.反射是Java被视为动态语言的关键

2.加载一个类时会生成一个class对象,通过获取这个对象来获取class的各种信息(一个class在加载的时候也只有一个class实例)

2.2.优缺点

优点:可以动态的创建对象和编译,体现出很大的灵活性;

缺点:对性能有影响,这是解释操作,慢于直接执行的操作

2.3获取方法

  • 若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高。
  Class c2 = Person.class;
  • 已知某个类的实例,调用该实例的getClass()方法获取Class对象
  Class c3 =  person.getClass();
  • 已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException
  Class c4 = Class.forName("包名+类名");
  • 内置基本数据类型可以直接用类名.Type
  Class c5 = Integer.TYPE

2.4哪些类型可以有Class对象

  • class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类。
  • interface:接口
  • []:数组
  • enum:枚举
  • annotation:注解@interface
  • primitive type:基本数据类型
  • void

只要类型一样并且维度一样,不论大小,他们的hashcode就一样(一维数组和二维数组不一样,但是int[10]和int[100]获得的Class对象的hashcode一样)

2.5获取运行时类的完整结构

例:通过类的对象的各个方法获取类的属性:

  //c1为类的对象
  c1.getName();//获得类的名字
  c1.getSimpleName()//获得类的简单名字
      
  //获得类的属性
  c1.getFiles();//获得所有属性,这是一个数组,但是这个只能找到piblic属性
  c1.getDeclaredFields();//找到全部的属性

  //获得类的方法
  c1.getMethods();
  c1.getDeclaredMethods();

2.6动态创建对象执行方法

创建类的对象:调用Class对象的newlnstance()方法

1)类必须有一个无参数的构造器
2)类的构造器的访问权限需要足够

  Class c1 = Class.forName("包名+类名");
  Obeject x = c1.newInstance();//可以进行类型的强转

☆当没有类的无参构造器时的做法

步骤如下:
1)通过Class类的getDeclaredConstructor(Class.…parameterTypes)取得本类的指定形参类型的构造器
2)向构造器的形参中传递一个对象数组进去,里面包含了构造器中所需的各个参数。
3)通过Constructor实例化对象

  Object object = c1.getDeclaredConstructor(参数.class)
  Obeject c2 = object.newInstance(参数)

通过反射调用方法:

  Class c1 = 	Class.forName("包名+类名");
  Object c2 = c1.newInstance();
  Method c3 = c2.getDeclaredMethod(参数);
  c3.invoke(对象,方法值);

还可以通过反射调用属性:

同上面一样,利用getDeclaredField()方法获取属性,然后用get,set方法进行属性的传参。

  • 但是注意,这种方法不能操作私有属性,会报错,必须在set之前使用:对象.setAccessible(true)语句关闭权限检测

2.7setAccessible

setAccessible作用是启动和禁用访问安全检查的开关。

  • 参数值为true则指示反射的对象在使用时应该取消Java语言访问检查。作用:

    • 提高反射的效率。如果代码中必须用反射,而该句代码需要频繁的被调用,那么请设置为true。(因为反射的效率低于正常操作的效率)
    • 使得原本无法访问的私有成员也可以访问。
  • 参数值为false则指示反射的对象应该实施Java语言访问检查

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值