JavaCodeDemo
Java基础示例代码
单例设计模式
1 | package Exer.java; |
点击查看运行结果
1 | true |
程序中成员变量赋值的执行顺序的例子
1 | /** |
点击查看运行结果
1 | Root的静态初始化块 |
创建线程的四种方式
JDK1.5 之前创建新执行线程有两种方法:①继承Thread类的方式;②实现Runnable接口的方式;
JDK1.5 ③新增实现Callable创建方式
- 定义子类继承Thread类。
- 子类中重写Thread类中的run方法。
- 创建Thread子类对象,即创建了线程对象。
- 调用线程对象start方法:启动线程,调用run方法。
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//1. Declare a class to be a subclass of Thread
class EvenNumber extends Thread {
int number = 0;
public EvenNumber(int number) {
this.number = number;
}
// 2. Override the run method of class Thread.
public void run() {
for (int i = 0; i < number; i++) {
if (i % 2 == 0) {
System.out.println(Thread.currentThread().getName() + ":" + i + " is a even number");
}
}
}
}
public class ThreadTest01 {
public static void main(String[] args) {
// 3.Build an instance of the subclass
EvenNumber n = new EvenNumber(10);
// 4. This instance can be allocated and started
n.start();
// This code will be executed in the main method
for (int i = 0; i < n.number; i++) {
if (i % 2 == 0) {
System.out.println(Thread.currentThread().getName() + ":" + i + " is a even number");
}
}
}
}点击查看运行结果
1
2
3
4
5
6
7
8
9
10
11
12
13D:\PATH-EN\java-path\bin\java.exe ...
main:0 is a even number
Thread-0:0 is a even number
Thread-0:2 is a even number
Thread-0:4 is a even number
Thread-0:6 is a even number
Thread-0:8 is a even number
main:2 is a even number
main:4 is a even number
main:6 is a even number
main:8 is a even number
Process finished with exit code 0
- 定义子类,实现Runnable接口。
- 子类中重写Runnable接口中的run方法。
- 通过Thread类含参构造器创建线程对象。
- 将Runnable接口的子类对象作为实际参数传递给Thread类的构造器中。
- 调用Thread类的start方法:开启线程,调用Runnable子类接口的run方法。
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// 1. Create a thread is to declare a class that implements the Runnable interface.
class PrimeRun implements Runnable {
long minPrime;
PrimeRun(long minPrime) {
this.minPrime = minPrime;
}
// 2.This class then implements the run method.
public void run() {
// Compute primes larger than minPrime
}
}
public class ThreadTest02 {
public static void main(String[] args) {
// 3. Create an instance of PrimeRun class
PrimeRun p = new PrimeRun(143);
// When you create a thread put the instance as arguments and start it
new Thread(p).start();
new Thread(p).start();
}
}
- 创建一个实现Callable的实现类
- 实现call方法,将此线程需要执行的操作声明在call()中
- 创建Callable接口实现类的对象
- 将此Callable接口实现类的对象作为传递到FutureTask构造器中,创建FutureTask的对象
- 将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()
- 获取Callable中call方法的返回值get()返回值即为FutureTask构造器参数Callable实现类重写的call()的返回值。
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
42
43
44import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class ThreadCallable {
public static void main(String[] args) {
// 3.创建Callable接口实现类的对象
SumOfEvenNumber sumOfEvenNumber = new SumOfEvenNumber();
// 4.将此Callable接口实现类的对象作为传递到FutureTask构造器中,创建FutureTask的对象
FutureTask futureTask = new FutureTask(sumOfEvenNumber);
// 5.将FutureTask的对象作为参数传递到Thread类的构造器中,创建Thread对象,并调用start()
new Thread(futureTask).start();
try {
// 6.获取Callable中call方法的返回值get()返回值即为FutureTask构造器参数Callable实现类重写的call()的返回值。
System.out.println("sum=" + futureTask.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
// 1.创建一个实现Callable的实现类
class SumOfEvenNumber implements Callable {
// 2.实现call方法,将此线程需要执行的操作声明在call()中
public Object call() throws Exception {
int sum = 0;
for (int i = 0; i < 10; i++) {
if (i % 2 == 0) {
System.out.println(i);
sum += i;
}
}
return sum;
}
}点击查看运行结果
1
2
3
4
5
6
7
8
9D:\PATH-EN\java-path\bin\java.exe ...
0
2
4
6
8
sum=20
Process finished with exit code 0
- 提供指定线程数量的线程池
设置线程池的属性 - 执行指定的线程的操作。需要提供实现Runnable接口或Callable接口实现类的对象
- 关闭连接池
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
42
43public class ThreadPoolTest {
public static void main(String[] args) {
// 1. 提供指定线程数量的线程池
ExecutorService service = Executors.newFixedThreadPool(10);
// 2. 执行指定的线程的操作。需要提供实现Runnable接口或Callable接口实现类的对象
service.execute(new EvenNum());
service.execute(new OddNumber());
// 3. 关闭连接池
service.shutdown();
// service.submit();
}
}
class EvenNum implements Runnable {
public void run() {
for (int i = 0; i < 10; i++) {
if (i % 2 == 0) {
System.out.println(Thread.currentThread().getName() +
":" + i);
}
}
}
}
class OddNumber implements Runnable {
public void run() {
for (int i = 0; i < 10; i++) {
if (i % 2 != 0) {
System.out.println(Thread.currentThread().getName() +
":" + i);
}
}
}
}点击查看运行结果
1
2
3
4
5
6
7
8
9
10
11
12
13D:\PATH-EN\java-path\bin\java.exe ...
pool-1-thread-1:0
pool-1-thread-1:2
pool-1-thread-1:4
pool-1-thread-1:6
pool-1-thread-1:8
pool-1-thread-2:1
pool-1-thread-2:3
pool-1-thread-2:5
pool-1-thread-2:7
pool-1-thread-2:9
Process finished with exit code 0
方式一和方式二相比:
- 避免了单继承的局限性
- 多个线程可以共享同一个接口实现类的对象,非常适合多个相同线程来处理同一份资源。
方式二和方式三相比:
- 与使用Runnable相比, Callable功能更强大
- 相比run()方法,可以有返回值
- 方法可以抛出异常
- 支持泛型的返回值
- 需要借助FutureTask类,比如获取返回结果
使用线程池的好处:
- 提高响应速度(减少了创建新线程的时间)
- 降低资源消耗(重复利用线程池中线程,不需要每次都创建)
- 便于线程管理
- corePoolSize:核心池的大小
- maximumPoolSize:最大线程数
- keepAliveTime:线程没有任务时最多保持多长时间后会终止
- …
死锁示例
1 | public class DeadLockTest { |
点击查看运行结果
1 | D:\PATH-EN\java-path\bin\java.exe ... |
反射的应用:动态代理
静态代理
1 | interface ClothFactory { |
点击查看运行结果
1 | D:\PATH-EN\java-path\bin\java.exe ... |
- 代理设计模式的原理:使用一个代理将对象包装起来, 然后用该代理对象取代原始对象。任何对原 始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原 始对象上。
- 动态代理是指客户通过代理类来调用其它对象的方法,并且是在程序运行时 根据需要动态创建目标类的代理对象。
动态代理使用场合:
- 调试
- 远程方法调用
动态代理相比于静态代理的优点:抽象角色中(接口)声明的所有方法都被转移到调用处理器一个集中的方法中 处理,这样,我们可以更加灵活和统一的处理众多的方法。
Java动态代理相关API
- Proxy :专门完成代理的操作类,是所有动态代理类的父类。通过此类为一个或多个接口动态地生成实现类。
- 提供用于创建动态代理类和动态代理对象的静态方法
- static Class<?>getProxyClass(ClassLoader loader, Class<?>… interfaces) 创建一个动态代理类所对应的Class对象
- static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h) 直接创建一个动态代理对象
动态代理步骤
- 创建一个实现接口InvocationHandler的类,它必须实现invoke方法,以完成代理的具体操作。
- 创建被代理的类以及接口
- 通过Proxy的静态方法newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 创建一个Subject接口代理
- 通过 Subject代理调用RealSubject实现类的方法
动态代理
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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
interface Human {
String getBelief();
void eat(String food);
}
//2. 创建被代理的类以及接口
class SuperMan implements Human {
public String getBelief() {
return "Peace and love!";
}
public void eat(String food) {
System.out.println("我喜欢吃" + food);
}
}
class ProxyFactory {
public static Object getProxyInstance(Object obj) {
MyInvocationHandler handler = new MyInvocationHandler();
handler.bind(obj);
// 3.通过Proxy的静态方法newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 创建一个Subject接口代理
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler);
}
}
//1. 创建一个实现接口InvocationHandler的类,它必须实现invoke方法,以完成代理的具体操作。
class MyInvocationHandler implements InvocationHandler {
//obj:被代理类的对象
private Object obj;
public void bind(Object obj) {
this.obj = obj;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//method:即为代理类对象调用的方法,此方法也就作为了被代理类对象要调用的方法
//obj:被代理类的对象
Object invoke = method.invoke(obj, args);
//上述方法的返回值就作为当前类中的invoke()的返回值。
return invoke;
}
}
public class ProxyTest {
public static void main(String[] args) {
SuperMan superMan = new SuperMan();
//4. 通过ProxyFactory代理调用getProxyInstance实现类的方法
Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);
String belief = proxyInstance.getBelief();
System.out.println(belief);
proxyInstance.eat("KFC");
}
}点击查看运行结果
1
2
3
4
5D:\PATH-EN\java-path\bin\java.exe ...
Peace and love!
我喜欢吃KFC
进程已结束,退出代码0SQL相关
7种SQL JOINS的实现
语法格式小结
1 | # 1. 左中图 |
JDBC
使用PreparedStatement实现CURD操作
1 | package Exer.curd; |
点击查看运行结果
1 | com.mysql.cj.jdbc.ConnectionImpl@1e6454ec |
1 | package Exer.junit; |
考虑到数据库事务的情况下的通用操作
1 | package Exer.connection; |
数据库连接池之一:C3P0数据库连接池
C3P0数据库连接池
1
2
3
4
5
6
7
8
9
10
11
12
13//使用C3P0数据库连接池的方式,获取数据库的连接:不推荐
public static Connection getConnection1() throws Exception{
ComboPooledDataSource cpds = new ComboPooledDataSource();
cpds.setDriverClass("com.mysql.jdbc.Driver");
cpds.setJdbcUrl("jdbc:mysql://localhost:3306/test");
cpds.setUser("root");
cpds.setPassword("abc123");
// cpds.setMaxPoolSize(100);
Connection conn = cpds.getConnection();
return conn;
}
1
2
3
4
5
6
7//使用C3P0数据库连接池的配置文件方式,获取数据库的连接:推荐
// new在外面,只需要生成一次就可以
private static DataSource cpds = new ComboPooledDataSource("helloc3p0");
public static Connection getConnection2() throws SQLException{
Connection conn = cpds.getConnection();
return conn;
}
其中,src下的配置文件为:【c3p0-config.xml】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
<c3p0-config>
<named-config name="helloc3p0">
<!-- 获取连接的4个基本信息 -->
<property name="user">root</property>
<property name="password">abc123</property>
<property name="jdbcUrl">jdbc:mysql:///test</property>
<property name="driverClass">com.mysql.jdbc.Driver</property>
<!-- 涉及到数据库连接池的管理的相关属性的设置 -->
<!-- 若数据库中连接数不足时, 一次向数据库服务器申请多少个连接 -->
<property name="acquireIncrement">5</property>
<!-- 初始化数据库连接池时连接的数量 -->
<property name="initialPoolSize">5</property>
<!-- 数据库连接池中的最小的数据库连接数 -->
<property name="minPoolSize">5</property>
<!-- 数据库连接池中的最大的数据库连接数 -->
<property name="maxPoolSize">10</property>
<!-- C3P0 数据库连接池可以维护的 Statement 的个数 -->
<property name="maxStatements">20</property>
<!-- 每个连接同时可以使用的 Statement 对象的个数 -->
<property name="maxStatementsPerConnection">5</property>
</named-config>
</c3p0-config>
数据库连接池之二:DBCP数据库连接池
- DBCP 是 Apache 软件基金组织下的开源连接池实现,该连接池依赖该组织下的另一个开源系统:Common-pool。如需使用该连接池实现,应在系统中增加如下两个 jar 文件:
- Commons-dbcp.jar:连接池的实现
- Commons-pool.jar:连接池实现的依赖库
- Tomcat 的连接池正是采用该连接池来实现的。该数据库连接池既可以与应用服务器整合使用,也可由应用程序独立使用。
- 数据源和数据库连接不同,数据源无需创建多个,它是产生数据库连接的工厂,因此整个应用只需要一个数据源即可。
- 当数据库访问结束后,程序还是像以前一样关闭数据库连接:conn.close(); 但上面的代码并没有关闭数据库的物理连接,它仅仅把数据库连接释放,归还给了数据库连接池。
- 配置属性说明
属性 | 默认值 | 说明 |
---|---|---|
initialSize | 0 | 连接池启动时创建的初始化连接数量 |
maxActive | 8 | 连接池中可同时连接的最大的连接数 |
maxIdle | 8 | 连接池中最大的空闲的连接数,超过的空闲连接将被释放,如果设置为负数表示不限制 |
minIdle | 0 | 连接池中最小的空闲的连接数,低于这个数量会被创建新的连接。该参数越接近maxIdle,性能越好,因为连接的创建和销毁,都是需要消耗资源的;但是不能太大。 |
maxWait | 无限制 | 最大等待时间,当没有可用连接时,连接池等待连接释放的最大时间,超过该时间限制会抛出异常,如果设置-1表示无限等待 |
poolPreparedStatements | false | 开启池的Statement是否prepared |
maxOpenPreparedStatements | 无限制 | 开启池的prepared 后的同时最大连接数 |
minEvictableIdleTimeMillis | 连接池中连接,在时间段内一直空闲, 被逐出连接池的时间 | |
removeAbandonedTimeout | 300 | 超过时间限制,回收没有用(废弃)的连接 |
removeAbandoned | false | 超过removeAbandonedTimeout时间后,是否进 行没用连接(废弃)的回收 |
1
2
3
4
5
6
7
8
9
10
11
12
13
14public static Connection getConnection3() throws Exception {
BasicDataSource source = new BasicDataSource();
source.setDriverClassName("com.mysql.jdbc.Driver");
source.setUrl("jdbc:mysql:///test");
source.setUsername("root");
source.setPassword("abc123");
//
source.setInitialSize(10);
Connection conn = source.getConnection();
return conn;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22//使用dbcp数据库连接池的配置文件方式,获取数据库的连接:推荐
private static DataSource source = null;
static{
try {
Properties pros = new Properties();
InputStream is = DBCPTest.class.getClassLoader().getResourceAsStream("dbcp.properties");
pros.load(is);
//根据提供的BasicDataSourceFactory创建对应的DataSource对象
source = BasicDataSourceFactory.createDataSource(pros);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection4() throws Exception {
Connection conn = source.getConnection();
return conn;
}
其中,src下的配置文件为:【dbcp.properties】1
2
3
4
5
6
7driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true&useServerPrepStmts=false
username=root
password=abc123
initialSize=10
#...
Druid(德鲁伊)数据库连接池
Druid是阿里巴巴开源平台上一个数据库连接池实现,它结合了C3P0、DBCP、Proxool等DB池的优点,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行情况,可以说是针对监控而生的DB连接池,可以说是目前最好的连接池之一。
1 | package com.atguigu.druid; |
其中,src下的配置文件为:【druid.properties】
1 | url=jdbc:mysql://localhost:3306/test?rewriteBatchedStatements=true |
详细配置参数:
- 详细配置参数:
配置 | 缺省 | 说明 |
---|---|---|
name | 配置这个属性的意义在于,如果存在多个数据源,监控的时候可以通过名字来区分开来。 如果没有配置,将会生成一个名字,格式是:”DataSource-” + System.identityHashCode(this) | |
url | 连接数据库的url,不同数据库不一样。例如:mysql : jdbc:mysql://10.20.153.104:3306/druid2 oracle : jdbc:oracle:thin:@10.20.149.85:1521:ocnauto | |
username | 连接数据库的用户名 | |
password | 连接数据库的密码。如果你不希望密码直接写在配置文件中,可以使用ConfigFilter。详细看这里:https://github.com/alibaba/druid/wiki/%E4%BD%BF%E7%94%A8ConfigFilter | |
driverClassName | 根据url自动识别 这一项可配可不配,如果不配置druid会根据url自动识别dbType,然后选择相应的driverClassName(建议配置下) | |
initialSize | 0 | 初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时 |
maxActive | 8 | 最大连接池数量 |
maxIdle | 8 | 已经不再使用,配置了也没效果 |
minIdle | 最小连接池数量 | |
maxWait | 获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。 | |
poolPreparedStatements | false | 是否缓存preparedStatement,也就是PSCache。PSCache对支持游标的数据库性能提升巨大,比如说oracle。在mysql下建议关闭。 |
maxOpenPreparedStatements | -1 | 要启用PSCache,必须配置大于0,当大于0时,poolPreparedStatements自动触发修改为true。在Druid中,不会存在Oracle下PSCache占用内存过多的问题,可以把这个数值配置大一些,比如说100 |
validationQuery | 用来检测连接是否有效的sql,要求是一个查询语句。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会其作用。 | |
testOnBorrow | true | 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 |
testOnReturn | false | 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能 |
testWhileIdle | false | 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 |
timeBetweenEvictionRunsMillis | 有两个含义: 1)Destroy线程会检测连接的间隔时间2)testWhileIdle的判断依据,详细看testWhileIdle属性的说明 | |
numTestsPerEvictionRun | 不再使用,一个DruidDataSource只支持一个EvictionRun | |
minEvictableIdleTimeMillis | ||
connectionInitSqls | 物理连接初始化的时候执行的sql | |
exceptionSorter | 根据dbType自动识别 当数据库抛出一些不可恢复的异常时,抛弃连接 | |
filters | 属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有: 监控统计用的filter:stat日志用的filter:log4j防御sql注入的filter:wall | |
proxyFilters | 类型是List,如果同时配置了filters和proxyFilters,是组合关系,并非替换关系 |
Apache-DBUtils实现CRUD操作
commons-dbutils 是 Apache 组织提供的一个开源 JDBC工具类库,它是对JDBC的简单封装,学习成本极低,并且使用dbutils能极大简化jdbc编码的工作量,同时也不会影响程序的性能。
API介绍:
- org.apache.commons.dbutils.QueryRunner
- org.apache.commons.dbutils.ResultSetHandler
- 工具类:org.apache.commons.dbutils.DbUtils
API包说明:
主要API的使用
DbUtils
DbUtils :提供如关闭连接、装载JDBC驱动程序等常规工作的工具类,里面的所有方法都是静态的。主要方法如下:- public static void close(…) throws java.sql.SQLException: DbUtils类提供了三个重载的关闭方法。这些方法检查所提供的参数是不是NULL,如果不是的话,它们就关闭Connection、Statement和ResultSet。
- public static void closeQuietly(…): 这一类方法不仅能在Connection、Statement和ResultSet为NULL情况下避免关闭,还能隐藏一些在程序中抛出的SQLEeception。
- public static void commitAndClose(Connection conn)throws SQLException: 用来提交连接的事务,然后关闭连接
- public static void commitAndCloseQuietly(Connection conn): 用来提交连接,然后关闭连接,并且在关闭连接时不抛出SQL异常。
- public static void rollback(Connection conn)throws SQLException:允许conn为null,因为方法内部做了判断
- public static void rollbackAndClose(Connection conn)throws SQLException
- rollbackAndCloseQuietly(Connection)
- public static boolean loadDriver(java.lang.String driverClassName):这一方装载并注册JDBC驱动程序,如果成功就返回true。使用该方法,你不需要捕捉这个异常ClassNotFoundException。
QueryRunner类
该类简单化了SQL查询,它与ResultSetHandler组合在一起使用可以完成大部分的数据库操作,能够大大减少编码量。
QueryRunner类提供了两个构造器:
- 默认的构造器
- 需要一个 javax.sql.DataSource 来作参数的构造器
QueryRunner类的主要方法:
- 更新
- public int update(Connection conn, String sql, Object… params) throws SQLException:用来执行一个更新(插入、更新或删除)操作。
- ……
- 插入
- public
T insert(Connection conn,String sql,ResultSetHandler rsh, Object… params) throws SQLException:只支持INSERT语句,其中 rsh - The handler used to create the result object from the ResultSet of auto-generated keys. 返回值: An object generated by the handler.即自动生成的键值 - ….
- public
- 批处理
- public int[] batch(Connection conn,String sql,Object[][] params)throws SQLException: INSERT, UPDATE, or DELETE语句
- public
T insertBatch(Connection conn,String sql,ResultSetHandler rsh,Object[][] params)throws SQLException:只支持INSERT语句 - …..
- 查询
- public Object query(Connection conn, String sql, ResultSetHandler rsh,Object… params) throws SQLException:执行一个查询操作,在这个查询中,对象数组中的每个元素值被用来作为查询语句的置换参数。该方法会自行处理 PreparedStatement 和 ResultSet 的创建和关闭。
- ……
- 更新
使用德鲁伊数据库连接池进行最终版本测试
1 | package Exer.curd; |
点击查看运行结果
1 | 5月 20, 2023 10:57:57 下午 com.alibaba.druid.pool.DruidDataSource info |
1 | package Exer.bean; |
1 | package Exer.junit; |