注解和反射

1.什么是注解

注解是以"@注解名"在代码中存在的,还可以添加一些参数值
例如;`@SuppressWarnings(value=“unchecked”)

注解的作用:

不是程序本身,可以对程序作出解释
可以被其他程序读取(比如:编辑器)

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

2. 内置注解

@Override注解定义在java.lang.Override 中, 此注解用于修辞方法, 表示一个方法声明打算重写超类(父类)中的方法
@Deprecated 注解定义在java.lang.Deprecated 中, 此注解用于修辞方法, 属性, 类. 表示不鼓励程序员去使用, 通常是因为它可能存在危险或者存在更好的选择
@SuppressWarnings 定义在java.lang.SuppressWarnings 中, 用来抑制编译时的警告信息

3. 元注解

元注解的作用就是负责注释其他注解,java定义了4个标准的meta-annotation类型,他们被用来提供对其他annotation类型作说明

//测试元注解
 @gja
 public class Test02 {
     public  void test(){
     }
 }
 //定义一个注解
 //Target表示我们的注解可以用在哪些地方
 @Target(value={ElementType.METHOD,ElementType.TYPE})
 //Retention表示我们的注解在什么地方还有效
 //runntime > class > sources
 @Retention(value = RetentionPolicy.RUNTIME)
 //Documented表示我们的注解是否生成在doc中
 @Documented
 //Inherited 子类可以继承父类的注解
 @Inherited
 @interface gja{}.

4. 自定义注解

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

 public @interface 注解名{
 定义内容
 }

4.1 注解的参数

自定义注解时,可以设置参数. 参数格式为 参数类型 参数名(); 例如: String name(); 在使用时如果没有默认值,则必须传递参数

// 自定义注解
 @Target({ElementType.TYPE,ElementType.METHOD})
 @Retention(RetentionPolicy.RUNTIME)
 @interface gja{
     // 注解的参数: 参数类型 + 参数名();
     String name();
 }//使用注解
 public class test{
     @gja(name = "gja")
     public void test(){}
 }

4.2 注解的默认值
如果注解已经自定义了默认值, 参数可以不用写.如下:

//自定义注解
 @Target({ElementType.TYPE,ElementType.METHOD})
 @Retention(RetentionPolicy.RUNTIME)
 @interface gja{
     //注解的参数:参数类型+参数名(); default为默认值
     String name() default  "";
     int age() default 0;
     int id() default -1;//如果默认值为-1,代表不存在,
     String[] school() default { "清华","北大"};
 }
 // 使用注解
 public class Test03 {
     // 因为注解里面 已经 有了默认值 default 0; 所以age的属性可写可不写
     //注解可以显示赋值,如果没有默认值,我们就必须给注解赋值
     @gja(name = "gja",school = "清华")
     public  void test(){ }

4.3 当注解只有一个参数时
如果说注解里只有一个值,建议使用value做参数名, 因为使用value做参数名, 写参数的时候就可以省略参数名

例如:

// 定义注解
 @Target({ElementType.TYPE,ElementType.METHOD})
 @Retention(RetentionPolicy.RUNTIME)
 @interface gja2{
     String value();
 }
 //使用注解
 public class test(){
      @gja2("李强")
     public  void test1(){ }
 }

5.反射

Reflection(反射) 是java被视为动态语言的关键, 反射机制允许程序在执行时期间借助Reflection的API获取任何类的内部信息, 并直接操作任意对象的内部属性及方法. 例如:

Class c = Class.forName("java.lang.String");

加载完类之后, 在堆内存的方法去就产生了一个class类型的对象(一个类只有一个Class对象, 这个对象就包含了完整的类的结构信息, 我们可以通过这个对象看到类的结构. 这个对象就像一面镜子, 透过这个镜子,可以看到类的结构,所以我们形象的称之为: 反射

Java反射机制提供的功能

在运行时判断任意一个对象所属的类
在运行时构造任意一个类的对象
在运行时判断任意一个类所具有的成员变量和方法
在运行时获取泛型信息
在运行时调用任意一个对象的成员变量和方法
在运行时处理注解
生成动态代理

package com.tedu.reflection;
 //什么叫反射
 public class Test1 extends Object{
     public static void main(String[] args) throws ClassNotFoundException {
         //通过反射获取类的Class对象
         Class c1 = Class.forName("com.tedu.reflection.User");
         System.out.println(c1);//class com.tedu.reflection.User
         Class c2 = Class.forName("com.tedu.reflection.User");
         Class c3 = Class.forName("com.tedu.reflection.User");
         Class c4 = Class.forName("com.tedu.reflection.User");
         //一个类在内存中只有一个Class对象
         //一个类被加载后,类的整个结构都会被封装在Class对象中
         System.out.println(c2.hashCode());//460141958
         System.out.println(c3.hashCode());//460141958
         System.out.println(c4.hashCode());//460141958
     }
 }
 //实体类 :pojo
 class User{
     private  String name;
     private  int id ;
     private  int age;//... 省略有参无参构造方法,get-set方法,toString方法
 }

获取Class实例

若已知具体类, 通过类的class属性可以获取,这种方法最安全最可靠,程序性能最高

 Class clazz = Person.class;

已知某个类的实例可以调用实力的getClass()方法获取

Class clazz = person.getClass();

已知一个类的全名 ,且在该类路径下,可通过Class类的静态方法,forName()获取,但是可能抛出ClassNotFoundException

Class clazz = Class.forName("com.tedu.reflection.Student");

8种基本类型的封装类都有一个Type属性(不常用)

Class clazz = Integer.Type;

通过子类获取(不常用)

// 例如Student对象继承了Person对象
 //所以可以使用Student对象获取父类Person的Class对象
 Class clazz = Student.class.getSuperClass();

6.类的加载与内存分析

类的加载分为三部分(加载,链接,初始化)

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

2.链接: 将java类的二进制代码合并到JVM的运行状态之中的过程.
验证: 确保加载类的信息符合JVM的规范, 没有安全方面的问题
准备; 正式为变量 (static) 分配内存并设置默认初始值的阶段, 这些内存将在方法区进行分配
解析: 虚拟机常量池的符号引用, (常量名) 替换为直接引用的( 地址) 的过程

3.初始化
执行类构造器的() 方法的过程. 类构造器()方法由编译期间自动收集类中的所有类变量的赋值动作和静 态代码块中的语句合并产生的.(类构造器是构造类的信息, 不是构造该类对象的构造器)
当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发父类的初始化.
虚拟机会保证一个类的()方法在多线程环境中被正确加锁和同步.

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值