1.16java学习之反射

注解和反射

注解Annotation

作用:

  1. 不是程序本身,可以对程序作出解释(和comment没区别)
  2. 可以被其他程序(比如:编译器)读取

格式:以**@注释名在**代码中存在,还可以添加一些参数

作用域:包,类,方法,文件

@override:重写父类的方法声明

@Deprecated:不鼓励程序员使用,有危险或者更好的选择

@SuppressWarnings:需要参数:用来抑制编译的警告信息

元注解:

注解(meta-Annotation)其他注解,有四个类型

  1. @target:表示注解能用在哪些地方,类,方法,,,
  2. @retention(source
  3. @Document,:是否写入Javadoc文件中
  4. @inherited:子类是否可以继承父类的注解
自定义注解

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

声明格式:public interface 注解名{},再类里面需要去掉public

@interface Myannotation{

String name ();//这不是方法,这是定义里面的参数,参数类型+参数名+(),如果调用该注解需要赋予参数值。

String name () default “”;//默认值,如果调用该注解不需要(也可以)赋予参数值。

}

如果只有一个参数值,名字最好是value。

反射

动态语言:在运行时可以改表结构的语言,例如加入新的函数,对象,甚至删除原有代码,主要的语言,c#,PHP,Pyhton

静态语言:java,c,c++

java 利用反射机制可以或得类似的动态语言的特性。

Reflection反射

利用反射机制允许程序在执行期间借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。class c = Class.forName(“java.lang.string”)

加载完类之后,再堆内存的方法区产生了一个Class类型的对象(一个类只有一个class对象),这个对象就包含了类的结构信息,形似一个镜子,看到类的结构,我们称之为反射。

反射方式:实例化对象-getclass()-得到完整的包类的名称

功能:

  1. 在运行时判断任意一个对象所属的类
  2. 在运行时构造任意一个类的对象
  3. 在运行时判断任意一个类的方法和属性
  4. 在运行时获取泛型信息
  5. 在运行时调用任意一个对象的变量和方法
  6. 在运行时处理注解
  7. 生成动态代理

优点:实现动态创建对象和编译,灵活性

缺点:对性能有影响,使用反射是一种解释操作,告诉jv,我们希望做什么,这类操作慢于执行相同的操作。

一个类被加载后类的整个结构都会发封装在Class对象中。

判断是不是属于同一个类:对象.hashcode();相同的话返回值相同

在object类中有getClass()方法,被所有子类继承。

public final Class getClass():返回值是、class类,这个是反射的源头,class的每一个对象都描述了一个定义的普通类。

Class本身也是一个类

Class对象是系统建立

一个加载的类在JVM中只会有一个Class的实例

一个Class对象对应一个加载到JVM的.class文件

每个类的实力都会记得自己是哪个类生成的

通过Class可以得到一个类中的完成结构信息

常用的方法:

static ClassforName(String name):返回指定类名的class对象

Object newInstance():返回class对象的实例

getName():返回名字

Class getSuperClass():返回当前Class对象的父类的Class对象

。。。。

获取class对象的实例

  1. 已知具体类名,Class a = Person.class;
  2. 已知类的实例:Class b = person.getClass()
  3. 已知类的全类名(包名+类名),Class c = Class…forName(“demo.Student”);
  4. 基本内置类型的包装类都有TYPE属性,比如:Integer Class d = Integer.TYPE;

哪些类型有Class对象:

class :外部类,成员内部类,静态内部类,匿名内部类,局部内部类

interface

数组

枚举

注解

基本数据类型

void

一个类只有一个Class对象

对于数组,只要元素类型和维度一样,就是一个Class对象

类内存分析

java内存:

  1. 堆: 存放new的对象和数组,以及可以被所有的线程共享,不会存放别的对象引用
  2. 栈:存放基本数据类型包括基本数据类型的具体数据,以及引用对象的变量(引用在堆里的地址)
  3. 方法去:可以被所有线程共享,包含所有的Class和static(属于特殊的堆)

类的加载过程:

  1. 加载:将类的class字节码(编译之后的)文件读入内存,将静态数据转化为方法区的运行时的数据结构,并创建一个Class对象,由加载器完成 ---------类的加载
  2. 连接: 将类的二进制数据合并到JJVM(1. 验证确保信息规范,2.准备,将类变量static设置初始值(在方法区进行分配),3. 替换,将常量池中引用类型替换为真实引用地址的过程 --------------------类的连接
  3. 初始化: JVM进行类的初始化-,先执行类的构造器方法将类变量和静态代码块合并,初始化类的时候发现父类没初始化,先初始化父类 ,保证类的 方法在多线程中安全 ----类的初始化

什么时候一定发生类初始化:

当类主动引用(一定发生类的初始化)

  1. 当虚拟机启动,先初始化一个main方法所在的类
  2. new一个类的的对象
  3. 调用类的静态成员(除了final常量)和静态方法
  4. 使用类的反射
  5. 初始化一个类,发现其父类没有初始化,要初始化父类

类的被动引用(不会发生类的初始化)

  1. 当访问一个静态域,只有真正声明的这个域的类才会初始化,比如子类调用父类的静态方法或者属性,是不会的,因为在连接阶段已经存在。
  2. 通过数组定义引用
  3. 引用常量不会触发类的初始化(常量在连接阶段就在第用用类的常量池了)
类的加载器

类加载器的作用:将类的class字节码(编译之后的)文件读入内存,将静态数据转化为方法区的运行时的数据结构,并创建一个Class对象,作为方法区类数据的访问入口

类缓存:在类加载器中的类会存在一段时间,不过JVM垃圾回收会回收这些Class对象

分类:

  1. 引导类加载器,C++编写,获取不到,java核心类库
  2. 扩展类加载器,JRE/lib/ext中的jar包
  3. 系统类加载器,当前项目或者目录下

反射的使用:

Class c1 = Class.forName(“包名+类名”)

获取类的信息

名字:

类名:类的对象c1.getName():包名+类名

类的对象c1.getSimpleName():类名

属性:

c1.getFields();只能找到pubic属性

c1.getDeclaredFields():找到全部属性

方法:

c1.getMethods:public

c1.getDeclaredFields():全部

构造方法:

c1.getConstructors(String.clss,int.class,int.class):回传参数时时基本数据类型.class

c1.getDealaredConstuctors

动态创建对象,通过反射:

Class c1 = Class.forName(“包名+类名”)

Object b = c1.newInstance();

类名 b = (类名)c1.newInstance();本质上调用了类的无参构造:

如果类中没有无参构造器,但是有有参构造器,可以通过构造器创建对象:

Constructor constructor = c1.getDealaredConstuctors(String.class,int.class,int.class)

类名 d = (类名)constuctor.newInstance(“sh”,001,002)

不能直接操作私有属性,要改编权限;

ll.setAccessible(true):关闭权限检测

通过反射调用类中的方法:

  1. 类名 m = (类名)c1.newInstance();

  2. Method kkk = c1.getDeclaredMethod(“方法名”,String.class)

//激活方法

不能直接操作私有属性,要改编权限;

ll.setAccessible(true):关闭权限检测

  1. kkk.invoke(m,“shfdhsh”)

  2. 类名 m = (类名)c1.newInstance();

  3. Field ll = c1.getDeclaredFields(“属性名”)

  4. 不能直接操作私有属性,要改编权限;

    ll.setAccessible(true):关闭权限检测

  5. ll.set(m,“hsifhoi”)

你可能感兴趣的:(1.16java学习之反射)