导图社区 JAVA
本导图根据廖雪峰网站学习总结的JAVA知识点,包含MAVEN、网络编程、java基础、XML与JSON、JDBC、javaEE。
编辑于2022-04-03 21:43:38JAVA
java基础
基本知识
版本
JAVASE
JAVAEE
JAVAME
JDK和JRE
┌─ ┌──────────────────────────────────┐ │ │ Compiler, debugger, etc. │ │ └──────────────────────────────────┘ JDK ┌─ ┌──────────────────────────────────┐ │ │ │ │ │ JRE │ JVM + Runtime Library │ │ │ │ │ └─ └─ └──────────────────────────────────┘ ┌───────┐┌───────┐┌───────┐┌───────┐ │Windows││ Linux ││ macOS ││others │ └───────┘└───────┘└───────┘└───────┘
JSR规范
设置环境变量
JAVA_HOME
PATH
运行java程序
javac
java
数据类型
基本类型
┌───┐ byte │ │ └───┘ ┌───┬───┐ short │ │ │ └───┴───┘ ┌───┬───┬───┬───┐ int │ │ │ │ │ └───┴───┴───┴───┘ ┌───┬───┬───┬───┬───┬───┬───┬───┐ long │ │ │ │ │ │ │ │ │ └───┴───┴───┴───┴───┴───┴───┴───┘ ┌───┬───┬───┬───┐ float │ │ │ │ │ └───┴───┴───┴───┘ ┌───┬───┬───┬───┬───┬───┬───┬───┐ double │ │ │ │ │ │ │ │ │ └───┴───┴───┴───┴───┴───┴───┴───┘ ┌───┬───┐ char │ │ │ └───┴───┘
整数
下划线
十六进制
二进制
long型结尾
浮点数
科学计数法
float类型
字符
转义字符'\u'
布尔
引用类型
String字符串
常量
final NAME
var关键字
运算
整数相除
只会得到结果的整数部分 除数为0时编译不报错,运行报错
整数左移
负数右移
无符号右移
位运算
与
或
非
亦或
转义字符
\" 表示字符" \' 表示字符' \\ 表示字符\ \n 表示换行符 \r 表示回车符 \t 表示Tab \u#### 表示一个Unicode编码的字符
空值null
流程控制
输入和输出
格式化输出
%d 格式化输出整数 %x 格式化输出十六进制整数 %f 格式化输出浮点数 %e 格式化输出科学计数法表示的浮点数 %s 格式化字符串 连续两个%%表示一个%字符本身。
用0位补足8位
public class Main { public static void main(String[] args) { int n = 12345000; System.out.printf("n=%d, hex=%08x", n, n); // 注意,两个%占位符必须传入两个数 } }
输入
scanner
if
switch
匹配字符串内容相等
java12
->
public class Main { public static void main(String[] args) { String fruit = "apple"; int opt = switch (fruit) { case "apple" -> 1; case "pear", "mango" -> 2; default -> 0; }; // 注意赋值语句要以;结束 System.out.println("opt = " + opt); } }
yield
public class Main { public static void main(String[] args) { String fruit = "orange"; int opt = switch (fruit) { case "apple" -> 1; case "pear", "mango" -> 2; default -> { int code = fruit.hashCode(); yield code; // switch语句返回值 } }; System.out.println("opt = " + opt); } }
for
for each
数组
List
Map
while
break
continue
数组
冒泡排序
Arrays.sort()
多维数组
Arrays.deepToString()
可变参数
class Group { private String[] names; public void setNames(String... names) { this.names = names; } }
static
静态字段
推荐用类名来访问静态字段。可以把静态字段理解为描述class本身的字段(非实例字段)。
静态方法
import
import static java.lang.System.*;
import java.lang.*
作用域
public
protected
继承
private
嵌套类
package
final
阻止继承
阻止被覆写
阻止被赋值
classpath
系统环境变量
启动JVM时设置
java -classpath .;C:\work\project1\bin;C:\shared abc.xyz.Hello java -cp .;C:\work\project1\bin;C:\shared abc.xyz.Hello
jar
jar包实际上就是一个zip格式的压缩文件,而jar包相当于目录。如果我们要执行一个jar包的class,就可以把jar包放到classpath中 java -cp ./hello.jar abc.xyz.Hello
MANIFEST.MF
java -jar hello.jar
模块
java9
jmod
编写模块
bin
build.sh
src
code
module-info.java
module hello.world { requires java.base; // 可不写,任何模块都会自动引入java.base requires java.xml; }
执行模块
javac -d bin src/module-info.java src/com/itranswarp/sample/*.java
打包jar
jar --create --file hello.jar --main-class com.itranswarp.sample.Main -C bin
将jar包转换成模块
jmod create --class-path hello.jar hello.jmod
运行模块
java --module-path hello.jar --module hello.world
打包jre
jlink --module-path hello.jmod --add-modules java.base,java.xml,hello.world --output jre/ jre/bin/java --module hello.world
访问权限
字符编码
Unicode
UTF-8
ANSI
ISO-8859-1
ASCLL
GBK
GB2312
BIG5
面向对象编程
基础
方法
构造方法
重载
抽象类
抽象方法
面向抽象编程
接口
接口继承
静态字段
public static final
default
继承
超类
父类
子类
基类
扩展类
protected
super
阻止继承
sealed
sealed类在Java 15中目前是预览状态,要启用它,必须使用参数--enable-preview和--source 15。
java15
向上转型
Person p = new Student();
向下转型
Person p1 = new Student(); // upcasting, ok Person p2 = new Person(); Student s1 = (Student) p1; // ok Student s2 = (Student) p2; // runtime error! ClassCastException!
instanceof
多态
Java的实例方法调用是基于运行时的实际类型的动态调用,而非变量的声明类型。
@Override
Object方法
toString()
equals()
equalsIgnoreCase()
hashCode()
@Overload
final
方法
类
属性
构造方法
包
包没有父子关系。java.util和java.util.zip是不同的包,两者没有任何继承关系。
内部类
Inner Class
public class Main { public static void main(String[] args) { Outer outer = new Outer("Nested"); // 实例化一个Outer Outer.Inner inner = outer.new Inner(); // 实例化一个Inner inner.hello(); } } class Outer { private String name; Outer(String name) { this.name = name; } class Inner { void hello() { System.out.println("Hello, " + Outer.this.name); } } }
Anonymous Class
public class Main { public static void main(String[] args) { Outer outer = new Outer("Nested"); outer.asyncHello(); } } class Outer { private String name; Outer(String name) { this.name = name; } void asyncHello() { Runnable r = new Runnable() { @Override public void run() { System.out.println("Hello, " + Outer.this.name); } }; new Thread(r).start(); } }
Static Nested Class
public class Main { public static void main(String[] args) { Outer.StaticNested sn = new Outer.StaticNested(); sn.hello(); } } class Outer { private static String NAME = "OUTER"; private String name; Outer(String name) { this.name = name; } static class StaticNested { void hello() { System.out.println("Hello, " + Outer.NAME); } } }
Java核心类
String字符串
转义字符'\'
多行字符串
Java13
字符串不可变
public class Main { public static void main(String[] args) { String s = "hello"; String t = s; s = "world"; System.out.println(t); // 输出hello } } public class Main { public static void main(String[] args) { String s1 = "hello"; String s2 = "HELLO".toLowerCase(); System.out.println(s1); System.out.println(s2); if (s1 == s2) { System.out.println("s1 == s2"); } else { System.out.println("s1 != s2");//输出 } } }
equals与==
equalsIgnoreCase()
indexOf
lastIndexOf()
contains()
startsWith
endsWith
substring
trim()
strip()
stripLeading()
stripTrailing
isEmpty()
isBlank()
replace()
replaceAll()
split()
join()
format()
%s
%d
%x
%f
valueOf()
parseInt()
parseBoolean()
getInteger()
char[]
toCharArray()
new String()
getBytes
byte[] b1 = "Hello".getBytes(); // 按系统默认编码转换,不推荐 byte[] b2 = "Hello".getBytes("UTF-8"); // 按UTF-8编码转换 byte[] b2 = "Hello".getBytes("GBK"); // 按GBK编码转换 byte[] b3 = "Hello".getBytes(StandardCharsets.UTF_8); // 按UTF-8编码转换
new String()
byte[] b = ... String s1 = new String(b, "GBK"); // 按GBK转换 String s2 = new String(b, StandardCharsets.UTF_8); // 按UTF-8转换
StringBuilder
append()
StringJoiner
add()
public class Main { public static void main(String[] args) { String[] names = {"Bob", "Alice", "Grace"}; var sj = new StringJoiner(", ", "Hello ", "!"); for (String name : names) { sj.add(name); } System.out.println(sj.toString()); } }
join()
包装类型
基本类型包装类
boolean java.lang.Boolean byte java.lang.Byte short java.lang.Short int java.lang.Integer long java.lang.Long float java.lang.Float double java.lang.Double char java.lang.Character
int和Integer的互相转换
Integer n = null; Integer n2 = new Integer(99); Integer n3 = Integer.valueOf(99); int n3 = n2.intValue();
Auto Boxing
不变类
equals
进制转换
public class Main { public static void main(String[] args) { System.out.println(Integer.toString(100)); // "100",表示为10进制 System.out.println(Integer.toString(100, 36)); // "2s",表示为36进制 System.out.println(Integer.toHexString(100)); // "64",表示为16进制 System.out.println(Integer.toOctalString(100)); // "144",表示为8进制 System.out.println(Integer.toBinaryString(100)); // "1100100",表示为2进制 } }
Number
// 向上转型为Number: Number num = new Integer(999); // 获取byte, int, long, float, double: byte b = num.byteValue(); int n = num.intValue(); long ln = num.longValue(); float f = num.floatValue(); double d = num.doubleValue();
处理无符号整型
public class Main { public static void main(String[] args) { byte x = -1; byte y = 127; System.out.println(Byte.toUnsignedInt(x)); // 255 System.out.println(Byte.toUnsignedInt(y)); // 127 } }
JavaBean
getter
setter
isBoolean
枚举属性
public class Main { public static void main(String[] args) throws Exception { BeanInfo info = Introspector.getBeanInfo(Person.class); for (PropertyDescriptor pd : info.getPropertyDescriptors()) { System.out.println(pd.getName()); System.out.println(" " + pd.getReadMethod()); System.out.println(" " + pd.getWriteMethod()); } } } class Person { private String name; private int 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; } }
枚举类
enum
比较
name()
ordinal()
指定int值
toString()
switch
记录类
JAVA14
record类
构造方法
of()
public record Point(int x, int y) { public static Point of() { return new Point(0, 0); } public static Point of(int x, int y) { return new Point(x, y); } }
BigInteger
pow()
add()
longValue()
longValueExact()
BigDecimal
scale()
返回负数
setScale()
public static void main(String[] args) { BigDecimal d1 = new BigDecimal("123.456789"); BigDecimal d2 = d1.setScale(4, RoundingMode.HALF_UP); // 四舍五入,123.4568 BigDecimal d3 = d1.setScale(4, RoundingMode.DOWN); // 直接截断,123.4567 System.out.println(d2); System.out.println(d3); }
stripTrailingZeros()
除数
BigDecimal d1 = new BigDecimal("123.456"); BigDecimal d2 = new BigDecimal("23.456789"); BigDecimal d3 = d1.divide(d2, 10, RoundingMode.HALF_UP); // 保留10位小数并四舍五入 BigDecimal d4 = d1.divide(d2); // 报错:ArithmeticException,因为除不尽
求除数和余数
public class Main { public static void main(String[] args) { BigDecimal n = new BigDecimal("12.345"); BigDecimal m = new BigDecimal("0.12"); BigDecimal[] dr = n.divideAndRemainder(m); System.out.println(dr[0]); // 102 System.out.println(dr[1]); // 0.105 } }
equals()
compareTo()
常用工具类
Math
abs()
max(),min()
pow()
sqrt()
exp()
log()
log10()
三角函数
Math.sin(3.14); // 0.00159... Math.cos(3.14); // -0.9999... Math.tan(3.14); // -0.0015... Math.asin(1.0); // 1.57079... Math.acos(1.0); // 0.0
数学常量
PI
E
random()
生成指定区间的随机数
// 区间在[MIN, MAX)的随机数 public class Main { public static void main(String[] args) { double x = Math.random(); // x的范围是[0,1) double min = 10; double max = 50; double y = x * (max - min) + min; // y的范围是[10,50) long n = (long) y; // n的范围是[10,50)的整数 System.out.println(y); System.out.println(n); } }
Random
Random r = new Random(); r.nextInt(); // 2071575453,每次都不一样 r.nextInt(10); // 5,生成一个[0,10)之间的int r.nextLong(); // 8811649292570369305,每次都不一样 r.nextFloat(); // 0.54335...生成一个[0,1)之间的float r.nextDouble(); // 0.3716...生成一个[0,1)之间的double
SecureRandom
public class Main { public static void main(String[] args) { SecureRandom sr = null; try { sr = SecureRandom.getInstanceStrong(); // 获取高强度安全随机数生成器 } catch (NoSuchAlgorithmException e) { sr = new SecureRandom(); // 获取普通的安全随机数生成器 } byte[] buffer = new byte[16]; sr.nextBytes(buffer); // 用安全随机数填充buffer System.out.println(Arrays.toString(buffer)); } }
异常
┌───────────┐ │ Object │ └───────────┘ ▲ │ ┌───────────┐ │ Throwable │ └───────────┘ ▲ ┌─────────┴─────────┐ │ │ ┌───────────┐ ┌───────────┐ │ Error │ │ Exception │ └───────────┘ └───────────┘ ▲ ▲ ┌───────┘ ┌────┴──────────┐ │ │ │ ┌─────────────────┐ ┌─────────────────┐┌───────────┐ │OutOfMemoryError │... │RuntimeException ││IOException│... └─────────────────┘ └─────────────────┘└───────────┘ ▲ ┌───────────┴─────────────┐ │ │ ┌─────────────────────┐ ┌─────────────────────────┐ │NullPointerException │ │IllegalArgumentException │... Exception │ ├─ RuntimeException │ │ │ ├─ NullPointerException │ │ │ ├─ IndexOutOfBoundsException │ │ │ ├─ SecurityException │ │ │ └─ IllegalArgumentException │ │ │ └─ NumberFormatException │ ├─ IOException │ │ │ ├─ UnsupportedCharsetException │ │ │ ├─ FileNotFoundException │ │ │ └─ SocketException │ ├─ ParseException │ ├─ GeneralSecurityException │ ├─ SQLException │ └─ TimeoutException
分类
ERROR
EXCEPTION
RuntimeException及其子类
非RuntimeException
不需要捕获的异常
必须捕获的异常
throw
try catch
多个catch
finally
printStackTrace()
异常的转化
public class Main { public static void main(String[] args) { try { process1(); } catch (Exception e) { e.printStackTrace(); } } static void process1() { try { process2(); } catch (NullPointerException e) { throw new IllegalArgumentException(e); } } static void process2() { throw new NullPointerException(); } }
Throwable.getCause()
异常屏蔽
Throwable.addSuppressed()
public class Main { public static void main(String[] args) throws Exception { Exception origin = null; try { System.out.println(Integer.parseInt("abc")); } catch (Exception e) { origin = e; throw e; } finally { Exception e = new IllegalArgumentException(); if (origin != null) { e.addSuppressed(origin); } throw e; } } }
自定义异常
NullPointerException
JAVA14
java -XX:+ShowCodeDetailsInExceptionMessages Main.java
Assertion
可选的断言消息
assert x >= 0 : "x must >= 0";
启用断言
java -ea Main.java
Logging
JDK Logging
级别
SEVERE
WARNING
INFO
CONFIG
FINE
FINER
FINEST
Commons Logging(日志API)
级别
FATAL
ERROR
WARNING
INFO
DEBUG
TRACE
log.error
Log4j(日志底层)
<?xml version="1.0" encoding="UTF-8"?> <Configuration> <Properties> <!-- 定义日志格式 --> <Property name="log.pattern">%d{MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36}%n%msg%n%n</Property> <!-- 定义文件名变量 --> <Property name="file.err.filename">log/err.log</Property> <Property name="file.err.pattern">log/err.%i.log.gz</Property> </Properties> <!-- 定义Appender,即目的地 --> <Appenders> <!-- 定义输出到屏幕 --> <Console name="console" target="SYSTEM_OUT"> <!-- 日志格式引用上面定义的log.pattern --> <PatternLayout pattern="${log.pattern}" /> </Console> <!-- 定义输出到文件,文件名引用上面定义的file.err.filename --> <RollingFile name="err" bufferedIO="true" fileName="${file.err.filename}" filePattern="${file.err.pattern}"> <PatternLayout pattern="${log.pattern}" /> <Policies> <!-- 根据文件大小自动切割日志 --> <SizeBasedTriggeringPolicy size="1 MB" /> </Policies> <!-- 保留最近10份 --> <DefaultRolloverStrategy max="10" /> </RollingFile> </Appenders> <Loggers> <Root level="info"> <!-- 对info级别的日志,输出到console --> <AppenderRef ref="console" level="info" /> <!-- 对error级别的日志,输出到err,即上面定义的RollingFile --> <AppenderRef ref="err" level="error" /> </Root> </Loggers> </Configuration>
SLF4J
Logback
<?xml version="1.0" encoding="UTF-8"?> <configuration> <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> </encoder> </appender> <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <encoder> <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> <charset>utf-8</charset> </encoder> <file>log/output.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy"> <fileNamePattern>log/output.log.%i</fileNamePattern> </rollingPolicy> <triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy"> <MaxFileSize>1MB</MaxFileSize> </triggeringPolicy> </appender> <root level="INFO"> <appender-ref ref="CONSOLE" /> <appender-ref ref="FILE" /> </root> </configuration>
反射
定义
如果获取了某个Class实例,我们就可以通过这个Class实例获取到该实例对应的class的所有信息。 这种通过Class实例获取class信息的方法称为反射(Reflection)。
作用
反射是为了解决在运行期,对某个实例一无所知的情况下,如何调用其方法。
获取一个class的Class实例
通过静态变量
Class cls = String.class;
实例变量的getClass()方法
String s = "Hello"; Class cls = s.getClass();
完整类名Class.forName()
Class cls = Class.forName("java.lang.String");
Class实例与instanceof的差别
用instanceof不但匹配指定类型,还匹配指定类型的子类。而用==判断class实例可以精确地判断数据类型,但不能作子类型比较。
newInstance()
// 获取String的Class实例: Class cls = String.class; // 创建一个String实例: String s = (String) cls.newInstance();
public的无参构造方法
动态加载
访问字段
getField()
getName()
getType()
getModifiers()
getDeclaredField()
getFields()
getDeclareFields()
获取字段值
Field.get(Object)
Field.setAccessible(true)
设置字段值
Field.set()
调用方法
public class Main { public static void main(String[] args) throws Exception { // String对象: String s = "Hello world"; // 获取String substring(int)方法,参数为int: Method m = String.class.getMethod("substring", int.class); // 在s对象上调用该方法并获取结果: String r = (String) m.invoke(s, 6); // 打印调用结果: System.out.println(r); } }
getMethod()
getName()
getReturnType()
getParameterTypes()
getModifiers()
getDeclaredMethod()
getMethods()
getDeclareMethods()
invoke()
调用静态方法
调用非public
Method.setAccessible(true)
多态
调用构造方法
getConstructor()
getDeclaredConstructor()
getConstructors()
getDeclaredConstructors()
获取继承关系
获取父类的class
getSuperClass()
interface
getInterfaces()
isAssignableFrom()
// Integer i = ? Integer.class.isAssignableFrom(Integer.class); // true,因为Integer可以赋值给Integer // Number n = ? Number.class.isAssignableFrom(Integer.class); // true,因为Integer可以赋值给Number // Object o = ? Object.class.isAssignableFrom(Integer.class); // true,因为Integer可以赋值给Object // Integer i = ? Integer.class.isAssignableFrom(Number.class); // false,因为Number不能赋值给Integer
动态代理
interface实例
public class Main { public static void main(String[] args) { InvocationHandler handler = new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(method); if (method.getName().equals("morning")) { System.out.println("Good morning, " + args[0]); } return null; } }; Hello hello = (Hello) Proxy.newProxyInstance( Hello.class.getClassLoader(), // 传入ClassLoader new Class[] { Hello.class }, // 传入要实现的接口 handler); // 传入处理调用方法的InvocationHandler hello.morning("Bob"); } } interface Hello { void morning(String name); }
接口方法的调用
InvocationHandler
创建interface实例
newProxyInstance()
classloader
实现的接口数组
调用的InvocationHandler实例
将Object强制转型为接口
注解
定义
注解是放在Java源码的类、方法、字段、参数前的一种特殊“注释”: 注释会被编译器直接忽略,注解则可以被编译器打包进入class文件,因此,注解是一种用作标注的“元数据”。
分类
编译器使用
工具处理.class文件使用
程序运行时可以读取
配置参数
所有基本类型
String
枚举类型
基本类型、String、Class以及枚举的数组
元注解
@Target
METHOD
FIELD
@Retention
SOURCE
CLASS
RUNTIME
@Repeatable
@Inherited
定义注解
public @interface Report { int type() default 0; String level() default "info"; String value() default ""; }
定义
添加参数
元注解配置注解
处理注解
判断注解是否存在
isAnnotationPresent()
读取注解
getAnnotation()
泛型
向上转型
泛型接口
静态泛型方法
多个泛型类型
擦拭法
无法持有基本类型
无法取得带泛型的class
不能判断带泛型类型的类型
无法实例化T类型
借助额外参数
public class Pair<T> { private T first; private T last; public Pair(Class<T> clazz) { first = clazz.newInstance(); last = clazz.newInstance(); } }
泛型继承
┌────┐ │Type│ └────┘ ▲ │ ┌────────────┬────────┴─────────┬───────────────┐ │ │ │ │ ┌─────┐┌─────────────────┐┌────────────────┐┌────────────┐ │Class││ParameterizedType││GenericArrayType││WildcardType│ └─────┘└─────────────────┘└────────────────┘└────────────┘
PECS原则
extends通配符
static int add(Pair<? extends Number> p) { Number first = p.getFirst(); Number last = p.getLast(); return first.intValue() + last.intValue(); }
限定T类型
super通配符
使用<? super Integer>通配符表示: 允许调用set(? super Integer)方法传入Integer的引用; 不允许调用get()方法获得Integer的引用。
无限定通配符
<?>
集合
List
方法
add
末尾添加元素
指定索引添加元素
remove
删除指定索引
删除某个元素
get
获取指定索引的元素
size
of
contains
equals
indexOf
转化
List——>Array
toArray()
toArray(T[])
public class Main { public static void main(String[] args) { List<Integer> list = List.of(12, 34, 56); Number[] array = list.toArray(new Number[3]); //Integer[] array = list.toArray(new Integer[list.size()]); for (Number n : array) { System.out.println(n); } } }
toArray(Integer[]::new)
Array——>List
实现类
ArrayList
LinkedList
链表
Map
map中不存在重复的key Map<String, Integer> map = new HashMap<>(10000);
实现类
HashMap
覆写equals方法
覆写hashCode方法
int hashCode() { return Objects.hash(firstName, lastName, age); }
哈希冲突
EnumMap
SortedMap
TreeMap
不用equals和hascode方法
Comparable
public class Main { public static void main(String[] args) { Map<Person, Integer> map = new TreeMap<>(new Comparator<Person>() { public int compare(Person p1, Person p2) { return p1.name.compareTo(p2.name); } }); map.put(new Person("Tom"), 1); map.put(new Person("Bob"), 2); map.put(new Person("Lily"), 3); for (Person key : map.keySet()) { System.out.println(key); } // {Person: Bob}, {Person: Lily}, {Person: Tom} System.out.println(map.get(new Person("Bob"))); // 2 } } class Person { public String name; Person(String name) { this.name = name; } public String toString() { return "{Person: " + name + "}"; } }
方法
get
put
contains
遍历
key
keySet
public class Main { public static void main(String[] args) { Map<String, Integer> map = new HashMap<>(); map.put("apple", 123); map.put("pear", 456); map.put("banana", 789); for (String key : map.keySet()) { Integer value = map.get(key); System.out.println(key + " = " + value); } } }
key,value
entrySet
public class Main { public static void main(String[] args) { Map<String, Integer> map = new HashMap<>(); map.put("apple", 123); map.put("pear", 456); map.put("banana", 789); for (Map.Entry<String, Integer> entry : map.entrySet()) { String key = entry.getKey(); Integer value = entry.getValue(); System.out.println(key + " = " + value); } } }
getKey
getValue
配置文件
本质上是从hashtable派生的
读取配置文件
#setting.properties last_open_file=/data/hello.txt auto_save_interval=60 //demo String f = "setting.properties"; Properties props = new Properties(); props.load(new java.io.FileInputStream(f)); String filepath = props.getProperty("last_open_file"); String interval = props.getProperty("auto_save_interval", "120");
创建properties实例
调用load()读取文件
利用FIleInputStream和getClass可以实现覆盖默认配置文件: 可以把默认配置文件放到classpath中,然后,根据机器的环境编写另一个配置文件,覆盖某些默认的配置。
FileInputStream
props.load(new java.io.FileInputStream(f));
getClass()
Properties props = new Properties(); props.load(getClass().getResourceAsStream("/common/setting.properties"));
getProperty()获取配置
classpath读取
Properties props = new Properties(); props.load(inputStreamFromClassPath("/default.properties")); props.load(inputStreamFromFile("./conf.properties"));
写入配置文件
Properties props = new Properties(); props.setProperty("url", "http://www.liaoxuefeng.com"); props.setProperty("language", "Java"); props.store(new FileOutputStream("C:\\conf\\setting.properties"), "这是写入的properties注释");
编码
inputstream是字节流,Reader是字符流,字符流在内存中以char类型表示,不涉及编码。
Set
方法
add
remove
contains
实现类
HashSet
覆写equals
覆写hascode
SortedSet
TreeSet
Queue
实现类
LinkedList
PriorityQueue
Comparable接口
public class Main { public static void main(String[] args) { Queue<User> q = new PriorityQueue<>(new UserComparator()); // 添加3个元素到队列: q.offer(new User("Bob", "A1")); q.offer(new User("Alice", "A2")); q.offer(new User("Boss", "V1")); System.out.println(q.poll()); // Boss/V1 System.out.println(q.poll()); // Bob/A1 System.out.println(q.poll()); // Alice/A2 System.out.println(q.poll()); // null,因为队列为空 } } class UserComparator implements Comparator<User> { public int compare(User u1, User u2) { if (u1.number.charAt(0) == u2.number.charAt(0)) { // 如果两人的号都是A开头或者都是V开头,比较号的大小: return u1.number.compareTo(u2.number); } if (u1.number.charAt(0) == 'V') { // u1的号码是V开头,优先级高: return -1; } else { return 1; } } } class User { public final String name; public final String number; public User(String name, String number) { this.name = name; this.number = number; } public String toString() { return name + "/" + number; } }
Deque接口
实现类
ArrayDeque
LinkedList
方法
First
Last
模拟stack
push
pop
peek
计算中缀表达式
编辑器将中缀表达式转化为后缀表达式
方法
size
add
offer
remove
poll
element
peek
Iterator
自定义集合实现迭代器
Iterable接口
iterator
要求返回iterator对象,即需要自定义iterator对象,该对象需要实现iterator接口
Iterator接口
hasNext
next
Collections
创建空集合
List<T> emptyList()
Map<K, V> emptyMap()
Set<T> emptySet()
创建单元素集合
List<T> singletonList(T o)
Map<K, V> singletonMap(K key, V value)
Set<T> singleton(T o)
排序
sort
洗牌
shuffle
将可变集合封装成不可变集合
public class Main { public static void main(String[] args) { List<String> mutable = new ArrayList<>(); mutable.add("apple"); mutable.add("pear"); // 变为不可变集合: List<String> immutable = Collections.unmodifiableList(mutable); // 立刻扔掉mutable的引用: mutable = null; System.out.println(immutable); } }
List<T> unmodifiableList(List<? extends T> list)
Set<T> unmodifiableSet(Set<? extends T> set)
Map<K, V> unmodifiableMap(Map<? extends K, ? extends V> m)
线程
List<T> synchronizedList(List<T> list)
Set<T> synchronizedSet(Set<T> s)
Map<K,V> synchronizedMap(Map<K,V> m)
IO
同步和异步
File对象
定义file
绝对路径
相对路径
获得路径
getPath
getAbsolutePath
getCanonicalPath
获得当前平台的系统分隔符
separator
判断存在
isFile
isDirectory
文件权限和大小
canRead()
canWrite()
canExecute()
length()
创建和删除文件
createNewFile
delete
createTempFile
deleteOnExit
创建和删除目录
mkdir
mkdirs
delete
遍历文件和目录
list
listFiles
FilenameFilter
accept
endWith
Path对象
get
toAbsolutePath
normalize
toFile
遍历
for (Path p : Paths.get("..").toAbsolutePath()) { // 可以直接遍历Path System.out.println(" " + p); }
序列化
定义
Serializable
空接口,又叫标记接口(Marker Interface)
ObjectOutputStream
public class Main { public static void main(String[] args) throws IOException { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); try (ObjectOutputStream output = new ObjectOutputStream(buffer)) { // 写入int: output.writeInt(12345); // 写入String: output.writeUTF("Hello"); // 写入Object: output.writeObject(Double.valueOf(123.456)); } System.out.println(Arrays.toString(buffer.toByteArray())); } }
ObjectInputStream
try (ObjectInputStream input = new ObjectInputStream(...)) { int n = input.readInt(); String s = input.readUTF(); Double d = (Double) input.readObject(); }
ClassNotFoundException
InvalidClassException
serialVersionUID
字节流
Filter
┌─────────────┐ │ InputStream │ └─────────────┘ ▲ ▲ ┌────────────────────┐ │ │ ┌─────────────────┐ │ FileInputStream │─┤ └─│FilterInputStream│ └────────────────────┘ │ └─────────────────┘ ┌────────────────────┐ │ ▲ ┌───────────────────┐ │ByteArrayInputStream│─┤ ├─│BufferedInputStream│ └────────────────────┘ │ │ └───────────────────┘ ┌────────────────────┐ │ │ ┌───────────────────┐ │ ServletInputStream │─┘ ├─│ DataInputStream │ └────────────────────┘ │ └───────────────────┘ │ ┌───────────────────┐ └─│CheckedInputStream │ └───────────────────┘ ┌─────────────┐ │OutputStream │ └─────────────┘ ▲ ▲ ┌─────────────────────┐ │ │ ┌──────────────────┐ │ FileOutputStream │─┤ └─│FilterOutputStream│ └─────────────────────┘ │ └──────────────────┘ ┌─────────────────────┐ │ ▲ ┌────────────────────┐ │ByteArrayOutputStream│─┤ ├─│BufferedOutputStream│ └─────────────────────┘ │ │ └────────────────────┘ ┌─────────────────────┐ │ │ ┌────────────────────┐ │ ServletOutputStream │─┘ ├─│ DataOutputStream │ └─────────────────────┘ │ └────────────────────┘ │ ┌────────────────────┐ └─│CheckedOutputStream │ └────────────────────┘
InputStream
方法
read()
close()
try(resource)自动关闭
public void readFile() throws IOException { try (InputStream input = new FileInputStream("src/readme.txt")) { int n; while ((n = input.read()) != -1) { System.out.println(n); } } // 编译器在此自动为我们写入finally并调用close() }
AutoCloseable接口
缓冲
public void readFile() throws IOException { try (InputStream input = new FileInputStream("src/readme.txt")) { // 定义1000个字节大小的缓冲区: byte[] buffer = new byte[1000]; int n; while ((n = input.read(buffer)) != -1) { // 读取到缓冲区 System.out.println("read " + n + " bytes."); } } }
int read(byte[] b)
int read(byte[] b, int off, int len)
阻塞
实现类
FileInputStream
ByteArrayInputStream
模拟InputStream
public class Main { public static void main(String[] args) throws IOException { byte[] data = { 72, 101, 108, 108, 111, 33 }; try (InputStream input = new ByteArrayInputStream(data)) { int n; while ((n = input.read()) != -1) { System.out.println((char)n); } } } }
FilterInputStream
ZipInputStream
读取zip包
try (ZipInputStream zip = new ZipInputStream(new FileInputStream(...))) { ZipEntry entry = null; while ((entry = zip.getNextEntry()) != null) { String name = entry.getName(); if (!entry.isDirectory()) { int n; while ((n = zip.read()) != -1) { ... } } } }
getNextEntry()
read()
ZipEntry
getName
isDirectory
写入zip包
try (ZipOutputStream zip = new ZipOutputStream(new FileOutputStream(...))) { File[] files = ... for (File file : files) { zip.putNextEntry(new ZipEntry(file.getName())); zip.write(getFileDataAsBytes(file)); zip.closeEntry(); } }
putNextEntry()
write()
close()
getResourceAsStream()
try (InputStream input = getClass().getResourceAsStream("/default.properties")) { if (input != null) { // TODO: } }
OutputStream
方法
write()
void write(byte[])
public void writeFile() throws IOException { try (OutputStream output = new FileOutputStream("out/readme.txt")) { output.write("Hello".getBytes("UTF-8")); // Hello } // 编译器在此自动为我们写入finally并调用close() }
close()
flush()
缓冲
阻塞
实现类
FileOutputStream
ByteArrayOutputStream
模拟OutputStream
public class Main { public static void main(String[] args) throws IOException { byte[] data; try (ByteArrayOutputStream output = new ByteArrayOutputStream()) { output.write("Hello ".getBytes("UTF-8")); output.write("world!".getBytes("UTF-8")); data = output.toByteArray(); } System.out.println(new String(data, "UTF-8")); } }
FileOutputStream
方法
println
System.out
System.err
字符流
Reader
方法
read()
子类
FileReader
public void readFile() throws IOException { // 创建一个FileReader对象: Reader reader = new FileReader("src/readme.txt"); // 字符编码是??? for (;;) { int n = reader.read(); // 反复调用read()方法,直到返回-1 if (n == -1) { break; } System.out.println((char)n); // 打印char } reader.close(); // 关闭流 }
指定编码
Reader reader = new FileReader("src/readme.txt", StandardCharsets.UTF_8);
缓冲区
public void readFile() throws IOException { try (Reader reader = new FileReader("src/readme.txt", StandardCharsets.UTF_8)) { char[] buffer = new char[1000]; int n; while ((n = reader.read(buffer)) != -1) { System.out.println("read " + n + " chars."); } } }
CharArrayReader
try (Reader reader = new CharArrayReader("Hello".toCharArray())) { }
StringReader
try (Reader reader = new StringReader("Hello")) { }
InputStreamReader
//将字节流转化为字符流 try (Reader reader = new InputStreamReader(new FileInputStream("src/readme.txt"), "UTF-8")) { // TODO: }
Writer
方法
void write(int c)
void write(char[] c)
void write(String s)
子类
FileWriter
try (Writer writer = new FileWriter("readme.txt", StandardCharsets.UTF_8)) { writer.write('H'); // 写入单个字符 writer.write("Hello".toCharArray()); // 写入char[] writer.write("Hello"); // 写入String }
CharArrayWriter
try (CharArrayWriter writer = new CharArrayWriter()) { writer.write(65); writer.write(66); writer.write(67); char[] data = writer.toCharArray(); // { 'A', 'B', 'C' } }
StringWriter
StringBuffer
PrintWriter
public class Main { public static void main(String[] args) { StringWriter buffer = new StringWriter(); try (PrintWriter pw = new PrintWriter(buffer)) { pw.println("Hello"); pw.println(12345); pw.println(true); } System.out.println(buffer.toString()); } }
OutputStreamWriter
try (Writer writer = new OutputStreamWriter(new FileOutputStream("readme.txt"), "UTF-8")) { // TODO: }
Files和Paths
方法
读取文件
readAllBytes
byte[] data = Files.readAllBytes(Paths.get("/path/to/file.txt"));
readString
// 默认使用UTF-8编码读取: String content1 = Files.readString(Paths.get("/path/to/file.txt")); // 可指定编码: String content2 = Files.readString(Paths.get("/path/to/file.txt"), StandardCharsets.ISO_8859_1);
readAllLines
// 按行读取并返回每行内容: List<String> lines = Files.readAllLines(Paths.get("/path/to/file.txt"));
写入文件
// 写入二进制文件: byte[] data = ... Files.write(Paths.get("/path/to/file.txt"), data); // 写入文本并指定编码: Files.writeString(Paths.get("/path/to/file.txt"), "文本内容...", StandardCharsets.ISO_8859_1); // 按行写入文本: List<String> lines = ... Files.write(Paths.get("/path/to/file.txt"), lines);
write
writeString
读写小文件
JavaEE
技术
JDBC
JNDI
EJB
Servlet
RMI
JSP
XML
JMS
JAVA IDL
JTS
JTA
JavaMail
JAF
框架
SSH
Structs
Spring
Hibernate
SSM
Spring
SpringMVC
MyBatis
spring
Spring Framework
模块
支持IoC和AOP的容器; 支持JDBC和ORM的数据访问模块; 支持声明式事务的模块; 支持基于Servlet的MVC开发; 支持基于Reactive的Web开发; 以及集成JMS、JavaMail、JMX、缓存等其他模块。
IoC容器(依赖注入)
作用
将组件的创建+配置与组件的使用相分离,并且,由IoC容器负责管理组件的生命周期。
注入方法
set()
public class BookService { private DataSource dataSource; public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; } }
构造方法
public class BookService { private DataSource dataSource; public BookService(DataSource dataSource) { this.dataSource = dataSource; } }
bean
装配bean
ApplicationContext
public class Main { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("application.xml"); UserService userService = context.getBean(UserService.class); User user = userService.login("bob@example.com", "password"); System.out.println(user.getName()); } }
BeanFactory
BeanFactory factory = new XmlBeanFactory(new ClassPathResource("application.xml")); MailService mailService = factory.getBean(MailService.class);
二者区别
BeanFactory的实现是按需创建,即第一次获取Bean时才创建这个Bean,而ApplicationContext会一次性创建所有的Bean
方式
xml
读取xml文件后使用反射完成的 <beans> <bean id="dataSource" class="HikariDataSource" /> <bean id="bookService" class="BookService"> <property name="dataSource" ref="dataSource" /> </bean> <bean id="userService" class="UserService"> <property name="dataSource" ref="dataSource" /> </bean> </beans>
注入bean
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="userService" class="com.itranswarp.learnjava.service.UserService"> <property name="mailService" ref="mailService" /> </bean> <bean id="mailService" class="com.itranswarp.learnjava.service.MailService" /> </beans>
注入数据类型
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource"> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test" /> <property name="username" value="root" /> <property name="password" value="password" /> <property name="maximumPoolSize" value="10" /> <property name="autoCommit" value="true" /> </bean>
Annotation
@Component
@Autowired
@Configuration
@ComponentScan
定制bean
scope
我们每次调用getBean(Class),容器都返回一个新的实例,这种Bean称为Prototype(原型),它的生命周期显然和Singleton不同。声明一个Prototype的Bean时,需要添加一个额外的@Scope注解 @Component @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) // @Scope("prototype") public class MailSession { ... }
注入列表
@Order(1)
可选注入
@Autowired(required = false)
创建第三方类
Spring对标记为@Bean的方法只调用一次,因此返回的Bean仍然是单例。
初始化和销毁
@PostConstruct
调用构造方法创建MailService实例; 根据@Autowired进行注入; 调用标记有@PostConstruct的init()方法进行初始化。
@PreDestroy
指定别名
@Bean("name")
@Bean+@Qualifier("name")
@Primary
注入
@Autowired(required = false) @Qualifier("z") // 指定注入名称为"z"的ZoneId
工厂模式
@Component public class ZoneIdFactoryBean implements FactoryBean<ZoneId> { String zone = "Z"; @Override public ZoneId getObject() throws Exception { return ZoneId.of(zone); } @Override public Class<?> getObjectType() { return ZoneId.class; } }
getObject()
getObjectType()
Resource
@Value
@Component public class AppService { @Value("classpath:/logo.txt") private Resource resource; private String logo; @PostConstruct public void init() throws IOException { try (var reader = new BufferedReader( new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8))) { this.logo = reader.lines().collect(Collectors.joining("\n")); } } }
注入配置
方式
properties
@PropertySource("app.properties")
@Value("${app.zone:Z}")
"${app.zone}"表示读取key为app.zone的value,如果key不存在,启动将报错; "${app.zone:Z}"表示读取key为app.zone的value,但如果key不存在,就使用默认值Z。
javaBean持配置
JavaBean
@Component public class SmtpConfig { @Value("${smtp.host}") private String host; @Value("${smtp.port:25}") private int port; public String getHost() { return host; } public int getPort() { return port; } }
配置注入
@Component public class MailService { @Value("#{smtpConfig.host}") private String smtpHost; @Value("#{smtpConfig.port}") private int smtpPort; }
条件装配
@Profile
@Conditional
@Conditional(OnSmtpEnvCondition.class)
@ConditionalOnProperty(name="app.smtp", havingValue="true")
@ConditionalOnClass(name = "javax.mail.Transport")
AOP
访问数据库
JDBC
Spring Boot
Spring Cloud
JDBC
MySQL
安装配置
my.ini
[client] port=3306 default-character-set=utf8 [mysqld] basedir=D:\development\mysql-5.7.36-winx64\ datadir=D:\development\mysql-5.7.36-winx64\data\ port=3306 #最大连接数 max_connections=200 #编码 character-set-server=utf8 default-storage-engine=INNODB sql_mode=NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES [mysql] #编码 default-character-set=utf8
环境变量
管理员身份运行命令行
mysqld -install
mysqld --initialize
net start mysql
设置MySQL密码
net stop mysql
skip-grant-tables
net start mysql
mysql -u root -p
use mysql
update user set authentication_string=password("xxxxxx") where user="root";
手动停止MySQL服务
删除skip-grant-tables
net start mysql
mysql -u root -p
alter user user() identified by "xxxxxx";
检查编码
mysql> show variables like '%char%'; +--------------------------+--------------------------------------------------------+ | Variable_name | Value | +--------------------------+--------------------------------------------------------+ | character_set_client | utf8 | | character_set_connection | utf8 | | character_set_database | utf8 | | character_set_filesystem | binary | | character_set_results | utf8 | | character_set_server | utf8 | | character_set_system | utf8 | | character_sets_dir | /usr/local/mysql-5.1.65-osx10.6-x86_64/share/charsets/ | +--------------------------+--------------------------------------------------------+ 8 rows in set (0.00 sec)
JDBC驱动
结构图
┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ │ ┌───────────────┐ │ │ Java App │ │ └───────────────┘ │ │ │ ▼ │ ┌───────────────┐ │ │JDBC Interface │<─┼─── JDK └───────────────┘ │ │ │ ▼ │ ┌───────────────┐ │ │ JDBC Driver │<───── Vendor │ └───────────────┘ │ │ └ ─ ─ ─ ─ ─│─ ─ ─ ─ ─ ┘ ▼ ┌───────────────┐ │ Database │ └───────────────┘
添加maven依赖
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> <scope>runtime</scope> </dependency>
数据类型

JDBC连接
Connection
URL
mysql
jdbc:mysql://<hostname>:<port>/<db>?key1=value1&key2=value2 jdbc:mysql://localhost:3306/learnjdbc?useSSL=false&characterEncoding=utf8
用户名
口令
获得连接
// JDBC连接的URL, 不同数据库有不同的格式: String JDBC_URL = "jdbc:mysql://localhost:3306/test"; String JDBC_USER = "root"; String JDBC_PASSWORD = "password"; // 获取连接: Connection conn = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD); // TODO: 访问数据库... // 关闭连接: conn.close();
Connection
close
DriverManager
getConnection
CRUD
SQL注入
PreparedStatement
User login(String name, String pass) { ... String sql = "SELECT * FROM user WHERE login=? AND pass=?"; PreparedStatement ps = conn.prepareStatement(sql); ps.setObject(1, name); ps.setObject(2, pass); ... }
setObject
JDBC查询
try (Connection conn = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD)) { try (Statement stmt = conn.createStatement()) { try (ResultSet rs = stmt.executeQuery("SELECT id, grade, name, gender FROM students WHERE gender=1")) { while (rs.next()) { long id = rs.getLong(1); // 注意:索引从1开始 long grade = rs.getLong(2); String name = rs.getString(3); int gender = rs.getInt(4); } } } }
Connection
createStatement
Statement
executeQuery
ResultSet
getInt
getString
getLong
JDBC插入
try (Connection conn = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD)) { try (PreparedStatement ps = conn.prepareStatement( "INSERT INTO students (id, grade, name, gender) VALUES (?,?,?,?)")) { ps.setObject(1, 999); // 注意:索引从1开始 ps.setObject(2, 1); // grade ps.setObject(3, "Bob"); // name ps.setObject(4, "M"); // gender int n = ps.executeUpdate(); // 1 } }
获取自增主键
Statement.RETURN_GENERATED_KEYS
getGeneratedKeys
JDBC更新
try (Connection conn = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD)) { try (PreparedStatement ps = conn.prepareStatement("UPDATE students SET name=? WHERE id=?")) { ps.setObject(1, "Bob"); // 注意:索引从1开始 ps.setObject(2, 999); int n = ps.executeUpdate(); // 返回更新的行数 } }
JDBC删除
try (Connection conn = DriverManager.getConnection(JDBC_URL, JDBC_USER, JDBC_PASSWORD)) { try (PreparedStatement ps = conn.prepareStatement("DELETE FROM students WHERE id=?")) { ps.setObject(1, 999); // 注意:索引从1开始 int n = ps.executeUpdate(); // 删除的行数 } }
JDBC事务
ACID特性
原子性
一致性
隔离性
Read Uncommitted
Read Committed
Repeatable Read
Serilizable
持久性
Connection
setTransactionIsolation
REPEATABLE READ
MYSQL默认隔离级别
setAutoCommit
true
false
commit
rollback
close
JDBC Batch
try (PreparedStatement ps = conn.prepareStatement("INSERT INTO students (name, gender, grade, score) VALUES (?, ?, ?, ?)")) { // 对同一个PreparedStatement反复设置参数并调用addBatch(): for (Student s : students) { ps.setString(1, s.name); ps.setBoolean(2, s.gender); ps.setInt(3, s.grade); ps.setInt(4, s.score); ps.addBatch(); // 添加到batch } // 执行batch: int[] ns = ps.executeBatch(); for (int n : ns) { System.out.println(n + " inserted."); // batch中每个SQL执行的结果数量 } }
addBatch
excuteBatch
JDBC 连接池
连接池的实现
HikariCP
依赖
<dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> <version>2.7.1</version> </dependency>
DataSource
创建DataSource实例
HikariConfig config = new HikariConfig(); config.setJdbcUrl("jdbc:mysql://localhost:3306/test"); config.setUsername("root"); config.setPassword("password"); config.addDataSourceProperty("connectionTimeout", "1000"); // 连接超时:1秒 config.addDataSourceProperty("idleTimeout", "60000"); // 空闲超时:60秒 config.addDataSourceProperty("maximumPoolSize", "10"); // 最大连接数:10 DataSource ds = new HikariDataSource(config);
getConnection
C3P0
BoneCP
Druid
XML与JSON
XML
结构
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE note SYSTEM "book.dtd"> <book id="1"> <name>Java核心技术</name> <author>Cay S. Horstmann</author> <isbn lang="CN">1234567</isbn> <tags> <tag>Java</tag> <tag>Network</tag> </tags> <pubDate/> </book>
转义

支持技术
DTD和XSD
Namespace
XSLT
XPath
解析API
DOM
InputStream input = Main.class.getResourceAsStream("/book.xml"); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.parse(input);
DocumentBuilderFactory
newInstance
newDocumentBuilder
DocumentBuilder
parse
接收InputStream,File或者URL
Document
遍历
void printNode(Node n, int indent) { for (int i = 0; i < indent; i++) { System.out.print(' '); } switch (n.getNodeType()) { case Node.DOCUMENT_NODE: // Document节点 System.out.println("Document: " + n.getNodeName()); break; case Node.ELEMENT_NODE: // 元素节点 System.out.println("Element: " + n.getNodeName()); break; case Node.TEXT_NODE: // 文本 System.out.println("Text: " + n.getNodeName() + " = " + n.getNodeValue()); break; case Node.ATTRIBUTE_NODE: // 属性 System.out.println("Attr: " + n.getNodeName() + " = " + n.getNodeValue()); break; default: // 其他 System.out.println("NodeType: " + n.getNodeType() + ", NodeName: " + n.getNodeName()); } for (Node child = n.getFirstChild(); child != null; child = child.getNextSibling()) { printNode(child, indent + 1); } }
SAX
InputStream input = Main.class.getResourceAsStream("/book.xml"); SAXParserFactory spf = SAXParserFactory.newInstance(); SAXParser saxParser = spf.newSAXParser(); saxParser.parse(input, new MyHandler());
SAXParserFactory
newInstance
newSAXParser
SAXParser
DafaultHandler
class MyHandler extends DefaultHandler { public void startDocument() throws SAXException { print("start document"); } public void endDocument() throws SAXException { print("end document"); } public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { print("start element:", localName, qName); } public void endElement(String uri, String localName, String qName) throws SAXException { print("end element:", localName, qName); } public void characters(char[] ch, int start, int length) throws SAXException { print("characters:", new String(ch, start, length)); } public void error(SAXParseException e) throws SAXException { print("error:", e); } void print(Object... objs) { for (Object obj : objs) { System.out.print(obj); System.out.print(" "); } System.out.println(); } }
Jackson
maven依赖
com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.10.1 org.codehaus.woodstox:woodstox-core-asl:4.4.1
JacksonXmlModule
XmlMapper
readValue
Book(自定以JavaBean)
JSON
优点
UTF-8编码
双引号为key,\转义
浏览器内置JSON支持
层次结构
键值对
数组
字符串
数值
布尔值
空值
解析
Jackson
InputStream input = Main.class.getResourceAsStream("/book.json"); ObjectMapper mapper = new ObjectMapper(); // 反序列化时忽略不存在的JavaBean属性: mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); Book book = mapper.readValue(input, Book.class); String json = mapper.writeValueAsString(book);
maven依赖
com.fasterxml.jackson.core:jackson-databind:2.12.0
ObjectMapper
configure
readValue
writeValueAsString
解析为特定的Java对象
maven依赖
com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.12.0
JavaTimeModule()
ObjectMapper mapper = new ObjectMapper().registerModule(new JavaTimeModule());
自定义解析
JsonDeserializer
public class IsbnDeserializer extends JsonDeserializer<BigInteger> { public BigInteger deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { // 读取原始的JSON字符串内容: String s = p.getValueAsString(); if (s != null) { try { return new BigInteger(s.replace("-", "")); } catch (NumberFormatException e) { throw new JsonParseException(p, s, e); } } return null; } }
注解
public class Book { public String name; // 表示反序列化isbn时使用自定义的IsbnDeserializer: @JsonDeserialize(using = IsbnDeserializer.class) public BigInteger isbn; }
反序列化
网络编程
IP地址
IPV4
IPV6
公网IP地址
内网IP地址
127.0.0.1
网关
路由
域名
nslookup
localhost
网卡
配置
IPV4地址
IPV4子网掩码
IPV4默认网关
OSI网络模型
应用层
表示层
会话层
传输层
网络层
链路层
物理层
TCP/IP模型
常用协议
IP协议
分组交换
TCP协议
面向连接
可靠传输
UDP协议
无连接
不可靠传输
socket
IP地址
端口号
0~65535 特权端口:1024以下 普通端口:1024以上
TCP编程
服务器端
步骤
指定端口监听
返回socket实例
多线程
ServerSocket
accept
Socket
getRemoteSocketAddress
客户端
步骤
连接服务器端并指定接口
socket流
flush
Socket
getInputStream
getOutputStream
UDP编程
服务器端
DatagramSocket
receive
send
DatagramPacket
getData
getOffset
getLength
setData
客户端
DatagramSocket
setSoTimeout
connect
send
receive
disconnect
DatagramPacket
getData
getOffset
getLength
MUA
MTA
MDA
POP3协议
IMAP协议
发送Email
准备SMTP登录信息
MTA邮件服务器地址和端口号
用户名
登录口令
导入依赖
<dependency> <groupId>javax.mail</groupId> <artifactId>javax.mail-api</artifactId> <version>1.6.2</version> </dependency> <dependency> <groupId>com.sun.mail</groupId> <artifactId>javax.mail</artifactId> <version>1.6.2</version> </dependency>
JavaMail API连接到SMTP服务器
// 服务器地址: String smtp = "smtp.office365.com"; // 登录用户名: String username = "jxsmtp101@outlook.com"; // 登录口令: String password = "********"; // 连接到SMTP服务器587端口: Properties props = new Properties(); props.put("mail.smtp.host", smtp); // SMTP主机名 props.put("mail.smtp.port", "587"); // 主机端口号 props.put("mail.smtp.auth", "true"); // 是否需要用户认证 props.put("mail.smtp.starttls.enable", "true"); // 启用TLS加密 // 获取Session实例: Session session = Session.getInstance(props, new Authenticator() { protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(username, password); } }); // 设置debug模式便于调试: session.setDebug(true);
发送邮件
MimeMessage
setFrom
setRecipient
setSubject
setText
Transport
send
发送html邮件
setTerxt
发送附件
Multipart multipart = new MimeMultipart(); // 添加text: BodyPart textpart = new MimeBodyPart(); textpart.setContent(body, "text/html;charset=utf-8"); multipart.addBodyPart(textpart); // 添加image: BodyPart imagepart = new MimeBodyPart(); imagepart.setFileName(fileName); imagepart.setDataHandler(new DataHandler(new ByteArrayDataSource(input, "application/octet-stream"))); multipart.addBodyPart(imagepart); // 设置邮件内容为multipart: message.setContent(multipart);
Multipart
addBodyPart
BodyPart
setContent
添加纯文本
添加html文本
附件
setFileName
setDataHandler
发送内嵌图片的html邮件
setHeader
Multipart multipart = new MimeMultipart(); // 添加text: BodyPart textpart = new MimeBodyPart(); textpart.setContent("<h1>Hello</h1><p><img src=\"cid:img01\"></p>", "text/html;charset=utf-8"); multipart.addBodyPart(textpart); // 添加image: BodyPart imagepart = new MimeBodyPart(); imagepart.setFileName(fileName); imagepart.setDataHandler(new DataHandler(new ByteArrayDataSource(input, "image/jpeg"))); // 与HTML的<img src="cid:img01">关联: imagepart.setHeader("Content-ID", "<img01>"); multipart.addBodyPart(imagepart);
常见问题
535登陆失败
554拒绝发送错误
554被识别为垃圾邮件
接受Email
准备登录信息
启动SSL
连接到Store
获取收件箱
获取Message对象
递归解析获取邮件正文
关闭Folder和Store
HTTP编程
HTTP请求
HTTP Header
Host
User-Agent
Accept
Accept-Language
HTTP Body
GET请求
Header
POST请求
Header
Body
Content-Type
Content-Length
HTTP响应
响应代码: 1xx:表示一个提示性响应,例如101表示将切换协议,常见于WebSocket连接; 2xx:表示一个成功的响应,例如200表示成功,206表示只发送了部分内容; 3xx:表示一个重定向的响应,例如301表示永久重定向,303表示客户端应该按指定路径重新发送请求; 4xx:表示一个因为客户端问题导致的错误响应,例如400表示因为Content-Type等各种原因导致的无效请求,404表示指定的路径不存在; 5xx:表示一个因为服务器问题导致的错误响应,例如500表示服务器内部故障,503表示服务器暂时无法响应。
编程
HttpClient
JAVA11
newBuilder
send
HttpRequest
newBuilder
header
timeout
version
POST
build
HttpReponse
BodyHandlers
ofString
ofByteArray
ofInputStream
body
RMI远程调用
┌ ─ ─ ─ ─ ─ ─ ─ ─ ┐ ┌ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┐ ┌─────────────┐ ┌─────────────┐ │ │ Service │ │ │ │ Service │ │ └─────────────┘ └─────────────┘ │ ▲ │ │ ▲ │ │ │ │ │ │ │ │ │ ┌─────────────┐ Network ┌───────────────┐ ┌─────────────┐ │ │ Client Stub ├─┼─────────┼>│Server Skeleton│──>│Service Impl │ │ └─────────────┘ └───────────────┘ └─────────────┘ └ ─ ─ ─ ─ ─ ─ ─ ─ ┘ └ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ┘
服务器端(skeleton)
WorldClock
UnicastRemoteObject.exportObject(worldClock, 0
Registry
rebind
LocateRegistry
createRegistry
客户端(stub)
WorldClock
Registry
lookup
LocateRegistry
getRegistry
LocalDateTime
MAVEN
构成
groupId
artifactId
version
依赖管理
依赖关系
compile
test
junit
runtime
mysql
provided
唯一ID
MAVEN镜像仓库
<settings> <mirrors> <mirror> <id>aliyun</id> <name>aliyun</name> <mirrorOf>central</mirrorOf> <!-- 国内推荐阿里云的Maven镜像 --> <url>https://maven.aliyun.com/repository/central</url> </mirror> </mirrors> </settings>
搜索第三方组件
search.maven.org
编译jar包
mvn clean package
构建流程
lifecycle
phase
常用phase
clean
compile
test
package
goal
自定义插件
<project> ... <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.2.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> ... </configuration> </execution> </executions> </plugin> </plugins> </build> </project>
插件配置
<configuration> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>com.itranswarp.learnjava.Main</mainClass> </transformer> </transformers> </configuration>
模块管理
模块继承
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.itranswarp.learnjava</groupId> <artifactId>parent</artifactId> <version>1.0</version> <relativePath>../parent/pom.xml</relativePath> </parent> <artifactId>module-a</artifactId> <packaging>jar</packaging> <name>module-a</name> </project>
模块依赖
<dependencies> <dependency> <groupId>com.itranswarp.learnjava</groupId> <artifactId>module-b</artifactId> <version>1.0</version> </dependency> </dependencies>
仓库
中央仓库
私有仓库
本地仓库
mvnw
安装
mvn -N io.takari:maven:0.7.6:wrapper -Dmaven=3.3.3
发布artifact
以静态文件发布
创建maven工程目录
how-to-become-rich ├── maven-repo <-- Maven本地文件仓库 ├── pom.xml <-- 项目文件 ├── src │ ├── main │ │ ├── java <-- 源码目录 │ │ └── resources <-- 资源目录 │ └── test │ ├── java <-- 测试源码目录 │ └── resources <-- 测试资源目录 └── target <-- 编译输出目录
pom
<project ...> ... <distributionManagement> <repository> <id>local-repo-release</id> <name>GitHub Release</name> <url>file://${project.basedir}/maven-repo</url> </repository> </distributionManagement> <build> <plugins> <plugin> <artifactId>maven-source-plugin</artifactId> <executions> <execution> <id>attach-sources</id> <phase>package</phase> <goals> <goal>jar-no-fork</goal> </goals> </execution> </executions> </plugin> <plugin> <artifactId>maven-javadoc-plugin</artifactId> <executions> <execution> <id>attach-javadocs</id> <phase>package</phase> <goals> <goal>jar</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
mvn clean package deploy
推到github
使用
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>example</groupId> <artifactId>how-to-become-rich-usage</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> <java.version>11</java.version> </properties> <repositories> <repository> <id>github-rich-repo</id> <name>The Maven Repository on Github</name> <url>https://michaelliao.github.io/how-to-become-rich/maven-repo/</url> </repository> </repositories> <dependencies> <dependency> <groupId>com.itranswarp.rich</groupId> <artifactId>how-to-become-rich</artifactId> <version>1.0.0</version> </dependency> </dependencies> </project>
以Nexus发布到仓库
注册账号
central.sonatype.org 1. 在Publish Your Project下方点击“Learn how »” 2. 找到Provide project details,点击Provide 3. 在Error页面点击“sign up”注册
正确创建GPG签名
setting.xml
用户名
口令
GPG口令
添加OSS的Maven repo地址
mvn clean package deploy
发布到私有仓库