第7章 Java反射与注解

注解Annotation

Annotation的作用

不是程序本身,可以对程序做出解释(这一点和注释没有什么区别)
可以被其它程序,比如编译器读取

Annotation的格式

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

Annotation使用位置

可以附加在package、class、method、field等上面,相当于给他们添加了额外的辅助信息
通过反射机制变成实现对这些元数据的控制

内置注解

@Override:定义在 java.lang.Override中,此注释只适用于修饰方法,表示一个方法声明打算重写超类中的另一个方法声明
实现一个新的方法
加上@Override注解后,表明这个方法可以被覆盖、重写

@Deprecated:定义在java.lang.Deprecated中,此注释可以用于修饰方法,属性,类,表示不鼓励程序员使用这样的元素,通常是因为它很危险,或者存在更好的选择
@SuppressWarnings:定义在java.lang.SuppressWarnings中,用来抑制编译时的警告信息,与前面的两个注释不同,你需要额外添加一个参数才能正确使用,这些参数都是已经定义好了的,我们选择性的使用就好了。
@SuppressWarnings(“all”)
@SuppressWarnings(“unchecked”)
@SuppressWarnings(value={“unchecked”, “deprecation”})

元注解

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

这些类型和它们所支持的类在 java.lang.annotation包可以找到
@Target 、@Retention、@Documented、@Inherited

@Target:用于描述注解的使用范围,即:被描述的注解可以在什么地方使用
@Retention:表示需要什么保存该注释信息,用于描述注解的生命周期
级别范围:Source < Class < Runtime
@Document:说明该注解被包含在java doc中 (Java 说明文档)
@Inherited:说明子类可以集成父类中的注解

自定义注解

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

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

设置后自动生成的注解

/**
 * 自定义注解
 *
 * @author: Larray
 * @create: 2020-03-28-22:57
 */

2.反射机制

动态语言与静态语言

动态语言

动态语言是一类在运行时可以改变其结构的语言:例如新的函数,对象,甚至代码可以被引进,已有的函数可以被删除或是其它结构上的变化。通俗点说就是在运行时代码可以根据某些条件改变自身结构

主要的动态语言有:Object-c、C#、JavaScript、PHP、Python等

静态语言

与动态语言相比,运行时结构不可变的语言就是静态语言。例如Java、C、C++

Java不是动态语言

,但是Java可以称为“准动态语言”。即Java有一定的动态性,我们可以利用反射机制来获取类似于动态语言的 特性,Java的动态性让编程的时候更加灵活。

Java反射机制

反射:正常方式的逆过程
在这里插入图片描述

什么是反射
Java Reflection:Java反射是Java被视为动态语言的关键,反射机制运行程序在执行期借助于Reflection API 去的任何类内部的信息,并能直接操作任意对象的内部属性及方法。

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

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

反射可以获取到private修饰的成员变量和方法

反射的应用

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

Java反射的优缺点

优点:可以实现动态创建对象和编译,体现出很大的灵活性
缺点:对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求,这类操作总是慢于直接执行相同的操作。也就是说new创建和对象,比反射性能更高

反射的主要API

java.lang.Class:代表一个类
java.lang.reflect.Method:代表类的方法
java.lang.reflect.Field:代表类的成员变量
java.lang.reflect.Constructor:代表类的构造器

API(Application Programming Interface)

应用程序接口(英语:Application Programming Interface,简称:API),又称为应用编程接口,就是软件系统不同组成部分衔接的约定。由于近年来软件的规模日益庞大,常常需要把复杂的系统划分成小的组成部分,编程接口的设计十分重要。程序设计的实践中,编程接口的设计首先要使软件系统的职责得到合理划分。良好的接口设计可以降低系统各部分的相互依赖,提高组成单元的内聚性,降低组成单元间的耦合程度,从而提高系统的维护性和扩展性。

/**
 * 反射Demo
 *
 * @author: Larry
 * @create: 2020-03-29-8:21
 */
public class ReflectionDemo {
    public static void main(String[] args) throws ClassNotFoundException {
        // 通过反射获取类的Class对象
        Class c1 = Class.forName("com.ctgu.entity.User");
        Class c2 = Class.forName("com.ctgu.entity.User");
        Class c3 = Class.forName("com.ctgu.entity.User");

        System.out.println(c1.hashCode());
        System.out.println(c2.hashCode());
        System.out.println(c3.hashCode());

    }
}

通过对象来获取到它的Class,相当于逆过程。

Class本身也是一个类

Class对象只能由系统建立对象
一个加载的类在JVM中只会有一个Class实例
一个Class对象对应的是一个加载到JVM中的一个.class文件
每个类的实例都会记得自己是由哪个Class实例所生成
通过Class可以完整地得到一个类中所有被加载的结构
Class类是Reflection的根源,针对任何你想动态加载、运行的类、唯有先获得相应的Class对象

Class类常用的方法

ClassforName(String name):返回指定类name的Class对象
newInstance():调用缺省构造函数,返回Class对象的一个实例
getName():返回此Class对象所表示的实体(类,接口,数组或void)的名称
getSuperClass():返回当前Class对象的父类Class对象
getinterfaces():返回当前对象的接口
getClassLoader():返回该类的类加载器
getConstructors():返回一个包含某些Constructor对象的数组
getMethod(String name, Class… T):返回一个Method对象,此对象的形参类型为paramsType
getDeclaredFields():返回Field对象的一个数组

获取对象实例的方法

若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高
Class clazz = Person.class;
已知某个类的实例,调用该实例的getClass()方法获取Class对象
Class clazz = person.getClass()
已经一个类的全类名,且该类在类路径下,可以通过Class类的静态方法forName()获取,HIA可能抛出ClassNotFoundException
Class clazz = Class.forName(“demo01.Sutdent”)
内置数据类型可以直接通过 类名.Type
还可以利用ClassLoader

在这里插入图片描述

哪些类型可以有Class对象?

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

interface:接口

[]:数组

enum:枚举

annotation:注解@interface

primitive type:基本数据类型

void

在这里插入图片描述

3.Java内存分析

java内存分为以下三部分


存放new的对象和数组
可以被所有的线程共享,不会存放别的对象引用

存放基本变量(会包含这个基本类型的具体数值)
引用对象的变量(会存放这个引用在对堆里面的具体地址)
方法区
可以被所有线程共享
包含了所有的class和static变量

在这里插入图片描述

JVM(Java Virtual Machine)

JVM是Java Virtual Machine(Java虚拟机)的缩写,它是整个java实现跨平台的最核心的部分,所有的java程序会首先被编译为.class的类文件,这种类文件可以在虚拟机上执行,也就是说class并不直接与机器的操作系统相对应,而是经过虚拟机间接与操作系统交互,由虚拟机将程序解释给本地系统执行。

JRE(java runtime environment)

JRE是java runtime environment(java运行环境)的缩写。光有JVM还不能让class文件执行,因为在解释class的时候JVM需要调用解释所需要的类库lib。在JDK的安装目录里你可以找到jre目录,里面有两个文件夹bin和lib,在这里可以认为bin里的就是jvm,lib中则是jvm工作所需要的类库,而jvm和lib合起来就称为jre。

JDK(java development kit)

JDK是java development kit(java开发工具包)的缩写。每个学java的人都会先在机器上装一个JDK,那 让我们看一下JDK的安装目录。在目录下面有六个文件夹、一个src类库源码压缩包、和其他几个声明文件。其中,真正在运行java时起作用的是以下四个文件夹:bin、include、lib、jre。现在我们可以看出这样一个关系,JDK包含JRE,而JRE包含JVM。

什么时候发生类初始化

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

当虚拟机启动,先初始化main方法所有在类
new 一个类的对象
调用类的静态成员(除了 final常量)和静态方法
使用 java.lang.reflect包的方法对类进行反射调用
当初始化一个类,如果其父类没有被初始化,则会先初始化它的父类

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

当访问一个静态域时,只有真正的申明这个域的类才会被初始化,如:当通过子类引用父类的静态变量,不会导致子类初始化
通过数组定义类引用,不会触发此类的初始化
引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池了)

类加载的作用

类加载的作用:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成了一个代表这个类的 java.lang.Class对象,作为方法区中类数据的访问入口。
类缓存:标准的JavaSE类加载器可以按要求查找类,但是一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间。不过JVM垃圾回收机制可以回收这些Class对象在这里插入图片描述

在这里插入图片描述

双亲委派机制

定义一个:java.lang.string 包,无法创建

因为类在加载的时候,会逐级往上

也就是说当前的系统加载器,不会马上的创建该类,而是将该类委派给 扩展类加载器,扩展类加载器在委派为根加载器,然后引导类加载器去看这个类在不在能访问的路径下,发现 string包已经存在了,所以就无法进行,也就是我们无法使用自己自定义的string类,而是使用初始化的stirng类

当一个类收到了类加载请求,他首先不会尝试自己去加载这个类,而是把这个请求委派给父类去完成,每一个层次类加载器都是如此,因此所有的加载请求都应该传送到启动类加载其中,只有当父类加载器反馈自己无法完成这个请求的时候(在它的加载路径下没有找到所需加载的Class),子类加载器才会尝试自己去加载。

采用双亲委派的一个好处是比如加载位于rt.jar 包中的类java.lang.Object,不管是哪个加载器加载这个类,最终都是委托给顶层的启动类加载器进行加载,这样就保证了使用不同的类加载器最终得到的都是同样一个Object 对象

反射操作泛型

Java采用泛型擦除机制来引入泛型,Java中的泛型仅仅是给编译器Java才使用的,确保数据的安全性和免去强制类型转换的问题,但是一旦编译完成后,所有的泛型有关的类型全部被擦除

为了通过反射操作这些类型,Java新增了ParameterizedType,GenericArrayType,TypeVariable和WildcardType几种类型来代表不能被归一到Class类中的类型但是有何原始类型齐名的类型。

ParameterizedType:表示一种参数化类型,比如Collection
GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型
TypeVariable:是各种类型变量的公共父接口
WildcardType:代表一种通配符类型的表达式

映射工程

ORM对象关系映射,可实现增删改查的功能

ORM(Object relationship Mapping)

即为:Object relationship Mapping,对象关系映射

类和表结构对应
属性和字段对应
对象和记录对应

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值