赞
踩
学习链接:Java 视频教程全集
课件链接:Java课件
声明:全是本人边学习边手打的,希望对大家有帮助。
反射Reflection:把java类中的各种结构(方法、属性、构造器、类名)映射成一个个的java对象。利用反射技术可以对一个类进行解剖,反射是框架设计的灵魂。
获取Class对象(三种方式):推荐使用Class.forName(“完整路径”)
可以动态创建对象:clz.getConstructor().newInstance()
练习
package com.sxt.Server_study01; import java.lang.reflect.InvocationTargetException; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: ReflectTest.java * @time: 2019/11/29 14:55 * @desc: */ public class ReflectTest { public static void main(String[] args){ // 1. 对象.getClass() | 买iphone照着做 Iphone iphone = new Iphone(); Class clz = iphone.getClass(); // 2. 类.class() | 买通工程师给图纸 clz = Iphone.class; // 3. Class.forName("包名.类名") | 偷图纸 try { clz = Class.forName("com.sxt.Server_study01.Iphone"); } catch (ClassNotFoundException e) { e.printStackTrace(); } // 创建对象 try { Iphone iphone2 = (Iphone)clz.newInstance(); System.out.println(iphone2); } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); } // 创建对象推荐方式 try { Iphone iphone3 = (Iphone)clz.getConstructor().newInstance(); System.out.println(iphone3); } catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { e.printStackTrace(); } } } class Iphone{ public Iphone(){ } }
XML:Extensible Markup Language,可扩展标记语言,作为数据的一种存储格式或用于存储软件的参数,程序解析此配置文件,就可以达到不修改代码就能更改程序的目的。
利用Sax解析XML
xml例子
<?xml version="1.0" encoding="UTF-8"?>
<persons>
<person>
<name>至尊宝</name>
<age>9000</age>
</person>
<person>
<name>白晶晶</name>
<age>7000</age>
</person>
</persons>
制作Person类
package com.sxt.Server_study01; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Person.java * @time: 2019/11/29 15:29 * @desc: */ public class Person { private String name; private int age; public Person() { } public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
熟悉sax解析流程
package com.sxt.Server_study01; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import java.io.IOException; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: XmlTest01.java * @time: 2019/11/29 15:10 * @desc: 熟悉sax解析流程 */ public class XmlTest01 { public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException { // SAX解析 // 1. 获取解析工厂 SAXParserFactory factory = SAXParserFactory.newInstance(); // 2. 从解析工厂获取解析器 SAXParser parse = null; parse = factory.newSAXParser(); // 3. 加载文档Document注册处理器 // 4. 编写处理器 PHandler handler = new PHandler(); parse.parse(Thread.currentThread().getContextClassLoader().getResourceAsStream("com/sxt/Server_study01/p.xml"), handler); } } class PHandler extends DefaultHandler { @Override public void startDocument() throws SAXException { System.out.println("解析文档开始"); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { System.out.println(qName + "-->解析开始"); } @Override public void characters(char[] ch, int start, int length) throws SAXException { String contents = new String(ch, start, length).trim(); if(contents.length()>0) { System.out.println("内容为:" + contents); }else{ System.out.println("内容为空!"); } } @Override public void endDocument() throws SAXException { System.out.println("解析文档结束"); } @Override public void endElement(String uri, String localName, String qName) throws SAXException { System.out.println(qName + "-->解析结束"); } }
获取xml中的内容
package com.sxt.Server_study01; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: XmlTest02.java * @time: 2019/11/29 15:31 * @desc: 获取xml中的内容 */ public class XmlTest02 { public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException { // SAX解析 // 1. 获取解析工厂 SAXParserFactory factory = SAXParserFactory.newInstance(); // 2. 从解析工厂获取解析器 SAXParser parse = null; parse = factory.newSAXParser(); // 3. 加载文档Document注册处理器 // 4. 编写处理器 PersonHandler handler = new PersonHandler(); parse.parse(Thread.currentThread().getContextClassLoader().getResourceAsStream("com/sxt/Server_study01/p.xml"), handler); // 5. 获取数据 List<Person> persons = handler.getPersons(); for (Person p : persons) { System.out.println(p.getName() + "-->" + p.getAge()); } } } class PersonHandler extends DefaultHandler { private List<Person> persons; private Person person; private String tag; // 存储操作的标签 @Override public void startDocument() throws SAXException { System.out.println("解析文档开始"); persons = new ArrayList<>(); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (null != qName) { tag = qName; // 存储标签名 if (tag.equals("person")) { person = new Person(); } } } @Override public void characters(char[] ch, int start, int length) throws SAXException { String contents = new String(ch, start, length).trim(); if (contents.length() > 0) { if (tag.equals("name")) { person.setName(contents); } else if (tag.equals("age")) { person.setAge(Integer.valueOf(contents)); } } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if (qName.equals("person")) { persons.add(person); } } @Override public void endDocument() throws SAXException { System.out.println("解析文档结束"); } public List<Person> getPersons() { return persons; } }
webxml例子
<?xml version="1.0" encoding="UTF-8"?> <web-app> <servlet> <servlet-name>login</servlet-name> <servlet-class>com.sxt.server.basic.servlet.LoginServlet</servlet-class> </servlet> <servlet> <servlet-name>reg</servlet-name> <servlet-class>com.sxt.server.basic.servlet.RegisterServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>login</servlet-name> <url-pattern>/login</url-pattern> <url-pattern>/g</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>reg</servlet-name> <url-pattern>/reg</url-pattern> </servlet-mapping> </web-app>
解析webxml
package com.sxt.Server_study01.servlet; import com.sxt.Server_study01.Person; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: XmlTest02.java * @time: 2019/11/29 15:31 * @desc: 解析Webxml */ public class XmlTest02 { public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException { // SAX解析 // 1. 获取解析工厂 SAXParserFactory factory = SAXParserFactory.newInstance(); // 2. 从解析工厂获取解析器 SAXParser parse = null; parse = factory.newSAXParser(); // 3. 加载文档Document注册处理器 // 4. 编写处理器 WebHandler handler = new WebHandler(); parse.parse(Thread.currentThread().getContextClassLoader().getResourceAsStream("com/sxt/Server_study01/servlet/web.xml"), handler); // 5. 获取数据 List<Entity> entitys = handler.getEntitys(); List<Mapping> mappings = handler.getMappings(); System.out.println(entitys.size()); System.out.println(mappings.size()); } } class WebHandler extends DefaultHandler { private List<Entity> entitys; private List<Mapping> mappings; private Entity entity; private Mapping mapping; private String tag; private boolean isMapping = false; public List<Entity> getEntitys() { return entitys; } public void setEntitys(List<Entity> entitys) { this.entitys = entitys; } public List<Mapping> getMappings() { return mappings; } public void setMappings(List<Mapping> mappings) { this.mappings = mappings; } @Override public void startDocument() throws SAXException { entitys = new ArrayList<>(); mappings = new ArrayList<>(); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (null != qName) { tag = qName; // 存储标签名 if (tag.equals("servlet")) { entity = new Entity(); isMapping = false; } else if (tag.equals("servlet-mapping")) { mapping = new Mapping(); isMapping = true; } } } @Override public void characters(char[] ch, int start, int length) throws SAXException { String contents = new String(ch, start, length).trim(); if (contents.length() > 0) { if (isMapping) {// 操作servlet-mapping if (tag.equals("servlet-name")) { mapping.setName(contents); } else if (tag.equals("url-pattern")) { mapping.addPattern(contents); } } else {// 操作servlet if (tag.equals("servlet-name")) { entity.setName(contents); } else if (tag.equals("servlet-class")) { entity.setClz(contents); } } } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if (qName.equals("servlet")) { entitys.add(entity); } else if (qName.equals("servlet-mapping")) { mappings.add(mapping); } } }
xml样例
<?xml version="1.0" encoding="UTF-8"?> <web-app> <servlet> <servlet-name>login</servlet-name> <servlet-class>com.sxt.Server_study01.servlet.LoginServlet</servlet-class> </servlet> <servlet> <servlet-name>reg</servlet-name> <servlet-class>com.sxt.Server_study01.servlet.RegisterServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>login</servlet-name> <url-pattern>/login</url-pattern> <url-pattern>/g</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>reg</servlet-name> <url-pattern>/reg</url-pattern> </servlet-mapping> </web-app>
解析xml
Entity类
package com.sxt.Server_study01.servlet; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Entity.java * @time: 2019/12/2 13:20 * @desc: */ public class Entity { private String name; private String clz; public Entity() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getClz() { return clz; } public void setClz(String clz) { this.clz = clz; } }
Mapping类
package com.sxt.Server_study01.servlet; import java.util.HashSet; import java.util.Set; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Mapping.java * @time: 2019/12/2 13:21 * @desc: */ public class Mapping { private String name; private Set<String> patterns; public Mapping() { patterns = new HashSet<>(); } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<String> getPatterns() { return patterns; } public void setPatterns(Set<String> patterns) { this.patterns = patterns; } public void addPattern(String pattern){ this.patterns.add(pattern); } }
通过URL的路径找到了对应的class
package com.sxt.Server_study01.servlet; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: WebContext.java * @time: 2019/12/3 10:51 * @desc: */ public class WebContext { private List<Entity> entitys = null; private List<Mapping> mappings = null; // key-->servlet-name value-->servlet-class private Map<String, String> mappingMap = new HashMap<>(); // key-->url-pattern value-->servlet-name private Map<String, String> entityMap = new HashMap<>(); public WebContext(List<Entity> entitys, List<Mapping> mappings) { this.entitys = entitys; this.mappings = mappings; // 将entity的List转成了对应的map for(Entity entity: entitys){ entityMap.put(entity.getName(), entity.getClz()); } // 将map的List转成了对应的map for(Mapping mapping: mappings){ for(String pattern: mapping.getPatterns()){ mappingMap.put(pattern, mapping.getName()); } } } // 通过URL的路径找到了对应的class public String getClz(String pattern) { String name = mappingMap.get(pattern); return entityMap.get(name); } }
核心代码,取出数据
package com.sxt.Server_study01.servlet; import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer; import org.xml.sax.Attributes; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: XmlTest02.java * @time: 2019/11/29 15:31 * @desc: 解析Webxml */ public class XmlTest02 { public static void main(String[] args) throws Exception { // SAX解析 // 1. 获取解析工厂 SAXParserFactory factory = SAXParserFactory.newInstance(); // 2. 从解析工厂获取解析器 SAXParser parse = null; parse = factory.newSAXParser(); // 3. 加载文档Document注册处理器 // 4. 编写处理器 WebHandler handler = new WebHandler(); parse.parse(Thread.currentThread().getContextClassLoader().getResourceAsStream("com/sxt/Server_study01/servlet/web.xml"), handler); // 5. 获取数据 WebContext context = new WebContext(handler.getEntitys(), handler.getMappings()); // 假设你输入了 /login or /g String className = context.getClz("/g"); Class clz = Class.forName(className); Servlet servlet = (Servlet)clz.getConstructor().newInstance(); System.out.println(servlet); servlet.service(); } } class WebHandler extends DefaultHandler { private List<Entity> entitys; private List<Mapping> mappings; private Entity entity; private Mapping mapping; private String tag; private boolean isMapping = false; public List<Entity> getEntitys() { return entitys; } public void setEntitys(List<Entity> entitys) { this.entitys = entitys; } public List<Mapping> getMappings() { return mappings; } public void setMappings(List<Mapping> mappings) { this.mappings = mappings; } @Override public void startDocument() throws SAXException { entitys = new ArrayList<>(); mappings = new ArrayList<>(); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if (null != qName) { tag = qName; // 存储标签名 if (tag.equals("servlet")) { entity = new Entity(); isMapping = false; } else if (tag.equals("servlet-mapping")) { mapping = new Mapping(); isMapping = true; } } } @Override public void characters(char[] ch, int start, int length) throws SAXException { String contents = new String(ch, start, length).trim(); if (contents.length() > 0) { if (isMapping) {// 操作servlet-mapping if (tag.equals("servlet-name")) { mapping.setName(contents); } else if (tag.equals("url-pattern")) { mapping.addPattern(contents); } } else {// 操作servlet if (tag.equals("servlet-name")) { entity.setName(contents); } else if (tag.equals("servlet-class")) { entity.setClz(contents); } } } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if (qName.equals("servlet")) { entitys.add(entity); } else if (qName.equals("servlet-mapping")) { mappings.add(mapping); } } }
Servlet接口
package com.sxt.Server_study01.servlet;
/**
* @author: Li Tian
* @contact: litian_cup@163.com
* @software: IntelliJ IDEA
* @file: Servlet.java
* @time: 2019/12/3 15:59
* @desc:
*/
public interface Servlet {
void service();
}
需要被映射的类:Loginservlet
package com.sxt.Server_study01.servlet; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: LoginServlet.java * @time: 2019/12/3 15:59 * @desc: */ public class LoginServlet implements Servlet { @Override public void service() { System.out.println("LoginServlet"); } }
需要被映射的类:RegisterServlet
package com.sxt.Server_study01.servlet; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: RegisterServlet.java * @time: 2019/12/3 15:59 * @desc: */ public class RegisterServlet implements Servlet{ @Override public void service() { System.out.println("RegisterServlet"); } }
HyperText Markup Language ,超文本标记语言,简单理解为浏览器使用的语言。
name是后端用的,id是前端用的
<html> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <head> <title>第一个html登陆</title> </head> <body> <h1>表单的使用</h1> <pre> post: 提交,基于http协议不同 量大 请求参数url不可见 安全<br/> get: 默认,获取,基于http协议不同 量小 请求参数url可见 不安全<br/> action: 请求web服务器的资源 URL<br/> name: 作为后端使用,区分唯一,请求服务器,必须存在,数据不能提交<br/> id: 作为前端使用,区分唯一<br/> </pre> <form method="post" action="http://localhost:8888/index.html"> 用户名: <input type="text" name="uname" id="uname"/> 密码: <input type="password" name="pwd" id="pwd"/> <input type="submit" value="登陆"/> </form> </body> </html>
http请求协议
http响应协议
使用ServerSocket建立与浏览器的连接,获取请求协议
package com.sxt.Server_study02; import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Server01.java * @time: 2019/12/4 9:26 * @desc: 使用ServerSocket建立与浏览器的连接,获取请求协议 */ public class Server01 { private ServerSocket serverSocket; public static void main(String[] args) { Server01 server = new Server01(); server.start(); } // 启动服务 public void start() { try { serverSocket = new ServerSocket(8888); receive(); } catch (IOException e) { e.printStackTrace(); System.out.println("服务器启动失败..."); } } // 接受连接处理 public void receive() { try { Socket client = serverSocket.accept(); System.out.println("一个客户端建立了连接..."); // 获取请求协议 InputStream is = client.getInputStream(); byte[] datas = new byte[1024*1024]; int len = is.read(datas); String requstInfo = new String(datas, 0, len); System.out.println(requstInfo); } catch (IOException e) { e.printStackTrace(); System.out.println("客户端错误..."); } } // 停止服务 public void stop() { } }
两种请求方法get和post:GET和POST两种基本请求方法的区别,GET 和 POST 到底有什么区别?
package com.sxt.Server_study02; import java.io.BufferedWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStreamWriter; import java.net.ServerSocket; import java.net.Socket; import java.util.Date; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Server02.java * @time: 2019/12/4 9:26 * @desc: 返回响应协议 */ public class Server02 { private ServerSocket serverSocket; public static void main(String[] args) { Server02 server = new Server02(); server.start(); } // 启动服务 public void start() { try { serverSocket = new ServerSocket(8888); receive(); } catch (IOException e) { e.printStackTrace(); System.out.println("服务器启动失败..."); } } // 接受连接处理 public void receive() { try { Socket client = serverSocket.accept(); System.out.println("一个客户端建立了连接..."); // 获取请求协议 InputStream is = client.getInputStream(); byte[] datas = new byte[1024*1024]; int len = is.read(datas); String requstInfo = new String(datas, 0, len); System.out.println(requstInfo); StringBuilder content = new StringBuilder(); content.append("<html>"); content.append("<head>"); content.append("<title>"); content.append("服务器响应成功"); content.append("</title>"); content.append("</head>"); content.append("<body>"); content.append("终于回来了..."); content.append("</body>"); content.append("</html>"); int size = content.toString().getBytes().length; StringBuilder responseInfo = new StringBuilder(); String blank = " "; String CRLF = "\r\n"; // 返回 // 1. 响应行:HTTP/1.1 200 OK responseInfo.append("HTTP/1.1").append(blank); responseInfo.append(200).append(blank); responseInfo.append("OK").append(CRLF); // 2. 响应头(最后一行存在空行): responseInfo.append("Date:").append(new Date()).append(CRLF); responseInfo.append("Server:").append("shsxt Server/0.0.1;charset=GBK").append(CRLF); responseInfo.append("Content-type:text/html").append(CRLF); responseInfo.append("Content-length:").append(size).append(CRLF); responseInfo.append(CRLF); // 3. 正文 responseInfo.append(content.toString()); // 写出到客户端 BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream())); bw.write(responseInfo.toString()); bw.flush(); bw.close(); } catch (IOException e) { e.printStackTrace(); System.out.println("客户端错误..."); } } // 停止服务 public void stop() { } }
动态添加内容print
累加字节数的长度
根据状态码拼接响应头协议
根据状态码统一推送出去
package com.sxt.Server_study02; import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Server03.java * @time: 2019/12/4 9:26 * @desc: 封装响应信息 */ public class Server03 { private ServerSocket serverSocket; public static void main(String[] args) { Server03 server = new Server03(); server.start(); } // 启动服务 public void start() { try { serverSocket = new ServerSocket(8888); receive(); } catch (IOException e) { e.printStackTrace(); System.out.println("服务器启动失败..."); } } // 接受连接处理 public void receive() { try { Socket client = serverSocket.accept(); System.out.println("一个客户端建立了连接..."); // 获取请求协议 InputStream is = client.getInputStream(); byte[] datas = new byte[1024*1024]; int len = is.read(datas); String requstInfo = new String(datas, 0, len); System.out.println(requstInfo); Response response = new Response(client); // 关注了内容 response.print("<html>"); response.print("<head>"); response.print("<title>"); response.print("服务器响应成功"); response.print("</title>"); response.print("</head>"); response.print("<body>"); response.print("终于回来了..."); response.print("</body>"); response.print("</html>"); // 关注了状态码 response.pushToBrowser(200); } catch (IOException e) { e.printStackTrace(); System.out.println("客户端错误..."); } } // 停止服务 public void stop() { } }
package com.sxt.Server_study02; import java.io.BufferedWriter; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.net.Socket; import java.util.Date; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Response.java * @time: 2019/12/5 9:17 * @desc: */ public class Response { private BufferedWriter bw; // 正文 private StringBuilder content; // 协议头信息:状态行与请求头、回车 private StringBuilder headInfo; // 正文的字节数 private int len; private final String BLANK = " "; private final String CRLF = "\r\n"; public Response() { content = new StringBuilder(); headInfo = new StringBuilder(); len = 0; } public Response(Socket client) { this(); try { bw = new BufferedWriter(new OutputStreamWriter(client.getOutputStream())); } catch (IOException e) { e.printStackTrace(); headInfo = null; } } public Response(OutputStream os) { this(); bw = new BufferedWriter(new OutputStreamWriter(os)); } // 动态添加内容 public Response print(String info){ content.append(info); len += info.getBytes().length; return this; } public Response println(String info){ content.append(info).append(CRLF); len += (info + CRLF).getBytes().length; return this; } // 推送响应信息 public void pushToBrowser(int code) throws IOException { if (null == headInfo){ code = 505; } createHeadInfo(code); bw.append(headInfo); bw.append(content); bw.flush(); } // 构建头信息 private void createHeadInfo(int code) { // 1. 响应行:HTTP/1.1 200 OK headInfo.append("HTTP/1.1").append(BLANK); headInfo.append(code).append(BLANK); switch (code) { case 200: headInfo.append("OK").append(CRLF); break; case 404: headInfo.append("NOT FOUND").append(CRLF); break; case 505: headInfo.append("SERVER ERROR").append(CRLF); break; } // 2. 响应头(最后一行存在空行): headInfo.append("Date:").append(new Date()).append(CRLF); headInfo.append("Server:").append("shsxt Server/0.0.1;charset=GBK").append(CRLF); headInfo.append("Content-type:text/html").append(CRLF); headInfo.append("Content-length:").append(len).append(CRLF); headInfo.append(CRLF); } }
通过分解字符串获取method、URL和请求参数
POST请求参数可能在请求体中存在
分解协议
package com.sxt.Server_study02; import java.io.IOException; import java.io.InputStream; import java.net.Socket; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Request.java * @time: 2019/12/5 10:15 * @desc: */ public class Request { private String requestInfo; // 请求方式 private String method; // 请求url private String url; // 请求参数 private String queryStr; private final String BLANK = " "; private final String CRLF = "\r\n"; public Request(Socket client) throws IOException { this(client.getInputStream()); } public Request(InputStream is) { byte[] datas = new byte[1024 * 1024]; int len; try { len = is.read(datas); this.requestInfo = new String(datas, 0, len); } catch (IOException e) { e.printStackTrace(); return; } // 分解字符串 parseRequestInfo(); } private void parseRequestInfo() { System.out.println("---分解---"); System.out.println("1. 获取请求方式:开头到第一个/"); this.method = this.requestInfo.substring(0, this.requestInfo.indexOf("/")).toLowerCase().trim(); System.out.println("2. 获取请求url:第一个/ 到HTTP/"); System.out.println("可能包含请求参数?前面的url"); // 1. 获取/的位置 int startIdx = this.requestInfo.indexOf("/") + 1; // 2. 获取HTTP/的位置 int endIdx = this.requestInfo.indexOf("HTTP/"); // 3. 分割字符串 this.url = this.requestInfo.substring(startIdx, endIdx); // 4. 获取?的位置 int queryIdx = this.url.indexOf("?"); if (queryIdx >= 0) { // 表示存在请求参数 String[] urlArray = this.url.split("\\?"); this.url = urlArray[0].trim(); queryStr = urlArray[1].trim(); } System.out.println(this.url); System.out.println("3. 获取请求参数:若果Get已经获取,如果post可能在请求体中"); if (method.equals("post")) { String qStr = this.requestInfo.substring(this.requestInfo.lastIndexOf(CRLF)).trim(); if (null == queryStr) { queryStr = qStr; } else { queryStr += "&" + qStr; } } queryStr = null == queryStr?"": queryStr; System.out.println(method + "-->" + url + "-->" + queryStr); } }
package com.sxt.Server_study02; import java.io.IOException; import java.io.InputStream; import java.net.ServerSocket; import java.net.Socket; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Server04.java * @time: 2019/12/4 9:26 * @desc: 封装请求协议:获取method uri以及请求参数 */ public class Server04 { private ServerSocket serverSocket; public static void main(String[] args) { Server04 server = new Server04(); server.start(); } // 启动服务 public void start() { try { serverSocket = new ServerSocket(8888); receive(); } catch (IOException e) { e.printStackTrace(); System.out.println("服务器启动失败..."); } } // 接受连接处理 public void receive() { try { Socket client = serverSocket.accept(); System.out.println("一个客户端建立了连接..."); // 获取请求协议 Request request = new Request(client); Response response = new Response(client); // 关注了内容 response.print("<html>"); response.print("<head>"); response.print("<title>"); response.print("服务器响应成功"); response.print("</title>"); response.print("</head>"); response.print("<body>"); response.print("终于回来了..."); response.print("</body>"); response.print("</html>"); // 关注了状态码 response.pushToBrowser(200); } catch (IOException e) { e.printStackTrace(); System.out.println("客户端错误..."); } } // 停止服务 public void stop() { } }
分解参数
package com.sxt.Server_study02; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.Socket; import java.util.*; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Request2.java * @time: 2019/12/5 10:15 * @desc: 封装请求协议:封装请求参数为Map */ public class Request2 { private String requestInfo; // 请求方式 private String method; // 请求url private String url; // 请求参数 private String queryStr; // 存储参数 private Map<String, List<String>> parameterMap; private final String BLANK = " "; private final String CRLF = "\r\n"; public Request2(Socket client) throws IOException { this(client.getInputStream()); } public String getMethod() { return method; } public String getUrl() { return url; } public String getQueryStr() { return queryStr; } public Request2(InputStream is) { parameterMap = new HashMap<>(); byte[] datas = new byte[1024 * 1024]; int len; try { len = is.read(datas); this.requestInfo = new String(datas, 0, len); } catch (IOException e) { e.printStackTrace(); return; } // 分解字符串 parseRequestInfo(); } private void parseRequestInfo() { System.out.println("---分解---"); System.out.println("1. 获取请求方式:开头到第一个/"); this.method = this.requestInfo.substring(0, this.requestInfo.indexOf("/")).toLowerCase().trim(); System.out.println("2. 获取请求url:第一个/ 到HTTP/"); System.out.println("可能包含请求参数?前面的url"); // 1. 获取/的位置 int startIdx = this.requestInfo.indexOf("/") + 1; // 2. 获取HTTP/的位置 int endIdx = this.requestInfo.indexOf("HTTP/"); // 3. 分割字符串 this.url = this.requestInfo.substring(startIdx, endIdx); // 4. 获取?的位置 int queryIdx = this.url.indexOf("?"); if (queryIdx >= 0) { // 表示存在请求参数 String[] urlArray = this.url.split("\\?"); this.url = urlArray[0].trim(); queryStr = urlArray[1].trim(); } System.out.println(this.url); System.out.println("3. 获取请求参数:若果Get已经获取,如果post可能在请求体中"); if (method.equals("post")) { String qStr = this.requestInfo.substring(this.requestInfo.lastIndexOf(CRLF)).trim(); if (null == queryStr) { queryStr = qStr; } else { queryStr += "&" + qStr; } } queryStr = null == queryStr?"": queryStr; System.out.println(method + "-->" + url + "-->" + queryStr); // 转成Map fav=1&fav=2&uname=shsxt&age=18&other= convertMap(); } // 处理请求参数为Map private void convertMap(){ // 分割字符串 & String[] keyValues = this.queryStr.split("&"); for(String queryStr: keyValues){ // 再次分割字符串 = String[] kv = queryStr.split("="); // 保持两个长度 key 和 value kv = Arrays.copyOf(kv, 2); // 获取key 和 value String key = kv[0]; String value = kv[1]==null? null: decode(kv[1], "utf-8"); // 存储在Map中 if(!parameterMap.containsKey(key)){ // 容器里面没有,第一次 parameterMap.put(key, new ArrayList<String>()); } parameterMap.get(key).add(value); } } // 处理中文 private String decode(String value, String enc){ try { return java.net.URLDecoder.decode(value, enc); } catch (UnsupportedEncodingException e) { e.printStackTrace(); return null; } } // 通过name获取对应的多个值 public String[] getParameterValues(String key){ List<String> values = this.parameterMap.get(key); if(null == values || values.size()<1){ return null; } return values.toArray(new String[0]); } // 通过name获取对应的一个值 public String getParameter(String key){ String[] values = getParameterValues(key); return values == null?null: values[0]; } }
package com.sxt.Server_study02; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Server05.java * @time: 2019/12/4 9:26 * @desc: 封装请求信息中参数转成map */ public class Server05 { private ServerSocket serverSocket; public static void main(String[] args) { Server05 server = new Server05(); server.start(); } // 启动服务 public void start() { try { serverSocket = new ServerSocket(8888); receive(); } catch (IOException e) { e.printStackTrace(); System.out.println("服务器启动失败..."); } } // 接受连接处理 public void receive() { try { Socket client = serverSocket.accept(); System.out.println("一个客户端建立了连接..."); // 获取请求协议 Request2 request = new Request2(client); Response response = new Response(client); // 关注了内容 response.print("<html>"); response.print("<head>"); response.print("<title>"); response.print("服务器响应成功"); response.print("</title>"); response.print("</head>"); response.print("<body>"); response.print("终于回来了..." + request.getParameter("uname")); response.print("</body>"); response.print("</html>"); // 关注了状态码 response.pushToBrowser(200); } catch (IOException e) { e.printStackTrace(); System.out.println("客户端错误..."); } } // 停止服务 public void stop() { } }
加入了Servlet解耦了业务代码
package com.sxt.Server_study03; import com.sxt.tcp.Server; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Server06.java * @time: 2019/12/4 9:26 * @desc: 加入了Servlet解耦了业务代码 */ public class Server06 { private ServerSocket serverSocket; public static void main(String[] args) { Server06 server = new Server06(); server.start(); } // 启动服务 public void start() { try { serverSocket = new ServerSocket(8888); receive(); } catch (IOException e) { e.printStackTrace(); System.out.println("服务器启动失败..."); } } // 接受连接处理 public void receive() { try { Socket client = serverSocket.accept(); System.out.println("一个客户端建立了连接..."); // 获取请求协议 Request request = new Request(client); Response response = new Response(client); // 关注了内容 Servlet servlet = null; if(request.getUrl().equals("login")){ servlet = new LoginServlet(); }else if (request.getUrl().equals("reg")){ servlet = new RegisterServlet(); }else { // 首页 } servlet.service(request, response); // 关注了状态码 response.pushToBrowser(200); } catch (IOException e) { e.printStackTrace(); System.out.println("客户端错误..."); } } // 停止服务 public void stop() { } }
Request和Response同上
Servlet
package com.sxt.Server_study03;
/**
* @author: Li Tian
* @contact: litian_cup@163.com
* @software: IntelliJ IDEA
* @file: Servlet.java
* @time: 2019/12/9 12:03
* @desc: 服务器小脚本接口
*/
public interface Servlet {
void service(Request request, Response response);
}
RegisterServlet
package com.sxt.Server_study03; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: RegisterServlet.java * @time: 2019/12/3 15:59 * @desc: */ public class RegisterServlet implements Servlet{ @Override public void service(Request request, Response response){ response.print("注册成功..."); } }
LoginServlet
package com.sxt.Server_study03; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: LoginServlet.java * @time: 2019/12/3 15:59 * @desc: */ public class LoginServlet implements Servlet { @Override public void service(Request request, Response response) { response.print("<html>"); response.print("<head>"); response.print("<title>"); response.print("第一个servlet"); response.print("</title>"); response.print("</head>"); response.print("<body>"); response.print("欢迎回来..." + request.getParameter("uname")); response.print("</body>"); response.print("</html>"); } }
将之前的Mapping,Entity,WebContext,WebHandler拷贝到工程中
解析web.xml代码
package com.sxt.Server_study03; import com.sxt.Server_study01.servlet.WebContext; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: WebApp.java * @time: 2019/12/9 12:37 * @desc: 解析代码 */ public class WebApp { private static WebContext context; static { try { // SAX解析 // 1. 获取解析工厂 SAXParserFactory factory = SAXParserFactory.newInstance(); // 2. 从解析工厂获取解析器 SAXParser parse = null; parse = factory.newSAXParser(); // 3. 加载文档Document注册处理器 // 4. 编写处理器 WebHandler handler = new WebHandler(); parse.parse(Thread.currentThread().getContextClassLoader().getResourceAsStream("web.xml"), handler); // 5. 获取数据 context = new WebContext(handler.getEntitys(), handler.getMappings()); } catch (Exception e) { System.out.println("解析配置文件错误!"); } } // 通过url获取配置文件对应的servlet public static Servlet getServletFromUrl(String url) { // 假设你输入了 /login or /g or /reg String className = context.getClz("/" + url); Class clz = null; try { clz = Class.forName(className); Servlet servlet = (Servlet) clz.getConstructor().newInstance(); return servlet; } catch (Exception e) { e.printStackTrace(); } return null; } }
新增OthersServlet
package com.sxt.Server_study03; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: OthersServlet.java * @time: 2019/12/9 13:17 * @desc: 其他测试页面 */ public class OthersServlet implements Servlet{ @Override public void service(Request request, Response response) { response.print("其他测试页面..."); } }
修改xml
<?xml version="1.0" encoding="UTF-8"?> <web-app> <servlet> <servlet-name>login</servlet-name> <servlet-class>com.sxt.Server_study03.LoginServlet</servlet-class> </servlet> <servlet> <servlet-name>reg</servlet-name> <servlet-class>com.sxt.Server_study03.RegisterServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>login</servlet-name> <url-pattern>/login</url-pattern> <url-pattern>/g</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>reg</servlet-name> <url-pattern>/reg</url-pattern> </servlet-mapping> <servlet> <servlet-name>others</servlet-name> <servlet-class>com.sxt.Server_study03.OthersServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>others</servlet-name> <url-pattern>/o</url-pattern> </servlet-mapping> </web-app>
整合配置文件
package com.sxt.Server_study03; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Server06.java * @time: 2019/12/4 9:26 * @desc: 整合配置文件 */ public class Server07 { private ServerSocket serverSocket; public static void main(String[] args) { Server07 server = new Server07(); server.start(); } // 启动服务 public void start() { try { serverSocket = new ServerSocket(8888); receive(); } catch (IOException e) { e.printStackTrace(); System.out.println("服务器启动失败..."); } } // 接受连接处理 public void receive() { try { Socket client = serverSocket.accept(); System.out.println("一个客户端建立了连接..."); // 获取请求协议 Request request = new Request(client); Response response = new Response(client); Servlet servlet = WebApp.getServletFromUrl(request.getUrl()); if(null != servlet){ servlet.service(request, response); // 关注了状态码 response.pushToBrowser(200); }else { // 错误页面... response.pushToBrowser(404); } } catch (IOException e) { e.printStackTrace(); System.out.println("客户端错误..."); } } // 停止服务 public void stop() { } }
多线程处理,加入分发器
package com.sxt.Server_study03; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Server08.java * @time: 2019/12/4 9:26 * @desc: 多线程处理,加入分发器 */ public class Server08 { private ServerSocket serverSocket; private boolean isRunning; public static void main(String[] args) { Server08 server = new Server08(); server.start(); } // 启动服务 public void start() { try { serverSocket = new ServerSocket(8888); isRunning = true; receive(); } catch (IOException e) { e.printStackTrace(); System.out.println("服务器启动失败..."); stop(); } } // 接受连接处理 public void receive() { while (isRunning) { try { Socket client = serverSocket.accept(); System.out.println("一个客户端建立了连接..."); // 多线程处理 new Thread(new Dispatcher(client)).start(); } catch (IOException e) { e.printStackTrace(); System.out.println("客户端错误..."); } } } // 停止服务 public void stop() { isRunning = false; try { this.serverSocket.close(); System.out.println("服务器已停止..."); } catch (IOException e) { e.printStackTrace(); } } }
分发器
package com.sxt.Server_study03; import java.io.IOException; import java.net.Socket; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Dispatcher.java * @time: 2019/12/12 16:36 * @desc: 分发器 */ public class Dispatcher implements Runnable { private Socket client; private Request request; private Response response; public Dispatcher(Socket client) { this.client = client; try { // 获取请求和响应 request = new Request(client); response = new Response(client); } catch (IOException e) { e.printStackTrace(); this.release(); } } @Override public void run() { try { Servlet servlet = WebApp.getServletFromUrl(request.getUrl()); if (null != servlet) { servlet.service(request, response); // 关注了状态码 response.pushToBrowser(200); } else { // 错误页面... response.pushToBrowser(404); } }catch (Exception e){ try { response.pushToBrowser(500); } catch (IOException ex) { ex.printStackTrace(); } } release(); } // 释放资源 private void release() { try { client.close(); } catch (IOException ex) { ex.printStackTrace(); } } }
这一部分有问题is.readAllBytes()这里报错,并且也没有找到解决办法
分发器
package com.sxt.Server_study03; import java.io.IOException; import java.io.InputStream; import java.net.Socket; import java.nio.file.Files; import java.nio.file.Paths; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Dispatcher.java * @time: 2019/12/12 16:36 * @desc: 分发器 */ public class Dispatcher implements Runnable { private Socket client; private Request request; private Response response; public Dispatcher(Socket client) { this.client = client; try { // 获取请求和响应 request = new Request(client); response = new Response(client); } catch (IOException e) { e.printStackTrace(); this.release(); } } @Override public void run() { try { if (null == request.getUrl() || request.getUrl().equals("")) { InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("index.html"); response.print(new String(is.readAllBytes())); response.println(new String(Files.readAllBytes(Paths.get("index.html")))); response.pushToBrowser(200); is.close(); return; } Servlet servlet = WebApp.getServletFromUrl(request.getUrl()); if (null != servlet) { servlet.service(request, response); // 关注了状态码 response.pushToBrowser(200); } else { InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("error.html"); response.print(new String(is.readAllBytes())); response.pushToBrowser(404); is.close(); } } catch (Exception e) { try { response.print("你好我不好,我会马上好"); response.pushToBrowser(500); } catch (IOException ex) { ex.printStackTrace(); } } release(); } // 释放资源 private void release() { try { client.close(); } catch (IOException ex) { ex.printStackTrace(); } } }
处理404/505和首页
package com.sxt.Server_study03; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Server08.java * @time: 2019/12/4 9:26 * @desc: 处理404/505和首页 */ public class Server09 { private ServerSocket serverSocket; private boolean isRunning; public static void main(String[] args) { Server09 server = new Server09(); server.start(); } // 启动服务 public void start() { try { serverSocket = new ServerSocket(8888); isRunning = true; receive(); } catch (IOException e) { e.printStackTrace(); System.out.println("服务器启动失败..."); stop(); } } // 接受连接处理 public void receive() { while (isRunning) { try { Socket client = serverSocket.accept(); System.out.println("一个客户端建立了连接..."); // 多线程处理 new Thread(new Dispatcher(client)).start(); } catch (IOException e) { e.printStackTrace(); System.out.println("客户端错误..."); } } } // 停止服务 public void stop() { isRunning = false; try { this.serverSocket.close(); System.out.println("服务器已停止..."); } catch (IOException e) { e.printStackTrace(); } } }
Annotation
作用
格式
package com.sxt.test.annotation; import java.util.ArrayList; import java.util.Date; import java.util.List; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo01.java * @time: 2019/12/16 9:34 * @desc: */ public class Demo01 { @Override // 重写父类方法 public String toString() { return ""; } @Deprecated // 该方法不建议使用 public static void test1() { System.out.println("你大爷"); } @SuppressWarnings("all") // 不显示所有警告信息 public static void test2() { List list = new ArrayList(); } @SuppressWarnings(value = {"unchecked", "deprecation"}) // 不显示某几个警告信息 public static void main(String[] args) { test1(); } }
ORM:Object Relationship Mapping,对象关系映射
使用注解完成类和表结构的映射关系
类注解
package com.sxt.test.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: LTTable.java * @time: 2019/12/16 12:44 * @desc: */ @Target(value = {ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface LTTable { String value(); }
属性注解
package com.sxt.test.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: LTField.java * @time: 2019/12/16 12:46 * @desc: 说明属性的特征 */ @Target(value = {ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface LTField { String columnName(); String type(); int length(); }
学生类
package com.sxt.test.annotation; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Student.java * @time: 2019/12/16 12:43 * @desc: */ @LTTable("tb_student") public class Student { @LTField(columnName = "id", type = "int", length = 10) private int id; @LTField(columnName = "sname", type = "varchar", length = 10) private String studentName; @LTField(columnName = "age", type = "int", length = 3) private int age; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getStudentName() { return studentName; } public void setStudentName(String studentName) { this.studentName = studentName; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
使用反射读取注解的信息,模拟处理注解信息的流程
package com.sxt.test.annotation; import java.lang.annotation.Annotation; import java.lang.reflect.Field; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo03.java * @time: 2019/12/16 12:49 * @desc: 使用反射读取注解的信息,模拟处理注解信息的流程 */ public class Demo03 { public static void main(String[] args) { try { Class clazz = Class.forName("com.sxt.test.annotation.Student"); // 获得类的所有有效注解 Annotation[] annotations = clazz.getAnnotations(); for (Annotation a : annotations) { System.out.println(a); } // 获得类的指定的注解 LTTable st = (LTTable) clazz.getAnnotation(LTTable.class); System.out.println(st.value()); // 获得类的属性的注解 Field f = clazz.getDeclaredField("studentName"); LTField ltField = f.getAnnotation(LTField.class); System.out.println(ltField.columnName()+"-->"+ltField.type()+"-->"+ltField.length()); // 根据获得的表明、字段的信息,拼出DDL语句,然后使用JDBC执行这个SQL,在数据库中生成相关的表 } catch (Exception e) { e.printStackTrace(); } } }
介绍+Class对象获取
动态语言:程序运行时,可以改变程序结构或变态类型。(如python、javascript)
Java不是动态语言,但可以称为“准动态语言”。Java有一定的动态性,我们可以利用反射机制、字节码操作获得类似动态语言的特性。
反射机制
测试各种类型对应的java.lang.Class对象的获取方式
package com.sxt.test.reflection; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo01.java * @time: 2019/12/17 18:59 * @desc: 测试各种类型对应的java.lang.Class对象的获取方式 */ public class Demo01 { public static void main(String[] args) { String path = "com.sxt.test.bean.User"; try { Class clazz = Class.forName(path); // 对象是表示或封装一些数据。一个类被加载后,JVM会创建一个对应该类的Class对象, // 类的整个结构信息会放到对应的Class对象中。这个Class对象就像一面镜子一样, // 通过这面镜子我们可以看到对应类的全部信息。 System.out.println(clazz); System.out.println(clazz.hashCode()); // 一个类只对应一个Class对象 Class clazz2 = Class.forName(path); System.out.println(clazz2.hashCode()); Class strClazz = String.class; Class strClazz2 = path.getClass(); // 获得的都是String的Class对象 System.out.println(strClazz==strClazz2); Class intClazz = int.class; System.out.println(intClazz.hashCode()); // 数组跟维度、类型都有关 int[] arr01 = new int[10]; int[] arr02 = new int[30]; int[][] arr03 = new int[10][10]; double[] arr04 = new double[10]; System.out.println(arr01.getClass().hashCode() == arr02.getClass().hashCode()); System.out.println(arr01.getClass().hashCode() == arr03.getClass().hashCode()); System.out.println(arr01.getClass().hashCode() == arr04.getClass().hashCode()); } catch (Exception e) { e.printStackTrace(); } } }
动态操作+构造器+方法+属性
应用反射的API获取类的信息(类的名字、属性、方法、构造器等)
package com.sxt.test.reflection; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo02.java * @time: 2020/1/7 14:33 * @desc: 应用反射的API获取类的信息(类的名字、属性、方法、构造器等) */ public class Demo02 { public static void main(String[] args) { String path = "com.sxt.test.bean.User"; try { Class clazz = Class.forName(path); // 获取类的全名 System.out.println(clazz.getName()); // 获取类的包名+全名 System.out.println(clazz.getSimpleName()); // 获取属性信息 // 只能获得public的field // Field[] fields = clazz.getFields(); // 返回所有的field Field[] fields = clazz.getDeclaredFields(); System.out.println(fields.length); for(Field temp: fields){ System.out.println("属性:" + temp); } // 通过名称获取属性 Field f = clazz.getDeclaredField("uname"); System.out.println(f); // 获取方法信息 Method[] methods = clazz.getDeclaredMethods(); Method m1 = clazz.getDeclaredMethod("getUname"); Method m2 = clazz.getDeclaredMethod("setUname", String.class); for(Method temp: methods){ System.out.println("方法:" + temp); } // 获取构造器信息 Constructor[] constructors = clazz.getDeclaredConstructors(); for(Constructor temp: constructors){ System.out.println("构造器:" + temp); } // 获取某个特定的构造器 Constructor c1 = clazz.getDeclaredConstructor(); System.out.println("无参构造器:" + c1); Constructor c2 = clazz.getDeclaredConstructor(int.class, int.class, String.class); System.out.println("有参构造器:" + c2); } catch (Exception e) { e.printStackTrace(); } } }
通过反射API动态的操作:构造器、方法、属性
package com.sxt.test.reflection; import com.sxt.test.bean.User; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo3.java * @time: 2020/1/8 17:03 * @desc: 通过反射API动态的操作:构造器、方法、属性 */ public class Demo3 { public static void main(String[] args) { String path = "com.sxt.test.bean.User"; try { Class<User> clazz = (Class<User>) Class.forName(path); // 通过反射API调用构造方法,构造对象 // 其实是调用了User的无参构造方法 User u = clazz.newInstance(); System.out.println(u); // 指定构造器的调用 Constructor<User> c = clazz.getDeclaredConstructor(int.class, int.class, String.class); User u2 = c.newInstance(1001, 18, "李英俊"); System.out.println(u2.getUname()); // 通过反射API调用普通方法 User u3 = clazz.newInstance(); u3.setUname("李不羁"); // 上一句用反射来写如下 Method method = clazz.getDeclaredMethod("setUname", String.class); method.invoke(u3, "李不羁"); System.out.println(u3.getUname()); // 通过反射API操作属性 User u4 = clazz.newInstance(); Field f = clazz.getDeclaredField("uname"); // 这个属性不需要做安全检查了,可以直接访问 f.setAccessible(true); // 通过反射直接写属性 f.set(u4, "李傻瓜"); System.out.println(u4.getUname()); // 通过反射直接读属性的值 System.out.println(f.get(u4)); } catch (Exception e) { e.printStackTrace(); } } }
提高反射效率+操作泛型+操作注解
setAccessible
反射操作泛型(Generic)
操作泛型
package com.sxt.test.reflection; import com.sxt.test.bean.User; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.List; import java.util.Map; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo4.java * @time: 2020/1/9 10:44 * @desc: 操作泛型 */ public class Demo4 { public void test01(Map<String, User> map, List<User> list){ System.out.println("Demo04.test01()"); } public Map<Integer, User> test02(){ System.out.println("Demo04.test02()"); return null; } public static void main(String[] args){ try{ // 获得指定方法参数泛型信息 Method m = Demo4.class.getMethod("test01", Map.class, List.class); Type[] t = m.getGenericParameterTypes(); for (Type paramType: t){ System.out.println("#" + paramType); if(paramType instanceof ParameterizedType){ Type[] genericTypes = ((ParameterizedType) paramType).getActualTypeArguments(); for (Type genericType: genericTypes){ System.out.println("泛型类型:" + genericType); } } } // 获得指定方法返回值泛型信息 Method m2 = Demo4.class.getMethod("test02"); Type returnType = m2.getGenericReturnType(); if(returnType instanceof ParameterizedType){ Type[] genericTypes = ((ParameterizedType) returnType).getActualTypeArguments(); for (Type genericType: genericTypes){ System.out.println("返回值,泛型类型:" + genericType); } } } catch (NoSuchMethodException e) { e.printStackTrace(); } } }
操作注解
package com.sxt.test.annotation; import java.lang.annotation.Annotation; import java.lang.reflect.Field; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo5.java * @time: 2020/1/9 10:57 * @desc: 操作注解 */ public class Demo5 { public static void main(String[] args) { try { Class clazz = Class.forName("com.sxt.test.annotation.Student"); // 获得类的所有有效注解 Annotation[] annotations = clazz.getAnnotations(); for (Annotation a : annotations) { System.out.println(a); } // 获得类指定的注解 LTTable st = (LTTable) clazz.getAnnotation(LTTable.class); System.out.println(st.value()); // 获得类的属性的注解 Field f = clazz.getDeclaredField("studentName"); LTField ltField = f.getAnnotation(LTField.class); System.out.println(ltField.columnName() + "--" + ltField.type() + "--" + ltField.length()); // 根据获得的表名、字段的信息,拼出DDL语句,然后,使用JDBC执行这个SQL,在数据库中生成相关的表 } catch (Exception e) { e.printStackTrace(); } } }
通过JavaCompiler动态编译
public static int compileFile(String sourceFile){
// 动态编译
JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
int result = compiler.run(null, null, null, sourceFile);
System.out.println(result==0?"编译成功": "编译失败");
return result;
}
package com.sxt.test.testDynamicCompile; import javax.tools.JavaCompiler; import javax.tools.ToolProvider; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.lang.reflect.Method; import java.net.URL; import java.net.URLClassLoader; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo1.java * @time: 2020/1/9 14:38 * @desc: 动态编译 */ public class Demo1 { public static void main(String[] args) throws IOException { // 如果是给的字符串的话,可以 // 通过IO流操作,将字符串存储成一个临时文件,然后调用动态编译方法! // 如果是文件的话,就按下面的方法 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); int result = compiler.run(null, null, null, "D:\\java_test\\HelloWorld.java"); System.out.println(result == 0 ? "编译成功" : "编译失败"); // 上面只是进行了编译,下面还要进行动态运行编译好的类 // 1. 通过Runtime调用执行类 Runtime run = Runtime.getRuntime(); Process process = run.exec("java -cp D:\\java_test HelloWorld"); InputStream in = process.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(in)); String info = ""; while ((info = reader.readLine()) != null) { System.out.println(info); } // 2. 通过反射调用执行类 try { URL[] urls = new URL[]{new URL("file:/" + "D:\\java_test\\")}; URLClassLoader loader = new URLClassLoader(urls); Class c = loader.loadClass("HelloWorld"); // 调用加载类的main方法 Method m = c.getMethod("main", String[].class); // 如果这里不用Object强制转型的话,invoke后面传入的就不是一个String // 的字符串数组,而是两个字符串,认为是两个参数,于是就会发生参数个数不匹配的问题 m.invoke(null, (Object) new String[]{}); } catch (Exception e) { e.printStackTrace(); } } }
JAVA脚本引擎是从JDK6.0之后添加的新功能
在写Demo的时候存在一些报错的情况,这是因为JDK6.0的语法在JDK8.0中已经过时了
function test(){
var a = 3;
var b = 4;
print("invoke js file: " + (a+b));
}
// 执行test方法
test();
package com.sxt.test.testRhino; import javax.script.Invocable; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import java.io.FileReader; import java.net.URL; import java.util.List; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo01.java * @time: 2020/1/13 15:58 * @desc: 测试脚本引擎执行JavaScript代码 */ public class Demo01 { public static void main(String[] args) throws Exception { // 获得脚本引擎的对象 ScriptEngineManager sem = new ScriptEngineManager(); ScriptEngine engine = sem.getEngineByName("javascript"); // 定义变量,存储到引擎上下文中 engine.put("msg", "liyingjun is g good man!"); String str = "var user = {name: 'litian', age: 18, schools: ['清华大学', '北京尚学堂']};"; str += "print(user.name);"; // 执行脚本 engine.eval(str); engine.eval("msg = 'sxt is a good school!'"); System.out.println(engine.get("msg")); System.out.println("########################"); // 定义函数 engine.eval("function add(a, b){var sum = a + b; return sum;}"); // 取得调用接口 Invocable jsInvoke = (Invocable) engine; // 执行脚本中定义的方法 Object result1 = jsInvoke.invokeFunction("add", new Object[]{13, 20}); System.out.println(result1); // 导入其他java包,使用其他包中的java类 String jsCode = "var list=java.util.Arrays.asList([\"北京尚学堂\", \"清华大学\", \"中国石油大学\"]);"; engine.eval(jsCode); List<String> list2 = (List<String>) engine.get("list"); for (String temp : list2) { System.out.println(temp); } // 执行一个js文件 URL url = Demo01.class.getClassLoader().getResource("com/sxt/test/testRhino/test.js"); FileReader fr = new FileReader(url.getPath()); engine.eval(fr); fr.close(); } }
Java动态性的两种常见实现方式:
运行时操作字节码可以让我们实现如下功能:
优势
常见的字节码操作类库
测试使用javassist生成一个新的类
package com.sxt.test.testJavassist; import javassist.*; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo1.java * @time: 2020/1/14 9:21 * @desc: 测试使用javassist生成一个新的类 */ public class Demo1 { public static void main(String[] args) throws Exception { ClassPool pool = ClassPool.getDefault(); CtClass cc = pool.makeClass("com.sxt.test.testJavassist.EmpTest"); // 创建属性 CtField f1 = CtField.make("private int empno;", cc); CtField f2 = CtField.make("private String ename;", cc); cc.addField(f1); cc.addField(f2); // 创建方法 CtMethod m1 = CtMethod.make("public int getEmpno(){return empno;}", cc); CtMethod m2 = CtMethod.make("public void setEmpno(int empno){this.empno=empno;}", cc); cc.addMethod(m1); cc.addMethod(m2); // 添加构造器 CtConstructor constructor = new CtConstructor(new CtClass[]{CtClass.intType, pool.get("java.lang.String")}, cc); constructor.setBody("{this.empno = empno; this.ename = ename;}"); cc.addConstructor(constructor); // 将上面构造好的类写入到下面的工作空间下面 cc.writeFile("D:\\java_test"); System.out.println("生成类,成功!"); } }
测试javassist的API
Emp.java
package com.sxt.test.testJavassist; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Emp.java * @time: 2020/1/14 9:28 * @desc: */ @Author(name="litian", year=2020) public class Emp { private int empno; private String name; public int getEmpno() { return empno; } public void setEmpno(int empno) { this.empno = empno; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Emp() { } public Emp(int empno, String name) { this.empno = empno; this.name = name; } public void sayHello(int a){ System.out.println("Hello!: " + a); } }
Author.java
package com.sxt.test.testJavassist;
/**
* @author: Li Tian
* @contact: litian_cup@163.com
* @software: IntelliJ IDEA
* @file: Author.java
* @time: 2020/1/14 14:50
* @desc:
*/
public @interface Author {
String name();
int year();
}
测试javassist的API
package com.sxt.test.testJavassist; import javassist.*; import java.lang.reflect.Method; import java.util.Arrays; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo2.java * @time: 2020/1/14 10:45 * @desc: 测试javassist的API */ public class Demo2 { /* 处理类的基本用法 */ public static void test1() throws Exception { ClassPool pool = ClassPool.getDefault(); CtClass cc = pool.get("com.sxt.test.testJavassist.Emp"); byte[] bytes = cc.toBytecode(); System.out.println(Arrays.toString(bytes)); // 获取类名 System.out.println(cc.getName()); // 获取简要类名 System.out.println(cc.getSimpleName()); // 获得父类 System.out.println(cc.getSuperclass()); // 获得接口 System.out.println(cc.getInterfaces()); } public static void test2() throws Exception { /* 测试产生新的方法 */ ClassPool pool = ClassPool.getDefault(); CtClass cc = pool.get("com.sxt.test.testJavassist.Emp"); // 新建方法1 CtMethod m1 = CtNewMethod.make("public int add(int a, int b){return a+b;}", cc); // 新建方法2 CtMethod m2 = new CtMethod(CtClass.intType, "add", new CtClass[]{CtClass.intType, CtClass.intType}, cc); // 设置权限 m2.setModifiers(Modifier.PUBLIC); // 设置方法体 $1等等代表的是形参的占位符 m2.setBody("{System.out.println(\"冲冲冲!\"); return $1+$2;}"); cc.addMethod(m2); // 通过反射调用新生成的方法 Class clazz = cc.toClass(); // 通过调用Emp无参构造器,创建新的Emp对象 Object obj = clazz.newInstance(); Method method = clazz.getDeclaredMethod("add", int.class, int.class); Object result = method.invoke(obj, 200, 300); System.out.println(result); } public static void test3() throws Exception { /* 对已有的方法进行修改 */ ClassPool pool = ClassPool.getDefault(); CtClass cc = pool.get("com.sxt.test.testJavassist.Emp"); CtMethod cm = cc.getDeclaredMethod("sayHello", new CtClass[]{CtClass.intType}); cm.insertBefore("System.out.println($1);System.out.println(\"start!!!\");"); cm.insertAfter("System.out.println(\"end!!!\");"); // 在某一行前面加代码,从1开始计数,不存在迭代效应,也就是改行代码的行数不会因加入了新的代码而改变 cm.insertAt(41, "System.out.println(\"???\");"); cm.insertAt(42, "System.out.println(\"!!!\");"); // 通过反射调用新生成的方法 Class clazz = cc.toClass(); Object obj = clazz.newInstance(); Method method = clazz.getDeclaredMethod("sayHello", int.class); Object result = method.invoke(obj, 200); System.out.println(result); } public static void test4() throws Exception { /* 对已有的属性进行修改 */ ClassPool pool = ClassPool.getDefault(); CtClass cc = pool.get("com.sxt.test.testJavassist.Emp"); // CtField f1 = CtField.make("private int empno;", cc); CtField f1 = new CtField(CtClass.intType, "salary", cc); f1.setModifiers(Modifier.PRIVATE); // 后面的参数是默认值,如果不写的话,就没有默认值 cc.addField(f1, "1000"); // 获取指定的属性 cc.getDeclaredField("salary"); // 除了直接通过增加方法的方式提供getter和setter方法,还可以通过以下方式 cc.addMethod(CtNewMethod.getter("getSalary", f1)); cc.addMethod(CtNewMethod.setter("setSalary", f1)); } public static void test5() throws Exception { /* 查看已有构造方法,并进行修改 */ ClassPool pool = ClassPool.getDefault(); CtClass cc = pool.get("com.sxt.test.testJavassist.Emp"); CtConstructor[] cs = cc.getConstructors(); for (CtConstructor c : cs) { System.out.println(c.getLongName()); c.insertBefore("System.out.println(\"what?\");"); } // 通过反射调用新生成的方法 Class clazz = cc.toClass(); Object obj = clazz.newInstance(); } public static void test6() throws Exception { /* 注解 */ ClassPool pool = ClassPool.getDefault(); CtClass cc = pool.get("com.sxt.test.testJavassist.Emp"); Object[] all = cc.getAnnotations(); Author a = (Author) all[0]; String name = a.name(); int year = a.year(); System.out.println("name: " + name + "year: " + year); } public static void main(String[] args) throws Exception { test6(); } }
Javassist库的局限性
JVM运行和类加载全过程
类的加载机制(JVM内存分析+反射机制核心原理+常量池理解)
JVM把class文件加载到内存,并对数据进行校验、解析和初始化,最终形成JVM可以直接使用的Java类型的过程。
加载:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区中的运行时数据结构,在堆中生成一个代表这个类的java.lang.Class对象,作为方法区类数据的访问入口。
链接:将Java类的二进制代码合并到JVM的运行状态之中的过程
初始化
<clinit>()
方法的过程。类构造器<clinit>()
方法是由编译器自动收集类中的所有类变量的赋值动作和静态语句块(static块)中的语句合并产生的。<clinit>()
方法在多线程环境中被正确加锁和同步。过程图解
初始化时机+静态初始化块执行的顺序问题
类的主动引用和被动引用
深入类加载器
类加载器原理
类加载器树状结构、双亲委托(代理)机制
分类:
类加载器的代理模式
类加载器实战
package com.sxt.test.classLoader; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo01.java * @time: 2020/1/30 21:40 * @desc: */ public class Demo01 { public static void main(String[] args){ // 应用加载器 System.out.println(ClassLoader.getSystemClassLoader()); // 扩展加载器(上一个的父类) System.out.println(ClassLoader.getSystemClassLoader().getParent()); // 引导加载器,但是是C写的,所以为null(上一个的父类) System.out.println(ClassLoader.getSystemClassLoader().getParent().getParent()); // 系统中类的路径 System.out.println(System.getProperty("java.class.path")); } }
自定义类加载器(文件、网路、加密)
自定义加载器的流程:
自定义文件系统类加载器
FileSystemClassLoader
package com.sxt.test.classLoader; import java.io.*; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: FileSystemClassLoader.java * @time: 2020/1/31 20:58 * @desc: 自定义文件系统类加载器 */ public class FileSystemClassLoader extends ClassLoader { // com.sxt.test.bean.User --> F:/BookStudy/else/JAVAPro/src/com/sxt/test/bean/User.class private String rootDir; public FileSystemClassLoader(String rootDir) { this.rootDir = rootDir; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { Class<?> c = findLoadedClass(name); // 应该要先查询有没有加载过这个类,如果已经加载,则直接返回加载好的类,如果没有,则加载新的类。 if (c != null) { return c; } else { ClassLoader parent = this.getParent(); // 委派给父类加载 try { c = parent.loadClass(name); }catch (Exception e){ System.out.println("父类加载器没有加载到这个类哦!"); } if (c != null) { return c; } else { byte[] classData = getClassData(name); if (classData == null) { throw new ClassNotFoundException(); } else { c = defineClass(name, classData, 0, classData.length); } } } return c; } private byte[] getClassData(String classname) { String path = rootDir + "/" + classname.replace('.', '/') + ".class"; // 可以使用IOUtils将流中的数据转成字节数组,这里采用手写了 InputStream is = null; ByteArrayOutputStream baos = null; try { is = new FileInputStream(path); baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int temp = 0; while ((temp = is.read(buffer)) != -1) { baos.write(buffer, 0, temp); } return baos.toByteArray(); } catch (IOException e) { e.printStackTrace(); return null; } finally { try { if (is != null) { is.close(); } }catch(IOException e){ e.printStackTrace(); } try { if (baos != null) { baos.close(); } }catch(IOException e){ e.printStackTrace(); } } } }
测试自定义类加载器FileSystemClassLoader
package com.sxt.test.classLoader; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo02.java * @time: 2020/1/31 21:17 * @desc: 测试自定义类加载器FileSystemClassLoader */ public class Demo02 { public static void main(String[] args) throws ClassNotFoundException { FileSystemClassLoader loader1 = new FileSystemClassLoader("F:\\Java WorkSpace"); FileSystemClassLoader loader2 = new FileSystemClassLoader("F:\\Java WorkSpace"); System.out.println(loader1 == loader2); Class<?> c1 = loader1.loadClass("NewClass"); Class<?> c2 = loader1.loadClass("NewClass"); Class<?> c3 = loader2.loadClass("NewClass"); Class<?> c4 = loader1.loadClass("java.lang.String"); Class<?> c5 = loader1.loadClass("com.sxt.test.classLoader.Demo01"); System.out.println(c1); System.out.println(c1.hashCode()); System.out.println(c2); System.out.println(c2.hashCode()); // 注意:被两个类加载器加载的同一个类,JVM不认为是相同的类。 System.out.println(c3); System.out.println(c3.hashCode()); System.out.println(c4); System.out.println(c4.hashCode()); System.out.println(c1.getClassLoader()); System.out.println(c2.getClassLoader()); System.out.println(c3.getClassLoader()); // 自定义的类加载器 System.out.println(c4.getClassLoader()); // 引导类加载器 System.out.println(c5.getClassLoader()); // 系统默认的类加载器 } }
自定义网路类加载器
package com.sxt.test.classLoader; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: FileSystemClassLoader.java * @time: 2020/1/31 20:58 * @desc: 自定义网路类加载器 */ public class NetSystemClassLoader extends ClassLoader { // com.sxt.test.bean.User --> www.sxt.cn/JAVAPro/src/com/sxt/test/bean/User.class private String rootUrl; public NetSystemClassLoader(String rootDir) { this.rootUrl = rootDir; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { Class<?> c = findLoadedClass(name); // 应该要先查询有没有加载过这个类,如果已经加载,则直接返回加载好的类,如果没有,则加载新的类。 if (c != null) { return c; } else { ClassLoader parent = this.getParent(); // 委派给父类加载 try { c = parent.loadClass(name); }catch (Exception e){ System.out.println("父类加载器没有加载到这个类哦!"); } if (c != null) { return c; } else { byte[] classData = getClassData(name); if (classData == null) { throw new ClassNotFoundException(); } else { c = defineClass(name, classData, 0, classData.length); } } } return c; } private byte[] getClassData(String classname) { String path = rootUrl + "/" + classname.replace('.', '/') + ".class"; // 可以使用IOUtils将流中的数据转成字节数组,这里采用手写了 InputStream is = null; ByteArrayOutputStream baos = null; try { URL url = new URL(path); is = url.openStream(); baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int temp = 0; while ((temp = is.read(buffer)) != -1) { baos.write(buffer, 0, temp); } return baos.toByteArray(); } catch (IOException e) { e.printStackTrace(); return null; } finally { try { if (is != null) { is.close(); } }catch(IOException e){ e.printStackTrace(); } try { if (baos != null) { baos.close(); } }catch(IOException e){ e.printStackTrace(); } } } }
自定义加密解密类加载器
加密工具类
package com.sxt.test.classLoader; import java.io.*; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: EncrpUtil.java * @time: 2020/2/1 22:52 * @desc: 加密工具类 */ public class EncrpUtil { public static void main(String[] args) { encrpt("F:/Java WorkSpace/NewClass.class", "F:/Java WorkSpace/temp/NewClass.class"); } public static void encrpt(String src, String dest) { FileInputStream fis = null; FileOutputStream fos = null; try { fis = new FileInputStream(src); fos = new FileOutputStream(dest); int temp = -1; while ((temp = fis.read()) != -1) { // 取反操作 fos.write(temp ^ 0xff); } } catch (IOException e) { e.printStackTrace(); } finally { try { if (fis != null) { fis.close(); } } catch (IOException e) { e.printStackTrace(); } } try { if (fos != null) { fos.close(); } } catch (IOException e) { e.printStackTrace(); } } }
解密工具类:加载文件系统中加密后的class字节码的类加载器
package com.sxt.test.classLoader; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: DecrptClassLoader.java * @time: 2020/2/1 23:03 * @desc: 解密工具类:加载文件系统中加密后的class字节码的类加载器 */ public class DecrptClassLoader extends ClassLoader { // com.sxt.test.bean.User --> F:/BookStudy/else/JAVAPro/src/com/sxt/test/bean/User.class private String rootDir; public DecrptClassLoader(String rootDir) { this.rootDir = rootDir; } @Override protected Class<?> findClass(String name) throws ClassNotFoundException { Class<?> c = findLoadedClass(name); // 应该要先查询有没有加载过这个类,如果已经加载,则直接返回加载好的类,如果没有,则加载新的类。 if (c != null) { return c; } else { ClassLoader parent = this.getParent(); // 委派给父类加载 try { c = parent.loadClass(name); } catch (Exception e) { System.out.println("父类加载器没有加载到这个类哦!"); } if (c != null) { return c; } else { byte[] classData = getClassData(name); if (classData == null) { throw new ClassNotFoundException(); } else { c = defineClass(name, classData, 0, classData.length); } } } return c; } private byte[] getClassData(String classname) { String path = rootDir + "/" + classname.replace('.', '/') + ".class"; // 可以使用IOUtils将流中的数据转成字节数组,这里采用手写了 InputStream is = null; ByteArrayOutputStream baos = null; try { is = new FileInputStream(path); baos = new ByteArrayOutputStream(); int temp = -1; while ((temp = is.read()) != -1) { // 取反操作,进行解密 baos.write(temp ^ 0xff); } return baos.toByteArray(); } catch (IOException e) { e.printStackTrace(); return null; } finally { try { if (is != null) { is.close(); } } catch (IOException e) { e.printStackTrace(); } try { if (baos != null) { baos.close(); } } catch (IOException e) { e.printStackTrace(); } } } }
测试简单加密解密(取反)操作
package com.sxt.test.classLoader; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo03.java * @time: 2020/2/1 22:49 * @desc: 测试简单加密解密(取反)操作 */ public class Demo03 { public static void main(String[] args) throws ClassNotFoundException { int a = 3; // 00000011 System.out.println(Integer.toBinaryString(a ^ 0xff)); // 加载这个加密的类会报类格式错误ClassFormatError FileSystemClassLoader loader1 = new FileSystemClassLoader("F:/Java WorkSpace"); Class<?> c1 = loader1.loadClass("NewClass_encrp"); System.out.println(c1); // 使用解密类加载器加载加密后的类 DecrptClassLoader loader = new DecrptClassLoader("F:/Java WorkSpace/temp"); Class<?> c = loader.loadClass("NewClass"); System.out.println(c); } }
线程上下文类加载器
线程上下文类加载器测试
package com.sxt.test.classLoader; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Demo05.java * @time: 2020/2/2 22:51 * @desc: 线程上下文类加载器测试 */ public class Demo05 { public static void main(String[] args) throws ClassNotFoundException { ClassLoader loader = Demo05.class.getClassLoader(); System.out.println(loader); ClassLoader loader2 = Thread.currentThread().getContextClassLoader(); System.out.println(loader2); Thread.currentThread().setContextClassLoader(new FileSystemClassLoader("F:/Java WorkSpace")); System.out.println(Thread.currentThread().getContextClassLoader()); Class<Demo01> c = (Class<Demo01>) Thread.currentThread().getContextClassLoader().loadClass("com.sxt.test.classLoader.Demo01"); System.out.println(c); System.out.println(c.getClassLoader()); } }
服务器类加载原理和OSGI介绍
核心作用:保证一个类只有一个实例,并且提供一个访问该实例的全局访问点。
常见的应用场景:
单例模式的优点:
常见的五种单例模式实现方式:
(单例对象立即加载)
代码
package com.sxt.singleton; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: SingletonDemo01.java * @time: 2020/2/3 18:41 * @desc: 测试饿汉式单例模式 */ public class SingletonDemo01 { // 上来就把这个对象先new了,不管后面你使不使用它。所以叫做饿汉式。 // 类初始化时,立即加载这个对象。(所以不能延时加载) // 由于加载类时,天然的是线程安全的! private static SingletonDemo01 instance = new SingletonDemo01(); private SingletonDemo01(){ } // 方法没有同步,调用效率高! public static SingletonDemo01 getInstance(){ return instance; } }
饿汉式单例模式代码中,static变量会在类装载时初始化,此时也不会涉及多个线程对象访问该对象的问题。虚拟机保证只会装载一次该类,肯定不会发生并发访问的问题。因此,可以省略synchronized关键字。
问题:如果只是加载本类,而不是要调用getInstance(),甚至永远没有调用,则会造成资源浪费!
(单例对象延迟加载)
代码
package com.sxt.singleton; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: SingletonDemo01.java * @time: 2020/2/3 18:41 * @desc: 测试懒汉式单例模式 */ public class SingletonDemo02 { // 类初始化时,不初始化这个对象。(延时加载,真正用的时候再创建) private static SingletonDemo02 instance; private SingletonDemo02() { } // 方法同步,调用效率低! public static synchronized SingletonDemo02 getInstance() { if (instance == null){ instance = new SingletonDemo02(); } return instance; } }
要点:lazy load!延迟加载,懒加载!真正用的时候才加载!
问题:资源利用率高了。但是,每次调用getInstance()方法都要同步,并发效率较低。
代码
package com.sxt.singleton; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: SingletonDemo01.java * @time: 2020/2/3 18:41 * @desc: 测试双重检测锁实现单例模式 */ public class SingletonDemo03 { private static SingletonDemo03 instance = null; private SingletonDemo03() { } public static SingletonDemo03 getInstance() { if (instance == null){ SingletonDemo03 sc; synchronized (SingletonDemo03.class){ sc = instance; if(sc == null){ synchronized (SingletonDemo03.class){ if(sc == null){ sc = new SingletonDemo03(); } } instance = sc; } } } return instance; } }
这个模式将同步内容下放到if内部,提高了执行的效率,不必每次获取对象时都进行同步,只有第一次才同步,创建了以后就没必要了。
问题:由于编辑器优化原因和JVM底层内部模型原因,偶尔会出问题,不建议使用。
(也是一种懒加载方式)
代码
package com.sxt.singleton; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: SingletonDemo01.java * @time: 2020/2/3 18:41 * @desc: 测试静态内部类实现单例模式,这种方式线程安全,调用效率高,并且实现了延时加载 */ public class SingletonDemo04 { private static class SingletonClassInstance{ private static final SingletonDemo04 instance = new SingletonDemo04(); } private SingletonDemo04(){ } // 方法没有同步,调用效率高! public static SingletonDemo04 getInstance(){ return SingletonClassInstance.instance; } }
要点
问题:
代码
package com.sxt.singleton; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: SingletonDemo01.java * @time: 2020/2/3 18:41 * @desc: 测试枚举实现单例模式(没有延时加载) */ public enum SingletonDemo05 { // 这个枚举元素,本身就是单例对象! INSTANCE; // 添加自己需要的操作! public void singletonOperation(){ } }
优点
缺点
UML类图
如何选用?
测试懒汉式单例模式
package com.sxt.singleton; import java.io.Serializable; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: SingletonDemo01.java * @time: 2020/2/3 18:41 * @desc: 测试懒汉式单例模式(如何防止反射和反序列化) */ public class SingletonDemo06 implements Serializable { // 类初始化时,不初始化这个对象。(延时加载,真正用的时候再创建) private static SingletonDemo06 instance; private SingletonDemo06() { // 通过检查是否已经创建对象了,如果有了,则抛出异常 if (instance != null) { throw new RuntimeException(); } } // 方法同步,调用效率低! public static synchronized SingletonDemo06 getInstance() { if (instance == null) { instance = new SingletonDemo06(); } return instance; } // 反序列化时,如果定了readResolve方法,则直接返回此方法指定的对象,而不需要单独再创建新对象! private Object readResolve() throws Exception{ return instance; } }
测试反射和反序列化被破解单例模式
package com.sxt.singleton; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/3 20:13 * @desc: 测试反射和反序列化被破解单例模式 */ public class Client2 { public static void main(String[] args) throws Exception { // 测试饿汉实现单例 SingletonDemo06 s1 = SingletonDemo06.getInstance(); SingletonDemo06 s2 = SingletonDemo06.getInstance(); System.out.println(s1); System.out.println(s2); // 通过反射的方式直接调用私有构造器 Class<SingletonDemo06> clazz = (Class<SingletonDemo06>) Class.forName("com.sxt.singleton.SingletonDemo06"); Constructor<SingletonDemo06> c = clazz.getDeclaredConstructor(null); // 这样设置就可以访问private的构造器了,这种方式则跳过了单例模式的限制 c.setAccessible(true); SingletonDemo06 s3 = c.newInstance(); SingletonDemo06 s4 = c.newInstance(); System.out.println(s3); System.out.println(s4); // 通过反序列化的方式构造多个对象 FileOutputStream fos = new FileOutputStream("a.txt"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(s1); oos.close(); fos.close(); ObjectInputStream ois = new ObjectInputStream(new FileInputStream("a.txt")); SingletonDemo06 s5 = (SingletonDemo06) ois.readObject(); System.out.println(s5); } }
CountDownLatch
测试五种创建单例模式的效率
package com.sxt.singleton; import java.util.concurrent.CountDownLatch; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/3 20:13 * @desc: 测试五种创建单例模式的效率 */ public class Client03 { public static void main(String[] args) throws Exception { long start = System.currentTimeMillis(); int threadNum = 10; final CountDownLatch countDownLatch = new CountDownLatch(threadNum); for (int i = 0; i < threadNum; i++) { new Thread(new Runnable() { @Override public void run() { for (int i = 0; i < 100000; i++) { // Object o = SingletonDemo04.getInstance(); Object o = SingletonDemo05.INSTANCE; } countDownLatch.countDown(); } }).start(); } // main线程阻塞,直到计数器变为0,才会继续往下执行! countDownLatch.await(); long end = System.currentTimeMillis(); System.out.println("总耗时:" + (end - start)); } }
要点:
代码:
Car接口
package com.sxt.factory.simplefactor;
/**
* @author: Li Tian
* @contact: litian_cup@163.com
* @software: IntelliJ IDEA
* @file: Car.java
* @time: 2020/2/5 15:59
* @desc:
*/
public interface Car {
void run();
}
奥迪车
package com.sxt.factory.simplefactor; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Audi.java * @time: 2020/2/5 16:00 * @desc: */ public class Audi implements Car { @Override public void run() { System.out.println("奥迪在跑!"); } }
比亚迪车
package com.sxt.factory.simplefactor; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Byd.java * @time: 2020/2/5 16:01 * @desc: */ public class Byd implements Car { @Override public void run() { System.out.println("比亚迪在跑!"); } }
测试在没有工厂模式的情况下
package com.sxt.factory.simplefactor; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client01.java * @time: 2020/2/5 16:02 * @desc: 测试在没有工厂模式的情况下 */ public class Client01 { // 调用者 public static void main(String[] args){ Car c1 = new Audi(); Car c2 = new Byd(); c1.run(); c2.run(); } }
简单工厂类1
package com.sxt.factory.simplefactor; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: CarFactory.java * @time: 2020/2/5 16:04 * @desc: */ public class CarFactory { public static Car createCar(String type){ if("奥迪".equals(type)){ return new Audi(); }else if("比亚迪".equals(type)){ return new Byd(); }else{ // 简单工厂还是有点小问题的,这里如果要加新的车辆的话,就需要改代码,违反了开闭原则OCP return null; } } }
简单工厂2
package com.sxt.factory.simplefactor; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: CarFactory.java * @time: 2020/2/5 16:04 * @desc: 简单工厂类2 */ public class CarFactory2 { public static Car createAudi() { return new Audi(); } public static Car createByd() { return new Byd(); } }
测试在简单工厂模式的情况下
package com.sxt.factory.simplefactor; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client01.java * @time: 2020/2/5 16:02 * @desc: 测试在简单工厂模式的情况下 */ public class Client02 { // 调用者 public static void main(String[] args){ Car c1 = CarFactory.createCar("奥迪"); Car c2 = CarFactory.createCar("比亚迪"); c1.run(); c2.run(); } }
UML类图
为了避免简单工厂模式的缺点,不完全满足OCP。
工厂方法模式和简单工厂模式最大的不同在于,简单工厂模式只有一个(对于一个项目或者一个独立模块而言)工厂类,而工厂方法模式有一组实现了相同接口的工厂类。
代码:
新增了车的工厂interface
package com.sxt.factory.factorymethod;
/**
* @author: Li Tian
* @contact: litian_cup@163.com
* @software: IntelliJ IDEA
* @file: CarFactory.java
* @time: 2020/2/5 19:42
* @desc:
*/
public interface CarFactory {
Car createCar();
}
实现了车工厂的audi工厂
package com.sxt.factory.factorymethod; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: AudiFactory.java * @time: 2020/2/5 19:42 * @desc: */ public class AudiFactory implements CarFactory { @Override public Car createCar() { return new Audi(); } }
实现了车工厂的byd工厂
package com.sxt.factory.factorymethod; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: BydFactory.java * @time: 2020/2/5 19:43 * @desc: */ public class BydFactory extends Byd implements CarFactory { @Override public Car createCar() { return new Byd(); } }
客户端
package com.sxt.factory.factorymethod; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/5 19:44 * @desc: */ public class Client { public static void main(String[] args){ Car c1 = new AudiFactory().createCar(); Car c2 = new BydFactory().createCar(); Car c3 = new BenzFactory().createCar(); c1.run(); c2.run(); c3.run(); } }
如果需要新增车的类型的话,不需要修改原来的代码,只需要增加类就行,即满足了OCP
新增benz类
package com.sxt.factory.factorymethod; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Benz.java * @time: 2020/2/5 19:45 * @desc: */ public class Benz extends BenzFactory implements Car { @Override public void run() { System.out.println("奔驰在跑!"); } }
新增benz工厂
package com.sxt.factory.factorymethod; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Benz.java * @time: 2020/2/5 19:45 * @desc: */ public class Benz extends BenzFactory implements Car { @Override public void run() { System.out.println("奔驰在跑!"); } }
简单工厂模式和工厂方法模式PK:
根据设计理论建议:工厂方法模式。但实际上,我们一般都用简单工厂模式。
用来生产不同产品族的全部产品。(对于增加新的产品,无能为力;支持增加产品族)
抽象工厂模式是工厂方法模式的升级版本,在有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。
代码:
发动机
package com.sxt.factory.abstractfactory; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Engine.java * @time: 2020/2/6 12:40 * @desc: */ public interface Engine { void run(); void start(); } class LuxuryEngine implements Engine{ @Override public void run() { System.out.println("转得快!"); } @Override public void start() { System.out.println("启动快!可以自动启停!"); } } class LowerEngine implements Engine{ @Override public void run() { System.out.println("转得慢!"); } @Override public void start() { System.out.println("启动慢!可以自动启停!"); } }
座位
package com.sxt.factory.abstractfactory; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Seat.java * @time: 2020/2/6 12:42 * @desc: */ public interface Seat { void massage(); } class LuxurySeat implements Seat{ @Override public void massage() { System.out.println("可以按摩!"); } } class LowerSeat implements Seat{ @Override public void massage() { System.out.println("不可以按摩!"); } }
轮胎
package com.sxt.factory.abstractfactory; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Tyre.java * @time: 2020/2/6 12:43 * @desc: */ public interface Tyre { void revolve(); } class LuxuryTyre implements Tyre{ @Override public void revolve() { System.out.println("磨损慢!"); } } class LowerTyre implements Tyre{ @Override public void revolve() { System.out.println("磨损快!"); } }
车工厂
package com.sxt.factory.abstractfactory; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: CarFactory.java * @time: 2020/2/6 12:44 * @desc: */ public interface CarFactory { Engine createEngine(); Seat createSeat();; Tyre createTyre(); }
高端车工厂
package com.sxt.factory.abstractfactory; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: LuxuryCarFactory.java * @time: 2020/2/6 12:45 * @desc: */ public class LuxuryCarFactory implements CarFactory { @Override public Engine createEngine() { return new LuxuryEngine(); } @Override public Seat createSeat() { return new LuxurySeat(); } @Override public Tyre createTyre() { return new LuxuryTyre(); } }
低端车工厂
package com.sxt.factory.abstractfactory; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: LowerCarFactory.java * @time: 2020/2/6 12:45 * @desc: */ public class LowerCarFactory implements CarFactory { @Override public Engine createEngine() { return new LowerEngine(); } @Override public Seat createSeat() { return new LowerSeat(); } @Override public Tyre createTyre() { return new LowerTyre(); } }
客户端
package com.sxt.factory.abstractfactory; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/6 12:47 * @desc: */ public class Client { public static void main(String[] args){ CarFactory factory = new LuxuryCarFactory(); Engine e = factory.createEngine(); e.run(); e.start(); } }
工厂模式要点
应用场景
场景:
建造者模式的本质
代码:
宇宙飞船
package com.sxt.builder; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: AirShip.java * @time: 2020/2/6 13:48 * @desc: 宇宙飞船 */ public class AirShip { // 轨道舱 private OrbitalModule orbitalModule; // 发动机 private Engine engine; // 逃逸仓 private EscapeTower escapeTower; public void launch(){ System.out.println("发动机【" + engine.getName() + "】" + "轨道舱【" + orbitalModule.getName() + "】" + "逃离塔【" + escapeTower.getName() + "】" + "-->发射!"); } public OrbitalModule getOrbitalModule() { return orbitalModule; } public void setOrbitalModule(OrbitalModule orbitalModule) { this.orbitalModule = orbitalModule; } public Engine getEngine() { return engine; } public void setEngine(Engine engine) { this.engine = engine; } public EscapeTower getEscapeTower() { return escapeTower; } public void setEscapeTower(EscapeTower escapeTower) { this.escapeTower = escapeTower; } } class OrbitalModule { private String name; public OrbitalModule(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } class Engine { private String name; public Engine(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } } class EscapeTower{ private String name; public EscapeTower(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
构建者接口
package com.sxt.builder; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: AirShipBuilder.java * @time: 2020/2/6 13:53 * @desc: */ public interface AirShipBuilder { Engine buildEngine(); OrbitalModule builderOrbitalModule(); EscapeTower buildEscapeTower(); }
装配者接口
package com.sxt.builder;
/**
* @author: Li Tian
* @contact: litian_cup@163.com
* @software: IntelliJ IDEA
* @file: AirShipDirector.java
* @time: 2020/2/6 13:54
* @desc: 组装飞船对象
*/
public interface AirShipDirector {
// 组装飞船对象
AirShip directAirShip();
}
构建者
package com.sxt.builder; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: MyAirShipBuilder.java * @time: 2020/2/6 13:55 * @desc: */ public class MyAirShipBuilder implements AirShipBuilder{ @Override public Engine buildEngine() { System.out.println("构建发动机!"); return new Engine("我的发动机"); } @Override public OrbitalModule builderOrbitalModule() { System.out.println("构建轨道舱!"); return new OrbitalModule("我的轨道舱"); } @Override public EscapeTower buildEscapeTower() { System.out.println("构建逃逸塔!"); return new EscapeTower("我的逃逸塔"); } }
装配者
package com.sxt.builder; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: MyAirShipDirector.java * @time: 2020/2/6 13:59 * @desc: */ public class MyAirShipDirector implements AirShipDirector{ private AirShipBuilder builder; public MyAirShipDirector(AirShipBuilder builder) { this.builder = builder; } @Override public AirShip directAirShip() { // 从构建者获取组件 Engine e = builder.buildEngine(); OrbitalModule o = builder.builderOrbitalModule(); EscapeTower es = builder.buildEscapeTower(); // 进行组装 AirShip ship = new AirShip(); ship.setEngine(e); ship.setOrbitalModule(o); ship.setEscapeTower(es); return ship; } }
客户端
package com.sxt.builder; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/6 14:02 * @desc: */ public class Client { public static void main(String[] args) { AirShipDirector director = new MyAirShipDirector(new MyAirShipBuilder()); AirShip ship = director.directAirShip(); ship.launch(); } }
UML类图
开发中应用场景:
代码:
羊
package com.sxt.prototype; import java.util.Date; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Sheep1.java * @time: 2020/2/6 15:53 * @desc: 测试浅复制 */ public class Sheep1 implements Cloneable{ private String sname; private Date birthday; public String getSname() { return sname; } public void setSname(String sname) { this.sname = sname; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public Sheep1(String sname, Date birthday) { this.sname = sname; this.birthday = birthday; } public Sheep1() { } @Override protected Object clone() throws CloneNotSupportedException { // 直接调用object对象的clone()方法 Object obj = super.clone(); return obj; } }
客户端
package com.sxt.prototype; import java.util.Date; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client2.java * @time: 2020/2/6 15:57 * @desc: 测试原型模式(浅复制) */ public class Client1 { public static void main(String[] args) throws CloneNotSupportedException { Date d = new Date(3333333333L); Sheep1 s1 = new Sheep1("少理", d); System.out.println(s1); System.out.println(s1.getSname()); System.out.println(s1.getBirthday()); // 两个是不同的对象,但是值是一样的! Sheep1 s2 = (Sheep1) s1.clone(); // 修改s1生日 d.setTime(22222222222L); System.out.println("--------------------------"); System.out.println(s1.getBirthday()); System.out.println(s2); System.out.println(s2.getSname()); System.out.println(s2.getBirthday()); // 修改s2的值 System.out.println("--------------------------"); s2.setSname("多里"); System.out.println(s2); System.out.println(s2.getSname()); System.out.println(s2.getBirthday()); } }
代码
羊
package com.sxt.prototype; import java.util.Date; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Sheep2.java * @time: 2020/2/6 15:53 * @desc: 测试深复制 */ public class Sheep2 implements Cloneable{ private String sname; private Date birthday; public String getSname() { return sname; } public void setSname(String sname) { this.sname = sname; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public Sheep2(String sname, Date birthday) { this.sname = sname; this.birthday = birthday; } public Sheep2() { } @Override protected Object clone() throws CloneNotSupportedException { // 直接调用object对象的clone()方法 Object obj = super.clone(); // 添加如下代码实现深复制 Sheep2 s = (Sheep2) obj; // 把属性也进行克隆 s.birthday = (Date) this.birthday.clone(); return obj; } }
客户端同上
区别
浅克隆和深克隆的区别
运行结果区别:浅克隆只是复制了生日变量对应的地址,这样即使值改变了,地址相同,则获得的生日的值也相同;深克隆将生日变量复制了一份,两个地址不同,因此原型的值变了,与复制的值无关,因此生日的值依然是之前复制的值。
利用序列化和反序列化的技术实现深克隆!
package com.sxt.prototype; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.Date; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/6 15:57 * @desc: 测试原型模式(深复制),使用序列化和反序列化的方式实现深复制 */ public class Client3 { public static void main(String[] args) throws Exception { Date d = new Date(3333333333L); Sheep1 s1 = new Sheep1("少理", d); System.out.println(s1); System.out.println(s1.getSname()); System.out.println(s1.getBirthday()); // 两个是不同的对象,但是值是一样的! // Sheep1 s2 = (Sheep1) s1.clone(); // 这里用序列化和反序列化实现深复制,所以用的是Sheep1,即浅复制的类 ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(s1); byte[] bytes = bos.toByteArray(); ByteArrayInputStream bis = new ByteArrayInputStream(bytes); ObjectInputStream ois = new ObjectInputStream(bis); Sheep1 s2 = (Sheep1) ois.readObject(); // 修改s1生日 d.setTime(22222222222L); System.out.println("--------------------------"); System.out.println(s1.getBirthday()); System.out.println(s2); System.out.println(s2.getSname()); System.out.println(s2.getBirthday()); } }
短时间大量创建对象时,原型模式和普通new方式效率测试:如果需要短时间创建大量对象,并且new的过程比较耗时。则可以考虑使用原型模式!
开发中的应用场景
创建型模式:都是来帮助我们创建对象的!
结构型模式:
什么是适配器模式(adapter):将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作。
模式中的角色:
代码:
被适配的类(没有usb插口的键盘)
package com.sxt.adapter; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Adaptee.java * @time: 2020/2/7 11:01 * @desc: 被适配的类,相当于PS/2键盘 */ public class Adaptee { public void request(){ System.out.println("可以完成客户请求的需要的功能!"); } }
客户端(只有usb接口的笔记本电脑)
package com.sxt.adapter; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/7 11:02 * @desc: 客户类,相当于笔记本,只有USB接口 */ public class Client { public void test1(Target t){ t.handleReq(); } public static void main(String[] args){ Client c = new Client(); Adaptee a = new Adaptee(); // 方式1:类适配器方式 Target t1 = new Adapter(); // 方式2:对象适配器方式 Target t2 = new Adapter2(a); c.test1(t2); } }
接口:usb插口
package com.sxt.adapter;
/**
* @author: Li Tian
* @contact: litian_cup@163.com
* @software: IntelliJ IDEA
* @file: Target.java
* @time: 2020/2/7 11:02
* @desc: 相当于USB插口
*/
public interface Target {
void handleReq();
}
package com.sxt.adapter; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Adapter.java * @time: 2020/2/7 11:03 * @desc: 【类适配器方式】适配器,相当于把键盘转换成usb接口的转接器 */ public class Adapter extends Adaptee implements Target{ // 我的理解:把适配器变成键盘(子类),并实现USB接口-->打字 @Override public void handleReq() { super.request(); } }
package com.sxt.adapter; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Adapter2.java * @time: 2020/2/7 11:07 * @desc: 【对象组合的方式,对象适配器方式】适配器 */ public class Adapter2 implements Target{ // 我的理解:把原来不兼容的键盘接口变成Target(即USB接口) private Adaptee adaptee; @Override public void handleReq() { adaptee.request(); } public Adapter2(Adaptee adaptee) { this.adaptee = adaptee; } }
工作中的场景:
我们学习中见过的场景
以对象适配器为例,绘制UML类图
代码:
明星接口
package com.sxt.proxy.staticproxy; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Star.java * @time: 2020/2/7 13:51 * @desc: */ public interface Star { // 面谈 void confer(); // 签合同 void signContract(); // 订票 void bookTicket(); // 唱歌 void sing(); // 收钱 void collectMoney(); }
真实明星
package com.sxt.proxy.staticproxy; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: RealStar.java * @time: 2020/2/7 13:53 * @desc: */ public class RealStar implements Star { private String name = "真实明星"; @Override public void confer() { System.out.println(name + "面谈!"); } @Override public void signContract() { System.out.println(name + "签合同"); } @Override public void bookTicket() { System.out.println(name + "订票"); } @Override public void sing() { System.out.println(name + "唱歌"); } @Override public void collectMoney() { System.out.println(name + "收钱"); } }
代理经纪人
package com.sxt.proxy.staticproxy; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: ProxyStar.java * @time: 2020/2/7 13:55 * @desc: */ public class ProxyStar implements Star { private String name = "经纪人"; private Star star; public ProxyStar(Star star) { this.star = star; } @Override public void confer() { System.out.println(name + "面谈!"); } @Override public void signContract() { System.out.println(name + "签合同"); } @Override public void bookTicket() { System.out.println(name + "订票"); } @Override public void sing() { star.sing(); } @Override public void collectMoney() { System.out.println(name + "收钱"); } }
客户端
package com.sxt.proxy.staticproxy; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/7 13:57 * @desc: */ public class Client { public static void main(String[] args){ Star real = new RealStar(); Star proxy = new ProxyStar(real); proxy.confer(); proxy.signContract(); proxy.bookTicket(); proxy.sing(); proxy.collectMoney(); } }
动态生成代理类
动态代理相比于静态代理的优点:抽象角色中(接口)声明的所有方法都被转移到调用处理器一个集中的方法中处理,这样我们可以更加灵活和统一的处理众多的方法。
JDK自带的动态代理
代码:
明星接口和真实明星接口同上
动态代理类
package com.sxt.proxy.dynamicproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: StarHandler.java * @time: 2020/2/7 16:19 * @desc: */ public class StarHandler implements InvocationHandler { Star realStar; public StarHandler(Star realStar) { this.realStar = realStar; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object obj = null; System.out.println("真正的方法执行前!"); System.out.println("面谈,签合同等。。。"); if (method.getName().equals("sing")) { obj = method.invoke(realStar, args); } System.out.println("真正的方法执行后!"); System.out.println("收钱!"); return obj; } }
客户端
package com.sxt.proxy.dynamicproxy; import java.lang.reflect.Proxy; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/7 16:22 * @desc: */ public class Client { public static void main(String[] args){ Star realStar = new RealStar(); StarHandler handler = new StarHandler(realStar); Star proxy = (Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Star.class}, handler); proxy.sing(); } }
bridge pattern
场景:商场系统中常见的商品分类,以电脑为类,如何良好的处理商品分类销售的问题?
我们可以用多继承结构实现下图关系
问题:
桥接模式核心要点:处理多层集成结构,处理多维度变化的场景,将各个维度设计成独立的继承结构,使各个维度可以独立的扩展在抽象层建立关联。
桥接模式总结:
桥接模式实际开发中应用场景
不用桥接模式的话
package com.sxt.bridge; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Computer.java * @time: 2020/2/9 14:44 * @desc: */ public interface Computer { void sale(); } class Desktop implements Computer{ @Override public void sale() { System.out.println("销售台式机!"); } } class Laptop implements Computer{ @Override public void sale() { System.out.println("销售笔记本!"); } } class Pad implements Computer{ @Override public void sale() { System.out.println("销售平板电脑!"); } } class LenovoDesktop extends Desktop{ @Override public void sale() { System.out.println("销售联想台式机!");; } } class LenovoLaptop extends Laptop{ @Override public void sale() { System.out.println("销售联想笔记本!");; } } class LenovoPad extends Pad{ @Override public void sale() { System.out.println("销售联想平板电脑!");; } } class ShenzhouDesktop extends Desktop{ @Override public void sale() { System.out.println("销售神舟台式机!");; } } class ShenzhouLaptop extends Laptop{ @Override public void sale() { System.out.println("销售神舟笔记本!");; } } class ShenzhouPad extends Pad{ @Override public void sale() { System.out.println("销售神舟平板电脑!");; } } class DellDesktop extends Desktop{ @Override public void sale() { System.out.println("销售戴尔台式机!");; } } class DellLaptop extends Laptop{ @Override public void sale() { System.out.println("销售戴尔笔记本!");; } } class DellPad extends Pad{ @Override public void sale() { System.out.println("销售戴尔平板电脑!");; } }
使用桥接模式
品牌
package com.sxt.bridge; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Brand.java * @time: 2020/2/9 14:56 * @desc: 品牌 */ public interface Brand { void sale(); } class Lenovo implements Brand{ @Override public void sale() { System.out.println("销售联想电脑!"); } } class Dell implements Brand{ @Override public void sale() { System.out.println("销售戴尔电脑!"); } }
电脑类型的维度
package com.sxt.bridge; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: ComputerBridge.java * @time: 2020/2/9 14:58 * @desc: 电脑类型的维度 */ public class ComputerBridge { protected Brand brand; public ComputerBridge(Brand brand) { this.brand = brand; } public void sale(){ brand.sale(); } } class Desktop2 extends ComputerBridge{ public Desktop2(Brand brand) { super(brand); } @Override public void sale() { super.sale(); System.out.println("销售台式机!"); } } class Laptop2 extends ComputerBridge{ public Laptop2(Brand brand) { super(brand); } @Override public void sale() { super.sale(); System.out.println("销售笔记本电脑!"); } }
客户顿
package com.sxt.bridge; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/9 15:01 * @desc: */ public class Client { public static void main(String[] args){ // 销售联想的笔记本电脑 ComputerBridge c = new Laptop2(new Lenovo()); c.sale(); // 销售戴尔的台式机 ComputerBridge c2 = new Desktop2(new Dell()); c2.sale(); } }
composite patern
使用组合模式的场景:把部分和整体的关系用树形结构来表示,从而使得客户端可以使用统一的方式处理部分对象和整体对象。
组合模式核心:
抽象组件构成代码
package com.sxt.composite; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Component.java * @time: 2020/2/9 16:39 * @desc: 抽象组件 */ public interface Component { void operation(); } // 叶子组件 interface Leaf extends Component { } // 容器组件 interface Composite extends Component{ void add(Component c); void remove(Component c); Component getChild(int index); }
组合模式工作流程分析:
使用组合模式,模拟杀毒软件架构设计
抽象构建
package com.sxt.composite; import java.util.ArrayList; import java.util.List; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: AbstarctFile.java * @time: 2020/2/9 16:46 * @desc: 抽象构建 */ public interface AbstarctFile { void killVirus(); } class ImageFile implements AbstarctFile{ private String name; public ImageFile(String name) { this.name = name; } @Override public void killVirus() { System.out.println("---图像文件:" + name + ",进行查杀!"); } } class TextFile implements AbstarctFile{ private String name; public TextFile(String name) { this.name = name; } @Override public void killVirus() { System.out.println("---文本文件:" + name + ",进行查杀!"); } } class VideoFile implements AbstarctFile{ private String name; public VideoFile(String name) { this.name = name; } @Override public void killVirus() { System.out.println("---视频文件:" + name + ",进行查杀!"); } } class Folder implements AbstarctFile{ private String name; // 定义容器,用来存放本容器构建下的子节点 private List<AbstarctFile> list = new ArrayList<>(); public Folder(String name) { this.name = name; } public void add(AbstarctFile file){ list.add(file); } public void remove(AbstarctFile file){ list.remove(file); } public AbstarctFile getChild(int index){ return list.get(index); } @Override public void killVirus() { System.out.println("---文件夹:" + name + ",进行查杀!"); for (AbstarctFile file: list){ file.killVirus(); } } }
客户端
package com.sxt.composite; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/9 16:54 * @desc: */ public class Client { public static void main(String[] args){ AbstarctFile f2, f3, f5, f6; Folder f1 = new Folder("我的收藏"); f2 = new ImageFile("我的头像.jpg"); f3 = new TextFile("Hello.txt"); f1.add(f2); f1.add(f3); Folder f4 = new Folder("电影"); f5 = new VideoFile("神雕侠侣.avi"); f6 = new VideoFile("笑傲江湖.avi"); f4.add(f5); f4.add(f6); f1.add(f4); f1.killVirus(); } }
开发中的应用场景
decorator pattern
职责:
实现细节:
代码
抽象组件
package com.sxt.decorator; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: ICar.java * @time: 2020/2/9 18:07 * @desc: 抽象组件 */ public interface ICar { void move(); } // 真实对象 class Car implements ICar{ @Override public void move() { System.out.println("陆地上跑"); } } //装饰角色 class SuperCar implements ICar{ private ICar car; public SuperCar(ICar car) { this.car = car; } @Override public void move() { car.move(); } } // 具体装饰对象 class FlyCar extends SuperCar{ public FlyCar(ICar car) { super(car); } public void fly(){ System.out.println("天上飞!"); } @Override public void move() { super.move(); fly(); } } class WaterCar extends SuperCar{ public WaterCar(ICar car) { super(car); } public void swim(){ System.out.println("水上游!"); } @Override public void move() { super.move(); swim(); } } class AICar extends SuperCar{ public AICar(ICar car) { super(car); } public void autoMove(){ System.out.println("无人驾驶!"); } @Override public void move() { super.move(); autoMove(); } }
客户端
package com.sxt.decorator; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/9 18:13 * @desc: */ public class Client { public static void main(String[] args){ Car car = new Car(); car.move(); System.out.println("增加新的功能,飞行!"); FlyCar flyCar = new FlyCar(car); flyCar.move(); System.out.println("增加新的功能,游泳!"); WaterCar waterCar = new WaterCar(car); waterCar.move(); System.out.println("增加新的功能,飞行和游泳!"); WaterCar car2 = new WaterCar(new FlyCar(car)); car2.move(); } }
UML类图
开发中使用的场景
IO流实现细节
总结:
优点:
缺点:
装饰模式和桥接模式的区别:
两个模式都是为了解决过多子类对象的问题。但是他们的诱因不一样。
我的理解是:
迪米特法则(最少知识原则):一个软件实体应当尽可能少的与其他实体发生相互作用。
外观模式核心:为子系统提供统一的入口。封装子系统的复杂性,便于客户端调用。
公司注册流程:
不使用外观模式
使用外观模式
开发中常见的场景
FlyWeight Pattern
场景:内存属于稀缺资源,不要随便浪费。如果有很多个完全相同或相似的对象,我们可以通过享元模式,节省内存。
核心:
围棋软件设计:每个围棋棋子都是一个对象,有如下属性:
享元模式实现:
FlyweightFactory享元工厂类:
创建并管理享元对象,享元池一般设计成键值对
FlyWeight抽象享元类
通常是一个接口或抽象类,声明公共方法,这些方法可以向外界提供对象的内部状态,设置外部状态。
ConcreteFlyWeight具体享元类
为内部状态提供成员变量进行存储
UnsharedConcreteFlyWeight非共享享元类
不能被共享的子类可以设计为非共享享元类
享元模式实现的UML图
代码:
享元类和实际享元实现类(这里实现了颜色共享)
package com.sxt.flyweight; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: ChessFlyWeight.java * @time: 2020/2/10 12:37 * @desc: 享元类 */ public interface ChessFlyWeight { void setColor(String c); String getColor(); void display(Coordinate c); } class ConcreteChess implements ChessFlyWeight{ private String color; public ConcreteChess(String color) { this.color = color; } @Override public void setColor(String c) { this.color = c; } @Override public String getColor() { return color; } @Override public void display(Coordinate c) { System.out.println("棋子颜色:" + color); System.out.println("棋子位置:" + c.getX() + ", " + c.getY()); } }
外部类,这里是坐标,即非享元类
package com.sxt.flyweight; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Coordinate.java * @time: 2020/2/10 12:37 * @desc: 外部状态,UnsharedConcreteFlyWeight非共享享元类 */ public class Coordinate { private int x, y; public Coordinate(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public void setY(int y) { this.y = y; } }
享元工厂类(用来生成享元对象)
package com.sxt.flyweight; import java.util.HashMap; import java.util.Map; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: ChessFlyWeightFactory.java * @time: 2020/2/10 12:43 * @desc: 享元工厂类 */ public class ChessFlyWeightFactory { // 享元池 private static Map<String, ChessFlyWeight> map = new HashMap<>(); public static ChessFlyWeight getChess(String color){ if(map.get(color) != null){ return map.get(color); }else{ ChessFlyWeight cfw = new ConcreteChess(color); map.put(color, cfw); return cfw; } } }
客户端
package com.sxt.flyweight; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/10 12:47 * @desc: */ public class Client { public static void main(String[] args){ ChessFlyWeight chess1 = ChessFlyWeightFactory.getChess("black"); ChessFlyWeight chess2 = ChessFlyWeightFactory.getChess("black"); System.out.println(chess1); System.out.println(chess2); // 增加外部状态的处理 chess1.display(new Coordinate(10, 10)); chess1.display(new Coordinate(20, 20)); } }
享元模式开发中应用的场景:
享元模式的优点:
享元模式的缺点:
封装请假的基本信息
package com.sxt.chainofresp; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: LeaveRequest.java * @time: 2020/2/10 18:01 * @desc: 封装请假的基本信息 */ public class LeaveRequest { private String empName; private int leaveDays; private String reason; public LeaveRequest(String empName, int leaveDays, String reason) { this.empName = empName; this.leaveDays = leaveDays; this.reason = reason; } public String getEmpName() { return empName; } public void setEmpName(String empName) { this.empName = empName; } public int getLeaveDays() { return leaveDays; } public void setLeaveDays(int leaveDays) { this.leaveDays = leaveDays; } public String getReason() { return reason; } public void setReason(String reason) { this.reason = reason; } }
抽象类领导
package com.sxt.chainofresp; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Leader.java * @time: 2020/2/10 18:02 * @desc: 抽象类 领导 */ public abstract class Leader { protected String name; // 领导的下一个责任领导 protected Leader nextLeader; public Leader(String name) { this.name = name; } // 设定责任链上的后继对象 public void setNextLeader(Leader nextLeader) { this.nextLeader = nextLeader; } // 处理请求的核心业务方法 public abstract void handleRequest(LeaveRequest request); }
上级
package com.sxt.chainofresp; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Director.java * @time: 2020/2/10 18:06 * @desc: */ public class Director extends Leader { public Director(String name) { super(name); } @Override public void handleRequest(LeaveRequest request) { if(request.getLeaveDays() < 3){ System.out.println("员工:" + request.getEmpName() + "请假:" + request.getLeaveDays() + "天,理由是:" + request.getReason()); System.out.println("主任:" + this.name + "审批通过!"); }else{ if(this.nextLeader != null){ this.nextLeader.handleRequest(request); } } } }
经理
package com.sxt.chainofresp; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Manager.java * @time: 2020/2/10 18:06 * @desc: 经理 */ public class Manager extends Leader { public Manager(String name) { super(name); } @Override public void handleRequest(LeaveRequest request) { if(request.getLeaveDays() < 10){ System.out.println("员工:" + request.getEmpName() + "请假:" + request.getLeaveDays() + "天,理由是:" + request.getReason()); System.out.println("经理:" + this.name + "审批通过!"); }else{ if(this.nextLeader != null){ this.nextLeader.handleRequest(request); } } } }
总经理
package com.sxt.chainofresp; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Manager.java * @time: 2020/2/10 18:06 * @desc: 总经理 */ public class GeneralManager extends Leader { public GeneralManager(String name) { super(name); } @Override public void handleRequest(LeaveRequest request) { if(request.getLeaveDays() < 30){ System.out.println("员工:" + request.getEmpName() + "请假:" + request.getLeaveDays() + "天,理由是:" + request.getReason()); System.out.println("总经理:" + this.name + "审批通过!"); }else{ System.out.println("莫非" + request.getEmpName() + "想辞职!竟然请假" + request.getLeaveDays() + "天!"); } } }
客户端
package com.sxt.chainofresp; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/10 18:11 * @desc: */ public class Client { public static void main(String[] args){ Leader a = new Director("张三"); Leader b = new Manager("李四"); Leader c = new GeneralManager("王五"); // 组织责任链对象关系 a.setNextLeader(b); b.setNextLeader(c); // 开始请假操作 LeaveRequest req1 = new LeaveRequest("Tom", 10, "回家睡觉!"); a.handleRequest(req1); } }
iterator pattern
场景:
基本案例:
实现正向遍历的迭代器
自定义的迭代器接口
package com.sxt.iterator; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: MyIterator.java * @time: 2020/2/14 18:42 * @desc: 自定义的迭代器接口 */ public interface MyIterator { // 将游标指向第一个元素 void first(); // 将游标指向下一个元素 void next(); // 判断是否存在下一个元素 boolean hasNext(); boolean ifFirst(); boolean isLast(); // 获取当前游标指向的对象 Object getCurrentObj(); }
自定义的聚合类
package com.sxt.iterator; import java.util.ArrayList; import java.util.List; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: ConcreteMyAggregate.java * @time: 2020/2/14 18:45 * @desc: 自定义的聚合类 */ public class ConcreteMyAggregate { private List<Object> list = new ArrayList<Object>(); public void addObject(Object obj) { this.list.add(obj); } public void removeObject(Object obj) { this.list.remove(obj); } public List<Object> getList() { return list; } public void setList(List<Object> list) { this.list = list; } // 获得迭代器 public MyIterator createIterator(){ return new ConcreteIterator(); } // 使用内部类定义迭代器,可以直接使用外部类的属性 private class ConcreteIterator implements MyIterator { // 定义游标用于记录遍历时的位置 private int cursor; @Override public void first() { cursor = 0; } @Override public void next() { if (cursor < list.size()) { cursor++; } } @Override public boolean hasNext() { return cursor < list.size(); } @Override public boolean ifFirst() { return cursor == 0; } @Override public boolean isLast() { return cursor == (list.size() - 1); } @Override public Object getCurrentObj() { return list.get(cursor); } } }
客户端
package com.sxt.iterator; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/14 18:53 * @desc: */ public class Client { public static void main(String[] args){ ConcreteMyAggregate cma = new ConcreteMyAggregate(); cma.addObject("aa"); cma.addObject("bb"); cma.addObject("cc"); MyIterator iter = cma.createIterator(); while(iter.hasNext()){ System.out.println(iter.getCurrentObj()); iter.next(); } } }
实现逆向遍历的迭代器
开发中常见的场景:
Mediator Pattern
场景:总经理协调各个部门之间的关系,起到一个中介的作用。
核心:
代码类图
代码:
总经理类的接口
package com.sxt.mediator;
/**
* @author: Li Tian
* @contact: litian_cup@163.com
* @software: IntelliJ IDEA
* @file: Mediator.java
* @time: 2020/2/14 19:07
* @desc: 总经理类的接口
*/
public interface Mediator {
void regitster(String dname, Department d);
void command(String dname);
}
同事类接口
package com.sxt.mediator; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Department.java * @time: 2020/2/14 19:08 * @desc: 同事类的接口 */ public interface Department { // 做本部门的事情 void selfAction(); // 向总经理发出申请 void outAction(); }
研发部门
package com.sxt.mediator; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Development.java * @time: 2020/2/14 19:09 * @desc: */ public class Development implements Department { // 持有中介者(总经理)的引用 private Mediator m; public Development(Mediator m) { this.m = m; m.regitster("development", this); } @Override public void selfAction() { System.out.println("专心搞科研!"); } @Override public void outAction() { System.out.println("向总经理汇报工作!需要资金支持!"); } }
财务部门
package com.sxt.mediator; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Finacial.java * @time: 2020/2/14 19:11 * @desc: */ public class Finacial implements Department { // 持有中介者(总经理)的引用 private Mediator m; public Finacial(Mediator m) { this.m = m; m.regitster("finacial", this); } @Override public void selfAction() { System.out.println("数钱!"); } @Override public void outAction() { System.out.println("钱太多了啊总经理!怎么花!"); } }
市场部门
package com.sxt.mediator; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Market.java * @time: 2020/2/14 19:13 * @desc: */ public class Market implements Department { // 持有中介者(总经理)的引用 private Mediator m; public Market(Mediator m) { this.m = m; m.regitster("market", this); } @Override public void selfAction() { System.out.println("跑去接项目!"); } @Override public void outAction() { System.out.println("承接项目的进度!需要资金支持!"); m.command("finacial"); } }
总经理
package com.sxt.mediator; import java.util.HashMap; import java.util.Map; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: President.java * @time: 2020/2/14 19:14 * @desc: */ public class President implements Mediator { private Map<String, Department> map = new HashMap<String, Department>(); @Override public void regitster(String dname, Department d) { map.put(dname, d); } @Override public void command(String dname) { map.get(dname).selfAction(); } }
客户端
package com.sxt.mediator; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/14 19:17 * @desc: */ public class Client { public static void main(String[] args){ Mediator m = new President(); Market market = new Market(m); Development devp = new Development(m); Finacial f = new Finacial(m); market.selfAction(); market.outAction(); } }
中介者模式的本质:解耦多个同事对象之间的交互关系。每个对象都持有中介者对象的引用,只跟中介者对象打交道。我们通过中介者对象统一管理这些交互关系。
开发中常见的场景:
command pattern
介绍:将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。也称为:动作Action模式、事务transaction模式。
结构:
Command抽象命令类
ConcreteCommand具体命令类
Invoker调用者/请求者:请求的发送者,它通过命令对象来执行请求。一个调用者并不需要在设计时确定其接受者,因此它只与抽象命令类之间存在关联。在程序运行时,将调用命令对象的execute(),间接调用接受者的相关操作。
Receiver接受者
Client客户类:在客户类中需要创建调用者对象、具体命令类对象,在创建具体命令对象时指定对应的接受者。发送者和接受者之间没有直接联系,都通过命令对象间接调用。
类图
代码:
真正的命令执行者
package com.sxt.command; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Receiver.java * @time: 2020/2/15 14:28 * @desc: 真正的命令执行者 */ public class Receiver { public void action(){ System.out.println("Receiver.action()"); } }
命令管理
package com.sxt.command; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Command.java * @time: 2020/2/15 14:29 * @desc: 命令管理 */ public interface Command { // 这个方法是一个返回结果为空的方法 // 实际项目中,可以根据需求设计多个不同的方法 void execute(); } class ConcreteCommand implements Command{ // 命令的真正执行者 private Receiver receiver; public ConcreteCommand(Receiver receiver) { this.receiver = receiver; } @Override public void execute() { // 命令真正执行前或后,执行相关的处理 receiver.action(); } }
命令的调用者和发起者
package com.sxt.command; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Invoke.java * @time: 2020/2/15 14:34 * @desc: 命令的调用者和发起者 */ public class Invoke { // 也可以通过容器放很多很多命令,进行批处理。比如数据库底层的事务管理 private Command command; public Invoke(Command command) { this.command = command; } // 业务方法,用于调用命令类的方法 public void call(){ command.execute(); } }
客户端
package com.sxt.command; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/15 14:36 * @desc: */ public class Client { public static void main(String[] args){ Command c = new ConcreteCommand(new Receiver()); Invoke i = new Invoke(c); i.call(); } }
开发中常见的场景:
strategy pattern
场景:
本质:分离算法,选择实现
开发中常见的场景
策略模式对应于解决某一个问题的一个算法族,允许用户从该算法族中任选一个算法解决某以问题,同时可以方便的更换算法或者增加新的算法。并且由客户端决定调用哪个算法。
代码
策略接口
package com.sxt.strategy;
/**
* @author: Li Tian
* @contact: litian_cup@163.com
* @software: IntelliJ IDEA
* @file: Strategy.java
* @time: 2020/2/29 16:37
* @desc:
*/
public interface Strategy {
public double getPrice(double standarPrice);
}
普通客户小批量购买
package com.sxt.strategy; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @time: 2020/2/29 16:37 * @desc: 普通客户小批量购买 */ public class NewCustomerFewStrategy implements Strategy{ @Override public double getPrice(double standarPrice) { System.out.println("不打折原价!"); return standarPrice; } }
普通客户大批量购买
package com.sxt.strategy; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @time: 2020/2/29 16:37 * @desc: 普通客户大批量购买 */ public class NewCustomerManyStrategy implements Strategy{ @Override public double getPrice(double standarPrice) { System.out.println("打九折!"); return standarPrice*0.9; } }
老客户小批量购买
package com.sxt.strategy; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @time: 2020/2/29 16:37 * @desc: 老客户小批量购买 */ public class OldCustomerFewStrategy implements Strategy{ @Override public double getPrice(double standarPrice) { System.out.println("打八五折!"); return standarPrice*0.85; } }
老客户大批量购买
package com.sxt.strategy; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @time: 2020/2/29 16:37 * @desc: 老客户大批量购买 */ public class OldCustomerManyStrategy implements Strategy{ @Override public double getPrice(double standarPrice) { System.out.println("打八折!"); return standarPrice*0.8; } }
负责和具体的策略类交互
package com.sxt.strategy; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Context.java * @time: 2020/2/29 16:40 * @desc: 负责和具体的策略类交互,这样的话,具体的算法和直接的客户端调用分类了,使得算法可以独立于客户端独立的变化。 * 如果使用Spring的依赖注入功能,还可以通过配置文件,动态的注入不同策略对象,动态的切换不同的算法。 */ public class Context { // 当前采用的算法对象 private Strategy strategy; // 可以通过构造器来注入 public Context(Strategy strategy) { this.strategy = strategy; } // 或者通过加一个set方法来注入 public void setStrategy(Strategy strategy) { this.strategy = strategy; } public void printPrice(double s){ System.out.println("您的报价:" + strategy.getPrice(s)); } }
客户端
package com.sxt.strategy; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/29 16:56 * @desc: | */ public class Client { public static void main(String[] args){ Strategy s1 = new OldCustomerManyStrategy(); Context ctx = new Context(s1); ctx.printPrice(998); } }
template method pattern
场景:客户到银行办理业务:
代码
模拟银行业务流程
package com.sxt.template; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: BankTemplateMethod.java * @time: 2020/2/29 17:10 * @desc: | */ public abstract class BankTemplateMethod { // 具体方法 public void takeNumber(){ System.out.println("取号排队!"); } // 办理具体的业务,钩子方法 public abstract void transact(); public void evaluate(){ System.out.println("反馈评分!"); } // 模板方法 public final void process(){ this.takeNumber(); this.transact(); this.evaluate(); } }
客户端
package com.sxt.template; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/29 17:11 * @desc: | */ public class Client { public static void main(String[] args){ BankTemplateMethod btm = new DrawMoney(); btm.process(); // 通常采用匿名内部类 BankTemplateMethod btm2 = new BankTemplateMethod() { @Override public void transact() { // 存钱 System.out.println("我要存钱"); } }; btm2.process(); } } // 取款 class DrawMoney extends BankTemplateMethod{ @Override public void transact() { System.out.println("我要取款!"); } }
方法回调(钩子方法)
什么时候用到模板方法模式:实现一个算法时,整体步骤很固定,但是,某些部分易变。易变的部分可以抽象出来,供子类实现。
开发中常见的场景:非常频繁。各个框架、类库中都有影子。比如常见的优:
state pattern
场景:
核心:用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题
结构:
类图:
代码
状态接口
package com.sxt.state;
/**
* @author: Li Tian
* @contact: litian_cup@163.com
* @software: IntelliJ IDEA
* @file: State.java
* @time: 2020/2/29 18:11
* @desc: |
*/
public interface State {
void handle();
}
空闲状态
package com.sxt.state; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @time: 2020/2/29 18:11 * @desc: |空闲状态 */ public class FreeState implements State{ @Override public void handle() { System.out.println("房间空闲!没人住!"); } }
预定状态
package com.sxt.state; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @time: 2020/2/29 18:11 * @desc: |预定状态 */ public class BookedState implements State{ @Override public void handle() { System.out.println("房间已预订!"); } }
已入住状态
package com.sxt.state; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @time: 2020/2/29 18:11 * @desc: |已入住状态 */ public class CheckedState implements State{ @Override public void handle() { System.out.println("房间已入住!"); } }
上下文环境类:代表当前的状态和状态之间切换的核心方法
package com.sxt.state; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Context.java * @time: 2020/2/29 18:15 * @desc: | */ public class HomeContext { // 当前状态 private State state; public HomeContext(State state) { this.state = state; this.state.handle(); } // 设置不同状态 public void setState(State s){ System.out.println("修改状态!"); state = s; state.handle(); } }
客户端
package com.sxt.state; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/2/29 18:17 * @desc: | */ public class Client { public static void main(String[] args) { HomeContext ctx = new HomeContext(new FreeState()); ctx.setState(new BookedState()); ctx.setState(new CheckedState()); } }
开发中常见的场景:
Observer Pattern
场景
上面这些场景,我们都可以使用观察者模式处理。我们可以把多个订阅者、客户称之为观察者;需要同步给多个订阅者的数据封装到对象中,称之为目标。
核心:
UML类图
代码:
消息发布对象
package com.sxt.observer; import java.util.ArrayList; import java.util.List; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Subject.java * @time: 2020/3/1 13:36 * @desc: | */ public class Subject { protected List<Observer> list = new ArrayList<>(); public void registerObserver(Observer obs) { list.add(obs); } public void removeObserver(Observer obs) { list.remove(obs); } // 通知所有的观察者更新状态 public void notifyAllObservers() { for (Observer obs : list) { obs.update(this); } } }
消息发布对象的具体实现
package com.sxt.observer; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: ConcreteSubject.java * @time: 2020/3/1 13:41 * @desc: | */ public class ConcreteSubject extends Subject { private int state; public int getState() { return state; } public void setState(int state) { this.state = state; // 主题对象/目标对象的值发生了变化,请通知所有的观察者 this.notifyAllObservers(); } }
观察者接口
package com.sxt.observer;
/**
* @author: Li Tian
* @contact: litian_cup@163.com
* @software: IntelliJ IDEA
* @file: Observer.java
* @time: 2020/3/1 13:36
* @desc: |
*/
public interface Observer {
void update(Subject subject);
}
观察者
package com.sxt.observer; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: ObserverA.java * @time: 2020/3/1 13:43 * @desc: | */ public class ObserverA implements Observer { // myState需要跟目标对象的值保持一致 private int myState; public int getMyState() { return myState; } public void setMyState(int myState) { this.myState = myState; } @Override public void update(Subject subject) { myState = ((ConcreteSubject)subject).getState(); } }
客户端
package com.sxt.observer; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/3/1 13:45 * @desc: | */ public class Client { public static void main(String[] args){ // 创建目标对象 ConcreteSubject subject = new ConcreteSubject(); // 创建多个观察者 ObserverA obs1 = new ObserverA(); ObserverA obs3 = new ObserverA(); ObserverA obs2 = new ObserverA(); // 让这三个观察者添加到subject对象的观察者队伍中 subject.registerObserver(obs1); subject.registerObserver(obs2); subject.registerObserver(obs3); // 改变subject的状态 subject.setState(3000); // 查看观察者的状态 System.out.println(obs1.getMyState()); System.out.println(obs2.getMyState()); System.out.println(obs3.getMyState()); } }
JAVASE中提供了java.util.Observable和java.util.Observer来实现观察者模式
目标对象
package com.sxt.observer2; import java.util.Observable; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: ConcreteSubject.java * @time: 2020/3/1 14:05 * @desc: | */ public class ConcreteSubject extends Observable { private int state; public int getState() { return state; } public void setState(int state) { this.state = state; } public void set(int s){ // 目标对象的状态发生了改变 state = s; // 表示目标对象已经发生了更改 setChanged(); // 通知所有的观察者 notifyObservers(state); } }
观察者对象
package com.sxt.observer2; import java.util.Observable; import java.util.Observer; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: ObserverA.java * @time: 2020/3/1 14:07 * @desc: | */ public class ObserverA implements Observer { private int myState; public int getMyState() { return myState; } public void setMyState(int myState) { this.myState = myState; } @Override public void update(Observable o, Object arg) { myState = ((ConcreteSubject)o).getState(); } }
客户端
package com.sxt.observer2; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/3/1 14:09 * @desc: | */ public class Client { public static void main(String[] args){ // 创建目标对象Observable ConcreteSubject subject = new ConcreteSubject(); // 创建观察者 ObserverA obs1 = new ObserverA(); ObserverA obs2 = new ObserverA(); ObserverA obs3 = new ObserverA(); // 将上面三个观察者对象加到目标对象subject的观察者容器中 subject.addObserver(obs1); subject.addObserver(obs2); subject.addObserver(obs3); // 改变subject对象的状态 subject.set(300); // 看看观察者的状态发生变化了没 System.out.println(obs1.getMyState()); System.out.println(obs2.getMyState()); System.out.println(obs3.getMyState()); } }
开发中常见的场景
memento pattern
场景:
核心:就是保存某个对象内部状态的拷贝,这样以后就可以将该对象恢复到原先的状态。
结构
代码:
源发器类
package com.sxt.memento; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Emp.java * @time: 2020/3/1 14:38 * @desc: |源发器类 */ public class Emp { private String name; private int age; private double salary; // 进行备忘操作,并返回备忘录对象 public EmpMemento memento() { return new EmpMemento(this); } // 进行数据恢复,恢复成制定备忘录对象的值 public void recovery(EmpMemento mmt){ this.name = mmt.getName(); this.age = mmt.getAge(); this.salary = mmt.getSalary(); } public Emp(String name, int age, double salary) { this.name = name; this.age = age; this.salary = salary; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } }
备忘录类
package com.sxt.memento; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: EmpMemento.java * @time: 2020/3/1 14:54 * @desc: |备忘录类 */ public class EmpMemento { private String name; private int age; private double salary; public EmpMemento(Emp e){ this.name = e.getName(); this.age = e.getAge(); this.salary = e.getSalary(); } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } }
负责人类:管理备忘录对象
package com.sxt.memento; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: CareTaker.java * @time: 2020/3/1 14:58 * @desc: |负责人类:管理备忘录对象 */ public class CareTaker { private EmpMemento memento; public EmpMemento getMemento() { return memento; } public void setMemento(EmpMemento memento) { this.memento = memento; } }
客户端
package com.sxt.memento; /** * @author: Li Tian * @contact: litian_cup@163.com * @software: IntelliJ IDEA * @file: Client.java * @time: 2020/3/1 14:58 * @desc: | */ public class Client { public static void main(String[] args) { CareTaker taker = new CareTaker(); Emp emp = new Emp("李英俊", 18, 900); System.out.println("第一次创建对象:" + emp.getName() + emp.getAge() + emp.getSalary()); // 进行一次备份 taker.setMemento(emp.memento()); emp.setAge(38); emp.setName("哈哈"); emp.setSalary(10); System.out.println("第二次创建对象:" + emp.getName() + emp.getAge() + emp.getSalary()); // 恢复到备忘录对象保存的状态 emp.recovery(taker.getMemento()); System.out.println("第三次创建对象:" + emp.getName() + emp.getAge() + emp.getSalary()); } }
UML类图
备忘点较多时
开发中常见的应用场景:
我的CSDN:https://blog.csdn.net/qq_21579045
我的博客园:https://www.cnblogs.com/lyjun/
我的Github:https://github.com/TinyHandsome
纸上得来终觉浅,绝知此事要躬行~
欢迎大家过来OB~
by 李英俊小朋友
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。