文章目录
public class BedAndBreakfast {
// initialize to 10
public static int capacity = 10;
// initialize to false
private boolean full = false;
}
✏️ As you have seen, you can often provide an initial value for a field in its declaration.
📜 正如上面你所看到的,你可以在属性声明的时候就给它提供一个初始值(Initial Value)
✏️ This works well when the initialization value is available and the initialization can be put on one line.
📜 当初始值可用或比较简单,以至于可以一行书写的时候,这样写是很好的。
✏️ However, this form of initialization has limitations because of its simplicity.
📜 然而,由于其简单性(simplicity),这种形式的初始化也有其局限性(limitation)
✏️ If initialization requires some logic (for example:error handling or a for loop to fill a complex array), simple assignment is inadequate.
📜 如果初始化需要一些逻辑处理(如:错误处理,或用 for 循环为复杂数组填充数据),那么简单的赋值是完全不够的。
✏️ Instance variables can be initialized in constructors, where error handling or other logic can be used. To provide the same capability for class variables, the Java programming language includes static initialization blocks.
📜 实例变量(Instance Variable)可以在构造方法中初始化属性,错误处理或其他逻辑也可以在构造方法中完成。为了给类变量(Class Variable)提供相同的功能,Java 语言提供了静态初始化块。
public class BedAndBreakfast {
public static int capacity = 10;
/*
whatever code is needed for initialization goes here
初始化所需的任何代码都放在这里
*/
static {
capacity = 12;
}
public static void main(String[] args) {
// 12
System.out.println(capacity);
}
}
✏️ A static initialization block is a normal block of code enclosed in braces { } , and preceded by the static keyword.
📜 如上所示:静态初始化块就是一个普通的代码块,它包含在花括号 { } 中,花括号的前方有一个 static 关键字。
✏️ A class can have any number of static initialization blocks, and they can appear anywhere in the class body. The runtime system guarantees that static initialization blocks are called in the order that they appear in the source code.
📜 一个类中可以有任意数量的静态初始化块,静态初始化块可以出现在类体的任意位置。运行时系统会按照静态初始化块在源代码中出现的顺序挨个调用它们。
✏️ There is an alternative to static blocks — you can write a private static method.
📜 你也可以编写一个私有的静态方法来进行类变量的初始化,以此来替代静态初始化块【如下所示】
public class Whatever {
public static Double money = initClassVar();
/**
* 该静态方法用于初始化某个类变量
*/
private static Double initClassVar() {
// initialization code goes here
// 初始化代码放这儿
return Math.pow(10, 5);
}
public static void main(String[] args) {
// 100000.0
System.out.println(money);
}
}
✏️ The advantage of private static methods is that they can be reused later if you need to reinitialize the class variable.
📜 私有静态方法初始化类变量的好处是:如果你需要重新为类变量进行初始化的时候,私有静态方法可以被重复使用
✏️ Normally, you would put code to initialize an instance variable in a constructor. There are two alternatives to using a constructor to initialize instance variables: initializer blocks and final methods.
📜 为了初始化一个实例变量,通常情况下,你可能会把代码放在构造方法中。有两种可选的方式可用于在构造方法中初始化实例变量:初始化块和 final 方法。
✏️ Initializer blocks for instance variables look just like static initializer blocks, but without the static keyword.
📜 实例变量的初始化块看起来和静态初始化块有点一样,只是没有 static 关键字罢了。
public class Whatever {
public int money = 666;
{
// 初始化实例变量的代码都放这儿
money = 9999;
}
public static void main(String[] args) {
// 9999
System.out.println(new Whatever().money);
}
}
✏️ The Java compiler copies initializer blocks into every constructor.
📜 Java 编译器会把初始化块(注意:是初始化块,不是静态初始化块)拷贝到每个构造方法中。

✏️ Therefore, this approach can be used to share a block of code between multiple constructors.
📜 因此,初始化块可以实现在多个构造方法之间共用代码块的功能。
✏️ A final method cannot be overridden(重写) in a subclass. Here is an example of using a final method for initializing an instance variable.
📜 被 final 关键字修饰的方法不能被子类重写。下面是一个用 final 方法初始化实例变量的例子。
public class Whatever {
private double money = initInstanceVar();
/* protected: 保证子类也可以重复使用该方法 */
protected final double initInstanceVar() {
// initialization code goes here
// 初始化代码放这儿
return Math.pow(Math.PI * 10, 3);
}
public static void main(String[] args) {
// 31006.276680299816
System.out.println(new Whatever().money);
// 31006.276680299816
System.out.println(new CuteSon().getSalary());
}
}
class CuteSon extends Whatever {
private double salary = initInstanceVar();
public double getSalary() {
return salary;
}
}
✏️ This is especially useful if subclasses might want to reuse the initialization method.
📜 该方式非常有用,尤其是子类需要重复使用初始化方法的时候。
✒️ 初始化块:Initializer block
✒️ 静态初始化块:Static Initialization Block
✏️ 编译器会按照初始化块在源代码中的出现顺序把初始化块拷贝到每个构造方法的方法体的最前面(先执行初始化块中的代码,后执行构造器中的代码)
✏️ 在源代码中越靠前的初始化块放在构造器方法体的越前面
public class Whatever {
private double money = 9;
private int age = 9;
{
money = 1;
age = 3;
}
public static void main(String[] args) {
// 6.0
System.out.println(new Whatever().money);
// 666
System.out.println(new Whatever().age);
}
{
money = 0;
}
private Whatever() {
age = 666;
}
{
money = 7;
age = 2;
}
{
money = 6;
}
}
✏️ 初始化块会被拷贝到每个构造器方法体的最前面,所以每当创建一个对象,初始化块中的代码就会被执行一次
public class Whatever {
// 记录 Whatever 对象的个数
public static int instanceNum;
{
System.out.println("第" + ++instanceNum + "次调用初始化块");
}
public static void main(String[] args) {
Whatever whatever1 = new Whatever();
Whatever whatever2 = new Whatever();
Whatever whatever3 = new Whatever();
Whatever whatever4 = new Whatever();
Whatever whatever5 = new Whatever();
/*
第1次调用初始化块
第2次调用初始化块
第3次调用初始化块
第4次调用初始化块
第5次调用初始化块
*/
}
}
public class Whatever {
private static double money = 9;
private int age = 9;
{
System.out.println("2.Initializer 初始化块");
money = 2;
age = 888;
}
private Whatever() {
System.out.println("3.Constructor 构造器");
}
static {
System.out.println("1.Static 静态初始化块");
money = 1;
// ERROR: Non-static field cannot be referenced from a static context
// 非静态变量不能再在静态(static)环境中被引用
// age = 7;
}
public static void main(String[] args) {
Whatever whatever = new Whatever();
// 6.0
System.out.println("4." + whatever.money);
// 666
System.out.println("5." + whatever.age);
}
/*
1.Static 静态初始化块
2.Initializer 初始化块
3.Constructor 构造器
4.2.0
5.888
*/
}
📕 从上面的代码中可以知道:
✏️ 1. 静态初始化块只能对类变量做初始化操作;初始化块可以对实例变量和类变量做初始化操作
✏️ 2. 静态初始化块、初始化块、构造器三者的执行顺序是:① 静态初始化块;② 初始化块;③ 构造器【静态初始化块与静态初始化块之间按照在源代码中的出现顺序依次执行,初始化块和初始化块之间按照在源代码中的出现顺序依次执行】
✏️ 当类被加载的时候,静态初始化块会被调用。静态初始化块中的代码只会被执行一次 (因为类加载只有一次)
❓ 类什么时候被加载 ❓
✒️ ① 创建本类对象的时候(new)
✒️ ② 使用本类的静态成员(静态变量、静态方法)的时候
✒️ ③ 创建子类对象或使用子类的静态成员
❓【调用】这个词一般用在方法上,但官方教程中对初始化块也使用了【调用】这个词:
类什么时候会被加载?
public class Whatever {
private static final double PI = 3.14;
private static String poem = "人生自古谁无死?";
private int num;
static {
System.out.println("static{}: 静态初始化块在被类被加载的时候被调用一次(仅一次)");
}
{
System.out.println("{}: 创建第 " + ++num + " 个 Whatever 对象");
}
public static void staticMethod() {
System.out.println("call staticMethod()");
}
public static void main(String[] args) {
/*
static{}: 静态初始化块在被类被加载的时候被调用一次(仅一次)
call staticMethod()
*/
// staticMethod();
/*
static{}: 静态初始化块在被类被加载的时候被调用一次(仅一次)
3.14
*/
// System.out.println(PI);
/*
static{}: 静态初始化块在被类被加载的时候被调用一次(仅一次)
人生自古谁无死?
*/
// System.out.println(poem);
/*
static{}: 静态初始化块在被类被加载的时候被调用一次(仅一次)
{}: 创建第 1 个 Whatever 对象
HandsomeSon()
*/
// new HandsomeSon();
/*
static{}: 静态初始化块在被类被加载的时候被调用一次(仅一次)
大头儿子
*/
// System.out.println(HandsomeSon.sonName);
/*
static{}: 静态初始化块在被类被加载的时候被调用一次(仅一次)
调用了子类的静态方法
*/
// System.out.println(HandsomeSon.sonStaticMethod());
/*
static{}: 静态初始化块在被类被加载的时候被调用一次(仅一次)
{}: 创建第 1 个 Whatever 对象
*/
new Whatever();
}
}
class HandsomeSon extends Whatever {
public static String sonName = "大头儿子";
public HandsomeSon() {
System.out.println("HandsomeSon()");
}
public static String sonStaticMethod() {
return "调用了子类的静态方法";
}
}
静态初始化块中的代码只会在类被加载的时候被执行一次(静态初始化块只会在类被加载的时候被调用一次)
public class Whatever {
private static final double PI = 3.14;
private static String poem = "人生自古谁无死?";
private int num;
static {
System.out.println("static{}: 静态初始化块在被类被加载的时候被调用一次(仅一次)");
}
{
System.out.println("{}: 创建第 " + ++num + " 个 Whatever 对象");
}
public static void staticMethod() {
System.out.println("call staticMethod()");
}
public static void main(String[] args) {
/*
下面的代码都会致使类被加载
静态代码块只会在类被加载的时候被执行一次
*/
staticMethod();
System.out.println(PI);
System.out.println(poem);
new HandsomeSon();
System.out.println(HandsomeSon.sonName);
System.out.println(HandsomeSon.sonStaticMethod());
new Whatever();
}
/*
static{}: 静态初始化块在被类被加载的时候被调用一次(仅一次)
call staticMethod()
3.14
人生自古谁无死?
{}: 创建第 1 个 Whatever 对象
HandsomeSon()
大头儿子
调用了子类的静态方法
{}: 创建第 1 个 Whatever 对象
*/
}
class HandsomeSon extends Whatever {
public static String sonName = "大头儿子";
public HandsomeSon() {
System.out.println("HandsomeSon()");
}
public static String sonStaticMethod() {
return "调用了子类的静态方法";
}
}
✏️ 初始化块会被编译器拷贝到每一个构造方法的最前部,随着构造方法被调用而执行【只是使用类的静态成员并不会导致初始化块中的代码被执行】
❓ 创建一个类的对象的时候,类中的静态初始化块、静态变量初始化、初始化块、实例变量初始化、构造器的调用顺序…
📕 ① 静态变量初始化:在本篇文章第一节介绍过,可以编写一个私有的静态方法来进行类变量的初始化,以此来替代静态初始化块

📕 ② 实例变量初始化:在本篇文章第二节介绍过,可以使用被 final 修饰的实例方法实现实例变量的初始化(如下图)

✏️ ① 调用静态初始化块和静态属性初始化(当有多个静态初始化块和多个静态变量初始化的时候,按照它们在源代码中的顺序依次调用)
public class Whatever {
static {
System.out.println("静态初始化块 Three");
}
// getCount() 是静态属性初始化
private static double count = getCount();
private static double getCount() {
System.out.println("静态属性初始化_getCount()");
return 1;
}
static {
System.out.println("静态初始化块 One");
}
public static void main(String[] args) {
System.out.println(count); // 3.14159
/*
静态初始化块 Three
静态属性初始化_getCount()
静态初始化块 One
静态初始化块 Two
3.14159
*/
}
static {
System.out.println("静态初始化块 Two");
count = 3.14159;
}
}
public class Whatever {
private static double getCount1() {
System.out.println("静态属性初始化_getCount()1");
return 12580; // 【幺儿我帮你】
}
static {
System.out.println("静态初始化块 Three");
}
static {
System.out.println("静态初始化块 One");
}
public static void main(String[] args) {
System.out.println(count); // 209420.0
/*
静态初始化块 Three
静态初始化块 One
静态属性初始化_getCount()1
静态初始化块 Two
静态属性初始化_getCount2()
209420.0
*/
}
private static double getCount2() {
System.out.println("静态属性初始化_getCount2()");
return 209420; // 【爱你就是爱你】
}
// getCount() 是静态属性初始化
private static double count = getCount1();
static {
System.out.println("静态初始化块 Two");
count = 3.14159; // 【山巅一寺一壶酒】
// 静态属性初始化
count = getCount2();
}
}
✏️ It is not necessary to declare fields at the beginning of the class definition, although this is the most common practice. It is only necessary that they be declared and initialized before they are used.
📜 在类定义的开头声明字段并不是必须的,它只是一种常见的做法而已。必须的是:在使用它们之前,必须声明和初始化。
✏️ ② 调用初始化块和实例变量初始化(当有多个初始化块和多个实例变量初始化的时候,按照它们在源代码中的顺序依次调用)
public class Whatever {
public int getNum1() {
System.out.println("getNum1()");
return 6;
}
private int num = getNum1(); // getNum1 初始化块1 初始化块2 getNum2 getNum1
{
System.out.println("初始化块1");
num = 2;
}
public static void main(String[] args) {
// num = 528
System.out.println("num = " + new Whatever().num);
/*
getNum1()
初始化块1
初始化块2
getNum2()
getNum1()
num = 528
*/
}
{
System.out.println("初始化块2");
num = getNum2() + getNum1() + num; // 520 + 6 + 2
}
public int getNum2() {
System.out.println("getNum2()");
return 520;
}
}
✏️ ③ 调用构造方法
思考下面代码的打印结果:
public class Whatever {
private int num;
private int getNum1() {
System.out.println("getNum1()");
return 1;
}
static {
System.out.println("静态初始化块1");
brand = "小米";
}
private static String brand = getBrand();
static {
System.out.println("静态初始化块2");
brand = "三星";
}
public Whatever() {
System.out.println("public Whatever()");
}
{
num = 2;
}
public static void main(String[] args) {
/*
静态初始化块1
getBrand()
静态初始化块2
public Whatever()
8
三星
*/
System.out.println(new Whatever().num);
System.out.println(Whatever.brand);
}
private int getNum2() {
return (int) Math.pow(num, 3);
}
private static String getBrand() {
System.out.println("getBrand()");
return "华为";
}
{
num = getNum2();
}
}
✏️ 构造器方法体的最顶部隐含了 super() 和初始化块
✏️ 静态初始化块和静态属性初始化在类加载时执行完毕
class Apple {
public Apple() {
// (1) 隐含 super();
// (2) 隐含初始化块
System.out.println("public Apple() { }");
}
}
思考下面代码的执行结果:
public class Whatever {
public static int n = getN(); // n = 27
public Whatever() {
// 1.super()
// 2.初始化块
n = getN() + 3; // n = 30
System.out.println("4.Whatever_n_" + n);
System.out.println("5.public Whatever()");
}
private static int getN() {
return (int) Math.pow(3, 3);
}
{
System.out.println("3.愿万事顺心");
cnt = 56;
}
static {
System.out.println("1.n = getN() + n");
n = getN() + n; // n = 27 + 27 = 54
}
private int cnt = 2;
public static void main(String[] args) {
new Apple();
}
}
class Apple extends Whatever { // num = 5
private static int num = 5;
{
System.out.println("6.Apple 初始化块");
}
private int count;
public static int getNum(int n) {
return n;
}
public Apple() {
// 1.super()
// 2.初始化块
System.out.println("7." + (getCount() + num + count + n)); // 31 + 5 + 2 + 30 = 68
System.out.println("8.public Apple()");
}
{
count = 1;
}
static {
System.out.println("2.getNum(6 + num)");
getNum(6 + num);
}
public int getCount() {
return n + count++;
}
}
🥤 自己总结的过程:
① 父静态初始化块(静态属性初始化)
② 子静态初始化块(静态属性初始化)
③ 父初始化块(实例属性初始化)
④ 父构造器
⑤ 子初始化块(实例属性初始化)
⑥ 子构造器
父静 子静 父初 父构 子初 子构

🍀 父静、子静、父初、父构、子初、子构
🍀 【谐音】父进、子进、父出、父go、子出、子go
🍀 看着上面的图片,并想象一个场景:
✒️ 父亲先进入电梯 (父类的静态初始化块和静态属性初始化)
✒️ 孩子后进入电梯 (子类的静态初始化块和静态属性初始化)
✒️ 父亲先出电梯 (父类的初始化块和实例属性初始化)
✒️ 父亲 go 了 (父类的构造器)
✒️ 孩子后出电梯(子类的初始化块和实例属性初始化)
✒️孩子也 go 了(子类的构造器)
思考下面代码的打印结果:
public class Whatever {
public static void main(String[] args) {
/*
1.getVal1()
2.A 静态初始化块1
3.getVal3()
4.B 的静态初始化块1
5.A 初始化块1
6.getVal2()
7.A 构造器
8.getVal4()
9.B 的初始化块1
10.B 的构造器
*/
new B();
}
}
/**
* 父类
*/
class A {
private static int n1 = getVal1();
static {
System.out.println("2.A 静态初始化块1");
}
{
System.out.println("5.A 初始化块1");
}
public int n3 = getVal2();
public static int getVal1() {
System.out.println("1.getVal1()");
return 10;
}
public static int getVal2() {
System.out.println("6.getVal2()");
return 10;
}
public A() {
System.out.println("7.A 构造器");
}
}
/**
* 子类
*/
class B extends A {
private static int n3 = getVal3();
static {
System.out.println("4.B 的静态初始化块1");
}
public int n5 = getVal4();
{
System.out.println("9.B 的初始化块1");
}
public static int getVal3() {
System.out.println("3.getVal3()");
return 10;
}
public static int getVal4() {
System.out.println("8.getVal4()");
return 10;
}
public B() {
// super();
// 初始化块
System.out.println("10.B 的构造器");
}
}
看下面的代码,思考打印结果;
public class Whatever {
public static void main(String[] args) {
// Static Initialization Block
// total: 8989
System.out.println("total: " + Money.total);
// total: 8989
System.out.println("total: " + Money.total);
}
}
class Money {
public static int total;
static {
total = 8989;
System.out.println("Static Initialization Block");
}
}
📕 使用类中的静态成员会导致类加载,进而静态初始化块中的代码会执行
📕 静态初始化块中的代码会在类加载的时候执行一次
public class Whatever {
public static void main(String[] args) {
// 【output:】
// Money(String): StaticMoney
// Static Initialization Block
// Money(String): Money
// House()
new House();
}
}
class House {
Money money1 = new Money("Money");
static Money money2 = new Money("StaticMoney");
static {
System.out.println("Static Initialization Block");
if (money2 == null) System.out.println("money is null");
}
House() {
// super()
// 初始化块
System.out.println("House()");
}
}
class Money {
Money(String s) {
System.out.println("Money(String): " + s);
}
Money() {
System.out.println("Money()");
}
}
再见!如有错误,请不吝赐教
在我的gem中,我需要yaml并且在我的本地计算机上运行良好。但是在将我的gem推送到rubygems.org之后,当我尝试使用我的gem时,我收到一条错误消息=>"uninitializedconstantPsych::Syck(NameError)"谁能帮我解决这个问题?附言RubyVersion=>ruby1.9.2,GemVersion=>1.6.2,Bundlerversion=>1.0.15 最佳答案 经过几个小时的研究,我发现=>“YAML使用未维护的Syck库,而Psych使用现代的LibYAML”因此,为了解决
我在Rails工作并有以下类(class):classPlayer当我运行时bundleexecrailsconsole然后尝试:a=Player.new("me",5.0,"UCLA")我回来了:=>#我不知道为什么Player对象不会在这里初始化。关于可能导致此问题的操作/解释的任何建议?谢谢,马里奥格 最佳答案 havenoideawhythePlayerobjectwouldn'tbeinitializedhere它没有初始化很简单,因为你还没有初始化它!您已经覆盖了ActiveRecord::Base初始化方法,但您没有调
我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/
我有用于控制用户任务的Rails5API项目,我有以下错误,但并非总是针对相同的Controller和路由。ActionController::RoutingError:uninitializedconstantApi::V1::ApiController我向您描述了一些我的项目,以更详细地解释错误。应用结构路线scopemodule:'api'donamespace:v1do#=>Loginroutesscopemodule:'login'domatch'login',to:'sessions#login',as:'login',via::postend#=>Teamroutessc
我正在阅读一本关于Ruby的书,作者在编写类初始化定义时使用的形式与他在本书前几节中使用的形式略有不同。它看起来像这样:classTicketattr_accessor:venue,:datedefinitialize(venue,date)self.venue=venueself.date=dateendend在本书的前几节中,它的定义如下:classTicketattr_accessor:venue,:datedefinitialize(venue,date)@venue=venue@date=dateendend在第一个示例中使用setter方法与在第二个示例中使用实例变量之间是
我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www
我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我
什么是ruby的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht
这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/
HashMap中为什么引入红黑树,而不是AVL树呢1.概述开始学习这个知识点之前我们需要知道,在JDK1.8以及之前,针对HashMap有什么不同。JDK1.7的时候,HashMap的底层实现是数组+链表JDK1.8的时候,HashMap的底层实现是数组+链表+红黑树我们要思考一个问题,为什么要从链表转为红黑树呢。首先先让我们了解下链表有什么不好???2.链表上述的截图其实就是链表的结构,我们来看下链表的增删改查的时间复杂度增:因为链表不是线性结构,所以每次添加的时候,只需要移动一个节点,所以可以理解为复杂度是N(1)删:算法时间复杂度跟增保持一致查:既然是非线性结构,所以查询某一个节点的时候