1.反射
- 反射是指对于任何一个Class类,在“运行的时候”都可以直接得到这个类的全部成分;这种运行时动态获取类信息以及动态调用类中成分的能力称为Java的反射机制
- 在运行时获取类的字节码文件对象(Class文件),然后解析类中的全部成分
2.反射获取Class类对象
- 源代码阶段:Class.forName(String className)
- 其中className为全限名:包名+类名
- Class对象阶段:类名.class
- Runtime运行时阶段:对象.getClass()
3.反射获取构造器对象
Class类中用于获取构造器的方法:
方法 | 说明 |
---|---|
Constructor<?>[ ] getConstructors() | 返回所有构造器对象的数组(只能拿public的) |
Constructor<?>[ ] getDeclaredConstructors() | 返回所有构造器对象的数组,存在就能拿到 |
Constructor< T> getConstructor(Class<?>… parameterTypes) | 按照参数类型定位并返回单个构造器对象(只能拿public的) |
Constructor< T> getDeclaredConstructor(Class<?>… parameterTypes) | 返回单个构造器对象,存在就能拿到 |
Constructor类中用于创建对象的方法:
方法 | 说明 |
---|---|
T newInstance(Object… initargs) | 根据指定的构造器创建对象 |
public void setAccessible(boolean flag) | 设置为true,表示取消访问检查(private),进行暴力反射 |
4.反射获取成员变量对象
- 先获取类对象,然后从类对象中获取类的成分对象
Class类中用于获取成员变量的方法:
方法 | 说明 |
---|---|
Field[ ] getFields() | 返回所有成员变量对象的数组(只能拿public) |
Field[ ] getDeclaredFields() | 返回所有成员变量对象的数组,存在就能拿到 |
Field getField(String name) | 返回单个成员变量对象(只能拿public的) |
Field getDeclaredField(String name) | 返回单个成员变量对象,存在就能拿到 |
Field类中用于取值、赋值的方法
方法 | 说明 |
---|---|
void set(Object obj, Object value) | 赋值 |
Object get(Object obj) | 取值 |
如果某成员变量是非public的,需要打开权限进行暴力反射,然后再取值、赋值;setAccessible(boolean)
5.反射获取方法对象
Class类中用于获取成员方法的方法
方法 | 说明 |
---|---|
Method[ ] getMethods() | 返回所有成员方法对象的数组(只能拿public的) |
Method[ ] getDeclaredMethods() | 返回所有成员方法对象的数组,存在就能拿到 |
Method getMethod(String name, Class<?>… parameterTypes) | 返回单个成员方法对象(只能拿public的) |
Method getDeclaredMethod(String name, Class<?>… parameterTypes) | 返回单个成员方法对象,存在就能拿到 |
Method类中用于触发执行的方法
方法 | 说明 |
---|---|
Object invoke(Object obj, Object… args) | 运行方法,参数一:用obj对象调用该方法;参数二:调用方法的传递的参数 |
6.反射的作用–绕过编译阶段为集合添加数据
- 反射是作用在运行时的技术,此时集合的泛型将不能产生约束了,此时是可以为集合存入其他任意类型的元素的
- 泛型只是在编译阶段可以约束集合只能操作某种数据类型,在编译成Class文件进入运行阶段时,其真实类型都是ArrayList了,泛型被擦除
7.反射的作用
- 可以在运行时得到一个类的全部成分然后操作
- 可以破坏封装性(private)(很突出)
- 可以破坏泛型的约束性(很突出)
- 更重要的用途是适合做Java高级框架
8.注解(Annotation)
- 对Java中类、方法、成员变量做标记,然后进行特殊处理
自定义注解—格式
public @interface 注解名称{
public 属性类型 属性名() default 默认值;
}
特殊属性:
- value属性,如果只有一个value属性的情况下,使用value属性的时候可以省略value名称不写
- 但是如果有多个属性,且多个属性没有默认值,那么value名称是不能省略的
元注解:
- @Target:约束自定义注解只能在哪些地方使用(比如只能在方法使用)
- @Retention:申明注解的生命周期
@Target(ElementType.METHOD, ELementType.FIELD)
public @interface MyTest{
}
@Target可使用的值定义在ElementType枚举类中,常用值如下:
- Type:类、接口
- FIELD:成员变量
- METHOD:成员方法
- PARAMETER:方法参数
- CONSTRUCTOR:构造器
- LOCAL_VARIABLE:局部变量
@Retention可使用的值定义在RetentionPolicy枚举类中,常用值如下:
- SOURCE:注解只作用在源码阶段,生成的字节码文件中不存在
- CLASS:注解作用在源码阶段,字节码文件阶段,运行阶段不存在,默认值
- RUNTIME:注解作用在源码阶段,字节码文件阶段,运行阶段 (开发常用)
9.注解的解析
- 判断注解是否存在,存在注解就解析出内容
与注解解析相关的接口:
- Annotation:注解的顶级接口,注解都是Annotation类型的对象
- AnnotatedElement:该接口定义了与注解解析相关的解析方法
方法 | 说明 |
---|---|
Annotation[ ] getDeclaredAnnotations() | 获得当前对象上使用的所有注解,返回注解数组 |
T getDeclaredAnnotation(Class< T> annotationClass) | 根据注解类型获得对应注解对象 |
boolean isAnnotationPresent(Class< Annotation> annotationClass) | 判断当前对象是否使用了指定的注解,如果使用了则返回true,否则false |
解析注解的技巧:
- 注解在哪个成分上,我们就要先拿哪个成分对象
- 成员方法:先获得该成员方法对应的Method对象,再拿上面的注解
10.动态代理
如何创建代理对象:
- Java中代理的代表类是:java.lang.reflect.Proxy
- Proxy提供了一个静态方法,用于为对象产生一个代理对象返回
public static Object newProxyInstance(ClassLoader loader, Class<?>[ ] interfaces, InvocationHandler h)
为对象返回一个代理对象
参数一:定义代理类的类加载器
参数二:代理类要实现的接口列表
参数三:将方法调用分派到的处理程序(代理对象的核心处理程序)
下面是为一个实现Skill接口的Star类的代理类StarAgentProxy
public class StarAgentProxy{
public static Skill getProxy(Star obj){
return (Skill) Proxy.newProxyInstance(obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(), new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[ ] args) throws Exception{
System.out.println("收首付款"); //代理做的
Object rs = method.invoke(obj, args); //真正对象做的
System.out.println("收尾款,把明星接回来"); //代理做的
return rs;
}
});
}
前两个参数都是固定的,第三个需要自己重写,代理类也都实现了原始类的接口,因为想要调用原始类的方法时都得通过代理类进行
实现动态代理:
- 必须存在接口
- 被代理对象需要实现接口
- 使用Proxy类提供的方法,得到对象的代理对象
当左右方法前面需要干的事情和后面需要干的事情一致时,我们可以考虑使用代理,例如测试每个方法的运行时间。而且可扩展性超级强,之后原对象里再添加方法,可以直接走代理
11.动态代理的优点
- 可以在不改变方法源码的情况下,实现对方法功能的增强,提高了代码的复用
- 简化了编程工作,提高了开发效率,以高了软件系统的可扩展性
- 可以为被代理对象的所有方法做代理
- 非常灵活,支持任意接口类型的实现类对象做代理(将Skill类型改成泛型< T>,也可以为接口本身做代理
12.XML
XML特点和使用场景:
- 一是纯文本,默认使用UTF-8;二是可嵌套
- 使用场景:XML内容经常被当成消息进行网络传输,或者作为配置文件用于存储系统的信息
XML的语法规则
- 文档声明必须是第一行
<?xml version="1.0" encoding="UTF-8" ?>
version:XML默认的版本号码
encoding:本XML文件的编码
XML的标签(元素)规则
- 标签由一对尖括号和合法标识符组成:< name>< /name>,必须存在一个根标签,有且只能有一个
- 标签必须成对出现,有开始,有结束
- 特殊的标签可以不成对,但是必须有结束标记,如:< br/>
- 标签中可以定义属性,属性和标签名空格隔开,属性值必须用引号引起来< student id=“1”>< /student>
XML的其他组成
- XML文件中可以定义注释信息:< !-- 注释内容 -->
- XML文件中可以存在以下特殊字符
< < 小于
> > 大于
& & 和号
' ' 单引号
" " 引号
- XML文件中可以存在CDATA区:<![CDATA[ ...内容... ]]>(里面的内容可以随便写,不用担心冲突)
13.文档约束
- 用来限定xml文件中的标签以及属性应该怎么写。
- 分类:DTD和schema
DTD
- 可以约束格式,但不能约束数据类型
schema
- 可以约束具体的数据类型,约束能力上更强大
- 后缀是.xsd(xml schema 约束)
14.XML解析技术
- SAX解析:一行行解析,适合大文件
- DOM解析(dom4j):将整个文件加载到内存,适合小文件
Dom解析的文档对象模型:
- Document对象:整个xml文档
- Element对象:标签
- Attribute对象:属性
- Text对象:文本内容
- Element、Attribute、Text三者都是Node对象
15.Dom4j:用于解析数据
得到Document对象:
SAXReader类
方法 | 说明 |
---|---|
public SAXReader() | 创建Dom4J的解析器对象 |
Document read(String url) | 加载XML文件成为Document对象 |
Document类
方法 | 说明 |
---|---|
Element getRootElement() | 获取根元素对象 |
Dom4j解析XML的元素、属性、文本
方法名 | 说明 |
---|---|
List< Element> elements() | 得到当前元素下所有一级子元素 |
List< Element> elements(String name) | 得到当前元素下指定名字的子元素返回集合 |
Element element(String name) | 得到当前元素下指定名字的子元素,如果重名返回第一个 |
String getName() | 得到元素名字 |
String attributeValue(String name) | 通过属性名直接得到属性值 |
String elementText(子元素名) | 得到指定名称的子元素的文本 |
String getText() | 得到文本 |
16.XPath:进行信息检索
使用Xpath检索XML文件:
- 导入jar包(dom4j和jaxen-1.1.2.jar),Xpath技术依赖Dom4j技术
- 通过dom4j的SAXReader获取Document对象
- 利用Xpath提供的API,结合XPath的语法完成选取XML文档元素进行节点解析操作
- Document中与Xpath相关的API如下:
方法名 | 说明 |
---|---|
Node selectSingleNode(“表达式”) | 获取符合表达式的唯一元素 |
List< Node> selectNodes(“表达式”) | 获取符合表达式的元素集合 |
XPath:绝对路径
- 采用绝对路径获取从根节点开始逐层的查找
方法名 | 说明 |
---|---|
/根元素/子元素/孙元素 | 从根元素开始,一级一级向下查找,不能跨级 |
XPath:相对路径
- 先得到根节点,在采用相对路径一级一级向下查找
方法名 | 说明 |
---|---|
./子元素/孙元素 | 从当前元素开始,一级一级向下查找,不能跨级 |
XPath:全文搜索
- 直接全文搜索所有的name元素并打印
方法名 | 说明 |
---|---|
//name | 找名称为name的元素,无论元素在哪里 |
//contact/name | 找contact,无论在哪一级,但name一定是contact的子节点 |
//contact//name | contact无论在哪一种,name只要是contact的子孙元素都可以找到 |
XPath:属性查找
- 在全文中搜索属性,或者带属性的元素
方法名 | 说明 |
---|---|
//@属性名 | 查找属性对象,无论是哪个元素,只要有这个属性即可 |
//元素[@属性名] | 查找元素对象,全文搜索指定元素名和属性名 |
//元素[@属性名=‘值’] | 查找元素对象,全文搜索指定元素名和属性名,并且属性值相等 |