对象创建过程
- 首次创建对象时或者对象的静态方法或静态属性被首次访问,Java解释器查找类路径,定位ClassName.class文件
- 载入ClassName.class(创建一个对象),所有静态初始化动作执行(首次使用这些动作或属性时),并且所有静态初始化动态只在此时执行一次
- 当new ClassName()创建对象时,首先在堆为className对象分配足够的内存空间
- 相对应的内存空间清零,className对象的所有基本数据类型设置默认值,引用型设置为NULL,进行初始化
- 执行所有出现在字段定义处的初始化动作,例如bowl3被赋予指向Bowl3对象的引用
- 执行构造器
对象
- 非内部类不能使用private或者protected修饰符
- 数组是不能指定长度的,只能获取引用
int[] nums = new int[4];其中 int[] nums里的[]里面不能填入数字所谓的数组长度其实是一个误区,new int[4]开辟了一个 4*4的内存块,这里才是长度,但这是内存的长度nums所做的只是获取这个内存的引用,即获取这块内存的位置所以说数组是无法指定长度的
所以下面这个数组扩充操作就很容易理解了 通过copyOf()函数实现数组长度扩充 source=Arrays.copyOf(source,source.length+mount) eg: int[] nums = new int[4]; nums = Arrays.copyOf(nums,nums.length+3); 这里其实是创建了两个数组内存,第一次是new int[4],然后nums获取了这块内存的地址 然后copyOf()创建了新数组内存,长度为原数组长度+3,并获取原数组的地址 然后将新内存的地址重新赋值给nums实例代码:public class Arrays { public static void main(String[] args) { String[] strings = new String[] { "asd", "fhd", "asd", "fdk" }; for (int i = 0; i < strings.length; i++) { System.out.println(strings[i] + "的hash值:" + strings[i].hashCode()); } strings = Arrays.copyOf(strings, strings.length + 1); strings[4] = "1243"; System.out.println("--------------------------"); for (int i = 0; i < strings.length; i++) { System.out.println(strings[i] + "的hash值:" + strings[i].hashCode()); } }}结果:asd的hash值:96882fhd的hash值:101346asd的hash值:96882fdk的hash值:101229--------------------------asd的hash值:96882fhd的hash值:101346asd的hash值:96882fdk的hash值:1012291243的hash值:1509472结果分析:结果符合预期,而且发现原来的string数组元素的hash值和后面的是一样的更加说明了java所有变量都是对常量引用
属性(类变量)
- 可以直接在定义时赋值初始化
class Test{ public int i = 9;}
- 可以通过调用其他函数进行初始化
- 类变量系统会自动赋值,甚至先于构造函数赋值
class Test{ public int i;//系统自动赋值i=0; Test{ i=8; //i从0重新赋值为8 }}
- 属性(类变量)一定先于方法调用之前赋值,无论变量在哪定义
class Test{ public int i;//系统自动赋值i=0; Test{ i=8; //i从0重新赋值为8 } int m = 9; //先于Test()赋值}
- 静态成员变量在且仅在第一次使用的时候初始化,初始化顺序为先静态变量,后静态方法,存放在方法区
- 成员变量和局部变量的变量名可以相同
- 变量在同名时采取的是就近原则
int i =3;void fun(){ int i =6;//合法 }int m =3;void f(int m){ m = m; //m != 3,这里的两个m都是形参带来的m }
构造方法
- 构造方法是超类开始执行的
示例代码:
public class PowerOfExtrend { public static void main(String[] args) { son son = new son(); }}class grandFather{ public grandFather() { System.out.println("grandFather!"); }}class father extends grandFather{ public father() { System.out.println("father!"); } }class son extends father{ public son() { System.out.println("son!"); }}结果:grandFather! father! son!结果分析:在子类的构造方法内部,系统会自动在最前面添加super();来调用父类的构造方法,所以构造方法的执行是从祖先类开始的,一直到当前类
权限
注意:为了清楚起见,应按public,protected,default,private来排列成员
- 每个编译单元(文件)都只能有由一个public类,表示没有编译单元都由单一的公共接口(public class),如果出现超过一个,则编译器会报错
- puiblic class 的名称必须完全和该编译单元的文件名相同,包括大小写
- 虽然不常用,但一个编译单元是可以没有任何public类,这种情况下可以随意给编译单元命名
初始化
初始化的4中方法
- 在定义对象的初始化,这意味着变量将在构造器调用被初始化
- 在类的构造器中初始化
- 在使用对象之前,这种方式被称为惰性初始化,这种方式可以减小额外的负担,使用函数调用来初始化。
*惰性初始化:当需要一个实例的时候才初始化一个对象。新建两个简单的类,第二个类中包含第一个类的一个引用,当需要第一个类的对象是调用Lazy()方法即可获得第一个类的对象。*/class Object1{ int i;}public class Object2{ Object1 oj1 ; public void print(){ if(oj1==null) oj1 = new Object(); } public static void main(String[] args){ Object2 object2 = new Object2(); object2.print(); }}
- 使用实例初始化
继承
Java中的继承与c++不同,java中的类的变量和方法继承后权限是不变的
示例代码:
public class PowerOfExtrend { public static void main(String[] args) { son son = new son(); son.power(); }}class grandFather{ protected int i =18; protected void power(){ System.out.println("grandGather!"); System.out.println("i="+i); }}class father extends grandFather{ @Override protected void power() { System.out.println("father!"); System.out.println("i="+i); }}class son extends father{ @Override protected void power() { System.out.println("son"); System.out.println("i="+i); }}结果: son i=18结果分析: 子类father继承了父类grandFather的protected变量i和prote方法power(), 但father的子类son还是可以访问protected变量i和prote方法power(), 没有出现因为继承而权限缩小,而导致grandFather类的孙类son无法访问 grandFather类相关方法和变量的问题
方法
- 静态方法是无法使用静态方法做参数的,会出现编译错误,但可以使用静态变量作为参数
代码:
public class Customer { static int m =34; public static void main(String[] args) { f1(); // f2(); } public static int f1() { System.out.println(m); return 1; } /* 会报错 public static void f2(int f1()) { System.out.println("1"); } */}结果:34