如果成员变量想要初始化的值不是一个硬编码的常量值,而是需要通过复杂的计算或读取文件、或读取运行环境信息等方式才能获取的一些值,该怎么办呢?此时,可以考虑代码块(或初始化块)。
-
代码块(或初始化块)的
作用
: -
对Java类或对象进行初始化
-
代码块(或初始化块)的
分类
:-
一个类中代码块若有修饰符,则只能被static修饰,称为静态代码块(static block)
-
没有使用static修饰的,为非静态代码块。
-
静态代码块
在代码块的前面加static,就是静态代码块。
【修饰符】 class 类{
static{
静态代码块
}
}
静态代码块的特点
-
可以有输出语句。
-
可以对类的属性、类的声明进行初始化操作。
-
不可以对非静态的属性初始化。即:不可以调用非静态的属性和方法。
-
若有多个静态的代码块,那么按照从上到下的顺序依次执行。
-
静态代码块的执行要先于非静态代码块。
-
静态代码块随着类的加载而加载,且只执行一次。
package com.atguigu.keyword;
public class Chinese {
// private static String country = "中国";private static String country;
private String name;{
System.out.println("非静态代码块,country = " + country);
}static {
country = "中国";
System.out.println("静态代码块");
}public Chinese(String name) {
this.name = name;
}
}
package com.atguigu.keyword;
public class TestStaticBlock {
public static void main(String[] args) {
Chinese c1 = new Chinese("张三");
Chinese c2 = new Chinese("李四");
}
}
非静态代码块
语法格式
【修饰符】 class 类{
{
非静态代码块
}
【修饰符】 构造器名(){
// 实例初始化代码
}
【修饰符】 构造器名(参数列表){
// 实例初始化代码
}
}
非静态代码块的作用
和构造器一样,也是用于实例变量的初始化等操作。
非静态代码块的意义
如果多个重载的构造器有公共代码,并且这些代码都是先于构造器其他代码执行的,那么可以将这部分代码抽取到非静态代码块中,减少冗余代码。
非静态代码块的执行特点
-
可以有输出语句。
-
可以对类的属性、类的声明进行初始化操作。
-
除了调用非静态的结构外,还可以调用静态的变量或方法。
-
若有多个非静态的代码块,那么按照从上到下的顺序依次执行。
-
每次创建对象的时候,都会执行一次。且先于构造器执行。
举例
举例1:
(1)声明User类,
-
包含属性:username(String类型),password(String类型),registrationTime(long类型),私有化
-
包含get/set方法,其中registrationTime没有set方法
-
包含无参构造,
-
输出“新用户注册”,
-
registrationTime赋值为当前系统时间,
-
username就默认为当前系统时间值,
-
password默认为“123456”
-
-
包含有参构造(String username, String password),
-
输出“新用户注册”,
-
registrationTime赋值为当前系统时间,
-
username和password由参数赋值
-
-
包含public String getInfo()方法,返回:“用户名:xx,密码:xx,注册时间:xx”
(2)编写测试类,测试类main方法的代码如下:
public static void main(String[] args) {
User u1 = new User();
System.out.println(u1.getInfo());User u2 = new User("song","8888");
System.out.println(u2.getInfo());
}
如果不用非静态代码块,User类是这样的:
package com.atguigu.block.no;
public class User {
private String username;
private String password;
private long registrationTime;public User() {
System.out.println("新用户注册");
registrationTime = System.currentTimeMillis();
username = registrationTime+"";
password = "123456";
}public User(String username,String password) {
System.out.println("新用户注册");
registrationTime = System.currentTimeMillis();
this.username = username;
this.password = password;
}public String getUsername() {
return username;
}public void setUsername(String username) {
this.username = username;
}public String getPassword() {
return password;
}public void setPassword(String password) {
this.password = password;
}public long getRegistrationTime() {
return registrationTime;
}
public String getInfo(){
return "用户名:" + username + ",密码:" + password + ",注册时间:" + registrationTime;
}
}
如果提取构造器公共代码到非静态代码块,User类是这样的:
package com.atguigu.block.use;
public class User {
private String username;
private String password;
private long registrationTime;{
System.out.println("新用户注册");
registrationTime = System.currentTimeMillis();
}public User() {
username = registrationTime+"";
password = "123456";
}public User(String username, String password) {
this.username = username;
this.password = password;
}public String getUsername() {
return username;
}public void setUsername(String username) {
this.username = username;
}public String getPassword() {
return password;
}public void setPassword(String password) {
this.password = password;
}public long getRegistrationTime() {
return registrationTime;
}
public String getInfo(){
return "用户名:" + username + ",密码:" + password + ",注册时间:" + registrationTime;
}
}
举例2:
private static DataSource dataSource = null;
static{
InputStream is = null;
try {
is = DBCPTest.class.getClassLoader().getResourceAsStream("dbcp.properties");
Properties pros = new Properties();
pros.load(is);
//调用BasicDataSourceFactory的静态方法,获取数据源。
dataSource = BasicDataSourceFactory.createDataSource(pros);
} catch (Exception e) {
e.printStackTrace();
}finally{
if(is != null){
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
小结:实例变量赋值顺序
练习
练习1:分析加载顺序
class Root{
static{
System.out.println("Root的静态初始化块");
}
{
System.out.println("Root的普通初始化块");
}
public Root(){
System.out.println("Root的无参数的构造器");
}
}
class Mid extends Root{
static{
System.out.println("Mid的静态初始化块");
}
{
System.out.println("Mid的普通初始化块");
}
public Mid(){
System.out.println("Mid的无参数的构造器");
}
public Mid(String msg){
//通过this调用同一类中重载的构造器
this();
System.out.println("Mid的带参数构造器,其参数值:"
+ msg);
}
}
class Leaf extends Mid{
static{
System.out.println("Leaf的静态初始化块");
}
{
System.out.println("Leaf的普通初始化块");
}
public Leaf(){
//通过super调用父类中有一个字符串参数的构造器
super("尚硅谷");
System.out.println("Leaf的构造器");
}
}
public class LeafTest{
public static void main(String[] args){
new Leaf();
//new Leaf();
}
}
练习2:分析加载顺序
class Father {
static {
System.out.println("11111111111");
}
{
System.out.println("22222222222");
}public Father() {
System.out.println("33333333333");}
}
public class Son extends Father {
static {
System.out.println("44444444444");
}
{
System.out.println("55555555555");
}
public Son() {
System.out.println("66666666666");
}
public static void main(String[] args) {
System.out.println("77777777777");
System.out.println("************************");
new Son();
System.out.println("************************");new Son();
System.out.println("************************");
new Father();
}}
练习3:
package com.atguigu05.field.interview;
/**
* @author 尚硅谷-宋红康
* @create 16:04
*/
public class Test04 {
public static void main(String[] args) {
Zi zi = new Zi();
}
}
class Fu{
private static int i = getNum("(1)i");
private int j = getNum("(2)j");
static{
print("(3)父类静态代码块");
}
{
print("(4)父类非静态代码块,又称为构造代码块");
}
Fu(){
print("(5)父类构造器");
}
public static void print(String str){
System.out.println(str + "->" + i);
}
public static int getNum(String str){
print(str);
return ++i;
}
}
class Zi extends Fu{
private static int k = getNum("(6)k");
private int h = getNum("(7)h");
static{
print("(8)子类静态代码块");
}
{
print("(9)子类非静态代码块,又称为构造代码块");
}
Zi(){
print("(10)子类构造器");
}
public static void print(String str){
System.out.println(str + "->" + k);
}
public static int getNum(String str){
print(str);
return ++k;
}
}