一、构造器自动初始化
创建对象时,自动调用,不能像普通方法调用(不能和构造器里调用其他构造器混淆。构造器里调其他构造器目的是减少冗余代码。不考虑内部情况,整体上还是构造器)
构造器是个特殊的方法,从方法角度讲:构造器的作用是初始化,是没有返回值的(但和);方法名要让编译器知道,所以与类名相同;自定义变量列表可以根据实际情况进行重载。
默认构造器
若不显式写,会有默认的构造器;若显式写(即使没有自变量列表),则不会生成默认构造器。
new classA(); 作用:创建一个对象,并自动调用构造器初始化对象。
classA a=new classA();作用:创建一个对象,并自动调用构造器初始化对象。将句柄指向该对象
this关键字(当前对象):this只能在方法内使用
方法执行是如何确定哪个对象的?
编译器的操作pick(a) 会将对象作为参数传入方法中,从而知道是对哪个对象的操作
类中一个方法(不是构造器)内部调用另一个方法,this可以不加(因为this已作为参数传入方法,明确了是对哪个对象进行操作)
在构造器里调用其他构造器
若一个类写了多个构造器,那么经常需要在构造器里调用其他构造器,避免重复代码 (必须写在第一行)
形参与成员数据同名,区分
通过this返回当前对象的句柄
理解了this关键字,可以更加完整的理解static方法。它意味着一个特定的方法没有this。我们不可从static方法内部发出对非static方法的调用(非static方法可以调用static方法)。不依赖对象,可从类本身发出对一个static方法的调用(这是static的基本含义)
)“由于static不需要创建任何对象,所以不可直接简单的调用其他成员,也不可引用一个已命名的对象,从而直接访问非static成员或方法。
二、成员初始化
数据成员(字段):包含静态、非静态
java尽自己的全力保证所有变量在使用前得到正确的初始化。
- 基本数据类型
各种类型有自带的默认值(因为任何方法都可以正确的初始化这个数据。有时此数据不同情况下赋值不同,所以强制初始化是不合理的,从而赋值为类型默认值)
与局部变量不同,局部变量只定义,并不会有默认值(是随机值)。为了确保使用前得到正确初始化,会有编译错误 - 句柄:默认值是null(什么也没有)
若不对其初始化,则直接使用,则会有空指针异常(即没有对象)java.lang.NullPointerException
总结:数据成员没有要求定义就初始化的原因?
数据成员可以在运行时(构造器、调用方法)初始化,更加灵活。
三、构造器初始化
初始化顺序:定义时初始化早于构造器初始化
在这个例子中,句柄t3初始化了2次:一次是定义时;一次是构造器,此时第一次的对象会被清理掉。似乎降低了效率,但能保证正确的初始化。若两处都没初始化,则使用会出现空指针异常。
静态数据的初始化
上图中若不创建Table对象或者Table.b1(2),则Table中静态数据t1、t2永远不会创建。若创建,则只创建1次。
总结一个类中初始化的创建顺序,假设为Dog
①对象首次创建或者static字段/方法首次访问时,java解释器必须找到Dog.class(编译会生成此文件)
②找到Dog.class后(它会创建一个Class对象),它的所有static初始化模块运行。因此,static初始化仅发生一次,即在Class对象首次载入的时候。
③创建new Dog()时,Dog对象的构建进程首先会在内存堆里为Dog对象分配空间
④这种空间会清为0,将Dog中的所有基本数据类型(这里已经是非静态了)设为他们的默认值(0用于数字,boolean和char等价设定)
⑤进行字段定义时发生的所有初始化都会执行
⑥执行构造器。实际要有相当多的操作,特别涉及到构造器时候
四、数组初始化
数组代表一系列相同的对象或者基本数据类型
- 基本数据类型 int[] a={1,2,3}、int[] a=new int[]{1,2,3}
int [] a=new int[3],这种情况初始值为基本数据类型默认值 - 引用类型(对象) Integer[] a1={new Integer(1)}; Integer[] a1=new Integer[]{new Integer(1)};
Integer[] a=new Integer[1]; 初始化为null - 有时只是创建句柄,因为可以引用赋值,从而指向同一个对象。a2=a1
有时数组的长度是不确定的(即运行时确定数组长度),则可以只创建句柄: - 对相同类型的理解(所有类型的父类均是Object,父类可以指向子类对象,子类只是细分)
Object[] o={new Integer(1),new classA()};