文章目录
黑马全套Java教程(一)
黑马全套Java教程(二)
黑马全套Java教程(三)
黑马全套Java教程(四)
黑马全套Java教程(五)
黑马全套Java教程(六)
黑马全套Java教程(七)
黑马全套Java教程(八)
黑马全套Java教程(九)
40 反射
40.1 单元测试
单元测试:针对最小的功能单元编写测试代码,Java程序最小的功能单元是方法,因此,单元测试就是针对Java方法的测试,进而检查方法的正确性
目前测试方法是怎么进行的,存在什么问题:
- 只有一个main方法,如果一个方法的测试失败了,其他方法测试会受到影响
- 无法得到测试的结果报告,需要程序员自己去观察测试是否成功
- 无法实现自动化测试
Junit单元测试框架:JUnit是使用Java语言实现的单元测试框架,它是开源的,Java开发者都应当学习并使用JUnit编写单元测试。此外,几乎所有的IDE工具都继承了JUnit,这样我们就可以直接在IDE中编写并运行JUnit,这样我们就可以直接在IDE中编写并运行JUnit测试,JUnit目前最新版本是。
JUnit优点:
- JUnit可以灵活的选择执行哪些测试方法,可以一键执行全部测试方法。
- Junit可以生成全部方法的测试报告。
- 单元测试中的某个方法测试失败了,不会影响其他测试方法的测试。
UserService.java
packaged1_junit;//业务方法publicclassUserService{publicStringloginName(String loginName,String passWord){if("admin".equals(loginName)&&"123456".equals(passWord)){return"登录成功!";}else{return"用户名或密码出错!";}}publicvoidselectNames(){System.out.println(10/0);System.out.println("查询全部用户名成功!");}}
TestUserService.java
packaged1_junit;importorg.junit.Assert;importorg.junit.Test;//测试类publicclassTestUserService{/*测试方法
注意点
1、必须是公开的,无参数,无返回值的方法
2、测试方法必须使用@Test注解标记
*/@TestpublicvoidtestLoginName(){UserService userService =newUserService();String rs = userService.loginName("admin","123456");//进行预期结果的正确性测试:断言Assert.assertEquals("您的功能业务可能出现问题","登录成功!", rs);}@TestpublicvoidtestSelectNames(){UserService userService =newUserService();
userService.selectNames();}}
packaged1_junit;importjdk.jfr.BooleanFlag;importorg.junit.*;//测试类publicclassTestUserService{//修饰实例方法的@Beforepublicvoidbefore(){System.out.println("===before方法执行一次===");}@Afterpublicvoidafter(){System.out.println("===after方法执行一次===");}//修饰静态方法@BeforeClasspublicstaticvoidbeforeClass(){System.out.println("===beforeClass方法执行一次===");}@AfterClasspublicstaticvoidafterClass(){System.out.println("===afterClass方法执行一次===");}/*测试方法
注意点
1、必须是公开的,无参数,无返回值的方法
2、测试方法必须使用@Test注解标记
*/@TestpublicvoidtestLoginName(){UserService userService =newUserService();String rs = userService.loginName("admin","123456");//进行预期结果的正确性测试:断言Assert.assertEquals("您的功能业务可能出现问题","登录成功!", rs);}@TestpublicvoidtestSelectNames(){UserService userService =newUserService();
userService.selectNames();}}
===beforeClass方法执行一次======before方法执行一次======after方法执行一次======before方法执行一次===5
查询全部用户名成功!
===after方法执行一次======afterClass方法执行一次===
40.2 反射
反射是指对于任何一个Class类,在运行的时候都可以直接得到这个类全部成分。
在运行时,可以直接得到这个类的构造器对象:Constructor
在运行时,可以直接得到这个类的成员变量对象:Field
在运行时,可以直接得到这个类的成员方法对象:Method
这种运行时动态获取类信息以及动态调用类中成分的能力称为Java语言的反射机制。
packaged2_reflect_class;publicclassTest{publicstaticvoidmain(String[] args)throwsClassNotFoundException{//1. Class类中的静态方法:forName(全限名:包名+类名)Class c =Class.forName("d2_reflect_class.Student");System.out.println(c);//Student.class//2. 类名.classClass c1 =Student.class;System.out.println(c1);//3. 对象.getClass()获取对象对应类的Class对象Student s =newStudent();Class c2 = s.getClass();System.out.println(c2);}}
classd2_reflect_class.Studentclassd2_reflect_class.Studentclassd2_reflect_class.Student
反射为何可以给约定了泛型的集合存入其他类型的元素?
- 编程成Class文件进入运行阶段的时候,泛型会自动擦除
- 反射是作用在运行时的技术,此时已经不存在泛型了
packaged6_reflect_genericity;importjava.lang.reflect.InvocationTargetException;importjava.lang.reflect.Method;importjava.util.ArrayList;//反射:突破泛型的约束publicclassReflectDemo{publicstaticvoidmain(String[] args)throwsNoSuchMethodException,InvocationTargetException,IllegalAccessException{//需求:反射实现泛型擦除后,加入其他类型的元素ArrayList<String> lists1 =newArrayList<>();ArrayList<Integer> lists2 =newArrayList<>();System.out.println(lists1.getClass());System.out.println(lists2.getClass());System.out.println(lists1.getClass()== lists2.getClass());System.out.println("--------------------");ArrayList<Integer> lists3 =newArrayList<>();
lists3.add(23);
lists3.add(22);//list.add("asdas");Class c = lists3.getClass();//定位c类中的add方法Method add = c.getDeclaredMethod("add",Object.class);boolean rs =(boolean)add.invoke(lists3,"黑马");//是否添加成功System.out.println(rs);System.out.println(lists3);ArrayList list4 = lists3;
list4.add("白马");
list4.add(false);}}
classjava.util.ArrayListclassjava.util.ArrayListtrue--------------------true[23,22, 黑马]
案例:反射做通用框架
Student.java
packaged7_reflect_framework;publicclassStudent{privateString name;privatechar sex;privateint age;privateString className;privateString hobby;publicStudent(){}publicStudent(String name,char sex,int age,String className,String hobby){this.name = name;this.sex = sex;this.age = age;this.className = className;this.hobby = hobby;}publicStringgetName(){return name;}publicvoidsetName(String name){this.name = name;}publicchargetSex(){return sex;}publicvoidsetSex(char sex){this.sex = sex;}publicintgetAge(){return age;}publicvoidsetAge(int age){this.age = age;}publicStringgetClassName(){return className;}publicvoidsetClassName(String className){this.className = className;}publicStringgetHobby(){return hobby;}publicvoidsetHobby(String hobby){this.hobby = hobby;}}
Teacher.java
packaged7_reflect_framework;publicclassTeacher{privateString name;privatechar sex;privatedouble salary;publicTeacher(){}publicTeacher(String name,char sex,double salary){this.name = name;this.sex = sex;this.salary = salary;}publicStringgetName(){return name;}publicvoidsetName(String name){this.name = name;}publicchargetSex(){return sex;}publicvoidsetSex(char sex){this.sex = sex;}publicdoublegetSalary(){return salary;}publicvoidsetSalary(double salary){this.salary = salary;}}
MybatisUtil.java
packaged7_reflect_framework;importjava.io.FileOutputStream;importjava.io.PrintStream;importjava.lang.reflect.Field;publicclassMybatisUtil{publicstaticvoidsave(Object obj){try(PrintStream ps =newPrintStream(newFileOutputStream("junit-app/src/data.txt",true));){//1. 提取这个对象的全部变量:只有反射可以解决Class c = obj.getClass();//c.getSimpleName()获取当前类名 c.getName获取全限名:包名+类名
ps.println("==========="+ c.getSimpleName()+"============");//2. 提取它的全部成员变量Field[] fields = c.getDeclaredFields();//3. 获取成员变量的信息for(Field field : fields){String name = field.getName();//提取本成员变量在obj中的值(取值)
field.setAccessible(true);String value = field.get(obj)+"";
ps.println(name +"="+ value);}}catch(Exception e){
e.printStackTrace();}}}
ReflectDemo.java
packaged7_reflect_framework;//目标:提供一个通用框架,支持保存所有对象的具体信息publicclassReflectDemo{publicstaticvoidmain(String[] args){Student s =newStudent();
s.setName("猪八戒");
s.setClassName("西天跑路班");
s.setAge(1000);
s.setHobby("吃,睡");
s.setSex('男');MybatisUtil.save(s);Teacher t =newTeacher();
t.setName("波仔");
t.setSex('男');
t.setSalary(6000);MybatisUtil.save(t);}}
40.3 注解
Java注解又称Java标注,是JDK5.09引入的一种注释机制。Java语言中的类、构造器、方法、成员变量、参数都可以被注解进行标注。
注解的作用:对Java中类、方法、成员变量做标记,然后进行特殊处理,至于到底做何种处理由业务需求来决定。例如:JUint框架中,标记了注解@Test的方法就可以被当成测试方法执行,而没有标记的就不能当成测试方法执行。
自定义注解格式:
public@interface 注解名称{public 属性类型 属性名()default 默认值;}
例:
MyBook.java
packaged8_annotation;public@interfaceMyBook{Stringname();String[]authors();doubleprice();}
AnnotationDemo1.java
packaged8_annotation;//目标:自定义注解@MyBook(name="《精通JavaSE》", authors ={"zdb","zzz"}, price =199)publicclassAnnotationDemo1{@MyBook(name="《精通JavaSE》", authors ={"zdb","zzz"}, price =199)privateAnnotationDemo1(){}@MyBook(name="《精通JavaSE》", authors ={"zdb","zzz"}, price =199)publicstaticvoidmain(String[] args){@MyBook(name="《精通JavaSE》", authors ={"zdb","zzz"}, price =199)int age =21;}}
特殊属性:value属性,如果只有一个value属性的情况下,使用value属性的时候可以省略value名称不写。但是如果有多个属性,且多个属性没有默认值,那么value名称是不能省略的。
Book.java
packaged8_annotation;public@interfaceBook{Stringvalue();//特殊属性doubleprice()default9.9;}
元注解:注解注解的注解
元注解有两个:
- @Target:约束自定义注解只能在哪些地方使用
- @Retention:声明注解的生命周期
MyTest.java
packaged8_annotation;importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;@Target({ElementType.METHOD,ElementType.FIELD})//元注解@Retention(RetentionPolicy.RUNTIME)//一直活着,在运行阶段这个注解也不消失public@interfaceMyTest{}
AnnotationDemo2.java
packaged8_annotation;//目标:认识元注解//@MyTest //只能注解方法和成员变量publicclassAnnotationDemo2{@MyTestprivateString name;@MyTestpublicvoidtest(){}publicstaticvoidmain(String[] args){}}
注解的解析:注解的操作中经常需要进行解析,注解的解析就是判断是否存在注解,存在注解就解析出内容。
bookk.java
packaged8_annotation;importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;@Target({ElementType.TYPE,ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)public@interface bookk {Stringvalue();doubleprice()default100;String[]author();}
AnnotationDemo3.java
packaged8_annotation;importorg.junit.Test;importjava.lang.reflect.Method;importjava.util.Arrays;//目标:完成注解的解析publicclassAnnotationDemo3{@Testpublicstaticvoidmain(String[] args)throwsNoSuchMethodException{//1. 先得到类对象Class c =BookStore.class;Method m = c.getDeclaredMethod("test");//2. 判断这个类上面是否存在这个注解if(c.isAnnotationPresent(bookk.class)){//3. 直接获取该注解对象
bookk book =(bookk)c.getDeclaredAnnotation(bookk.class);System.out.println(book.value());System.out.println(book.price());System.out.println(Arrays.toString(book.author()));}}}@bookk(value ="<情深深雨濛濛>", price =99.9, author ={"zzz","aaa"})classBookStore{@bookk(value ="<三少爷的剑>", price =22, author ={"zzz","aaa"})publicvoidtest(){}}
40.4 动态代理
Star.java
packaged9_proxy;publicclassStarimplementsSkill{privateString name;publicStar(String name){this.name = name;}@Overridepublicvoidjump(){System.out.println(name +"跳舞");}@Overridepublicvoidsing(){System.out.println(name +"唱歌");}}
Skill接口
packaged9_proxy;publicinterfaceSkill{voidjump();voidsing();}
StarAgentProxy.java
packaged9_proxy;importjava.lang.reflect.InvocationHandler;importjava.lang.reflect.Method;importjava.lang.reflect.Proxy;publicclassStarAgentProxy{//设计一个方法来返回一个明星对象的代理对象publicstaticSkillgetProxy(Star obj){//为杨超越这个对象,生成一个代理对象return(Skill)Proxy.newProxyInstance(obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(),newInvocationHandler(){@OverridepublicObjectinvoke(Object proxy,Method method,Object[] args)throwsThrowable{System.out.println("收首付款。。。");//真正的让杨超越去唱歌和跳舞。。。//method 正在调用的方法对象 args代表这个方法的参数Object rs = method.invoke(obj, args);System.out.println("收尾款。。。");return rs;}});}}
Test.java
packaged9_proxy;//目标:学习开发出一个动态代理的对象出来,理解动态代理的执行流程publicclassTest{publicstaticvoidmain(String[] args){//1. 创建一个对象(杨超越) 对象的类必须实现接口Star s =newStar("杨超越");// 为杨超越对象,生成一个代理对象(经纪人)Skill s2 =StarAgentProxy.getProxy(s);
s2.jump();
s2.sing();}}
UserService.java
packaged10_proxy2;publicinterfaceUserService{Stringlogin(String loginName,String passWord);voiddeleteUser();StringselectUsers();}
UserServiceImpl.java
packaged10_proxy2;publicclassUserServiceImplimplementsUserService{@OverridepublicStringlogin(String loginName,String passWord){String rs ="登录名和密码错误";if("admin".equals(loginName)&&"123456".equals(passWord)){
rs ="登录成功";}try{Thread.sleep(1000);}catch(InterruptedException e){
e.printStackTrace();}return rs;}@OverridepublicvoiddeleteUser(){try{System.out.println("您正在删除用户数据中。。。");Thread.sleep(2500);}catch(InterruptedException e){
e.printStackTrace();}}@OverridepublicStringselectUsers(){String rs ="查询了10000个用户数据。。。";try{Thread.sleep(3000);}catch(InterruptedException e){
e.printStackTrace();}return rs;}}
ProxyUtil.java
packaged10_proxy2;importjava.lang.reflect.InvocationHandler;importjava.lang.reflect.Method;importjava.lang.reflect.Proxy;publicclassProxyUtil{//通过一个静态方法,为用户业务对象返回一个代理对象publicstaticUserServicegetProxy(UserService obj){return(UserService)Proxy.newProxyInstance(obj.getClass().getClassLoader(),
obj.getClass().getInterfaces(),newInvocationHandler(){@OverridepublicObjectinvoke(Object proxy,Method method,Object[] args)throwsThrowable{long startTime =System.currentTimeMillis();//真正触发对象的行为执行的Object rs = method.invoke(obj, args);long endTime =System.currentTimeMillis();System.out.println(method.getName()+"方法耗时:"+(endTime - startTime)/1000.0+"s");return rs;}});}}
Test.java
packaged10_proxy2;//掌握使用动态代理解决问题,理解使用动态代理的优势publicclassTest{publicstaticvoidmain(String[] args){UserService userService =ProxyUtil.getProxy(newUserServiceImpl());System.out.println(userService.login("admin","123456"));System.out.println(userService.selectUsers());
userService.deleteUser();}}
41 XML
41.1 XML
XML是可扩展标记语言的缩写,它是一种数据表示格式,可以描述非常复杂的数据结构,常用于传输和存储数据
- 纯文本,默认使用UTF-8编码;二是可嵌套
- 如果把XML内容存为文件,那么它就是一个XML文件
- XML的使用场景:XML内容经常被当成消息进行网络传输,或者作为配置文件用于存储系统的消息语法规则:
hello_world.xml
<?xml version="1.0" encoding="UTF-8" ?><!-- 我是注释: 跟标签只能有一个--><student><name>女儿国网</name><sex>女</sex><hobby>唐僧</hobby><info><age>30</age><addr>女儿国</addr></info><sql>
select * from user where age < 18;
select * from user where age < 18 && age > 10;
<![CDATA[
select * from user where age < 18;
]]></sql></student>
文档约束:是用来限定xml文件中的标签以及属性应该怎么写;以此强制约束程序员必须按照文档约束的规定来编写xml文件。
DTD约束文档
例:
DTD的问题:
- 可以约束XML文件的编写
- 不能约束具体的数据类型
schema约束
例:
41.2 XML解析技术
什么是XML解析:使用程序读取XML中的数据
两种解析方式:
- SAX解析
- DOM解析
案例:dom4j解析
packaged1_dom4j;/*
* 目标:学会使用dom4j解析XML文件中的数据
* 1、导入dom4j框架
* 2、准备一个XML文件
*/importorg.dom4j.Document;importorg.dom4j.DocumentException;importorg.dom4j.Element;importorg.dom4j.io.SAXReader;importorg.junit.Test;importjava.io.File;importjava.io.InputStream;publicclassDom4JHelloWorldDemo1{@TestpublicvoidparseXMLData()throwsDocumentException{//1、创建一个Dom4j的解析对象,代表了整个dom4j框架SAXReader saxReader =newSAXReader();//2、把XML文件加载到内存中成为一个Document文档对象//Document document = saxReader.read(new File("xml-app\\src\\Contacts.xml")); //需要通过模块名定位//直接在src下寻找文件,改了模块名没有影响InputStream is =Dom4JHelloWorldDemo1.class.getResourceAsStream("/Contacts.xml");Document document = saxReader.read(is);//3、获取根元素对象Element root = document.getRootElement();System.out.println(root.getName());}}
packaged1_dom4j;/*
* 目标:学会使用dom4j解析XML文件中的数据
* 1、导入dom4j框架
* 2、准备一个XML文件
*/importorg.dom4j.Attribute;importorg.dom4j.Document;importorg.dom4j.DocumentException;importorg.dom4j.Element;importorg.dom4j.io.SAXReader;importorg.junit.Test;importorg.w3c.dom.Attr;importjava.io.File;importjava.io.InputStream;importjava.util.List;publicclassDom4JHelloWorldDemo1{@TestpublicvoidparseXMLData()throwsDocumentException{//1、创建一个Dom4j的解析对象,代表了整个dom4j框架SAXReader saxReader =newSAXReader();//2、把XML文件加载到内存中成为一个Document文档对象//Document document = saxReader.read(new File("xml-app\\src\\Contacts.xml")); //需要通过模块名定位//直接在src下寻找文件,改了模块名没有影响InputStream is =Dom4JHelloWorldDemo1.class.getResourceAsStream("/Contacts.xml");Document document = saxReader.read(is);//3、获取根元素对象Element root = document.getRootElement();System.out.println(root.getName());//4、拿根元素下的全部子元素对象List<Element> sonEles = root.elements();for(Element sonEle : sonEles){System.out.println(sonEle.getName());}//拿到某个子元素Element userEle = root.element("user");System.out.println(userEle.getName());//默认提取第一个子元素对象Element contact = root.element("contact");//获取子元素文本System.out.println(contact.elementText("name"));//去掉前后空格System.out.println(contact.elementTextTrim("name"));//根据元素获取属性值Attribute idAttr = contact.attribute("id");System.out.println(idAttr.getName()+"----->"+ idAttr.getValue());//直接提取属性值System.out.println(contact.attributeValue("id"));System.out.println(contact.attributeValue("vip"));//获取当前元素下的子元素对象Element email = contact.element("email");System.out.println(email.getText());}}
案例:
packaged1_dom4j;importorg.dom4j.Document;importorg.dom4j.DocumentException;importorg.dom4j.Element;importorg.dom4j.io.SAXReader;importorg.junit.Test;importjava.util.ArrayList;importjava.util.List;//需求:解析XML中的数据成为一个List集合对象publicclassDom4JTest2{@TestpublicvoidparseToList()throwsDocumentException{//需求:解析XML中的数据称为一个List集合对象//1、导入框架//2、创建SaxReader对象SAXReader saxReader =newSAXReader();//3、加载XML文件成为文档对象Document对象Document document = saxReader.read(Dom4JTest2.class.getResourceAsStream("/Contacts.xml"));//4、先拿根元素Element root = document.getRootElement();//5、提取contact子元素List<Element> contactEles = root.elements("contact");//6、准备一个ArrayList集合封装联系人信息List<Contact> contacts =newArrayList<>();//7、遍历Contact子元素for(Element contactEle : contactEles){//8、每个子元素都是一个联系人对象Contact contact =newContact();
contact.setId(Integer.valueOf(contactEle.attributeValue("id")));
contact.setVip(Boolean.valueOf(contactEle.attributeValue("vip")));
contact.setName(contactEle.attributeValue("Name"));
contact.setGender(contactEle.attributeValue("gender").charAt(0));//取一个字符
contact.setEmail(contactEle.attributeValue("email"));//9、把联系人对象数据加入到List集合
contacts.add(contact);}//10、遍历List集合for(Contact contact : contacts){System.out.println(contact);}}}
41.3 XPath
XPath使用路径表达式来定位XML文档中的元素节点或属性节点
41.4 设计模式
工厂模式
总结
版权归原作者 zdb呀 所有, 如有侵权,请联系我们删除。