[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cfodZkLj-1691793219502)(./assets/%E7%8E%84%E5%AD%90Share%20-%20Java%20%E5%BC%80%E5%8F%91%E4%B9%8B%E6%A1%86%E6%9E%B6%E5%9F%BA%E7%A1%80%E6%8A%80%E6%9C%AF.png)]
Java反射:在编译时不确定哪个类被加载,而在程序运行时才加载、探知、使用
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rPRhLuhe-1691793219503)(./assets/%E8%BF%90%E8%A1%8C%E6%9C%BA%E5%88%B6.png)]
反射是指能够在运行时,观察并修改自己运行时(Runtime)行为的特性 Java 反射机制主要提供了以下的一些功能
java.lang.reflect.*
Class 类是 Java 反射机制的起源和入口
Class 类存放类的结构信息
获取 Class 实例的常用方式
// 方法1:对象.getClass()
Class clazz = new Student().getClass();
// 方法2:类.class
Class clazz = Student.class;
// 方法3:Class.forName()
Class clazz = Class.forName("xxx.xxx.Student");
// 方法4:基本数据类型包装类.TYPE
Class<Integer> clazz = Integer.TYPE;
方法 | 说明 |
---|---|
String getName() | 以字符串形式返回该类型的名称 |
String getSimpleName() | 以字符串形式返回该类型的简称 |
Package getPackage() | 获取该类型所在的包 |
Class getSuperclass() | 返回该类型的超类的 Class 实例 |
Class[] getInterfaces() | 返回该类型所实现的全部接口的 Class 实例 |
int getModifiers() | 返回该类型的所有修饰符,由 public、protected、private、final、staic、abstract 等对应的 int 常量组成,返回的整数应使用 Modifier 工具类来解码,才可以判断修饰符的构成 |
Class[] getDeclaredClasses() | 返回该类型中包含的全部内部类的 Class 实例 |
Class getDeclaringClass() | 返回该类型所在的外部类的 Class 实例 |
public class Xz01 {
public static void main(String[] args) throws ClassNotFoundException {
Class<Student> c1 = Student.class;
Class<?> c2 = new Student().getClass();
Class<?> c3 = Class.forName("xuanzi.Student");
System.out.println(c1.hashCode());
System.out.println(c2.hashCode());
System.out.println(c3.hashCode());
System.out.println(c1 == c2);
// hashCode 编码以及 内存地址一致表示同一个 Class 对象
System.out.println("获取全类名(包含包路径):" + c1.getName());
System.out.println("获取类名(仅类名称):" + c1.getSimpleName());
System.out.println("获取包名(仅包名):" + c1.getPackage().getName());
System.out.println("获取类加载器:" + c1.getClassLoader());
System.out.println("获取父类路径:" + c1.getSuperclass().getName());
System.out.println("获取类访问修饰符:" + c1.getModifiers());
System.out.println("表示 PUBLIC:" + Modifier.PUBLIC);
}
}
// 1324119927
// 1324119927
// 1324119927
// true
// 获取全类名(包含包路径):xuanzi.Student
// 获取类名(仅类名称):Student
// 获取包名(仅包名):xuanzi
// 获取类加载器:jdk.internal.loader.ClassLoaders$AppClassLoader@63947c6b
// 获取父类路径:java.lang.Object
// 获取类访问修饰符:1
// 表示 PUBLIC:1
方法 | 说明 |
---|---|
Constructor getConstructor(Class… params) | 返回该类型指定参数列表的 public 构造方法,构造方法的参数列表与 params 所指定的类型列表所匹配 |
Constructor[] getConstructors() | 返回该类型的所有 public 构造方法 |
Constructor getDeclaredConstructor(Class… params) | 返回该类型的指定参数列表的构造方法,访问级别不限 |
Constructor[] getDeclaredConstructors() | 返回该类型的所有构造方法,访问级别不限 |
public class Xz02 {
public static void main(String[] args) throws NoSuchMethodException {
Class<Student> c1 = Student.class;
Constructor<Student> constructor = c1.getConstructor();
Constructor<?>[] constructors = c1.getConstructors();
Constructor<Student> declaredConstructor = c1.getDeclaredConstructor();
Constructor<?>[] declaredConstructors = c1.getDeclaredConstructors();
Constructor<?> declaredConstructors1 = c1.getDeclaredConstructor(String.class);
System.out.println(constructor);
System.out.println(Arrays.toString(constructors));
System.out.println(declaredConstructor);
System.out.println(Arrays.toString(declaredConstructors));
System.out.println(declaredConstructors1);
System.out.println("================================");
for (Constructor<?> cc : declaredConstructors) {
int modifier = cc.getModifiers();
String xiu = "";
if ((modifier & Modifier.PUBLIC) == Modifier.PUBLIC) {
xiu = "PUBLIC";
} else if ((modifier & Modifier.PROTECTED) == Modifier.PROTECTED) {
xiu = "PROTECTED";
} else if ((modifier & Modifier.FINAL) == Modifier.FINAL) {
xiu = "FINAL";
} else if ((modifier & Modifier.ABSTRACT) == Modifier.ABSTRACT) {
xiu = "ABSTRACT";
} else if ((modifier & Modifier.PRIVATE) == Modifier.PRIVATE) {
xiu = "PRIVATE";
} else {
xiu = "未知";
}
System.out.println(xiu);
}
System.out.println("================================");
Class<?>[] parameterTypes = declaredConstructors1.getParameterTypes();
if (parameterTypes.length == 0) {
System.out.println("无参");
} else {
for (int i = parameterTypes.length - 1; i >= 0; i--) {
System.out.println(parameterTypes[i].getSimpleName());
}
}
System.out.println("================================");
}
}
// public xuanzi.Student()
// [public xuanzi.Student(java.lang.String,int,char), public xuanzi.Student()]
// public xuanzi.Student()
// [public xuanzi.Student(java.lang.String,int,char), public xuanzi.Student(), protected xuanzi.Student(java.lang.String), private xuanzi.Student(java.lang.String,int)]
// protected xuanzi.Student(java.lang.String)
// ================================
// PUBLIC
// PUBLIC
// PROTECTED
// PRIVATE
// ================================
// String
// ================================
方法 | 说明 |
---|---|
Field getField(String name) | 返回该类型中指定名称的 public 属性,name 参数用于指定属性名称 |
Field[] getFields() | 返回该类型中所有 public 属性 |
Field getDeclaredField(String name) | 返回该类型中指定名称的属性,与属性的访问级别无关 |
Field[] getDeclaredFields() | 返回该类型中的全部属性,与属性的访问级别无关 |
public class Xz03 {
public static void main(String[] args) throws NoSuchMethodException, NoSuchFieldException {
Class<Student> c1 = Student.class;
Field[] fields = c1.getFields();
Field name = c1.getField("name");
Field declaredName = c1.getDeclaredField("name");
Field[] declaredFields = c1.getDeclaredFields();
System.out.println(Arrays.toString(fields));
System.out.println(name);
System.out.println(declaredName);
System.out.println(Arrays.toString(declaredFields));
System.out.println("================================");
for (Field df : declaredFields) {
int modifier = df.getModifiers();
String xiu = "";
if ((modifier & Modifier.PUBLIC) == Modifier.PUBLIC) {
xiu = "PUBLIC";
} else if ((modifier & Modifier.PROTECTED) == Modifier.PROTECTED) {
xiu = "PROTECTED";
} else if ((modifier & Modifier.FINAL) == Modifier.FINAL) {
xiu = "FINAL";
} else if ((modifier & Modifier.ABSTRACT) == Modifier.ABSTRACT) {
xiu = "ABSTRACT";
} else if ((modifier & Modifier.PRIVATE) == Modifier.PRIVATE) {
xiu = "PRIVATE";
} else {
xiu = "未知";
}
System.out.println(xiu);
}
System.out.println("================================");
for (Field declaredField : declaredFields) {
System.out.print(declaredField.getModifiers() + " - ");
System.out.print(declaredField.getName() + " - ");
System.out.print(declaredField.getType() + " - ");
System.out.println();
}
System.out.println("================================");
}
}
// [public java.lang.String xuanzi.Student.name, public int xuanzi.Student.age]
// public java.lang.String xuanzi.Student.name
// public java.lang.String xuanzi.Student.name
// [public java.lang.String xuanzi.Student.name, public int xuanzi.Student.age, private char xuanzi.Student.gender]
// ================================
// PUBLIC
// PUBLIC
// PRIVATE
// ================================
// 1 - name - class java.lang.String -
// 1 - age - int -
// 2 - gender - char -
// ================================
方法 | 说明 |
---|---|
Method getMethod(String name, Class… params) | 返回该实例中指定的 public 方法,name 参数用于指定方法名称,params 参数指定参数列表 |
Method[] getMethods() | 返回该实例中所有 public 方法 |
Method getDeclaredMethod(String name, Class… params) | 返回该实例中指定的方法,与方法的访问级别无关 |
Method[] getDeclaredMethods() | 返回该实例中的全部方法,与方法的访问级别无关 |
public class Xz04 {
public static void main(String[] args) throws NoSuchMethodException {
Class<Student> c1 = Student.class;
Method[] methods = c1.getMethods();
Method getStudent = c1.getMethod("setName", String.class);
Method[] declaredMethods = c1.getDeclaredMethods();
Method declaredMethod = c1.getDeclaredMethod("getGender");
System.out.println(getStudent);
System.out.println(Arrays.toString(methods));
System.out.println(Arrays.toString(declaredMethods));
System.out.println(declaredMethod);
System.out.println("================================");
for (Method dm : declaredMethods) {
int modifier = dm.getModifiers();
String xiu = "";
if ((modifier & Modifier.PUBLIC) == Modifier.PUBLIC) {
xiu = "PUBLIC";
} else if ((modifier & Modifier.PROTECTED) == Modifier.PROTECTED) {
xiu = "PROTECTED";
} else if ((modifier & Modifier.FINAL) == Modifier.FINAL) {
xiu = "FINAL";
} else if ((modifier & Modifier.ABSTRACT) == Modifier.ABSTRACT) {
xiu = "ABSTRACT";
} else if ((modifier & Modifier.PRIVATE) == Modifier.PRIVATE) {
xiu = "PRIVATE";
} else {
xiu = "未知";
}
System.out.println(xiu);
}
System.out.println("================================");
for (Method declaredField : declaredMethods) {
System.out.print((declaredField.getModifiers() == Modifier.PUBLIC ? "PUBLIC" : "PRIVATE") + " - ");
System.out.print(declaredField.getName() + " - ");
System.out.print(declaredField.getReturnType().getSimpleName() + " - ");
System.out.print(Arrays.toString(declaredField.getParameterTypes()) + " - ");
System.out.print(Arrays.toString(declaredField.getExceptionTypes()) + " - ");
System.out.println();
}
System.out.println("================================");
}
}
// public void xuanzi.Student.setName(java.lang.String)
// [public java.lang.String xuanzi.Student.getName(), public java.lang.String xuanzi.Student.toString() throws java.lang.IllegalArgumentException,java.lang.ArithmeticException, public void xuanzi.Student.setName(java.lang.String), public int xuanzi.Student.getAge(), public void xuanzi.Student.setAge(int), public void xuanzi.Student.setGender(char), public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException, public final void java.lang.Object.wait() throws java.lang.InterruptedException, public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException, public boolean java.lang.Object.equals(java.lang.Object), public native int java.lang.Object.hashCode(), public final native java.lang.Class java.lang.Object.getClass(), public final native void java.lang.Object.notify(), public final native void java.lang.Object.notifyAll()]
// [public java.lang.String xuanzi.Student.getName(), public java.lang.String xuanzi.Student.toString() throws java.lang.IllegalArgumentException,java.lang.ArithmeticException, public void xuanzi.Student.setName(java.lang.String), private char xuanzi.Student.getGender(), public int xuanzi.Student.getAge(), public void xuanzi.Student.setAge(int), private java.lang.String xuanzi.Student.show(java.lang.String,int,char), public void xuanzi.Student.setGender(char)]
// private char xuanzi.Student.getGender()
// ================================
// PUBLIC
// PUBLIC
// PUBLIC
// PRIVATE
// PUBLIC
// PUBLIC
// PRIVATE
// PUBLIC
// ================================
// PUBLIC - getName - String - [] - [] -
// PUBLIC - toString - String - [] - [class java.lang.IllegalArgumentException, class java.lang.ArithmeticException] -
// PUBLIC - setName - void - [class java.lang.String] - [] -
// PRIVATE - getGender - char - [] - [] -
// PUBLIC - getAge - int - [] - [] -
// PUBLIC - setAge - void - [int] - [] -
// PRIVATE - show - String - [class java.lang.String, int, char] - [] -
// PUBLIC - setGender - void - [char] - [] -
// ================================
Student student = Student.class.newInstance();
// 通过 class 获取对象
Student student = Student.class.getConstructor().newInstance();
// 通过构造获取对象
public class Xz05 {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
Student student = new Student();
// 直接 new 对象
Student student1 = Student.class.newInstance();
// 通过 class 获取对象
Student student2 = Student.class.getConstructor().newInstance();
// 通过构造获取对象
Constructor<Student> studentConstructor = Student.class.getConstructor(String.class, char.class);
studentConstructor.setAccessible(true);
// 通过有参构造获取对象
Student student3 = studentConstructor.newInstance("XuanZi", '男');
Constructor<Student> studentConstructor1 = Student.class.getDeclaredConstructor(String.class, int.class);
studentConstructor1.setAccessible(true);
// 可设置私有构造函数
Student student4 = studentConstructor1.newInstance("XuanZi", 12);
System.out.println(student);
System.out.println(student1);
System.out.println(student2);
System.out.println(student3);
System.out.println(student4);
}
}
// xuanzi.Student{name='null', age=0, gender= }
// xuanzi.Student{name='null', age=0, gender= }
// xuanzi.Student{name='null', age=0, gender= }
// xuanzi.Student{name='XuanZi', age=0, gender=男}
// xuanzi.Student{name='XuanZi', age=12, gender= }
java.lang.reflect.Field
方法 | 说明 |
---|---|
xxx getXxx(Object obj) | xxx 表示8种基本数据类型之一,若 Field 实例表示的是一个静态属性,则 obj 可以设置为 null |
Object get(Object obj) | 以 Object 类型返回 obj 中相关属性的值 |
void setXxx(Object obj, xxx val) | 将 obj 中相关属性的值设置为 val。xxx 为8种基本数据类型之一 |
void set(Object obj, Object val) | 将 obj 中相关属性的值设置为 val |
void setAccessible(boolean flag) | 对相关属性设置访问权限。设置为 true 可以禁止 Java 语言访问检查 |
public class Xz06 {
public static void main(String[] args) throws NoSuchFieldException, InstantiationException, IllegalAccessException {
Class<Student> studentClass = Student.class;
Student student = studentClass.newInstance();
Field name = studentClass.getField("name");
System.out.println(name.get(student));
name.set(student, "玄子");
System.out.println(name.get(student));
}
}
// null
// 玄子
java.lang.reflect.Method
public Object invoke( Object obj, Object... args )
- Object:返回值
- Object obj:执行该方法的对象
- Object… args:执行该方法时传入的参数
public class Xz07 {
public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException, InstantiationException {
Class<Student> studentClass = Student.class;
Student student = studentClass.newInstance();
Method name = studentClass.getMethod("setName", String.class);
name.invoke(student, "张三");
System.out.println(student);
}
}
// xuanzi.Student{name='张三', age=0, gender= }
XML(Extensible Markup Language),可扩展标记语言
<books>
<book id="bk101">
<title>.NET高级编程title>
<author>王姗author>
<description>包含C#框架和网络编程等description>
book>
<book id="bk102">
<title>XML基础编程title>
<author>李明明author>
<description>包含XML基础概念和基本用法description>
book>
books>
使用标签描述的文档元素信息,成对出现。
节点不包含子节点可自闭合
XML 文档的内容元素由一系列标签组成
<元素名 属性名="属性值">元素内容(子元素、字符等)元素名>
xml
(或者XML、Xml)开始 <、"、&
XML 中的特殊字符包括 < 、> 、' 、" 、&
使用预定义实体对特殊字符进行转义
特殊字符 | 实体名称 |
---|---|
< | < |
> | > |
" | " |
’ | ' |
& | & |
在元素的文本中使用 CDATA 节处理
<description>
以及的使用]]>
description>
格式良好的 XML 文档需要遵循如下规则
DOM 和 SAX 不针对特定语言,只是定义了一些接口,以及部分缺省实现(使用空方法实现接口)
文档对象模型(Document Object Model)DOM 把 XML 文档映射成一个倒挂的树
<book >
<title>三国演义title>
<author>罗贯中author>
<price>30元price>
book>
使用 Oracle 提供的 JAXP(Java API for XML Processing)
常用接口 | 说明 | 常用方法 |
---|---|---|
Node | 代表了文档树中的一个抽象节点,有 Document、Element、Text 等子对象 | NodeList getChildNodes() Node getFirstChild() Node getLastChild() Node getNextSibling() Node getPreviousSibling() Node appendChild(Node child) String getNodeName() String getNodeValue() short getNodeType() |
NodeList | 包含了一个或多个节点(Node)的列表 | int getLength() Node item(int index) |
Document | 表示整个 XML 文档 | NodeList getElementsByTagName(String tagname) Element getElementById(String id) Element getDocumentElement() Element createElement(String tagname) |
Element | XML 文档中的一个元素,是 Node 最主要的子对象 | String getAttribute(String name) NodeList getElementsByTagName(String tagname) String getTagName() |
显示 XML 文件中收藏的手机品牌和型号
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MLL8bxCf-1691793219504)(./assets/xml%E7%BB%93%E6%9E%841.png)]
<PhoneInfo>
<Brand name="华为">
<Type name="P90"/>
<Item>
<title>标题信息title>
<link>链接link>
<description>描述description>
<pubDate>2023-02-01pubDate>
Item>
Brand>
<Brand name="苹果">
<Type name="iPhone Z"/>
<Type name="iPhone ZL"/>
Brand>
<Brand name="三星">
<Type name="NoteX"/>
Brand>
PhoneInfo>
public class Book {
public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse("src/main/java/CH15_XML/PhoneInfo.xml");
NodeList bookList = doc.getElementsByTagName("Brand");
for (int i = 0; i < bookList.getLength(); i++) {
Node brand = bookList.item(i);
Element element = (Element) brand;
String attrVal = element.getAttribute("name");
NodeList types = element.getChildNodes();
for (int j = 0; j < types.getLength(); j++) {
Node typeNode = types.item(j);
if (typeNode.getNodeType() == Node.ELEMENT_NODE) {
Element typeElement = (Element) typeNode;
String type = typeElement.getAttribute("name");
System.out.println("手机:" + attrVal + type);
}
}
}
}
}
public class Xz01 {
public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException {
NodeList brandList = DocumentBuilderFactory
.newInstance()
.newDocumentBuilder()
.parse("src/main/resources/PhoneInfo.xml")
.getElementsByTagName("Brand");
for (int i = 0; i < brandList.getLength(); i++) {
Element brandElement = (Element) brandList.item(i);
System.out.println(brandElement.getTagName() + ":" + brandElement.getAttribute("name"));
NodeList typeList = brandElement.getElementsByTagName("Type");
for (int j = 0; j < typeList.getLength(); j++) {
Element typeElement = (Element) typeList.item(j);
System.out.println("\t" + typeElement.getTagName() + ":" + typeElement.getAttribute("name"));
NodeList itemList = brandElement.getElementsByTagName("Item");
for (int k = 0; k < itemList.getLength(); k++) {
Element itemElement = (Element) itemList.item(k);
NodeList pubDateList = itemElement.getElementsByTagName("pubDate");
System.out.print("\t" + itemElement.getTagName() + ":");
for (int l = 0; l < pubDateList.getLength(); l++) {
String textContent = pubDateList.item(l).getTextContent();
System.out.println(textContent);
}
}
}
}
}
}
// Brand:华为
// Type:P90
// Item:2023-02-01
// Brand:苹果
// Type:iPhone Z
// Type:iPhone ZL
// Brand:三星
// Type:NoteX
调用 Node 对象的 getChildNodes() 方法有时会包含 XML 文档中的空白符,导致调用 Node 对象方法出错,解决办法包括:
- 取得 Node 对象后判断
node.getNodeType() == Node.ELEMENT_NODE
,即判断是否是元素节- 点将 Node 对象转换为 Element 对象,使用 Element 的 getElementsByTagName(String name)
显示XML文件中手机新闻的发布日期
public class Book2 {
public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse("src/main/java/CH15_XML/PhoneInfo.xml");
NodeList bookList = doc.getElementsByTagName("pubDate");
Element pubDateElement = (Element) bookList.item(0);
String nodeValue = pubDateElement.getFirstChild().getNodeValue();
System.out.println(nodeValue);
}
}
// 2023-02-01
public class Book3 {
public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException, TransformerException {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse("src/main/java/CH15_XML/PhoneInfo.xml");
Element brandElement = doc.createElement("Brand");
brandElement.setAttribute("name", "三星");
Element typeElement = doc.createElement("Type");
typeElement.setAttribute("name", "NoteX");
brandElement.appendChild(typeElement);
Element phoneInfoElement = (Element) doc.getElementsByTagName("PhoneInfo").item(0);
phoneInfoElement.appendChild(brandElement);
TransformerFactory tff = TransformerFactory.newInstance();
Transformer tf = tff.newTransformer();
DOMSource domSource = new DOMSource(doc);
tf.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
StreamResult streamResult = new StreamResult(Files.newOutputStream(Paths.get("src/main/java/CH15_XML/PhoneInfo.xml")));
tf.transform(domSource, streamResult);
}
}
<Brand name="三星">
<Type name="NoteX"/>
Brand>
public class Book4 {
public static void main(String[] args) throws ParserConfigurationException, IOException, SAXException, TransformerException {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse("src/main/java/CH15_XML/PhoneInfo.xml");
NodeList list = doc.getElementsByTagName("Brand");
for (int i = 0; i < list.getLength(); i++) {
Element brandItem = ((Element) list.item(i));
String brandName = brandItem.getAttribute("name");
if ("三星".equals(brandName)) {
// ElementBrand.setAttribute("name", "OPPO");
brandItem.getParentNode().removeChild(brandItem);
// 先获取父节点,再删除子节点
}
}
TransformerFactory tff = TransformerFactory.newInstance();
Transformer tf = tff.newTransformer();
DOMSource domSource = new DOMSource(doc);
tf.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
StreamResult streamResult = new StreamResult(Files.newOutputStream(Paths.get("src/CH15_XML/PhoneInfo.xml")));
tf.transform(domSource, streamResult);
}
}
DOM4J 的主要接口都定义在 org.dom4j 包里
接口说明 |
---|
Node:为所有的 DOM4J 中的 XML 节点定义了多态行为 |
Branch:为能够包含子节点的节点定义了公共行为 |
Element:定义 XML 元素 |
Document:定义 XML 文档 |
Entity:定义 XML 实体 |
Attribute:定义了 XML 的属性 |
DocumentType:定义 XML DOCTYPE 声明 |
ProcessingInstruction:定义 XML 处理指令 |
CharacterData:标识接口,标识基于字符的节点 |
Text:定义 XML 文本节点 |
CDATA:定义了 XML CDATA 区域 |
Comment:定义了 XML 注释的行为 |
常用接口 | 常用方法 |
---|---|
Branch | Element elementById(String id) Element addElement(String name) boolean remove(Node node) |
Document | Element getRootElement() |
Element | Element element(String name) List elements() List elements(String tagname) Iterator elementIterator() Iterator elementIterator(String name) Attribute attribute(String name) Element addAttribute(String name, String value) String getText() |
package CH15_XML;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.File;
import java.util.Iterator;
public class Book5 {
public static void main(String[] args) throws DocumentException {
SAXReader saxReader = new SAXReader();
Document document = saxReader.read(new File("src/main/java/CH15_XML/PhoneInfo.xml"));
Element rootElement = document.getRootElement();
for (Iterator<Element> itBrand = rootElement.elementIterator(); itBrand.hasNext(); ) {
Element brand = itBrand.next();
System.out.println(brand.attributeValue("name"));
for (Iterator<Element> itType = brand.elementIterator(); itType.hasNext(); ) {
Element type = itType.next();
System.out.println("\t" + type.attributeValue("name"));
}
}
}
}
// 华为
// P90
// null
// 苹果
// iPhone Z
// iPhone ZL
// 三星
// NoteX
三十六计
GoF(Gang of Four,四人组)设计模式分为23种
范围/目的 | 创建型模式 | 结构型模式 | 行为型模式 |
---|---|---|---|
类模式 | 工厂方法 | (类)适配器 | 模板方法解释器 |
对象模式 | 单例 原型 抽象工厂 建造者 |
代理 (对象)适配器 桥接 装饰 外观 享元 组合 |
策略 命令 职责链 状态 观察者 中介者 迭代器 访问者 备忘录 |
单一职责原则
开闭原则
里氏替换原则
依赖倒置原则
接口隔离原则
迪米特法则
合成复用原则
如何解决类似“Service与某个具体Dao实现”耦合的问题?
将创建工作转移出来避免在Service中创建具体的Dao实现类,产生耦合
简单工厂模式,又叫做静态工厂方法模式,不属于 GoF 的23种设计模式之一,可以理解为工厂模式的一个特殊实现
依据依赖倒置原则,使用setter方法传递依赖关系,减少Service对工厂类的依赖,降低耦合
public class NewsServiceImpl implements NewsService {
private NewsDao dao;
public void setDao(NewsDao dao) {
this.dao = dao;
}
… …
}
简单工厂模式可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类
// 创建NewsDao实例的工厂方法
public static NewsDao getInstance(String key) {
switch (key) {
case "mysql":
return new NewsDaoMySqlImpl();
case "oracle":
return new NewsDaoOracleImpl();
case "redis":
return new NewsDaoRedisImpl();
default:
throw new RuntimeException("无效的数据库类型:" + key + " ,DAO获取失败");
}
}
要创建的产品不多且逻辑不复杂的情况,可以考虑简单工厂模式
简单工厂模式包含如下角色
增加新的产品需要修改,工厂方法的判断逻辑,不符合开闭原则
对简单工厂模式的进一步抽象,工厂方法模式的主要角色如下
创建抽象工厂接口
public interface AbstractFactory {
public NewsDao getInstance();
}
为不同NewsDao实现创建相对应的具体工厂
// 以生产NewsDaoMySqlImpl实例的工厂为例
public class MySqlDaoFactory implements AbstractFactory {
@Override
public NewsDao getInstance() {
return new NewsDaoMySqlImpl();
}
}
在测试方法中通过特定工厂生产相关的NewsDao实例
AbstractFactory factory = new MySqlDaoFactory();
// 改变具体工厂可创建不同产品
NewsDao dao = factory.getInstance();
优点
缺点
单一职责原则的体现,包含如下角色
实现方式总体上分为静态代理和动态代理
// 抽象主题接口 - 图片
public interface Image {
void display();
}
// 真实主题类 - 真实图片
public class RealImage implements Image {
private String filename;
public RealImage(String filename) {
this.filename = filename;
loadImageFromDisk();
}
private void loadImageFromDisk() {
System.out.println("Loading image from disk: " + filename);
}
public void display() {
System.out.println("Displaying image: " + filename);
}
}
// 代理类 - 图片代理
public class ImageProxy implements Image {
private RealImage realImage;
private String filename;
public ImageProxy(String filename) {
this.filename = filename;
}
public void display() {
if (realImage == null) {
realImage = new RealImage(filename);
}
realImage.display();
}
}
// 调用代码
public class Client {
public static void main(String[] args) {
// 创建代理对象并显示图片
Image image = new ImageProxy("example.jpg");
image.display();
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kXpBHobI-1691793219509)(./assets/image-20230804080107237.png)]
静态代理需要手工编写代理类,存在以下弊端
- 动态代理提供了运行时动态扩展对象行为的能力
- 能够依据给定的业务规则,在运行时动态生成代理类
从JDK 1.3版本开始引入
是面向接口的代理实现
核心API
如果被代理的目标对象不是通过接口进行定义的,JDK 动态代理将无法实施
需要使用继承和重写机制,CGLIB动态代理对于final类或final方法无能为力
从cglib https://github.com/cglib/cglib/releases下载所需的 jar 文件
主要 API
Redis 是开源、高性能的key-value
数据库,属于 NoSQL 数据库
NoSQL 数据库与关系型数据库
Linux 本地体验需安装 Linux 虚拟机
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d8khrxLX-1691793219510)(./assets/image-20230726080419008.png)]
Linux 安装 Redis 需学到第 15 节
【小白入门 通俗易懂】2021韩顺平 一周学会Linux
https://www.bilibili.com/video/BV1Sv411r7vd?p=15&vd_source=3b9216711765e1ac14ef21c8216ed8eb
redis https://download.redis.io/releases/
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XHir9fOg-1691793219511)(./assets/image-20230726121134846.png)]
选择需要的版本下载即可
此处默认您已会使用 VM 虚拟机运行 Linux 系统,包括 Xshell 与 Xftp
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jPqLeuAT-1691793219511)(./assets/%E6%90%9C%E7%8B%97%E6%88%AA%E5%9B%BE20230726102746.png)]
虚拟机输入
ifconfig -a
获取 Linux IP 地址
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1rXfhV9e-1691793219512)(./assets/image-20230726103135318.png)]
使用 Xftp 将 Redis 安装包上传到 Linux
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-R3Xz9RkE-1691793219512)(./assets/Snipaste_2023-07-26_11-02-56.png)]
使用 Xshell 连接 Linux 输入
ll
查看上传状态然后输入
tar -zxvf Redis 文件名
解压 Redis 压缩包Redis 文件名输入两个字母按下 Tab 键可自动补全
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6DZhfz1Q-1691793219512)(./assets/Snipaste_2023-07-26_11-03-45.png)]
输入
cd
进入到解压后的 Redis 目录
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nhfoROij-1691793219513)(./assets/Snipaste_2023-07-26_11-03-59.png)]
因为 Redis 使用 C 编写,所以需安装 GCC 依赖
输入
yum install -y gcc
这里的
-y
表示一键安装
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K8yj9UIV-1691793219513)(./assets/Snipaste_2023-07-26_11-04-23.png)]
安装完成后输入
gcc -v
校验安装再输入
make install
安装 Redis
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gcXvxShR-1691793219513)(./assets/Snipaste_2023-07-26_11-10-03.png)]
输入
cd utils
进入到utlis
目录
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hN1SwGOJ-1691793219513)(./assets/Snipaste_2023-07-26_11-11-01.png)]
输入
./install_server.sh
执行脚本
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bQAtR5KR-1691793219514)(./assets/ee43889607d8180259a4987c166d15a.png)]
这里可能会出现报错,打开脚本注释以下内容后重新执行
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Uj7sstd8-1691793219514)(./assets/%E6%90%9C%E7%8B%97%E6%88%AA%E5%9B%BE20230726111436.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-f20mG8wx-1691793219514)(./assets/Snipaste_2023-07-26_11-12-51.png)]
执行脚本可对 Redis 进行设置,无特殊需求直接回车结束即可
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5tX73YeN-1691793219515)(./assets/image-20230726121548324.png)]
Redis for Windows 5.0.14.1 https://github.com/tporadowski/redis/releases/tag/v5.0.14.1
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MuTrWCy1-1691793219515)(./assets/image-20230726090924583.png)]
Redis 7.0.11 for Windows https://github.com/zkteco-home/redis-windows/releases/tag/7.0.11
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QQ17N5Cf-1691793219515)(./assets/image-20230726093618285.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SD4jZNIB-1691793219515)(./assets/redis-1.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nTv4gIQf-1691793219515)(./assets/redis-2.png)]
选择安装路径,并勾选下方选项,将 Redis 添加到系统环境变量
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OIUy9LBp-1691793219516)(./assets/redis-3.png)]
这个是 Redis 默认的端口号,无特殊需求不用改
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xh7FUjED-1691793219516)(./assets/redis-4.png)]
设置最大内存限制,无特殊需求不用改
键盘按下 Win + R
输入 cmd
打开命令提示符,输入以下指令
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qi4igT7P-1691793219516)(./assets/%E6%90%9C%E7%8B%97%E6%88%AA%E5%9B%BE20230726091513.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-32gFADGi-1691793219516)(./assets/image-20230726091645826.png)]
RedisDesktopManager https://github.com/RedisInsight/RedisDesktopManager/releases/tag/2022.5
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tgFCxfAF-1691793219516)(./assets/%E6%90%9C%E7%8B%97%E6%88%AA%E5%9B%BE20230726182227.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Be7xOgEW-1691793219517)(./assets/af0e26cb23427e843680837320f8e93.png)]
设置内存分配策略
echo 1 > /proc/sys/vm/overcommit_memory
开放Redis端口
设置Redis配置文件redis.conf
bind 127.0.0.1 ::
- bind 0.0.0.0或使用 # 将bind指令注释掉,则可监听所有IP地址的请求
- 如果Redis服务运行于Internet上,建议仅绑定应用相关的客户端IP地址
port 6379
requirepass 123456
由于Redis的高性能特性,可以在很短的时间内并行尝试大量密码,因此应使用一个高强度的密码
daemonize yes
logfile "/usr/local/redis-3.2.8/log/redis.log"
databases 16
- Redis中不同的可选数据库以命名空间的形式管理,数据文件是同一个2. Redis划分数据库主要用于在必要的情况下分隔同一应用中存储的key(不同数据库中可以使用相同名称的key),而不是为了区分多个应用
dir /data/redisdata/
cd /usr/local/redis-3.2.8/
./bin/redis-server ./etc/redis.conf
启动Redis服务所依据的配置文件
注意daemonize指令设置为no或yes的区别
tail -F /usr/local/redis-3.2.8/log/redis.log
- daemonize为no时,可以另外开启一个会话连接至Redis服务器,并在此会话中跟踪Redis日志内容的变化2. 如果Redis的日志文件路径为默认的 logfile “”,则不会创建日志文件,daemonize为yes时,日志信息会直接输出在控制台中
执行Redis安装目录下bin目录中的redis-cli命令
redis-cli [选项]
选项 | 说明 |
---|---|
-h |
服务器主机地址,默认为127.0.0.1 |
-p |
服务端口,默认为6379 |
-a |
Redis服务访问密码 |
-n |
所要连接的数据库的id,默认为0 |
### 连接到本地Redis服务中dbid为0数据库
cd /usr/local/redis-3.2.8/
./bin/redis-cli
Windows 版 Redis 不支持 daemonize 参数
// 进入到Redis的安装目录下执行
redis-server --service-install redis.windows.conf --loglevel verbose
其他配置参数、使用方式与 Linux 版相同
auth
auth password
quit
set
set key value [ex seconds | px milliseconds] [nx | xx]
- ex:设置指定的过期时间seconds,以秒为单位
- px:设置指定的过期时间milliseconds,以毫秒为单位
- nx:仅在key不存在时设置该key(只创建、不覆盖)
- xx:仅在key已存在时设置该key(只覆盖、不创建)
get
get key
exists
exists key1 [key2 ...]
keys
keys pattern
支持的常用模式如下
h?llo
:匹配单个字符,如hello,hallo,hxllo等h*llo
:匹配任意字符,如hllo,heeeello等h[ae]llo
:包含一个指定字符,如hello或halloh[^ae]llo
:包含除指定字符外的一个字符,如hbllo,hcllo等,不包括hallo和helloh[a-c]llo
:匹配指定范围内的一个字符,如hallo,hbllo,hcllo- 如需匹配以上模式中特殊字符,需要使用
\
转义
del
del key1 [key2 ...]
rename
rename key newkey
expire
expire key timeout
ttl
ttl key
persist
persist key
select
select dbid
flushdb
flushall
Jedis 在 Java 应用中实现 Redis 客户端的功能
Jedis 的使用
public class Xz01 {
public static void main(String[] args) {
Jedis redis = new Jedis("localhost", 6379);
System.out.println(redis.ping());
}
}
先打 jar 包
<dependency>
<groupId>redis.clientsgroupId>
<artifactId>jedisartifactId>
<version>5.0.0-beta2version>
dependency>
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-pool2artifactId>
<version>2.11.1version>
dependency>
public class JedisAPI {
private static final JedisPool jedisPool;
static {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(50);
jedisPoolConfig.setMaxIdle(10);
jedisPoolConfig.setMinIdle(7);
jedisPoolConfig.setMaxWaitMillis(10000);
jedisPoolConfig.setTestOnBorrow(true);
jedisPool = new JedisPool(jedisPoolConfig, "localhost", 6379, 10000);
// ,"0207",0
}
public boolean set(String key, String value) {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
jedis.set(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
if (jedis != null) {
jedis.close();
}
}
}
public String get(String key) {
Jedis jedis = null;
String value = null;
try {
jedis = jedisPool.getResource();
value = jedis.get(key);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (jedis != null) {
jedis.close();
}
}
return value;
}
public void destroy() {
if ((jedisPool != null) || jedisPool.isClosed()) {
jedisPool.close();
}
}
public String ping() {
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
return jedis.ping();
} catch (Exception e) {
e.printStackTrace();
return "false";
} finally {
if (jedis != null) {
jedis.close();
}
}
}
}
public class Xz02 {
public static void main(String[] args) {
JedisAPI jedisAPI = new JedisAPI();
String set = jedisAPI.ping();
System.out.println(set);
jedisAPI.destroy();
}
}
玄子Share - Java 开发之框架基础技术 8.2