七 JAVA反射
7.1类的加载概述和加载时机
A:类的加载概述
当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。
1)加载
就是指将class文件读入内存,并为之创建一个Class对象。任何类被使用时系统都会建立一个Class对象。
2)连接
验证 是否有正确的内部结构,并和其他类协调一致
准备 负责为类的静态成员分配内存,并设置默认初始化值
解析 将类的二进制数据中的符号引用替换为直接引用
初始化 就是我们以前讲过的初始化步骤
B:加载时机
创建类的实例
访问类的静态变量,或者为静态变量赋值
调用类的静态方法
使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
初始化某个类的子类
直接使用java.exe命令来运行某个主类
7.2类加载器的概述和分类
A:类加载器的概述
负责将.class文件加载到内存中,并为之生成对应的Class对象。虽然我们不需要关心类加载机制,但是了解这个机制我们就能更好的理解程序的运行。
B:类加载器的分类
Bootstrap ClassLoader 根类加载器
Extension ClassLoader 扩展类加载器
Sysetm ClassLoader 系统类加载器
C:类加载器的作用
Bootstrap ClassLoader 根类加载器
也被称为引导类加载器,负责Java核心类的加载
比如System,String等。在JDK中JRE的lib目录下rt.jar文件中
Extension ClassLoader 扩展类加载器
负责JRE的扩展目录中jar包的加载。
在JDK中JRE的lib目录下ext目录
Sysetm ClassLoader 系统类加载器
负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径
7.3反射概述
Java反射机制:XxxYyy.class -->XxxYyy.java(框架)
1)JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
2)对于任意一个对象,都能够调用它的任意一个方法和属性;
3)这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
4)要想解剖一个类,必须先要获取到该类的字节码文件对象。
5)而解剖使用的就是Class类中的方法,所以先要获取到每一个字节码文件对应的Class类型的对象。
Java反编译技术:基于Java反射机制的实现
反编译工具/逆向工程工具
反射是Java自我管理的机制
可以通过反射机制发现对象的类型 发现类型的方法/属性/构造器
Java 反射 访问任意对象方法和属性等
Class 加载
类加载到内存: java 将磁盘类文件加载到内存中,为一个对象(实例)
这个对象是Class的实例, 也就是 这些对象都是Class实例
5)Class 实例获得
Class cls = String.class;
Class cls = Class.forName(“java.lang.String”);
Class cls = “abc”.getClass();
获取字节码对象的三种方式,返回的字节码对象都是唯一的
7.4 反射案例
1发现类的方法,属性,构造方法
1)首先获取字节码对象 2):通过字节码对象获取全部的属性方法等
public void call(Object obj){
Class> cla=obj.getClass();
System.out.println("----------------------->输出所有的属性");
Field[] fields = cla.getDeclaredFields();
StringBuilder sb=new StringBuilder();
for (Field field:fields) {
sb.append(Modifier.toString(field.getModifiers())+" ");
sb.append(subStrings(field.getType())+" ");
sb.append(field.getName()+"\n");
}
System.out.println(sb);
System.out.println("----------------------->输出所有的构造方法");
Constructor>[] constructors = cla.getDeclaredConstructors();
StringBuilder sb2=new StringBuilder();
for (Constructor> c : constructors) {
sb2.append(Modifier.toString(c.getModifiers())+" ");
sb2.append(subStrings(cla)+" (");
Class>[] type = c.getParameterTypes();
for (Class> typeVariable : type) {
sb2.append(subStrings(typeVariable)+",");
}
if(type.length!=0){
sb2.deleteCharAt(sb2.length()-1);
}
sb2.append("){} \n");
}
System.out.println(sb2);
System.out.println("----------------------->输出所有的方法");
Method[] methods = cla.getDeclaredMethods();
StringBuilder sb3=new StringBuilder();
for (Method method : methods) {
sb3.append(Modifier.toString(method.getModifiers())+" ");
sb3.append(subStrings(method.getReturnType())+" ");
sb3.append(method.getName()+"(");
Class>[] types = method.getParameterTypes();
for (Class> class1 : types) {
sb3.append(subStrings(class1)+",");
}
if(types.length!=0){
sb3.deleteCharAt(sb3.length()-1);
}
sb3.append("){} \n");
}
System.out.println(sb3);
}
//字符串截取
public String subStrings(Class> type){
String str=type.toString();
return str.substring(str.lastIndexOf(".")+1);
}
2调用类的属性,方法,构造方法
public void result(Object object){
System.out.println("----------------------->调用类的属性");
Class> cla=object.getClass();
Field field = cla.getDeclaredField(“type”);
field.set(object, “拉布拉多”);
Field field2 = cla.getDeclaredField(“age”);
field2.setAccessible(true);
field2.set(object, 5);
Field field3 = cla.getDeclaredField(“name”);
field3.set(object, “九月”);
System.out.println(object);
System.out.println("----------------------->调用类的构造方法");
Class>[] parameterTypes={String.class,int.class,String.class};
Constructor> constructor = cla.getDeclaredConstructor(parameterTypes);
Object newInstance = constructor.newInstance(new Object[]{"十月",10,"泰迪"});
System.out.println(newInstance);
System.out.println("----------------------->调用类的方法");
Class>[] types={String.class,int.class};
Method method = cla.getDeclaredMethod("print", types);
Object []agrs ={"泰迪",5};
System.out.println(method.invoke(object,agrs ));
}
八JAVA配置文件解析
8.1 配置文件类型properties与xml
properties属性文件:简单的数据源,只能是字母和数字
文件后缀名必须是xxx.properties
工具类ConfigUtils:专门用来加载属性文件
xml文件:框架使用
8.2配置文件对比
1、从结构上来说:
.xml文件主要是树形结构。
.properties文件主要是以key-value键值对的形式存在。
2、从灵活程度上来说:
.xml格式的文件要比.properties格式的文件更灵活一些
.properties格式的文件已键值对形式存在,主要就是赋值,而且只能赋值,不能够进行其他的操作。
.xml格式的文件可以有多种操作方法,例如添加一个属性,或者做一些其他的定义等。
3、从使用便捷程度来说:
.properties格式的文件要比.xml文件配置起来简单一些。
配置.properties只需要简单的getProperty(key)方法或者setProperty(key,value)方法就可以读取或者写入内容;
.配置.xml文件的时候通常要查看文档,因为配置比较繁琐,花费时间长才可以配置完整。
4、从应用程度上来说:
.properties文件比较适合于小型简单的项目。
.xml文件适合大型复杂的项目,因为它比较灵活。
8.3文件解析
1)Java里面的配置文件解析
properties文件:属性文件
2)xml文件:
DOM解析,SAX解析(Java基础解析方式)
DOM4J解析:扩展解析,Java里面使用频繁
PULL解析:扩展解析,Android SDK自带的解析方法
3)dom4j:dom for Java
第三方的Jar,必须引入到工程里面
项目根目录新建文件夹lib,复制dom4j.Jar包到lib,右键Build path,添加到项目
4)dom4j解析xml文件
1.获取SAXReader解析器
2.调用sax.read(is)方法返回Document对象
3.调用Document的getRootElement()方法返回根元素Element
4.调用Element的elements(“new”)返回List集合
5.遍历List集合获取属性值和元素值
List arrList=ele.attributes():获取属性值
ele.elementText(“title”):获取元素值
5)dom4j生成xml文件
1.通过DocumentHelper创建空xml文档对象Document
2.通过Document的addElement(“news”)方法添加节点元素Element
3.通过循环向节点添加数据
4.XMLWriter writer=new XMLWriter(os);
参考代码:
/**dom4j解析xml文件:工具类 */
public class Dom4jParseXmlUtils {
/**dom4j解析xml文件
* @param is 输入流
* @return
*/
public static List parse(InputStream is){
List lists=new ArrayList();
//1.获取SAXReader解析器
SAXReader sax=new SAXReader();
//调用sax.read(is)方法返回Document对象
try {
Document doc=sax.read(is);
//3.调用Document的getRootElement()方法返回根元素Element
Element rootEle=doc.getRootElement();
//4.通过根元素rootEle获取指定子元素
List eles = rootEle.elements(“new”);
//5.循环遍历每个Element,获取数据,封装到New对象
for (Element ele : eles) {
New newInfo=new New();
//获取元素的内容
String title=ele.elementText(“title”);
newInfo.setTitle(title);
String detail=ele.elementText(“detail”);
newInfo.setDetail(detail);
String comment=ele.elementText(“comment”);
newInfo.setComment(Long.parseLong(comment));//“89899”–>89899
String image=ele.elementText(“image”);
newInfo.setImage(image);
lists.add(newInfo);
}
return lists;
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}