Masimaro's blog - Java
type: channel
link: https://www.masimaro.top/tag/Java/
items: Mybatis框架
items: EL表达式与JSTL
items: jsp
items: Servlet 会话
items: Servlet 常用类
items: Servlet
items: Java 网络编程
items: Java 注解与单元测试
items: Java数据库操作
items: Java反射

Mybatis框架
type: item
date: 2019-12-16T14:59:00+08:00
description: 在之前的内容中，我写了Java的基础知识、Java Web的相关知识。有这些内容就可以编写各种各样丰富的程序。但是如果纯粹手写所有代码，工作量仍然很大。为了简化开发，隐藏一些不必要的细节，专心处理业务相关内容 ，Java提供了许多现成的框架可以使用Mybatis介绍在程序开发中讲究 MVC 的分层架构，其中M表示的是存储层，也就是与数据库交互的内容。一般来说使用jdbc时，需要经历：导入驱动、创建连接、创建statement对象，执行sql、获取结果集、封装对象、关闭连接这样几个过程。里面很多过程的代码都是固定的，唯一有变化的是执行sql并封装对象的操作。而封装对象时可以利用反射的机制，将返回字段的名称映射到Java实体类的各个属性上。这样我们很自然的就想到了，可以编写一个框架或者类库，实现仅配置sql语句和对应的映射关系，来实现查询到封装的一系列操作，从而简化后续的开发。Mybatis帮助我们实现了这个功能。Mybatis实例假设现在有一个用户表，存储用户的相关信息，我们现在需要使用mybatis来进行查询操作，可能要经历如下步骤：定义对应的实体类public class User { private Integer id; private String username; private String birthday; private char sex; private String address; //后面省略对应的getter和setter方法 //为了方便后面的实体类都会省略这些内容 } 编辑主配置文件，主要用来配置mybati的数据库连接信息以及指定对应dao的配置文件<?xml version="1.0" encoding="UTF-8"?> <configuration> <environments default="mybatis_demo"> <environment id="mybatis_demo"> <transactionManager type="JDBC"></transactionManager> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis_demo"/> <property name="username" value="root"/> <property name="password" value="masimaro_root"/> </dataSource> </environment> </environments> <mappers> <mapper resource="com/MybatisDemo/Dao/IUserDao.xml"></mapper> </mappers> </configuration>编写dao接口public interface IUserDao { public List<User> findAll(); }并提供dao的xml配置文件<?xml version="1.0" encoding="UTF-8"?> <mapper namespace="com.MyBatisDemo.Dao.IUserDao"> select * from user; </mapper>写完了对应的配置代码，接下来就是通过简单的几行代码来驱动mybatis，完成查询并封装的操作InputStream is = null; SqlSession = null; try { //加载配置文件 is = Resources.getResourceAsStream("dbconfig.xml"); //创建工厂对象 SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder(); SqlSessionFactory factory = builder.build(is); //创建sqlsession对象 sqlSession = factory.openSession(); //使用sqlsession对象创建dao接口的代理对象 IUserDao userDao = sqlSession.getMapper(IUserDao.class); //使用对象执行方法 List<User> users = this.userDao.findAll(); System.out.println(users); } catch (IOException e) { e.prin…

EL表达式与JSTL
type: item
date: 2019-12-07T15:01:00+08:00
description: JSP标准标签库（JSTL）是一个JSP标签集合，它封装了JSP应用的通用核心功能。JSTL支持通用的、结构化的任务，比如迭代，条件判断，XML文档操作，国际化标签，SQL标签。 除了这些，它还提供了一个框架来使用集成JSTL的自定义标签。JSTL安装要使用jstl需要导入对应的库，可以去官方站点下载, 点击这里下载然后解压文件将得到的jar包放入到WEB-INF的lib中导入之后，在要使用它的jsp文件中使用taglib 导入库<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>prefix 是标签的前缀，类似于命名空间，在使用库中的标签时需要加上这个前缀常用标签if 标签if标签用来做判断，当条件成立时，执行标签体的内容，条件写在test属性中，注意：只有if标签而没有对应的else标签。下面是一个例子:<c:if test="${not empty requestScope.error}"> ${requestScope.error} </c:if>上述这个例子表示，当服务器返回错误信息时，将错误信息显示到页面上choose 标签choose 标签相当于switch 语句，该标签中可以包含 when 和 otherwise 作为字标签，相当于switch语句中的case和default，例如下面的例子 当前薪水为 : <c:out value="${salary}"/> <c:choose> <c:when test="${salary <= 2000}"> 老板我是你爹, 这个工作谁爱干谁干 </c:when> <c:when test="${salary > 50000}"> 公司是我家，工作就是我的价值，我热爱工作 </c:when> <c:otherwise> 心中无半点波澜，甚至想提前下班 </c:otherwise> </c:choose>foreach 标签foreach 用来迭代容器中的元素，或者完成一些重复的操作。当使用foreach标签来进行重复性的操作时可以使用begin、end、var来控制循环，begin表示循环变量开始的值，end表示循环变量结束的值，与正常的for循环不同，循环变量的值可以等于end的值；使用var标签来定义循环变量的名称，使用step表示步进。例如:<c:foreach begin = "1" end = "10" var = "i step = "1"> ${i} </c:foreach>等价于for(int i = 1; i <= 10; i++){ System.out.println(i); }当使用 foreach来迭代容器时使用item和 var来迭代，其中item为需要迭代的容器，var表示获取到的容器中的元素。例如<c:foreach items = "list" var = "l"> ${l} </c:foreach>等价于for(String l:list){ System.out.println(l); }ELEL 表达式：Expression Language 表达式语言，用于替换和简化jsp页面中java代码的编写。EL 表达式使用 ${} 来表示jsp 默认支持el表达式，在page指令中可以使用 isELIgnored 来指定是否忽略jsp页面中的el表达式；当然也可以使用 \ 来作为转义符，表示 这个el表达式原样输出，例如 \${cookie}EL表达式中可以支持算数运算符、比较运算符、逻辑运算符合empty 空运算符；empty用于判断字符串、集合、数组对象是否为null或者长度为0。在使用el表达式时需要注意以下几点：el表达式只能从域对象中获取值el表达式中如果是类对象，可以根据Java Bean规范来获取属性值针对list这种有序集合可以使用 ${域对象.键名[索引].属性}针对Map集合,使用 ${域对象.键名.key名}或者 ${域对象.键名["key名"]}el 表达式中对域对象都做了重命名，pageScope 对应于 pageContext、requestScope对应于request、sessionScope对应于session、applicationScope对应于applicate(ServletContext)表达式${键名} 依次从最小的域中去查找对应的键值，直到找到为止

jsp
type: item
date: 2019-11-17T15:05:00+08:00
description: 之前聊过用java处理web请求，处理cookie和session等等，但是唯独没有提及如何返回信息。作为一个web程序，肯定需要使用HTML作为用户界面，这个界面需要由服务端返回。返回信息可以使用HttpResponse中的OutputStream对象来写入数据。但是既要在里面写入HTML，又要写入相应的值，造成程序很难编写，同时HTML代码长了也不容易维护。我们需要一种机制来专门处理返回给浏览器的信息。JSP就是用来专门处理这种需求的。JSP概述JSP (Java Server Page):Java 服务端页面。是由 Sun Microsystems 公司倡导和许多公司参与共同创建的一种使软件开发者可以响应客户端请求，而动态生成 HTML、XML 或其他格式文档的Web网页的技术标准。jsp可以很方便的在页面中通过java代码嵌入动态页面JSP原理分析下面是一个简单的hello world程序<%@ page contentType="text/html;charset=UTF-8" language="java" %> index <% out.println("hello world"); %> 我们将其部署到tomcat服务器上，启动并访问它之后会在tomcat所在目录的 work\Catalina\localhost\JSPDemo\org\apache\jsp (其中JSPDemo是项目名称), 在这个目录下面可以看到生成了一个index_jsp.java、index_jsp.class下面是这个jsp生成的部分源码package org.apache.jsp; import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.jsp.*; public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase implements org.apache.jasper.runtime.JspSourceDependent, org.apache.jasper.runtime.JspSourceImports { static { _jspx_imports_packages = new java.util.HashSet<>(); _jspx_imports_packages.add("javax.servlet"); _jspx_imports_packages.add("javax.servlet.http"); _jspx_imports_packages.add("javax.servlet.jsp"); _jspx_imports_classes = null; } public void _jspInit() { } public void _jspDestroy() { } public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response) throws java.io.IOException, javax.servlet.ServletException { final javax.servlet.jsp.PageContext pageContext; javax.servlet.http.HttpSession session = null; final javax.servlet.ServletContext application; final javax.servlet.ServletConfig config; javax.servlet.jsp.JspWriter out = null; final java.lang.Object page = this; javax.servlet.jsp.JspWriter _jspx_out = null; javax.servlet.jsp.PageContext _jspx_page_context = null; try { response.setContentType("text/html;charset=UTF-8"); out.write("\n"); out.write("\n"); out.write(" \n"); out.write(" \n"); out.write(" index \n"); out.write(" \n"); out.write(" \n"); ou…

Servlet 会话
type: item
date: 2019-11-03T15:19:00+08:00
description: 在网络的七层模型中，会话层位于传输层之上，它定义如何开始、控制和结束一个会话。七层模式目前仅仅处于理论阶段，但是Web中借鉴了其中的一些思路。在Web中浏览器第一次发送请求到服务器开始直到一方断开为止算作一个会话。HTTP协议本身没有状态，那么Web服务如何知道这次请求是否在一个会话中呢？Web提供了Cookie和Session两种技术。服务器在第一次收到请求之后，会在HTTP响应头的Set-Cookie中，设置Cookie值，浏览器收到响应后，保存这个Cookie在本地。后续再进行请求的时候在HTTP的请求头中设置Cookie值，服务器根据此Cookie来识别请求的状态。Cookie值本身是一个键值对，例如 Cookie: name=value;Servlet 使用Cookie在Servlet中，使用Cookie的步骤如下:创建Cookie对象 new Cookie(String name, String value)发送cookie到浏览器 response.addCookie(Cookie)获取浏览器中发送过来的cookie request.getCookies() 返回所有Cookie遍历Cookies 获取所有cookie对象调用Cookie.getName(), Cookie.getValue()获取Cookie中的键和值使用的注意事项如下:一次可以返回多个Cookie，多次调用response.addCookie即可默认情况下浏览器关闭页面后cookie失效，但是可以设置cookie失效时间Cookie虽然可以用来识别一次会话，但是也不能滥用，第一Cookie是存储在浏览器端的，可以被伪造，一般做过爬虫自动登录的都这样干过，第二浏览器对于单个cookie大小有限制，一般是4kb。同时浏览器对于单个域名的cookie也有限制，默认是20个。由于cookie本身是类似于小饼干的小料，一般来说不会把小料作为主菜。SessionCookie一般作为小料，作为会话标识来说，用Session更为常见。与 Cookie相比Session存储在服务器端，Session没有cookie的那些限制。实现原理Session的实现是基于Cookie的。第一次调用request.getSession获取Session，没有Cookie 会在内存中创建一个新的Cookie对象，名称为JSESSION值是一个唯一的ID，作为session的唯一标识在给客户端响应时会包含一个cookie值，Set-Cookie: JSESSION=ID浏览器在下一次访问web中的其他资源时会将cookie作为请求头发送到服务器。服务器会从cookie中取出ID值，并根据ID从内存中查找对应的Session对象使用 HttpSession session = request.getSession(); 来获取一个Session对象函数列表Session 对象常用函数如下:public Object getAttribute(String name); //该方法返回在该 session 会话中具有指定名称的对象，如果没有指定名称的对象，则返回 null。 public Enumeration getAttributeNames(); //该方法返回 String 对象的枚举，String 对象包含所有绑定到该 session 会话的对象的名称。 public long getCreationTime(); //该方法返回该 session 会话被创建的时间，自格林尼治标准时间 1970 年 1 月 1 日午夜算起，以毫秒为单位。 public String getId(); //该方法返回一个包含分配给该 session 会话的唯一标识符的字符串。 public long getLastAccessedTime(); //该方法返回客户端最后一次发送与该 session 会话相关的请求的时间自格林尼治标准时间 1970 年 1 月 1 日午夜算起，以毫秒为单位。 public int getMaxInactiveInterval(); //该方法返回 Servlet 容器在客户端访问时保持 session 会话打开的最大时间间隔，以秒为单位。 public void invalidate(); //该方法指示该 session 会话无效，并解除绑定到它上面的任何对象。 public boolean isNew(); //如果客户端还不知道该 session 会话，或者如果客户选择不参入该 session 会话，则该方法返回 true。 public void removeAttribute(String name); //该方法将从该 session 会话移除指…

Servlet 常用类
type: item
date: 2019-10-27T15:31:00+08:00
description: Servlet 是一套标准的接口规范，当用户通过web请求来访问服务器时，由web容器根据配置调用我们实现的对应的servlet对象来提供服务。同时为了方便开发，servlet标准中也提供了许多常用的工具类，比如基本的Request 和Response对象以及其他要说到的常用的类。ServletRequest 对象Servlet接口中的service方法的定义如下:public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;从接口上来看，我们只能在service方法中使用这个对象。当用户请求到达服务器时，服务器会将标准的HTTP请求包封装为一个 ServletRequest对象，并调用service将该对象作为参数传入。也就是说这个对象是与HTTP协议息息相关的下面是它的一些常用方法//请求行相关方法 public String getMethod(); //返回请求的方法 public String getContextPath(); //获取请求的虚拟目录（或者项目所在目录） public String getServletPath(); //获取servlet路径 public String getQueryString();// 获取查询字符串,也就是提交请求url中参数部分 public String getRequestURI(); //获取请求的URI public StringBuffer getRequestURL(); //获取请求的URL public String getProtocol(); //获取协议版本 public String getRemoteAddr(); //获取客户端的ip //请求头相关方法 public String getHeader(String name); //以字符串的形式返回请求头 public java.util.Enumeration<E> getHeaderNames(); //返回所有请求头名称的枚举 public java.util.Enumeration<E> getHeaders(String name); //返回指定请求头中的所有值的枚举 //请求体相关方法 public java.io.BufferedReader getReader() throws java.io.IOException; //获取请求体的字符流 public ServletInputStream getInputStream() throws java.io.IOException; //获取请求体中的字节流一般来说get方法会将请求参数放入到url中，而post则是将其放入到请求体中，根据上面的方法要获得请求参数，需要判断请求是get还是post，如果是get则采用 getQueryString, 如果是post则采用 getReader等方法。为了解决这个问题，Servlet提供了一些通用的方法。public String getParameter(String name); //获取请求参数,根据传入的键名获得请求的键值 public java.util.Map<K, V> getParameterMap(); //获取所有请求参数，以map方式返回 public String[] getParameterValues(String name); //如果请求中一个键对应多个值，可以使用这个方法获取所有的值请求中文乱码的问题一般HTML前端都使用utf-8编码，如果后台使用系统默认的编码则会可能造成乱码。我们可以先指定编码方式为utf-8，代码如下:request.setCharacterEncoding("UTF-8");请求转发为了保证程序模块的合理性，每个servlet 提供指定的功能，而有时候用户需要多个servlet来联合提供服务。这个时候需要使用请求转发。通过 request.getRequestDispatcher 方法来转发到其他servlet。它的特点如下:浏览器地址栏不变只能访问当前服务器的内部资源，也就是同一套web程序中的其他servlet转发是一次HTTP请求域对象每个servlet都有一个service。不同的servlet通过不同的serivce来提供服务。由于是不同的类对象和方法，不同的servlet之间不能进行信息的传递。但是有的时候需要不同的servlet之间进行数据的共享。这个时候可以使用域对象域对象是一个有作用范围的对象，域对象中数据随着对象的消亡而消亡。servlet中有下列几种作用域:一次请求…

Servlet
type: item
date: 2019-10-13T15:33:00+08:00
description: 通过前面一系列的博客的梳理，学习了一下Java基础的编程知识，从我自己的感觉上来说，Java与c++的差距并不是很大，Java将c++做了更进一步的抽象，同时丢弃了c++中一些容易出错和难懂的部分。Java的基础语法比起c++来说要简单很多。但是Java与c++一样，不能光学基础语法，还得从应用角度来学习它，使用它来做一些真真的项目。从现在开始博客内容从Java的基础过渡到了Java2E的学习Servlet 简介Servlet 英文全称是Server Applet，也叫做Java Servlet；是用Java编写的服务器端程序。其主要功能在于交互式地浏览和修改数据，生成动态Web内容。狭义的Servlet是指Java语言实现的一个接口，广义的Servlet是指任何实现了这个Servlet接口的类，一般情况下，人们将Servlet理解为后者。Servlet运行于支持Java的应用服务器中。从实现上讲，Servlet可以响应任何类型的请求，但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。———— 来自维基百科Servlet 容器从上面的定义来看 Servlet 就是一套Java的接口标准，在编写Java Web程序的时候需要遵循这套标准的接口，实现自己的Servlet 接口，并且由服务器端程序来调用，并向其他用户提供服务。目前市面上常见的支持Servlet 标准的Web容器有：Tomcat: 由Apache 基金会的一个项目，由 Apache、Sun和其他公司及个人合作开发而成。Tomcat 服务器是一个免费的开放源代码的Web 应用服务器，属于轻量级应用服务器，在中小型系统和并发访问用户不是很多的场合下被普遍使用，是开发和调试JSP 程序的首选。WebLogic: WebLogic是美国Oracle公司出品的一个application server;WebLogic是用于开发、集成、部署和管理大型分布式Web应用、网络应用和数据库应用的Java应用服务器,量级比Tomcat 要大上许多，同时也能承载更多用户的使用JBoss:是一个基于J2EE的开放源代码的应用服务器。 JBoss代码遵循LGPL许可，可以在任何商业应用中免费使用;但JBoss核心服务不包括支持servlet/JSP的WEB容器，一般与Tomcat或Jetty绑定使用。WebSphere: 是由IBM遵照开放标准，例如Java EE、XML及Web Services，开发并发行的一种应用服务器Servlet架构一般一个web项目中，主要分为WEB-INFO目录和一些jsp/html页面，其中WEB-INFO中主要包含 classes 目录(java 字节码文件)、web.xml(项目配置文件)、lib目录(项目依赖文件)在web.xml 中会指定哪些url由哪些Servlet 接口的实现类来处理，当url到达web服务器后，由服务器处理并调用对应的Servlet 类；Web容器要实现这个功能，必然会用到反射机制当用户在浏览器中输入对应的url并点击回车后:浏览器会向对应的地址发送 HTTP请求包对应的服务器收到这个请求包，并获取到请求的路径根据请求路径找到对应的项目在项目中查找对应的web.xml 文件，找到这个路径对应的Servlet 类调用Servlet 类并拿到返回值将返回封装到Http 的响应中，响应到浏览器上Servlet使用Servlet普通Servlet 接口定义如下:public interface Servlet { public void init(ServletConfig config) throws ServletException; public ServletConfig getServletConfig(); public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException; public String getServletInfo(); public void destroy(); }要回答这些接口函数都是干什么的，首先需要知道 一个Servlet对象的生命周期。当项目所在的Web容器启动之后，容器中的所有项目也随之启动，这个时候项目中所有的Servlet 被创建，当容器正常关闭之前，会停止所有项目并析构回收所有Servlet 资源。init方法：每当Servlet 创建的时候调用一次，并且仅调用这一次。，所有我们可以将一些在项目启动之时需要提前做的操作放到这个方法中service方法：用于提供服务，每当用户通过浏览器或者其他方式访问该servlet时，服务器会产生一个新的线程并…

Java 网络编程
type: item
date: 2019-09-08T15:34:00+08:00
description: Java 中网络编程接口在java.net 包中在使用C/C++进行网络编程时，针对TCP Server端需要这些操作创建SOCKET绑定监听接受连接收取数据包发送数据包TCP Client端需要这些操作创建SOCKET连接Server端发送数据包读取响应包Java中针对Server 端和Client端分别提供了两个类 ServerSocket 和 SocketServerScoket 使用步骤如下:创建ServerSocket 对象并传入一个端口号到构造函数中。在构造的时候会自动创建Socket对象并执行绑定端口、监听端口的操作调用对象的 accept 方法等待连接调用对象的 getInputStream 和 getOutputStream 获取输入输出流，并通过输入输出流来进行收发数据在不用时调用 close 方法关闭套接字Socket 类使用步骤如下:创建 Socket 对象调用 connet 方法连接到指定服务器端口(或者在构造时传入服务器和端口进行连接)调用对象的 getInputStream 和 getOutputStream 获取输入输出流，并通过输入输出流来进行收发数据在不用时调用 close 方法关闭套接字一个普通的TCP通信的实例如下:import java.net.ServerSocket; import java.net.Socket; import java.io.IOException; import java.io.OutputStream; import java.io.InputStream; public class TCPServer{ public static void main(String[] args) throws IOException{ ServerSocket server = new ServerSocket(6666); Socket socket = server.accept() ; InputStream is = socket.getInputStream(); OutputStream os = socket.getOutputStream(); byte[] bytes = new byte[1024]; int len = is.read(bytes); os.write(("echo:" + new String(bytes, 0, len)).getBytes()); server.close(); socket.close(); } }import java.net.Socket; import java.io.IOException; import java.io.OutputStream; import java.io.InputStream; public class TCPClient{ public static void main(String[] args)throws IOException{ Socket socket = new Socket("127.0.0.1", 6666); InputStream is = socket.getInputStream(); OutputStream os = socket.getOutputStream(); os.write("hello world!".getBytes()); byte[] bytes = new byte[1024]; int len = is.read(bytes); System.out.println(new String(bytes, 0, len)); socket.close(); } }下面是一个使用TCP协议进行文件传输的例子:import java.net.Socket; import java.io.IOException; import java.io.FileOutputStream; import java.io.InputStream; import java.net.ServerSocket; public class FileUploadServer{ public static void main(String[] args) throws IOException{ ServerSocket server = new ServerSocket(6666); FileOutputStream fos = new FileOutputStream("1.avi"); Socket socket = server.accept(); InputStream is = socket.getInputStream(); byte[] buf…

Java 注解与单元测试
type: item
date: 2019-09-01T15:38:00+08:00
description: 注解Java注解是在JDK1.5 之后出现的新特性，用来说明程序的，注解的主要作用体现在以下几个方面:编译检查，例如 @Override编写文档，java doc 会根据注解生成对应的文档代码分析，通过注解对代码进行分析[利用反射机制]JDK 中有一些常用的内置注解，例如:Override：检查被该注解修饰的方法是否是重写父类的方法Deprecatedd：被该注解标注的内容已过时SuppressWarnning: 压制警告，传入参数all表示压制所有警告自定义注解JDK中虽然内置了大量注解，但是它也允许我们自定义注解，这样就为程序编写带来了很大的便利，像有些框架就大量使用注解。java注解本质上是一个继承了 java.lang.annotation.Annotation 接口的一个接口，但是如果只是简单的使用关键字 interface来定义接口，仍然不是注解，仅仅是一个普通的接口，在定义注解时需要使用关键字 @interface， 该关键字会默认继承 Annotation 接口，并将定义的接口作为注解使用注解中可以定义方法，这些方法的返回值只能是基本类型、String、枚举类型、注解以及这些类型的数组，我们称这些方法叫做属性。在使用注解时需要注意以下几个事情必须给注解的属性赋值，如果不想赋值可以使用default来设置默认值如果属性列表中只有一个名为value的属性，那么在赋值时可以不用指定属性名称多个属性值之间使用逗号隔开数组属性的赋值使用 {}, 而当数组属性中只有一个值时, {} 可以省略不写元注解元注解是用来描述注解的注解，Java中提供的元注解有下列几个Target描述注解能够作用的位置，即哪些Java代码元素能够使用该注解,注解的源代码如下:@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Target { ElementType[] value(); }这个注解只有一个value属性，属性需要传入一个 ElementType枚举类型的数组，该枚举类型可以取下列几个值ElementType含义TYPE接口、类(包括注解)、枚举类型上使用FIELD字段声明（包括枚举常量）METHOD方法PARAMETER参数声明CONSTRUCTOR构造函数LOCAL_VARIABLE局部变量声明ANNOTATION_TYPE注解类型声明PACKAGE包声明Retention表示该注解类型的注解保留的时长,主要有3个阶段: 源码阶段，类对象阶段，运行阶段;源码阶段是只只存在与源代码中，类对象阶段是指被编译进 .class 文件中，类对象阶段是指执行时被加载到内存.则默认保留策略为RetentionPolicy.CLASS。它的源码如下:@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Retention { RetentionPolicy value(); }Documented表示拥有该注解的元素可通过javadoc此类的工具进行文档化。源码如下:@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Documented { }Inherited表示该注解类型被自动继承@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Inherited { }内置注解解读下面通过几个JDK内置注解的解读来说明注解相关使用Override@Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Override { }该注解用于编译时检查，被该注解注释的方法是否是重写父类的方法。从源码上看，它只能在方法上使用，并且它仅仅存在于源码阶段不会被编译进 .class 文件中Deprecatedd@Documented @Retention(RetentionPolicy.RUNTIME) @Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, …

Java数据库操作
type: item
date: 2019-08-25T15:39:00+08:00
description: 数据库操作是程序设计中十分重要的一个部分，Java内置JDBC来操作数据库JDBC使用JDBC——Java Database connecting Java数据库连接；本质上JDBC定义了操作数据库的一套接口，作为应用程序的开发人员来说只需要创建接口对应的对象即可，而接口的实现由各个数据库厂商去完成。要在应用程序中使用JDBC，需要根据数据库的不同导入对应的jar包。使用步骤如下：导入相应jar包注册驱动获取数据库连接对象定义sql语句获取执行sql语句的对象执行sql并获取结果集对象从结果集中获取数据释放资源相关对象的描述DriverManager在使用JDBC之前需要先注册驱动，也就是告诉JDBC，我们需要导入哪个jar包，这个工作由DriverManager对象来实现，可以调用它里面的方法 registerDriver 来实现，该方法的定义如下:static void registerDriver(Driver driver);这个方法需要传入一个driver 对象，driver对象是具体的数据库厂商来实现，后续相关操作其实是根据这个driver对象来调用相关代码，实现同一套接口操作不同数据库我们查阅相关实现类的代码如下:public class Driver extends NonRegisteringDriver implements java.sql.Driver { // // Register ourselves with the DriverManager // static { try { java.sql.DriverManager.registerDriver(new Driver()); } catch (SQLException E) { throw new RuntimeException("Can't register driver!"); } } /** * Construct a new driver and register it with DriverManager * * @throws SQLException * if a database error occurs. */ public Driver() throws SQLException { // Required for Class.forName().newInstance() } }在Driver对象中发现，它在静态代码块中执行了registerDriver方法，也就是说我们只要加载对应的类，类就会自动帮助我们进行注册的操作。所以在第一步注册驱动的代码中可以这样写:Class.forName("org.mariadb.jdbc.Driver"); //加载对应的Driver类到内存中Connection对象注册了驱动之后就是获取数据库的连接对象，在DriverManager中使用getConnection方法获取，它的定义如下:static Connection getConnection(String url); static Connection getConnection(String url, Properties info); static Connection getConnection(String url, String user, String password);上述3个方法中，常用的是第3个，参数分别为: 连接字串、用户名、密码连接字串的格式为: jdbc:数据库类型://数据库IP：端口/数据库名称,比如 jdbc:mariadb://localhost:3306/test获取连接字串的代码如下:Connection conn = DriverManager.getConnection("jdbc:mariadb://localhost:3306/study", "root", "root");执行sql语句获取连接对象之后，需要向数据库传递sql语句并执行它，执行sql语句需要使用对象 Statement, 常用的方法如下:boolean execute(String sql); ResultSet executeQuery(String sql); int executeUpdate(String sql);一般可以使用execute来执行相关操作，如果是查询语句，可以使用executeQuery来执行并获取返回的结果集，如果需要执行DELTE、UPDATE、INSERT等语句可以使用executeUpdate来更新数据库我们可以通过 Connection对象的createStatement方法获取一个Statement对象,代码如下:Statement statement = conn.c…

Java反射
type: item
date: 2019-08-18T15:41:00+08:00
description: Java中的类文件最终会被编译为.class 文件，也就是Java字节码。这个字节码中会存储Java 类的相关信息。在JVM执行这些代码时首先根据 java 命令中指定的类名找到.class 文件然后使用类加载器将class字节码文件加载到内存，在加载时会调用Class类的classLoader方法，读取.class 文件中保存类的成员变量、方法、构造方法，并将这些内容在需要时创建对应的对象。这个就是java中的反射机制。反射机制提供了由字符串到具体类对象的映射，提高了程序的灵活性，在一些框架中大量使用映射，做到根据用户提供的xml配置文件来动态生成并创建类对象反射机制最关键的就是从字节码文件中加载类信息并封装为对应的结构。在Java中专门提供了一个 Class 类，用于存储从.class 文件中读取出来的类的信息。 该类的定义和常用方法如下:public final class Class<?> extends Object implements Serializable, GenericDeclaration, Type, AnnotatedElement{ String getName(); //获取类名 ClassLoader getClassLoader(); //返回类的加载器 static Class<T> forName(String className); //根据类名返回对应类的Class对象 Field getField(String name); //根据名称返回对应的Filed对象 Field[] getFields(); //返回所有的Filed 对象 Field getDeclaredField(String name) //;返回一个 Field对象。 Field[] getDeclaredFields();//返回的数组 Field对象 Constructor<T> getConstructor(Class<?>... parameterTypes); Constructor<?>[] getConstructors(); Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes); Constructor<?>[] getDeclaredConstructors(); Method getDeclaredMethod(String name, Class<?>... parameterTypes); Method[] getDeclaredMethods(); Method getMethod(String name, Class<?>... parameterTypes); Method[] getMethods(); }获取 Class 对象获取Class对象常见的有3种:可以通过 Class 类的静态方法 forName 传入类名获取可以通过具体对象的getClass 方法获取，这种方式的前提是我们拿到了目标对象，也就是需要内存中已经加载了对应的对象,相对来说第一种方法相对方便。通过类的静态class 成员来获取。下面是3中方式对应的代码 //1. 使用forName 来获取 try { Class<?> student = Class.forName("Student"); System.out.println(student.getName()); } catch (ClassNotFoundException e) { e.printStackTrace(); } //2. 使用getClass 对象 Class<? extends Student> aClass = new Student().getClass(); System.out.println(aClass.getName()); //3. 使用class 静态变量 Class<Student> studentClass = Student.class; System.out.println(studentClass.getName());需要注意的是在每个进程中 一个类的 Class 只有一个，拿上面的代码来说,即使 我们获取了3次，在内存中只有一个对应的Class 对象。获取类成员变量通过一定的方法，我们已经获取到了对应的Class 成员，之前说过Class是对字节码中记录的类信息的封装，类的成员变量被封装到了Field对象中，我们可以使用上述4个与Field有关的方法来获取对应的成员变量。public class Student { public String name; private int age; public String sex…