java web 第六天
Java高级
- 课程介绍
本阶段课程先学习java高级的一些基础知识,然后学习Mybatis、Spring、SpringMVC框架,最后框架整合做一个实战项目。让学生真正学习、了解、掌握基本的web编程知识和项目实战技能要求,采用由浅入深、循序渐进的教学策略,先基础知识到案例再到项目实战的实施策略。
- 本章任务
- 使用Dom创建一个自定义xml文件
- 使用Dom解析xml文件
- 通过反射实现javaBean的克隆
- 实现自定义注解
- 本章目标
- 了解xml的数据格式
- 掌握常用的解析xml的API
- 了解反射的应用意义
- 熟练掌握反射中的常用API
- 了解注解的作用和本质
- 知识点
- XML
Xml格式的文件在接下来的框架学习尤为重要,比如在框架中的配置文件大多都是用的xml格式的文件来配置的,所以xml格式的文件创建与解析特别重要。
- 、XML概念
XML(eXtensible Markup Language)是一种可扩展标识语言,是一种简单的数据存储语言,使用一系列简单的标记描述数据。目前推荐遵循的是W3C组织于2000年发布的XML1.0版本。
(2)、XML语法规则
①、声明标签定在首行:<?xml version=“1.0” encoding=“utf-8|gb2312”?>
②、文档有且只有一个根元素
③、非空元素都必须有一对标签:起始/关闭标签
④、空元素的标签中同时表示起始和结束标签</>
⑤、大小写敏感
⑥、标签必须正确地嵌套
⑦、元素的属性必须有属性值且属性值必须加引号(单引或双引都可以)
⑧、在 XML 中,应使用实体引用来代替特殊字符
(3)、实体引用
< 小于号< 【必须】
> 大于号>
& 和号& 【必须】
' 单引号‘
" 双引号”
(4)、元素命名规则
名称可以含字母、数字以及其他的字符
名称不能以数字或者标点符号开始
名称不能以字符 “xml”(或者 XML、Xml)开始
名称不能包含空格
可使用任何名称,没有保留的字词
(5)、XML的特点
XML 仅仅是纯文本
XML 的设计宗旨是传输数据,而非显示数据
XML 是独立于软件和硬件的信息传输工具
XML 标签没有被预定义,需要自行定义标签
(6)、Dom4j概念
dom4j是一个Java的XML API,是jdom的升级品,用来读写XML文件的。dom4j是一个十分优秀的JavaXML API,具有性能优异、功能强大和极其易使用的特点,它的性能超过sun公司官方的dom技术,同时它也是一个开放源代码的软件,可以在SourceForge上找到它。在IBM developerWorks上面还可以找到一篇文章,对主流的Java XML API进行的性能、功能和易用性的评测,所以可以知道dom4j无论在哪个方面都是非常出色的。如今可以看到越来越多的Java软件都在使用dom4j来读写XML,特别值得一提的是连Sun的JAXM也在用dom4j。这已经是必须使用的jar包, Hibernate也用它来读写配置文件。
(7)、XML文档示例
<?xml version="1.0" encoding="UTF-8"?><books><!--This is a test for dom4j, holen, 2004.9.11--><book show="yes"><title>Dom4j Tutorials</title></book><book show="yes"><title>Lucene Studing</title></book><book show="no"><title>Lucene in Action</title></book><owner>O'Reilly</owner></books>
- 、解析XML文档
解析/创建都是基于dom4j实现
public static void main(String[] args) throws DocumentException {File file = new File("hello.xml");SAXReader sax = new SAXReader();Document doc = sax.read(file);Element rootElement = doc.getRootElement();String name = rootElement.getName();System.out.println("根节点="+name);//判断是否是根节点System.out.println(rootElement.isRootElement());Iterator it = rootElement.elementIterator();while(it.hasNext()){Element ele = (Element)it.next();String eleName = ele.getName();if(eleName.equals("book")){Attribute attribute = ele.attribute(0);System.out.println(attribute.getName()+"="+attribute.getValue());Iterator it2 = ele.elementIterator();while(it2.hasNext()){Element ele2 = (Element)it2.next();System.out.println(ele2.getName()+"="+ele2.getText());}}else{System.out.println(ele.getText());}}}
(9)、创建XML文档
public static void main(String[] args) throws IOException, XMLStreamException {Document document = DocumentHelper.createDocument();Element booksElement = document.addElement("books");booksElement.addComment("This is a test for dom4j, holen, 2004.9.11");Element bookElement = booksElement.addElement("book");bookElement.addAttribute("show","yes");Element titleElement = bookElement.addElement("title");titleElement.setText("Dom4j Tutorials");/** 类似的完成后两个book */bookElement = booksElement.addElement("book");bookElement.addAttribute("show","yes");titleElement = bookElement.addElement("title");titleElement.setText("Lucene Studing");bookElement = booksElement.addElement("book");bookElement.addAttribute("show","no");titleElement = bookElement.addElement("title");titleElement.setText("Lucene in Action");/** 加入owner节点 */Element ownerElement = booksElement.addElement("owner");ownerElement.setText("O'Reilly");//用于格式化xml内容和设置头部标签OutputFormat format = OutputFormat.createPrettyPrint();//设置xml文档的编码为utf-8format.setEncoding("utf-8");Writer out = new FileWriter("hello2.xml");XMLWriter writer = new XMLWriter(out,format);writer.write(document);writer.close();}
2.反射
(1)、反射定义
反射即反向探知,有点像考古学家根据发掘的物品来探知以前的事情。
程序中的反射指程序运行状态中,
1、对于给定的一个类(Class)对象,可以获得这个类(Class)对象的所有属性和方法;
2、对于给定的一个对象(new XXXClassName<? extends Object>),都能够调用它的任意一
个属性和方法。
这种动态获取类的内容以及动态调用对象的方法和获取属性的机制,就叫做Java反射机制
(2)、反射初识
public class User {public void eat(){System.out.println("---eat---");}}public class TestReflect{public static void main(String[] args) throws Exception {Class<User> clazz = User.class;//获取类对象对应的属性和方法System.out.println(clazz.getName());System.out.println(clazz.getPackage());System.out.println(clazz.getSuperclass());System.out.println(clazz.getClassLoader());//获取一个对象实例User user = clazz.newInstance();Method method = clazz.getDeclaredMethod("eat");method.invoke(user);}
(3)、为何用反射
直接new User()不就可以了,为什么要用这种反射写法?
实例化一个User()对象,不使用反射,如果想再实例化其他对象比如new Person(),那么
就需要修改源代码,并重新编译。使用反射后就不需要修改源代码只需要灵活改动类描述就
可以了,不需要重新再编译。 如下代码所示
//类描述,可根据需要实例化的描述而改动String className = "com.tledu.pojo.User";//使用反射中API创建对象Class.forName(className).newInstance();
(4)、反射的优缺点
优点:
增加程序的灵活性,避免固有逻辑写死到程序中
代码相对简洁,可以提高程序的复用性
缺点:
相比于直接调用反射有比较大的性能销毁
内部暴露和安全隐患
a、灵活性测试
public interface Ball {void playBall();}public class BasketBall implements Ball{@Overridepublic void playBall() {System.out.println("打篮球");}}public class FootBall implements Ball{@Overridepublic void playBall() {System.out.println("踢足球");}}//----------------------------public static void main(String[] args) {//System.out.println(getInstanceByKey("basket"));System.out.println(getInstanceReflectByKey("FootBall"));}public static Ball getInstanceByKey(String key) {if("foot".equals(key)){return new FootBall();}if("basket".equals(key)){return new BasketBall();}return null;}
如果我们想在添加一个乒乓球那么除了创建一个乒乓球类,还需要在方法中加入获取乒乓球对应的判断和乒乓球创建对象的返回,很显然不够灵活出现了写死代码的情况。
public static Ball getInstanceReflectByKey(String key) {String basePackage = "com.tledu.mjw";Ball ball = null;try {Class clazz = Class.forName(basePackage + "." + key);ball = (Ball)clazz.newInstance();} catch (Exception e) {e.printStackTrace();}return ball;}
使用反射的方式获取对象,可以看出代码灵活了很多而且不需要改动创建返回对象的源码。
b、性能测试
public static void main(String[] args) {//System.out.println(getInstanceByKey("basket"));//System.out.println(getInstanceReflectByKey("FootBall"));long start = System.currentTimeMillis();for (int i = 0; i < 1000000; i++){getInstanceByKey("basket");//getInstanceReflectByKey("FootBall");}long end = System.currentTimeMillis();System.out.println("耗时:" + (end - start));}
为什么这么慢呢?(分别查看forName()方法和newIntance()方法源码分析)
1、调用了native方法
2、每次调用newInstance()方法都会做安全检查,比较耗时
(5)、反射的操作
a、获取类对象的四种方式
//获取类对象的四种方式Class<User> clazz1 = User.class;Class<?> clazz2 = Class.forName("com.tledu.mjw.User");Class<? extends User> clazz3 = new User().getClass();Class<?> clazz4 = Demo3.class.getClassLoader().loadClass("com.tledu.mjw.User");
b、类中基本信息的获取
System.out.println(clazz1.getClassLoader());System.out.println(clazz1.getSuperclass());System.out.println(clazz1.getPackage());System.out.println(clazz1.getModifiers()); //获取类的修饰符System.out.println(clazz1.getName());System.out.println(clazz1.getSimpleName());System.out.println(clazz1.getInterfaces().length);//获取类实现的所有接口System.out.println(clazz1.getAnnotations().length);
c、类中字段的操作
创建User类继承Person类添加相应属性
public class Person {public String idCard;private String userName;}public class User extends Person{private String name;public String sex;public static String address;public void eat(){System.out.println("---eat---");}}
测试方法调用
public static void main(String[] args) throws Exception {Class<User> userClass = User.class;User user = userClass.newInstance();//getFields()获取的是本类及父类中的公共属性Field[] fields = userClass.getFields();for (Field field : fields) {System.out.println(field.getModifiers() + " " + field.getName());}System.out.println("---------------");//getDeclaredFields()获取本类中的所有属性Field[] fields2 = userClass.getDeclaredFields();for (Field field : fields2) {System.out.println(field.getModifiers() + " " + field.getName());}System.out.println("---------------");//获取name字段对应的fieldField nameField = userClass.getDeclaredField("name");//如果需要修改私有属性信息那么我们要放开权限nameField.setAccessible(true);nameField.set(user,"天亮教育");System.out.println(nameField.get(user));//System.out.println(user.getName());System.out.println("---------------");//如何对静态的属性赋值Field addressField = userClass.getDeclaredField("address");addressField.set(null,"Jack");System.out.println(addressField.get(null));//System.out.println(User.address);}
d、类中方法的操作
在User类中将eat方法改为私有的,并添加静态方法say
private void eat(){System.out.println("---eat---");}public static void say(String msg){System.out.println(msg);}
在Person类中添加共有的fn1()方法和私有的fn2()方法
public void fn1(){}private void fn2(){}
测试方法调用
public static void main(String[] args) throws Exception {Class<User> userClass = User.class;User user = userClass.newInstance();//获取本类及父类中的公共方法Method[] methods1 = userClass.getMethods();for (Method method : methods1) {System.out.println(method.getModifiers() + " " + method.getName());}System.out.println("--------------");//获取本类中所有的方法包括私有Method[] methods2 = userClass.getDeclaredMethods();for (Method method : methods2) {System.out.println(method.getModifiers() + " " + method.getName());}System.out.println("--------------");//调用方法执行Method eatMethod = userClass.getDeclaredMethod("eat");//调用私有方法时要先开放权限eatMethod.setAccessible(true);eatMethod.invoke(user);System.out.println("--------------");//调用静态的方法Method sayMethod = userClass.getDeclaredMethod("say",String.class);sayMethod.invoke(null,"你好");}
e、类中构造器的操作
在User中添加如下构造方法
public User() {}public User(String name) {this.name = name;}private User(String name,String sex) {this.name = name;this.sex = sex;}
通过反射操作User中的构造方法
public static void main(String[] args) throws Exception {Class<User> userClass = User.class;//获取公共的构造器Constructor<?>[] constructors = userClass.getConstructors();for (Constructor<?> constructor : constructors) {System.out.println(constructor.getModifiers() + " " + constructor.getName());}System.out.println("------------------");//获取所有的构造器Constructor<?>[] declaredConstructors = userClass.getDeclaredConstructors();for (Constructor<?> declaredConstructor : declaredConstructors) {System.out.println(declaredConstructor.getModifiers() + " " + declaredConstructor.getName());}//1、直接通过newInstance创建对象User user = userClass.newInstance();//2、获取对应的Constructor对象获取实例Constructor<User> constructor = userClass.getDeclaredConstructor(String.class, String.class);//操作私有的构造器要先打开权限constructor.setAccessible(true);User user1 = constructor.newInstance("乔森", "男");}
- 、反射破局单例
单例模式
public class PersonSingle {private static PersonSingle instance = null;private PersonSingle(){}public static PersonSingle getInstance(){if(instance == null){instance = new PersonSingle();}return instance;}}
测试单例、通过反射可以调用私有构造
public static void main(String[] args) throws Exception {PersonSingle instance1 = PersonSingle.getInstance();PersonSingle instance2 = PersonSingle.getInstance();PersonSingle instance3 = PersonSingle.getInstance();System.out.println(instance1);System.out.println(instance2);System.out.println(instance3);System.out.println("---------------------");Class<PersonSingle> personSingleClass = PersonSingle.class;Constructor<PersonSingle> declaredConstructor = personSingleClass.getDeclaredConstructor();declaredConstructor.setAccessible(true);System.out.println(declaredConstructor.newInstance());}
改进单例如下
private PersonSingle(){if(instance != null){throw new RuntimeException("实例已经存在不允许再创建")}}
- 、反射使用场景
1、jdbc封装
2、SpringIOC
3、JdbcTemplate
4、Mybatis
...................
3.注解
(1)、注解的概念
注释:用文字描述程序,给程序员看的
/*
* 多行注释
*/
// 单行注释
注解:说明程序的,给计算机看的
定义:
注释(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
作用:
- 编写文档:通过代码里标识的注释生成文档【生成doc文档】
- 代码分析:通过代码里标识的注解对代码进行分析【使用反射】
- 编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【Override】
生成文档演示:
创建User类
/*** 注解JavaDoc描述* @author mark* @since jdk1.5* @version 1.0*/public class User {private Integer id;private String userName;@Overridepublic String toString() {return "User{" +"id=" + id +", userName='" + userName + '\'' +'}';}/*** 两数相加* @param a 第一个整数* @param b 第二个整数* @return 返回两数和*/public int add(int a,int b){return a+b;}}
执行命令生成说明文档:javadoc User.java
(2)、JDK预定义的注解
@Override:检查被该注解标注的方式是否是继承自父类【接口】
@Deprecated:该注解表示注释的内容过时
@SuppressWarnings:压制警告
代码演示:
import java.util.Date;@SuppressWarnings("all")public class AnnoDemo01 {@Overridepublic String toString() {return "AnnoDemo01{}";}@Deprecatedpublic void show1(){//发现过时了,功能跟不上需求了}//@SuppressWarnings("all")public void show2(){//功能更加强大的方法}public void demo(){show1(); //不推使用但可以使用//show2();Date date = new Date();date.getYear();}}
(3)、自定义注解
查看jdk预定义的注解源码发现格式如下
public @interface 注解名{
}
自定义注解 MyAnno
public @interface MyAnno{
}
执行javac MyAnno.java 生成MyAnno.class
执行javap MyAnno.java 将class文件反编译
Compiled from "MyAnno.java"
public interface MyAnno extends java.lang.annotation.Annotation {
}
注解的本质其实就是一个接口,继承Annotation父接口
属性:在接口中定义的抽象方法
public @interface MyAnno{
String show1();
Int show2();
String[] show3();
MyAnno2 show4();
PsersonEnum show5();
}
返回结果必须是如下类型
- 基本数据类型
- String类型
- 枚举类型
- 注解
- 以上类型的数组
如何来用这些属性呢?
public @interface MyAnno{String name();int age(); //default 18;
}
赋值给属性
@MyAnno(name="tom",age=18)public void demo(){}
如果注解类中的属性是value且只有一个属性,那么可以再赋值的时候省去value
public @interface MyAnno{String value();//String name();//int age(); //default 18;
}
给注解中只有一个value的属性赋值
//@MyAnno(value="tom")@MyAnno("tom")public void demo(){}
在注解类中添加注解类型、枚举类型、数组类型的属性并赋值
public @interface MyAnno{String value();String[] show3();MyAnno2 show4();PsersonEnum show5();
}
给不同类型的属性赋值
//@MyAnno(value="tom")@MyAnno(value="tom",show3={“a”,”b”},show4=@MyAnno2,show5=PsersonEnum.name})public void demo(){}
属性赋值注意点:
- 如果定义属性时,使用default关键字给属性默认初始值,可以在使用注解时不赋值
- 如果只有一个属性需要赋值,而且该属性的名称是value,那么赋值时value可以省略
- 数组赋值的时候,使用{}括起来,如果数组中只有一个值,那么{}可以省略
(4)、元注解
JDK中给我们提供的4个元注解
@Target({ElementType.FIELD,ElementType.TYPE,ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)@Documented@Inheritedpublic @interface MyAnno2 {}
- @Target:描述当前注解能够作用的位置
ElementType.TYPE: 可以作用在类上
ElementType.METHOD:可以作用在方法上
ElementType.FIELD: 可以作用在成员变量上
- @Retention:描述注解被保留到的阶段
SOURCE<CLASS<RUNTIME
SOURCE:表示当前注解只在代码阶段有效
CLASS:表示该注解会被保留到字节码阶段
RUNTIME:表示该注解会被保留到运行阶段JVM
自定义的注解:RetentionPolicy.RUNTIME
- @Documented:描述注解是否被抽取到JavaDoc api中
- @inherited:描述注解是否可以被子类继承
- 、自定义注解案例
创建InvokAnno注解
/*** 自定义注解* 该注解表示要执行哪个类中的哪个方法*/@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface InvokAnno {String className();String methodName();}
创建Student1类
public class Student1 {public void show(){System.out.println("show1方法");}
}
创建MyMain测试类进行测试
@InvokAnno(className = "com.tledu.anno2.Student2",methodName = "show")public class MyMain {public static void main(String[] args) throws Exception {Class<MyMain> clazz = MyMain.class;InvokAnno anno = clazz.getAnnotation(InvokAnno.class);/*** 注解本质是接口 获取到的其实是接口实现* public class MyInvokAnno implements InvokAnno{* String className(){* return "com.tledu.anno2.Student1";* }* String methodName(){* return "show1";* }* }*/String className = anno.className();String methodName = anno.methodName();Class<?> aClass = Class.forName(className);Method method = aClass.getDeclaredMethod(methodName);Object o = aClass.newInstance();method.invoke(o);}}
java web 第六天相关推荐
- 在k8s中使用gradle构建java web项目镜像Dockerfile
在k8s中使用gradle构建java web项目镜像Dockerfile FROM gradle:6-jdk8 AS build COPY --chown=gradle:gradle . /home ...
- Jenkins 2.16.3默认没有Launch agent via Java Web Start,如何配置使用
问题:Jenkins 2.16.3默认没有Launch agent via Java Web Start,如下图所示,而这种启动方式在Windows上是最方便的. 如何设置才能让出来呢? 打开&quo ...
- Java Web项目结构
Java Web项目结构(一般) 1.Java src 2.JRE System Library 3.Java EE 6 Libraries 4.Web App Libraries 5.WebRoot ...
- Java Web 中的一些问题
http://localhost:8080/struts2demo/online/userLogin.jsp 请求模式 :// 主机名名称(或者服务器名称) : 端口 / Servlet容器的名称(通 ...
- java web ubuntu_Ubuntu部署Java web项目
登录服务器和给服务器传输文件,使用的工具是Xshell Xftp Mysql 安装mysql 输入:sudo apt-get update 更新软件列表 输入: ...
- JAVA Web项目中所出现错误及解决方式合集(不断更新中)
JAVA Web项目中所出现错误及解决方式合集 前言 一.几个或许会用到的软件下载官网 二.Eclipse的[preferences]下没有[sever]选项 三.Tomcat的安装路径找不到 四.T ...
- 使用Netbeans创建java Web项目
使用Netbeans创建java Web项目 需要先搭建JDK参考: Java开发环境的搭建以及使用eclipse创建项目 Linux环境安装卸载JDK 1.安装Tomcat 去官网下载最新的T ...
- java axis2 开发_基于Apache axis2开发Java Web服务
1.安装配置axis2环境 下载好后把axis2-1.4.1-war目录下面的axis2.war发布到tomcat的webapps中. 发布好,访问:http://localhost:8079/axi ...
- java web三大组件之filter过滤器
过滤器是java web中相当重要的组成成分,是JavaWeb三大组件之一,它与Servlet很相似.不过过滤器有以下三条特性: 过滤器是用来拦截请求的,而不是处理请求的. 当用户请求某个Servle ...
最新文章
- bzoj 2435: [Noi2011]道路修建【树形dp】
- Spring第一讲:初步了解Spring
- python字符编码在哪里_快速入手Python字符编码
- spring react_使用Spring WebFlux构建React性REST API –第1部分
- 设置启用树莓派的HDMI显示
- LeetCode 2149. 按符号重排数组(双指针)
- PostgreSQL 9.5 pg_dump新特性 你是我的眼
- php分享十三:mysql事物
- String 也能做性能优化,我只能说牛逼!
- windows配置phpredis
- PHP多进程网络爬虫
- Vue 移动端 股票 分时 K线
- C#读取MP3文件的专辑图片和ID3V2Tag信息(带代码)
- 虚拟机的安装、网关配置及安装man命令
- oracle plsql 绑定变量值,dbms_sqltune解析SQL的BIND_DATA绑定变量值
- JavaScript实现贷款利息计算器
- “基于485总线的评分系统”
- 4. 从IPv4到IPv6
- html input onfocus
- c语言中的pow(x, y)的使用
热门文章
- 百度飞桨小白逆袭大神被“虐”过程大公开--青春有你2 数据分析
- 《重新定义公司》总结
- 华为NE40E安全防御体系结构
- 线性插值改变图像尺寸_Photoshop从入门到精通:修改画布尺寸旋转,改变图像大小分辨率...
- 【iOS沉思录】iOS添加自定义字体详解
- 放弃继承权能不赡养父母吗
- (阿里云笔记)贝勾置阿里云轻量应用服务器CentOS7.6镜像——Linux系统
- 【JMeter】连接mysql数据库
- 2011年第四季度,DDR3最新进展,尔必达出品,25nm工艺,单颗粒最大512MB!
- 论文速递:AAAI 2023 | 优图16篇论文速览,含多标签分类、姿态估计、目标检测、HOI、小样本学习等研究方向