反射和注解

1.反射

反射:Java反射机制指的是在Java程序运行状态中,对于任何一个类,都可以获得这个类的所有属性和方法;对于给定的一个对象,都能够调用它的任意一个属性和方法。这种动态获取类的内容以及动态调用对象的方法称为反射机制。

作用:Java的反射机制允许编程人员在对类未知的情况下,获取类相关信息的方式变得更加多样灵活,调用类中相应的方法,是Java增加其灵活性和动态性的哟一种机制。

1.Class类(类的类型对象)

(1)Class类的实例表示正在运行的Java应用程序中的类和接口

(2)Class没有公共构造方法。Class对象是在加载类时由Java虚拟机以及通过调用类加载器中的defineClass方法自动构造的

(3)获得一个类的Class对象

        Java代码在执行中由三个阶段:

        1)源代码(source)阶段

        2)字节码(class)阶段,源代码编译后

        3)运行阶段(runTime)阶段

        获取class对象的三种方式:

        1)Class.forName("全类名"):把字节码文件加载到内存

        2)类名.class:通过类名的class属性获取

        3)对象.getClass():通过对象的getClass()获取

//第一种方式
Class c1 = Student.class;
System.out.println("c1:"+c1);
//第二种方式
Class c2 = Class.forName("com.test1.Student");
System.out.println("c2:"+c2);
//第三种方式
Student s=new Student();
Class c3 = s.getClass();
System.out.println("c3:"+c3);

双亲委派模型:

1、启动类加载器(Bootstrap ClassLoader),它是属于虚拟机自身的一部分,用C++实现的,主 要负责加载 \lib目录中或被-Xbootclasspath指定的路径中的并且文件名是被虚拟机识别的 文件。它等于是所有类加载器的爸爸。

2、扩展类加载器(Extension ClassLoader),它是Java实现的,独立于虚拟机,主要负责加载 \lib\ext目录中或被java.ext.dirs系统变量所指定的路径的类库。

3、应用程序类加载器(Application ClassLoader),它是Java实现的,独立于虚拟机。主要负责加 载用户类路径(classPath)上的类库,如果我们没有实现自定义的类加载器那这玩意就是我们程 序中的默认加载器

原理:当一个类加载器收到类加载任务时,会先交给自己的父加载器去完成,因此最终加载 任务都会传递到最顶层的BootstrapClassLoader,只有当父加载器无法完成加载任务时, 才会尝试自己来加载。

具体:根据双亲委派模式,在加载类文件的时候,子类加载器首先将加载请求委托给它的父加载器,父加载器会检测自己是否已经加载过类,如果已经加载则加载过程结束,如果没有加载的话则请求继续向上传递直Bootstrap ClassLoader。如果请求向上委托过程中,如果 始终没有检测到该类已经加载,则Bootstrap ClassLoader开始尝试从其对应路径中加载该 类文件,如果失败则由子类加载器继续尝试加载,直至发起加载请求的子加载器为止。

 作用:采用双亲委派模式可以保证类型加载的安全性,不管是哪个加载器加载这个类,最终都是委 托给顶层的BootstrapClassLoader来加载的,只有父类无法加载自己才尝试加载,这样就 可以保证任何的类加载器最终得到的都是同样一个Object对象。

2.Class类的常用方法

(1)getName() :以 String 的形式返回此 Class 对象所表示的实体(类、接口、数组类、基本 类型或 void)名称

(2)getSimpleName() :返回源代码中给出的基础类的简称

(3)newInstance() :创建此 Class 对象所表示的类的一个新实例

        newInstance()也是用来创建新的对象,其与new()的区别是:

        newInstance():弱类型,效率低,只能调用无参构造

        new():强类型,高效率,能调用任何public构造器

(4)forName(String className) :返回与带有给定字符串名的类或接口相关联的 Class 对象 (5) getConstructors() : 返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。

(6)getDeclaredField(String name) :返回一个 Field 对象,它反映此 Class 对象所表示的类 或接口的所有成员字段。

(7)getDeclaredFields() :返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象 所表示的类或接口的所有可访问字段。

(8)getDeclaredMethod(String name, Class... parameterTypes) : 返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定成员方法。

(9)getDeclaredMethods() :返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法。

Class cls = Student.class;
//获取指定类型的所有构造方法
Constructor[] cs = cls.getConstructors();
for (Constructor c:cs) {
System.out.println(c);
}
System.out.println("=========================");
//获取指定类型的所有字段
Field[] fs = cls.getDeclaredFields();
for (Field f: fs){
System.out.println(f);
}
System.out.println("=========================");
//获取指定类型的所有方法
Method[] ms = cls.getDeclaredMethods();
for (Method m:ms){
System.out.println(m);
}

3.Method类

Method 提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。所反映的方法可能 是类方法或实例方法(包括抽象方法)

(1)getName() :以 String 形式返回此 Method 对象表示的方法名称。

(2)getParameterTypes() :按照声明顺序返回 Class 对象的数组,这些对象描述了此 Method 对象所表示的方法的形参类型。

(3)getReturnType() :返回一个 Class 对象,该对象描述了此 Method 对象所表示的方法的正 式返回类型。

(4)invoke(Object obj, Object... args) :对带有指定参数的指定对象调用由此 Method 对象表 示的基础方法。

Student s=new Student();
Class cls = Student.class;
//获取指定方法名和参数类型的方法
Method m = cls.getDeclaredMethod("setName",String.class);
//调用方法,并传入参数
m.invoke(s,"张三");
System.out.println(s);

4.Field类

Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限。

(1)get(Object obj) :返回指定对象上此 Field 表示的字段的值

(2)set(Object obj, Object value) :将指定对象变量上此 Field 对象表示的字段设置为指定的新 值。

(3)getName() :返回此 Field 对象表示的字段的名称。、

Student s=new Student();
Field f = Student.class.getDeclaredField("name");
//设置可以访问私有字段
f.setAccessible(true);
f.set(s,"贾宝玉");
System.out.println(f.get(s));
System.out.println(s);

2.注解

注解(Annotation):在JDK1.5之后增加的一个新特性,这种特性被称为元数据特性,在JDK1.5 之后称为注解,即:使用注释的方式加入一些程序的信息。java.lang.annotation.Annotation接口是所有的Annotation都必须实现的接口。

1.系统内建的三个注解

在JDK1.5之后,系统中已经建立了如下三个Annotation类型,用户可以直接使用

(1)@Override:方法重写的注解

(2)@Deprecated:不赞成使用的注解

(3) @SuppressWarnings:压制安全警告的注解

2.系统元注解

Java的四种元注解(Meta Annotation) 元注解: 用来标记注解的注解。通过元注解,可以标记我们自定义注解使用目标(类,属性,方法,构 造,局部变量...),还可以标记注解的保留阶段(源代码,字节码,运行时)

3.自定义注解

 语法:

public @interface 注解名称{
数据类型 变量名称();
}
@Target(value=ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
}

数据类型 : 注解的类型只能是8中基本类型还有,String,基本类型的数组,枚举

标记注解:没有成员变量的注解类型,这种注解仅仅提供存在与否的标识信息,如: @Override。

测试目标类是否存在注解:

public static void main(String[] args) {
//测试目标类是否有对应的注解
//注意,如果想在运行的时候,对应注解依旧有效,
//则注解上必须设置元注解: @Retention(RetentionPolicy.RUNTIME)
boolean b = Student.class.isAnnotationPresent(MyAnnotation.class);
System.out.println(b);
}

注解的定义和使用:

1. 注解定义要设置两项内容: A. 注解的使用目标 @Target 类,字段,方法,构造,... B. 注解的作用阶段 @Retention 源代码,字节码,运行时

2. 注解中的属性,用方法的方式定义

3. 注解的属性可以设置默认值,为普通属性赋值,要加属性名,有默认值 的属性可以不设置值

4. 注解中可以定义一个默认属性value,如果只为value属性赋值,可以省 略value这个属性名

5.. 判断当前遍历的注解是哪种类型的注解

//使用反射获取类上的注解
Class cls = Class.forName("com.entity.Student");
//获取类上的注解,数组
Annotation[] as = cls.getDeclaredAnnotations();
for (Annotation a : as){
//a: MyAnno ,StuAnno
System.out.println(a);
//判断遍历到的a是否是学生注解
if(a instanceof StuAnno){
StuAnno sa = (StuAnno) a;
System.out.println(sa.studentId());
System.out.println(sa.name());
System.out.println(sa.sex());
}else if(a instanceof MyAnno){
//判断当前注解是否是MyAnno
System.out.println("现在遍历的是MyAnno");
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值