描述:今天看了一下开源的博客系统zconson,对其中的一些类进行了分析,所以有感而发 ,把好的代码拿出来加上我的理解分享一下,有些地方也是我根据知识点通过搜索引擎找到的,为了不误人子弟,有不足的地方请指正,我好及时更正再发布,非常感谢。
ConnectionManager.java这个类的代码分享:
import java.sql.Connection;
import java.sql.SQLException;
import javax.sql.DataSource;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import com.zcoson.exception.DBException;
public final class ConnectionManager {
① private static ConnectionManager connectionManager;
private static ComboPooledDataSource dataSource;
② public final static ConnectionManager getInstance () {
if (null ==connectionManager) {
connectionManager =new ConnectionManager();
}
return connectionManager;
}
③ static {
dataSource = new ComboPooledDataSource();
}
④ public final synchronized static DataSourcegetDataSource() {
return dataSource;
}
④ public final synchronized ConnectiongetConnection() throws DBException {
try {
return dataSource.getConnection();
} catch (SQLException e) {
throw new DBException("GetDataBase Connection error", e);
}
}
}
总述:这个类的作用是获得数据源、获得连接对象,使用了C3p0的方式使用连接池。
分享点(上面的红色背景块)解析:
①: 定义了两个静态变量(类变量),下面介绍一下静态变量,另外再抛砖引玉一下实例变量:
i:静态变量:就是用static声明的变量,对于静态变量在内存中只有一个拷贝(节省内存),JVM只为静态分配一次内存,在加载类的过程中完成静态变量的内存分配,然后其他地方的调用都是共享的这块内存区域;也就是说不用new.object();的方式,而是用类名直接访问(方便),当然也可以通过对象来访问(但是这是不推荐的)。这里的静态变量使用功能了private声明为私有静态变量,也就是说这个变量可以在类的静态代码块中,或者类的其他静态成员方法中使用(当然也可以在非静态成员方法中使用--废话),但是不能在其他类中通过类名来直接引用(一句话概括:这个静态变量可以不用实例化直接使用,用private声明后只能在当前类中使用)。
ii:实例变量:对于实例变量,每创建一个实例,就会为实例变量分配一次内存,实例变量可以在内存中有多个拷贝,互不影响(灵活),也就是每new一个类时,这个类的实例变量就会在内存中存在一份。
②: 这里采用了典型的单例模式,下面介绍一下单例模式:
I:描述:单例模式属于对象创建型模式,其意图是保证一个类仅有一个实例,并提供一个访问它的全局访问点。对一些类来说,只有一个实例是很重要的,譬如一个会计系统只能专用于一个公司。怎样才能保证一个类只有一个实例并且这个实例易于被访问,一个全局变量使得一个对象可以被访问,但它不能防止你实例化多个对象,一个更好的方法是让类自身负责保存他的唯一实例。这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法,这就是Singleton模式。
II:应用场景:在下面的情况下可以使用Singleton模式。
当类只能有一个实例而且客户可以从一个众所周知的访问点访问它时。
当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。
Singleton定义一个Instance操作,允许客户访问它的唯一实例,Instance是一个类操作。可能负责创建自己的唯一实例。客户只能通过Singleton的Instance操作访问一个Singleton的实例。
使用Singleton模式有许多优点:
⑴对唯一实例的受控访问,
⑵缩小命名空间,
⑶允许对操作和表示的精化,
⑷允许可变数目的实例。
⑸比类操作更灵活。
③: 这里使用了一个静态代码块,下面介绍一下静态代码块:
一个对象初始化的流程:
(1).将相应的class文件加载进内存
(2).执行类中的static代码块对类进行初始化
(3).在堆内存中开辟一块空间,并分配内存地址
(4).在堆内存中建立对象的特有属性,并进行默认初始化
(5).对属性进行显示初始化
(6).对对象进行构造代码块初始化
(7).对对象进行对应的构造函数初始化
(8).将内存地址赋给栈内存中的变量
用大白话形容上面这个流程:
首先执行父类静态的内容,父类静态的内容执行完毕后,接着去执行子类的静态的内容,当子类的静态内容执行完毕之后,再去看父类有没有非静态代码块,如果有就执行父类的非静态代码块,父类的非静态代码块执行完毕,接着执行父类的构造方法;父类的构造方法执行完毕之后,它接着去看子类有没有非静态代码块,如果有就执行子类的非静态代码块。子类的非静态代码块执行完毕再去执行子类的构造方法。总之一句话,静态代码块内容先执行,接着执行父类非静态代码块和构造方法,然后执行子类非静态代码块和构造方法。
注意:子类的构造方法,不管这个构造方法带不带参数,默认的它都会先去寻找父类的不带参数的构造方法。如果父类没有不带参数的构造方法,那么子类必须用supper关键子来调用父类带参数的构造方法,否则编译不能通过。
小结:静态代码块的作用和上面的静态变量是一样的,比构造方法先执行,就是在类初始化之前就存在了。
④: 这里使用了同步synchronized,下面介绍一下同步
先阐述一下同步:
A.无论synchronized关键字加在方法上还是对象上,他取得的锁都是对象,而不是把一段代码或函数当作锁――而且同步方法很可能还会被其他线程的对象访问。
B.每个对象只有一个锁(lock)和之相关联。
C.实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。
synchronized 方法控制对类成员变量的访问:每个类实例对应一把锁,每个 synchronized 方法都必须获得调用该方法的类实例的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得 该锁,重新进入可执行状态。这种机制确保了同一时刻对于每一个类实例,其所有声明为 synchronized 的成员方法中至多只有一个处于可执行状态(因为至多只有一个能够获得该类实例对应的锁),从而有效避免了类成员变量的访问冲突(只要所有可能访问类成员变 量的方法均被声明为 synchronized)转载于:https://my.oschina.net/mapsh/blog/598136