类和对象的初始化问题
初始值
public/private 数据类型 变量名=初始值
初始化块
{
初始化内容
}
/*
非静态初始化块:
作用:给对象进行初始化。对象一建立就运行,且优先于构造函数的运行。
与构造函数的区别:非静态初始化块给所有对象进行统一初始化,构造函数只给对应对象初始化。
应用:将所有构造函数共性的东西定义在构造代码块中。
*/
静态初始化块
static{ 初始化内容 }
/*
静态初始化块:
作用:给类进行初始化。随着类的加载而执行,且只执行一次
与构造代码块的区别:
1)构造代码块用于初始化对象,每创建一个对象就会被执行一次;静态代码块用于初始化类,随着类的加载而执行,不管创建几个对象,都只执行一次。
2)静态代码块优先于构造代码块的执行
3)都定义在类中,一个带static关键字,一个不带static
*/
构造函数
类名(形参){ 初始化 }
以上几种初始化比较,首先静态初始化块和字段的默认初始值在创建类的时候就执行了,因此只执行一次,在创建对象过程中不再执行,构造函数和初始化块是在创建对象的时候执行的,并且构造块比构造函数先执行,如果同时有静态初始化块和初始值,就看它们的出现的顺序
初始化块都是自动调用的
所以静态初始化块=静态初始值>初始化块>构造函数,如果有子类,则父类的初始化会先执行
如何在静态方法中访问类的实例成员
可以在该方法中定义本类的对象去通过对象调用类中的实例成员
关于为什么能在本类的方法中定义本类的对象
首先在本类中创建直接的对象有两种情况,一种是是在代码层面调用了自身(这种会陷入无限递归循环),还有一种是在编译层面调用自身
java的执行过程是:当程序载入时,读取了该java文件,将静态方法读到到了内存中的静态方法保存区域,将class读到了类的区域,注意:这时候的class并没有创建实例对象,内存中只是有了创建class的机器了。接下来main方法作为程序的入口方法被执行(这是只有方法没有实例对象),方法中调用了class的机器生产了一个A对象,再将A对象装载到内存中。说明编译层面其实并没有创建对象,只是告诉程序这里需要有一个对象,所以没有陷入递归。
例如
class A{ public A a=new A() /*或者 { A a=new A()}*/ } class text{ main(){ A aa=new A() } } //这样在创建对像aa时会创建对象aa中a,创建对象a时又会创建对象a中的a这样就会无限递归循环下去
class A{ public static A a=new A() /*或者 static { A a=new A()}*/ public void name(){A a=new A();} } class text{ main(){ A aa=new A()//因为静态变量是储存在类中的,因此所有对象共享的 aa.show();//只调用一次方法,在方法中创建一次对象,如果方法里面有a.show()则也会陷入无限递归 } }
Integer的特性
- IntegerCache
JSL规定IntegerCache为Integer类的缓存类,默认缓存了-128~127的Integer 值,如遇到[-128,127]范围的值需要转换为Integer时会直接从IntegerCache中获取。同时,我们可以通过设置java.lang.Integer.IntegerCache.high来设置缓存最大值
-Djava.lang.Integer.IntegerCache.high=255
Integer的边界问题
通过引入补码,计算机的加减运算简化为了简单的相加,数值在计算机内存中也以补码的形式存储。
原码 => 补码: 取反加一(符号位不参加运算)
补码=> 原码: 取反加一(一般情况下,符号位不参加运算)
在补码中,1000不再表示负零,而是-8。所以给定n位存储长度,可以表达数值范围为-2的n次方到2的(n-1)次方。
在计算机数值计算时,需要考虑数值精度是否一致和是否有溢出。
- 数值超过数据类型支持最大精度溢出后,计算结果出错(不仅仅是丢失进度)
- 数值计算,结果精度就最大的精度
- Integer计算需要考虑是否有缓存