一、反射
1.1 反射概念
- 概念:反射式先获取对象,由对象中的指定方法,获取其指定类中的成员方法、成员属性和构造方法。
- 对象:反射中的对象全部指的是字节码对象,字节码对象称为Class类声明的对象。
1.2 获取字节码对象的方法
- 方式1:通过类名.class获取
Class<?> clazz = 类名.class举例:Class<?> clazz = Person.class;
- 方式2:通过该类的对象获取字节码对象
类名 对象 = new 类名();Class<?> clazz = 对象.getClass();//举例:Person p1 = new Person();Class<?> clazz = p1.getClass();
- 使用Class类中提供的静态方法,可以通过类名的全路径获取字节码对象,推荐方式
Classs<?> clazz = Class.forName("类的全路径");//举例:Class<?> clazz = Class.forName("com.woniuxy.demo.Person");
1.3 反射涉及的方法
- 使用反射获取构造方法
//1、获取公共的构造方法,后面的参数,填写的是构造方法的数据类型的字节码对象,如果想要调用无参构造传入null即可,也可以直接空着getConstructor(Class<?>...parameterTypes);//2、获取私有的构造方法,后面的参数,填写的是构造方法的数据类型的字节码对象,如果想要调用无参构造传入null即可,也可以直接空着getDeclaredConstrcutor(Class<?>...parameterTypes);//注意:如果是私有的构造方法,需要在破解私有,使用方法c.setAccessible(true);//通过Class字节码对象调用获取构造方法的方法,获取的是构造方法的对象,用该对象执行newInstance()对应的对象,后面的参数表示:对应构造方法需要的实际参数,这个参数和上面的getConstructor()方法中的数据类型参数要对应newInstance(Object...initiargs);
- 使用反射获取成员方法
//1、获取公共的成员方法,括号里面由两个参数组成部分,第一个参数表示方法名称,第二个是可变参数,用于传递方法的形式参数数据类型的字节码对象.getMethod(String name,Class<?>...parameterTypes);//2、获取私有的成员方法,,括号里面由两个参数组成部分,第一个参数表示方法名称,第二个是可变参数,用于传递方法的形式参数数据类型的字节码对象.getDeclaredMethod(String name,Class<?>...parameterTypes);//需要破解method.setAccessible(true);//在Method类中,定义了invoke方法,该方法用于执行字节码对象对应的对象的成员方法//第一个参数:对应类的对象//第二个参数:对应方法需要的实际参数,需要和Method中的形式参数对应invoke(Object obj,Object...args);
- 获取成员属性
//1、获取公有的成员属性,括号中的参数表示成员属性的名称getField(String name)//2、获取私有的成员属性,括号中的参数表示成员属性的名称getDeclaredField(String name)//需要破解私有method.setAccessible(true);//在Field类中,定义了get(object obj)方法,用于获取字节码对象对应类中的成员属性值//参数:哪一个对象进行调用成员属性get(Object obj)
二、XML文件
2.1 概念
XML文件的全称可扩展的标记语言,XML文件由一些标签组成,可扩展的标签,标签和属性可以自定义,程序员可以根据自己的实际需求定义标签、属性及语言结构
XML文件本质上用来作为配置文件使用,和之前的文件:properties配置文件,txt文件作用类似,在实际开发中,一般数据的结构都是比较复杂的层级结构,比如: ```xml
<四川> <成都> <金牛区></金牛区> <武侯区></武侯区> <青羊区></青羊区> </成都> </四川> <重庆> <渝北区></渝北区> <渝中区></渝中区> <江北区></江北区> </重庆>
<field><field-name></field-name><field-type></field-type></field></class><class><class-name></class-name></class>
<a name="14963c09"></a>#### 2.2 XML文件的组成1.声明:每一个xml文件声明部分必须顶格,不能允许任何内容出现,也不能出现注释```xml<?xml version="1.0" encoding="utf-8" ?>
- 注释内容
<!--注释的内容部分,可以多行-->
- 标签:将单词或者单词组合放在尖括号里面,在两个尖括号之间可以存放文本内容,标签名称自定义
<name></name>
- 属性:在开始标签里面,新增的属性名称和属性值,属性名称自定义即可
<user name = "李四" age = "18"></user>
- 转义字符:因为标记语言和某些运算发存在冲突,因此需要直接显示运算符,需要转义
&---->&>----->大于符号<----->小于符号
- 内容部分:在两个标签之间的文本,称为内容部分
<user><user-name>张三</user-name><user-age>18</user-age></user>
- CDATA区:数据区,一般来说,如果想要在页面展示标签内容,需要CDATA区
2.3 XML解析
DOM解析方式:使用DOM解析方式,一开始会将所有的XML文件标签全部解析到内存中,生成文档树结构
优点:解析速度快
缺点:耗内存SAX解析方式:按需解析,需要使用到哪一个标签,然后解析到哪一个标签,没有涉及到的标签不解析
优点:内存消耗小
缺点:解析速度慢
2.4 XML解析的操作
步骤:
public class XMLDemo1 {public static void main(String[] args) throws Exception{//1、获取工厂DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();//2、通过工厂获取解析器DocumentBuilder builder = factory.newDocumentBuilder();//3、通过解析器获取文档树Document document = builder.parse(new File("src/user.xml"));System.out.println(document);}}
获取元素
public class QueryElement {public static void main(String[] args) throws Exception{//1、获取工厂DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();//2、获取解析器DocumentBuilder builder = factory.newDocumentBuilder();//3、获取文档树Document document = builder.parse(new File("src/user.xml"));//获取指定的标签,如果根据标签名称获取,则表示获取的是相同标签名的集合NodeList nodeList = document.getElementsByTagName("user-name");//从集合中获取指定的标签Node node = nodeList.item(0);//获取节点中的文本内容String text = node.getTextContent();System.out.println(text);}}
修改元素
public class UpdateElement {public static void main(String[] args) throws Exception{//1、获取工厂DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();//2、获取解析器DocumentBuilder builder = factory.newDocumentBuilder();//3、获取文档树Document document = builder.parse(new File("src/user.xml"));//根据标签名称获取标签NodeList nodeList = document.getElementsByTagName("user-name");//获取指定的标签Node node = nodeList.item(0);//修改文本属性值node.setTextContent("张三四");//获取转换流的工厂对象TransformerFactory transformerFactory = TransformerFactory.newInstance();//将工厂对象获取转换器Transformer transformer = transformerFactory.newTransformer();//将内存中的文档树更新到硬盘中/*第一个参数:表示内存中的文档树,作为源数据第二个参数:表示结果树,作为硬盘中的结果*/transformer.transform(new DOMSource(document),new StreamResult(new File("src/user.xml")));}}
新增元素
第一种方式:在指定的父标签下,新增子标签,只能新增在最后位置public class CreateElement {public static void main(String[] args) throws Exception{//获取工厂DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();//获取解析器DocumentBuilder builder = factory.newDocumentBuilder();//获取文档树Document document = builder.parse(new File("src/user.xml"));//新增标签Element e = document.createElement("account");e.setTextContent("1000");//找到要放入的父标签NodeList nodeList = document.getElementsByTagName("u");Node parent = nodeList.item(0);//将新增标签挂载到父标签内parent.appendChild(e);//更新到硬盘中TransformerFactory transformerFactory = TransformerFactory.newInstance();Transformer transformer = transformerFactory.newTransformer();transformer.transform(new DOMSource(document),new StreamResult(new File("src/user.xml")));}}
第二种方式:想要将新标签放置在指定父标签下的任意位置
public class CreateElement {public static void main(String[] args) throws Exception{method2();}public static void method2() throws Exception{//获取工厂DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();DocumentBuilder builder = factory.newDocumentBuilder();Document document = builder.parse(new File("src/user.xml"));//新增标签Element e = document.createElement("tel");e.setTextContent("1100");//获取要放入新标签的后面的兄弟标签NodeList nodeLlist = document.getElementsByTagName("user-age");Node node = nodeLlist.item(0);//获取父标签NodeList list = document.getElementsByTagName("u");Node parent = list.item(0);//通过父标签添加子标签,需要指定位置/*第一个参数:兄弟节点第二个参数:要放入新节点的后面兄弟节点*/parent.insertBefore(e,node);//将内存中的数据写出到硬盘中TransformerFactory transformerFactory = TransformerFactory.newInstance();Transformer transformer = transformerFactory.newTransformer();transformer.transform(new DOMSource(document),new StreamResult(new File("src/user.xml")));}}
删除元素
public class DeleteElement {public static void main(String[] args) throws Exception{//获取文档树DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();DocumentBuilder builder = factory.newDocumentBuilder();Document document = builder.parse(new File("src/user.xml"));//获取指定元素标签NodeList nodeList = document.getElementsByTagName("tel");Node node = nodeList.item(0);//删除node.getParentNode().removeChild(node);//更新到硬盘中TransformerFactory transformerFactory = TransformerFactory.newInstance();Transformer transformer = transformerFactory.newTransformer();transformer.transform(new DOMSource(document),new StreamResult(new File("src/user.xml")));}}
将公共的部分抽取成工具类
public class XMLUtils {public static Document getNode(String fileName) throws Exception{//获取文档树DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();DocumentBuilder builder = factory.newDocumentBuilder();Document document = builder.parse(new File(fileName));return document;}public static void flushData(String fileName,Document document) throws Exception{TransformerFactory transformerFactory = TransformerFactory.newInstance();Transformer transformer = transformerFactory.newTransformer();transformer.transform(new DOMSource(document),new StreamResult(new File(fileName)));}}
2.5 用xml文件封装JDBC工具类
public class JDBCUtils {//声明四个变量private static String driver;private static String url;private static String username;private static String password;//使用静态代码块实现获取xml文件中的数据及注册驱动static{try {//读取xml配置文件Document document = XMLUtils.getNode("src/db.xml");driver = document.getElementsByTagName("driver").item(0).getTextContent();url = document.getElementsByTagName("url").item(0).getTextContent();username = document.getElementsByTagName("username").item(0).getTextContent();password = document.getElementsByTagName("password").item(0).getTextContent();//注册驱动Class.forName(driver);}catch (Exception e){e.printStackTrace();}}//获取连接public static Connection getConn(){try {return DriverManager.getConnection(url,username,password);}catch (Exception e){e.printStackTrace();}return null;}//关闭资源public static void close(Object...args){try {if(args.length == 3 && args[2] != null){ResultSet rs = (ResultSet) args[2];rs.close();}if(args[1] != null){PreparedStatement ps = (PreparedStatement) args[1];ps.close();}if(args[0] != null){Connection conn = (Connection)args[0];conn.close();}}catch (Exception e){e.printStackTrace();}}}
三、拓展
3.1、单元测试junit
测试分为白盒和黑盒测试
黑盒:关注的是结果
百盒: 关注的是过程(会对每一句代码进行测试)—需要技术要求
junit属于白盒测试的一种,需要提供第三方jar包
步骤
1 引入jar2 写一个测试类(XxxTest),严禁取名叫Test3 写测试方法(TestXxx) ,严禁取名叫Test4 选中要测试的方法名,右键run as --- junit test4.5 如果要测所有方法,直接再空白处右键run as --- junit test5 运行后:绿色:正确无误红色:有错误注意:测试用的方法的权限修饰符必须是public注意:测试方法没有返回值和形参
语法:@Beforepublic void 方法名(){} 能够再@Test方法之前执行@Afterpublic void 方法名(){} 能够再@Test方法之后执行
3.2、断言
语法:
Assert.assertEquals(期望值,真实值);判断两个值是否相等,如果不相等,报错
@Testpublic void testAdd(){User u=new User();int sum=u.add(1, 2);Assert.assertEquals(4, sum);}
3.3、三种方式获取properties文件的数据
方式1:ResourceBundle
我们需要把properties文件放在src下,相对于src
如果是放在src下的xx包中:ResourceBundle.getBundle("xx/db");ResourceBundle.getBundle("xx.db");
ResourceBundle rb = ResourceBundle.getBundle("db");String root = rb.getString("user");System.out.println(root);
方式2: 通过流+properties对象
properties文件放在项目根目录,相对与项目根目录
如果是直接放在根目录:db.properties
如果是放在根目录下的xx文件夹:xx/db.properties
如果是放在src: src/db.properties
FileReader fr=new FileReader(new File("db.properties"));// FileInputStream fis=new FileInputStream(new File("db.properties"));//集合Properties pro=new Properties();pro.load(fr);System.out.println(pro.getProperty("user"));System.out.println(pro.getProperty("password"));
方式3: 通过类加载器搭配properties
//通过某个类的类加载器去读取流InputStream in = Demo3.class.getClassLoader().getResourceAsStream("db.properties");//集合Properties pro=new Properties();pro.load(in);System.out.println(pro.getProperty("user"));System.out.println(pro.getProperty("password"));
