一、反射
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 引入jar
2 写一个测试类(XxxTest),严禁取名叫Test
3 写测试方法(TestXxx) ,严禁取名叫Test
4 选中要测试的方法名,右键run as --- junit test
4.5 如果要测所有方法,直接再空白处右键run as --- junit test
5 运行后:
绿色:正确无误
红色:有错误
注意:测试用的方法的权限修饰符必须是public
注意:测试方法没有返回值和形参
语法:
@Before
public void 方法名(){} 能够再@Test方法之前执行
@After
public void 方法名(){} 能够再@Test方法之后执行
3.2、断言
语法:
Assert.assertEquals(期望值,真实值);判断两个值是否相等,如果不相等,报错
@Test
public 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"));