详谈Java的五个基础知识


1、数组
定义数组时不能指定数组的长度。
foreach
当使用foreach 来迭代访问数组元素时,foreach中的循环变量相当于一个临时变量,整个临时变量并不是数组元素,它只是保存了数组元素的值(深复制),因此如果希望改变数组元素的值,则不能使用这种foreach循环。

栈内存和堆内存之分
当一个方法执行是,每个方法都会建立自己的内存栈,在这个方法内定义的变量将会逐个放入这块栈内存里,随着方法的执行结束,这个方法的内存栈也将被销毁,因此,所有在方法定义的变量都是放在栈内存中的。
当我们在程序中创建一个对象时,这个对象将被保存到运行时数据区中,这个运行时数据区就是堆内存。只有当一个对象没有任何引用变量引用它时,才会在合适的时机回收它。

2、面向对象
this可以代表任何对象,当this出现在某个方法体中时,它所代表的对象是不确定的,但它的类型是确定的,它所代表对象只能是当前类;只有当这个方法被调用时,他所代表的对象才能被确定下来。
static 修饰的方法中不能使用this引用,所以static修饰的方法中不能访问没有使用static修饰的普通成员。static 用来修饰方法和属性等成员。局部成员的上已经程序单元是方法不是类,使用static修饰它们是没有意义的,所以局部成员都不能使用static修饰,
在构造器中使用this引用时,this总是引用该构造器正在初始化的对象。
方法本身是指令的操作码部分,保存在stack中,方法内部变量作为指令的操作数部分,跟着指令的操作码之后,保存在stack中(实际是简单类型保存在stack中,引用类型在stack中保存地址,在heap中保存值)。
对象实例以及非静态属性保存在heap中的,而heap必须通过stack中的地址指针才能够被指令(类的方法)访问到。静态属性保存在stack中(这是网上找到的说,笔者认为应该是静态属性的地址保存在stack中)。
非静态方法有一个隐含的传入参数,该参数是JVM给的,和我们的代码无关,这个隐含参数就是对象实例在stack中的地址指针(this)。因此非静态 方法(在stack中的指令代码)总是可以找到自己专用数据(在heap中的对象属性值)。当然非静态方法也必须获得该隐含参数,因此在调用非静态方法之 前,必须先new一个对象实例,获得stack中地址的指针,否则JVM将无法将隐含参数传给非静态方法。而静态方法无需此隐含参数,因此不需要new对 象,只要class文件被ClassLoader load进入JVM的stack,该方法即可被调用,当然此时静态方法存取不到heap中的对象属性的。

3、形成长度可变的方法
public void test(int a, String… books){}
可以传入多个字符串参数作为参数值,其实是可以看着参数数组。但一个方法只能有一个长度可变的形成且位于形参列表的最后。

4、方法重载
方法的重载要求:两同(同一个类中的方法名相同),一不同(参数列表不同)(不建议使用长度可变的形参重载方法),跟方法的其他部分(返回值类型(有时我们调用方法时不需要返回值,就不能根据返回值类型来确定到底是调用哪个方法),修饰符等)没有任何关系。
系统在第一次使用类加载类,并初始化类。类属性从这个类准备阶段起开始存在。系统不会为局部变量执行初始化,局部变量在访问之前一定要确定是已经初始化。
模块设计追求高内聚(尽可能把模块的内部数据,功能实现细节隐藏在模块内部独立完成,不允许外部直接干预),低耦合(仅暴露少来的方法给外部使用)

构造器
如果我们提供了自定义的构造器,系统不再提供默认的构造器,通常我们都保留无参数的默认构造器。

多态性
当编译时类型和运行时类型不一致,就会出现所谓的多态。
当把子类对象赋给父类引用变量时,被称为向上转型,这个总是可以成功的,但把一个父类对象赋给一个子类引用变量时,就需要强制类型转换,而且还可能在运 行时产生ClassCastException异常(当这个父类对象编译时类型为父类类型,运行时类型是子类类型才是正确的),使用instanceof 运算符可以让强制类型转换更安全。

Instanceof 运算符
a instanceof B a必须是具体的实例,B是一种类(或接口),可以是数组
如果A是编译时能够确定具体的类型,那么Instanceof 运算符前面操作数的编译时类型要么与后面类(接口,抽象类)相同,要么是后面类的父类,(即可以通过类型转换(B)a到B的,不能通过(B)a转换到B的 可以,转换到它们共有的父类如(Object)a,但仍返回false),否则会引起编译错误。如果要运行时才确定类型(如何调用函数 getObject()返回对象等,但new String()这个在编译时就会确定下类型,因为String Integer等类被final修饰,所以编译时就确定类型),没有这样的限定。
B不能是确定的泛型参数的泛型,可以是 List或者 List
Instanceof 运算符前面的对象是否是后面的类,或者其子类。实现类的实例。如果是,就返回true,否则返回false,若a是null则返回false。
经过instanceof 运算符判断一个对象是否可以强制类型转换,然后在使用(type)运算符进行强制转换,从而保证程序不会出现错误。

5、初始化块,构造器质性顺序
当Java创建一个对象时,系统先为该对象的所有实例属性分配内存(前提是该类已经被加载过了),接着程序开始对这些实例属性执行初始化,其初始化顺序是:先执行初始化块或声明属性是指定的初始化值,然后执行构造器里指定的初始值。
类初始化阶段:(类初始化只执行依次,然后会在虚拟机一直存在)
先执行最顶层父类的静态初始化块,依次向下,最后执行当前类的静态初始化块
对象初始化阶段:(每次创建实例对象是都要进行)
先执行最最顶层父类的初始化块,构造器,依次向下,最后执行当前类初始化块。
构造器。
初始化块和声明指定初始化值,他们的执行顺序与源代码中的排列顺序相同。
基本类型之间的转换
Xxx parseXxx(String s) 将字符串类型转换成基本类型(除了Character之外)
String 中的valueOf() 将基本类型转换成字符串。

相关教程推荐e良师益友网的Java教程