Java

Java 版本

JavaSE:标准版,桌面应用。
JavaEE:企业版。
JavaME:微系统版,嵌入式。

JDK

解压缩JDK,配置环境变量。

1
2
3
4
5
JAVA_HOME=/path/to/jdk
# jdk 1.6 之后不需要 CLASSPATH
CLASSPATH=.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;
# 更新PATH
PATH=PATH;%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;

主函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Main {
// 可变参数
public static void sum(int... x){
int r=0;
for(int i=0; i<x.length; ++i){
r+=x[i];
}
return r;
}

public static void main(String[] args) {
System.out.println("Hello");
}
}

说明注释

说明注释,以 /** 开始,以 */结束。

1
2
3
4
5
6
7
8
9
10
@author  标识一个类的作者
{@inheritDoc} 从直接父类继承的注释
@version 指定类的版本

@param 说明一个方法的参数
@return 说明返回值类型
@serial 说明一个序列化属性
@exception 标志一个类抛出的异常
@throws@exception标签一样
{@value} 显示常量的值,该常量必须是static属性。

数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 声明
int arr[];
int[] arr;
// 分配空间
int[] arr = new int[4];
int[] arr = new int[] {1, 2, 3, 4};

int[][] arr = new int[32][32];
int[][] arr = new int[32][];
int[][] arr = new int[][]{
{1, 2},
{3, 4}
};

// 使用
arr.length;

// 异常
ArrayIndexOutOfBoundsException // 数组越界
NullPointerException // 空指针

集合

List

1
2
LinkedList
ArrayList
1
2
3
4
5
6
7
8
9
add(e)
add(index, e)
remove(index)
remove(e)
get(index)
size()
toArray()

List list = Arrays.asList() // 只读

Map

1
2
3
HashMap
SortedMap #
TreeMap
1
2
3
4
5
put(k, v)
get(k)
containsKey(k)
keySet() // for(String key: map.keySet())
entrySet() // for(Map.Entry<String, Object> key: map.entrySet())

setting.properties 配置文件,不支持中文

1
2
3
4
Properties props = new Properties();
props.load(new FileInputStream(filepath));
// props.load(getClass().getResourceAsStream("/..."));
String url = props.getProperties("url", "default url");

Set

1
2
3
HashSet
SortedSet #
TreeSet
1
2
3
4
add(e)
remove(e)
contains(e)
size()

自定义排序非法

1
2
3
4
5
6
TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
return s1 > s2;
}
});

Queue

1
2
Queue
Priority
1
2
3
4
5
6
7
8
9
10
size()
isEmpty()
// 抛出异常
add()
remove()
element()
// 返回null或false
offer()
poll()
peek()

Deque

底层

1
2
LinkedList
ArrayList
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
size()
isEmpty()
// 抛出异常
addLast()
addFirst()
removeFirst()
removeLast()
elementFirst()
elementLast()
// 返回null或false
offerLast()
offerFirst()
pollFirst()
pollLast()
peekFirst()
peekLast()

Stack

不要使用遗留类Stack,而是使用Deque实现Stack

1
2
3
4
push()
peek()
pop()
isEmpty()

Iterator

1
2
3
list.iterator()
hasNext()
next()

Collections

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
boolean addAll(Collection<? super T> c, T... elements)
emptyList()
emptyMap()
emptySet()
singleton()
singletonList()
singletonMap()
sort(list)
sort(list, Comparator<> c)
shuffle(); // 打乱顺序
unmodifiableList()
unmodifiableSet()
unmodifiableMap()
// 不推荐使用
synchronizedList()
synchronizedSet()
synchronizedMap()

类和对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Animal {
private int age;

/**
* 获取年龄
* @return age
*/
public int getAge() {
return age;
}
}

public class Main {
public static void main(String[] args){
Animal a = new Animal();
new Animal().getAge();
}
}

自定义包,包名要与路径名一样。

1
2
3
4
5
6
package base.animal;

import Animal;

// ./base/animal/Cat.java
public class Cat{}
1
2
3
4
5
6
7
8
import java.lang;  // String System Math ...
import java.net; // 网络
import java.io; // 输入输出
import java.util; // 实用工具,日期相关
import java.text; // 格式化
import java.sql; // dbc相关
import java.awt; // 抽象窗口程序集
import java.applet;// applet相关

修饰符

1
2
3
4
5
static
final
synchronized
abstract
native

JavaBean

一种可重用组件:

  • public 属性
  • 有一个公共的无参构造器
  • 有属性,有 get set 方法

实例化过程

  1. 方法区:
  • 加载类
  1. 栈区:
  • 申请变量空间
  1. 堆区:
  • 开辟堆空间
  • 属性默认初始化
  • 成员变量显示初始化
  1. 栈区:
  • 调用构造函数初始化
  • 堆地址赋值给引用变量
  • 构造函数出栈

多态

方法的重载和重写。

对象的多态性:子类对父类覆盖,包括抽象类,接口。

编译时的(声明的)类型与运行时的(存储的)类型不一致,就出现多态。

1
2
3
// 动态绑定
Person p = new Student();
p.getInfo(); // 调用Student的方法

查看类型:

1
2
3
Person p = new Student();
p instanceof Person; // True 否则编译错误
p instanceof Student; // True 否则编译错误

Object

主要方法:

  • equals
  • hashCode
  • toString

==只有指向同一对象,类型匹配时才为True。

equals比较是否指向同一个对象,但是在File,Date,String以及包装类(Integer,Float之类)这些,是比较对象的内容,而不考虑是否是同一个对象。

包装类

JDK 1.5后支持自动拆箱,装箱。

装箱:

1
Integer i = new Integer(10);

拆箱:

1
int x = i.intValue();

初始化块

程序初始化顺序:

  1. 声明成员变量,默认初始化。
  2. 显式初始化,执行初始化块。
  3. 调用构造器,初始化变量。

静态初始化代码块优先于非静态代码块。

1
2
3
4
5
6
7
8
9
public class Test {
{
System.out.println("");
}

static {
System.out.println("");
}
}

Logger

1
2
3
4
Logger logger = Logger.getGlobal();
logger.info();
logger.log(Level.WARNING, "");
logger.warning();

级别

1
2
3
4
5
6
7
SEVERE
WARNING
INFO // Default
CONFIG
FINE
FINER
FINEST

配置文件需要通过启动参数传递。

commons logging 是 Apache 创建的日志模块,可以自动挂载Log4j或JDK Logging。

1
2
3
Log log = LogFactory.getLog(Main.class);
log.info();
log.warn();

级别

1
2
3
4
5
6
FATAL
ERROR
WARNING
INFO // Default
DEBUG
TRACE

LOG4J 分为 1x 2x

  • 可以将日志输出到Console,File,Socket。
  • 可以使用Layout格式化输出
  • 使用Filter过滤要输出的内容

配置文件 - 需设置 log4j.xml

泛型

1
2
3
4
5
6
7
class Pair<T> {
public Pair(Class<T> clazz){
T c = clazz.newInstance();
}
}
<? extends Number>
<? super Number>

注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// 内置注解
// 重写
@Override
// 弃用
@Deprecated
// 镇压警告
@SuppressWarnings("all")

// 元注解
// 可以用的范围 类,方法
@Target
// 何时使用注解 Runtime
@Retention
// 是否包含在文档
@Documented
// 表示可以继承父类注解
@Inherited

// 示例
@Inherited
@Documented
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.TYPE})
public @interface MyAnno {
String name() default "";
int age() default 0;
String[] phones;
String value(); // 只有value可以省略
}

反射

Class 类,是反射的核心类。创建一个类,内存中就对应生成一个Class对象,结构也会存在Class对象中。

功能:

  • 对象所属类
  • 访问对象的所有属性和方法
  • 处理注解
  • 对性能有影响
1
2
3
4
5
6
7
8
9
10
11
12
// 获取类型
Class c = Class.forName("java.lang.String");
getAnnotation();
getMethod();
newInstance();
getName();
getSuperClass();
getInterfaces();
getClassLoader();
getConstructors();
getMethod(String name, Class ...);
getDeclaredFields();

获取Class对象的方法。

1
2
3
4
5
Class c = Class.forName("java.lang.String");
Class c = Student.class;
Class c = student.getClass();
Class c = Integer.TYPE; // 内置类型特有
// Class Loader 方法

可以创建Class对象的类型:

  • 接口
  • 数组
  • 枚举
  • 注解
  • void
  • 基本数据类型

程序 类加载过程:

  1. class文件加载到内存,并同时生成对应的Class对象
  2. 链接,初始化为 0
  3. 执行<clinit>(),合并所有的类内静态代码块,并执行。

类加载器:

  • 引导类加载器:JVM自带的类加载器,用于装载核心类,无法直接获取。 jre/lib/rt.jar
  • 扩展类加载器:jre/lib/ext
  • 系统类加载器:java.class.path CLASS_PATH下的包,最常用
1
2
3
4
5
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
systemClassLoader.getParent(); // 扩展类加载器
systemClassLoader.getParent().getParent(); // 根加载器 返回 null 因为是由 C/C++ 编写

ClassLoader loader = Class.forName("java.lang.String").getClassLoader();

使用Class对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
Class c = Class.forName("java.lang.String");
// 名称
c.getName(); // packagename.classname
c.getSimpleName(); // classname
// 属性
Field[] fields = c.getFields(); // public
Field field = c.getField("name");
Field[] fields = c.getDeclaredFields(); // private
Field field = c.getDeclaredField("name");
// 方法
Method[] methods = c.getMethods(); // public + object.public
Method method = c.getMethod("getName", null); // null 表示 参数
Method[] methods = c.getDeclaredMethods(); // private 只有本类的
Method method = c.getDeclaredMethod("setName", String.class);


// 构造对象
String str = (String)c.newInstance(); // Object = String
// 调用方法
method.invoke(str, "123");
field.setAccessible(true); // 关闭 private 权限检测,也可以提高效率
field.set(str, "321");
// 操作泛型
Typep[] genInfos = method.getGenericParameterTypes(); // 获取泛型参数信息
for(Type info: genInfos){
if(info instanceof ParameterizedType){
Type[] subInfos = ((ParameterizedType)info).getActualTypeArguments();
}
}


// 操作注解
// c -> Class 对象 String
Annotation[] annotations = c.getAnnotations(); // 获取 String 的注解
Annotation annotation = c.getAnnotation(SuppressWarnings.class);
SuppressWarnings swanno = (SuppressWarnings)annotation;
Field field = c.getDeclaredField("name");
SuppressWarnings fsw = (SuppressWarnings)c.getAnnotation(SuppressWarnings.class);
// 获取注解的 value
swanno.value();
fsw.type();

Lambda

直接使用方法引用:

1
2
3
Arrays.sort(array, SortedBy::ignoreCase); // 静态方法
Arrays.sort(array, SortedBy::compareTo); // 实例方法
Arrays.sort(array, SortedBy::new); // 构造方法

单元测试

1
2
3
4
5
6
public class Test {
@Test
public void testFun() {
assertEquals(3, 1+2);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
@Before
@After
@BeforeClass
@AfterClass
// 异常测试
@Test(expected=Exception.class)
// 参数化测试
@Parameters
public static Collection<?> data() {return ...}
@RunWith
// 超时
@Test(timeout=1000)

编码与加密

编码

1
2
3
4
5
6
7
8
// URL
URLEncoder.encode("123", "UTF-8");
URLEncoder.decode("%E5%8F", "UTF-8");
// BASE 64
Base64.getEncoder().encodeToString("123".getBytes("UTF-8"));
Base64.getDecoder().decode(b64, "UTF-8");
Base64.getUrlEncoder().encodeToString("123".getBytes("UTF-8"));
Base64.getUrlDecoder().decode(b64, "UTF-8");

摘要

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// MD5
MessageDigest md = MessageDigest.getInstance("MD5");
md.update("123".getBytes("UTF-8"));
md.update(data2);
byte[] result = md.digest();
// SHA-1
MessageDigest md = MessageDigest.getInstance("SHA-1");
md.update("123".getBytes("UTF-8"));
md.update(data2);
byte[] result = md.digest();
// 第三方
Security.addProvider(new BouncyCastleProvider());
MessageDigest md = MessageDigest.getInstance("RipeMD160");
md.update("123".getBytes("UTF-8"));
md.update(data2);
byte[] result = md.digest();
// HmacMD5
KeyGenerator keygen = KeyGenerator.getInstance("HmacMD5");
SecretKey skey = keygen.generateKey();
Mac mac = Mac.getInstance("HmacMD5");
mac.init(skey);
mac.update(data);
byte[] result = mac.doFinal();

加密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// AES
String CIPHER_NAME = "AES/ECB/PKCS5Padding";
Cipher cipher = Cipher.getInstance(CIPHER_NAME);
SecretKeySpec keyspec = new SecretKeySpec(key, "AES");
cipher.init(Cipher.ENCRYPT_MODE, keyspec);
// cipher.init(Cipher.DECRYPT_MODE, keyspec);
return cipher.doFinal(input);

// 密钥交换 DH 算法
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("DH");
kpGen.initialize(512);
KeyPair kp = kpGen.generateKeyPair();
privateKey = kp.getPrivate();
publicKey = kp.getPublic();
// 收到 publicKey 后
keySpec = new X509EncodedKeySpec(publicKeyBytes);
kf = KeyFacotry.getInstance("DH");
publicKey = kf.generatePublic(keySpec);
keyAgreement = KeyAgreement.getInstance("DH");
keyAgreement.init(this.privateKey)
keyAgreement.doPhase(publicKey, true)

// RSA
KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA");
kpGen.initialize(1024);
KeyPair kp = kpGen.generateKeyPair();
privateKey = kp.getPrivate();
publicKey = kp.getPublic();
// 加解密
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKey);
// cipher.init(Cipher.DECRYPT_MODE, privateKey);
return cipher.doFinal(input);

签名

1

数字证书

1

线程

创建。

方法一:继承Thread类,重写run方法。

1
2
3
public class MyThread extends Thread {
public void run () {}
}

方法二:实现Runnable接口

1
2
3
public class MyThread implements Runnable {
public void run() {}
}

lambda方式:

1
Thread thread = new Thread(() -> { });

线程方法:

1
2
3
start() 启动
stop() 强制结束
join() 等待

异常:

1
InterruptedException e; //中断异常

线程间的共享数据,用volatile修饰

守护线程:

  • 不能持有任何资源

  • 系统结束时结束守护线程

    1
    setDaemon(true)

线程同步

  • 可以同步代码块

  • 可以同步方法

    1
    2
    3
    synchronized(lock) {
    // ...
    }

基本类型赋值,引用类型赋值都是原子操作。

一般对于需要同步的数据,封装成对象,将其中的方法改为同步方法。此时锁住的则是thisA.class

可重入锁:某个线程多次获取同一个锁。

多线程协调:

1
2
this.wait()  // 线程主动进入等待状态,期间释放一次锁,再获得一次锁
this.notify() // 唤醒一个等待this锁的线程,但是不释放锁

线程同步工具类:concurrent

ReentrantLock 需要手动释放的锁

1
2
3
4
5
6
7
Lock lock = new ReentrantLock();
lock.lock(); // 可能会失败
lock.tryLock(); // 尝试获取,可以设置超时时间
try{ }
finally{
lock.unlock();
}

ReadWriteLock 读时可多线程同时获取锁,写时只允许一个锁

1
2
3
Lock lock = new ReentrantReadWriteLock();
Lock r = lock.readLock();
Lock w = lock.writeLock();

Condition 实现wait、notify功能

1
2
3
lock.newCondition();
await(); // 相当于 wait
signalAll(); // 相当于 notifyAll

Concurrent 线程安全集合

1
2
3
4
5
6
CopyOnWriteArrayList
ConcurrentHashMap
CopyOnWriteArraySet
ArrayBlockingQueue
LinkedBlockingQueue
LinkedBlockingDeque

原子操作 CAS 操作

1
2
3
4
AtomicInteger value;
AtomicIntegerArray values;
addAndGet();
get();

ExecutorService 线程池

  • FixedThreadPool

  • CachedThreadPool

  • SingleThreadExecutor

  • ScheduleThreadPool 包括固定速率和固定间隔

    1
    2
    3
    4
    ExecutorService exe = Executors.newFixedThreadPool(4);
    exe.submit(task);
    // ...
    exe.shutdown();

Future 获取线程的返回值

1
2
3
4
5
Callable<String> task = new Task();
Future<String> futrue = exe.submit(task);
String s = future.get(); // 阻塞
cancel()
isDone()

CompletableFuture 任务结束后自动调用回调函数

1
2
3
4
5
6
7
8
9
10
CompletableFuture<String> cf = getCompletableFutureFromSomewhere(); // Supplier
cf.thenAccept((result) -> {});
cf.exceptionally((exception) -> {});
// 还可以串行执行
cf2 = cf.thenApplyAsync();
cf3 = cf2.thenApplyAsync();
// 还可以并行执行
<Object>cf = CompletableFuture.anyOf(); // 任意一个完成就调用thenAccept
<Void>cf = CompletableFuture.allOf(); // 都完成就调用thenAccept
cf.thenAccept();

Fork/Join 可以拆分任务为多个小任务并行计算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class SumTask extends RecursiveTask<Long> { // 或 RecursiveAction
@Override
protected Long compute() {
SumTask sub1 = new SumTask();
SumTask sub2 = new SumTask();
invokeAll(sub1, sub2);
res1 = fork1.join();
res2 = fork2.join();
return res1 + res2;
}
}

ForkJoinPool.commonPool().invoke(task);
Arrays.parallelSort(); // 并行排序

工具类

1
2
3
4
5
6
7
8
// 获取当前线程
Thread.currentThread();

// 同一线程内绑定全局对象
static ThreadLocal<String> tl = new ThreadLocal<>();
tl.set();
String s = tl.get();
tl.remove();

Maven

要求代码目录命名规范。

依赖关系:

  • compile
  • test
  • runtime
  • provided 编译时需要,运行时不需要

网络编程

TCP

1
2
3
4
5
6
7
8
Socket sock = new Socket(InetAddress, port);
sock.getInputStream();
sock.getOutputStream();

ServerSocket sock = new ServerSocket(port);
Socket sk = sock.accept();
sock.getInputStream();
sock.getOutputStream();
1
2
bindAddr = InetAddress.getByAddress(new byte[] {192, 168, 1, 1});
ServerSocket sock = new ServerSocket(port, backlog, bindAddr);

UDP

1
2
3
4
5
6
DatagramSocket sock = new DatagramSocket()
sock.connect(addr, 9090);
DatagramPacket packet = new DatagramPacket(data, data.length);
sock.send(packet);
resp = new DatagramPacket(buffer, buffer.length);
sock.receive(resp);

HTTP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// GET
URL url = new URL("");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
int code = conn.getResponseCode();
try(InputStream in = conn.getInputStream()) {
// read data
}
conn.disconnect();

// POST
URL url = new URL("");
byte[] postData = "".getBytes("UTF-8");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setDoOutput(true);
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("Content-length", String.valueOf(postData.length));
try(OutputStream out = conn.getOutputStream()){
out.write(postData);
}
int code = conn.getResponseCode();
try(InputStream in = conn.getInputStream()) {
// read data
}
conn.disconnect();

Stream util

表示任意Java对象,用于内存计算,业务逻辑。实时计算,惰性计算。

  • 可以存储无限个元素

  • 可以转换为另一个Steam

    1
    2
    3
    4
    Stream<BigInteger> naturals = createNaturalSteam();
    naturals.map((n) -> n.multiply(n))
    .limit(100)
    .forEach(System.out::println);
1
2
3
4
5
Stream<Integer> s = Stream.of(1,2,3,4,5);
Stream<Integer> s = Arrays.stream(oneArray);
Stream<Integer> s = oneList.stream();
Stream<T> s = Stream.generate(Supplier<T> s); // 实时计算新元素
Stream<String> lines = Files.lines(); // 文件变Stream

Map 方法,对序列的每个元素施加一个操作

1
Stream<Integer> s2 = s1.map((n) -> n * n);  // Functional

Filter 方法,对每个元素测试过滤

1
Stream<Integer> s2 = s1.filter((n) -> n % 2 == 1); // Predicate

Reduce 方法,对元素聚合

1
2
Stream<Integer> s2 = s1.reduce((acc, n) -> acc + n); // BinaryOperator
Stream<Integer> s2 = s1.reduce(1000 /* 初始值 */, (sum, n) -> sum + n); // BinaryOperator

其他方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
sorted()
distinct() // 去重
limit()
skip() // 跳过前N个元素
concat()
flatMap() // 扁平化
parallel() // 并行处理

reduce()
count()
max()
min()
sum()
average()
allMatch()
anyMatch()

forEach()
toArray() // Array
collect() // List / Set

Hutool 工具包