尽管以C++为基础,但是Java是一种更加纯粹的面向对象的程序设计语言。
1.1用引用(句柄)操纵对象
尽管将一切都看作“对象”,但操纵的标识符实际是指向一个对象的“句柄”(引用)。
安全的做法:创建一个句柄的时候,无论如何都要进行初始化:
String str="abc";
1.2所有对象都必须创建
String s=new String("abc");
1.3 保存到什么地方
有五个地方可以保存数据
寄存器:最快的保存区域,保存在处理器内部,寄存器数量有限,根据编译器分配。我们没有直接的控制权,也不可能在程序里找到他存在的踪迹。
堆栈:仅次于寄存器,存储在常规的RAM(随机访问存储器)区域,可以通过“堆栈指针”获得处理的直接支持。堆栈指针下移会创建新的内存,上移,则会释放那些内存。java编译器必须知道它存储所有数据的长度以及存在时间。由于他必须生成相应的代码以便上移和下移,影响灵活性,尽管有些java数据保存里(特别是对象句柄),但Java对象并不放在其中。
堆:常规用途的内存池(在RAM区域),用于存放所有的java对象,堆不同于栈的好处是:编译器不需要知道数据的存活时间。因此,在堆里面分配存储具有很高的灵活性。但是在堆里面进行分配存储和清理数据,会比在堆栈里面耗时。
常数存储
非RAM存储
作用域
1。基本类型与对象的作用域区别?
{
int x = 12;
String s = new String("a string");
}//End of scope
Java 中变量的作用域由花括号的位置决定。
对于基本类型,比如上面的 x ,一旦超出作用域,其生命周期就完结了,内存被释放。
对于对象,只会释放在作用域内定义的引用。比如上面创建的引用 s 在作用域终点就消失了,但指向的 String 对象仍然占据内存。如果在花括号内有把引用传递出去,String 对象仍是可用的,否则就继续占着内存直至被垃圾回收器回收。
句柄s 会在作用域的终点处消失,然而,s指向的String 对象依然占据着内存空间,这段代码,我们就无法访问对象,因为它指向的唯一一个句柄已经在作用域的终点消失,这样就会产生,只要我们愿意new创建的对象,只要我们愿意,就会一直保留下去,一直占据着内存空间,得不到释放,
Java提供了一个特别的机制,“垃圾收集器”,它会查找出不被引用的new对象,释放那些占用的内存空间。
垃圾回收机制,只知道释放那些new分配的对象的内存,Java还提供了一种未解决特殊内存释放的方法,finalize(),他会再垃圾回收期间提前进行一次重要的垃圾清除。
finalize():
用途:垃圾清除只跟内存有关!
2.为什么一般不要用finalize,什么时候会用到finalize?
finalize 在垃圾回收时刻提供一个清理占用的资源(特殊内存)的机会;
垃圾回收只与内存有关;
所有对象占据的内存最后都由垃圾回收器负责释放;
Java 中一切都是对象。
既然一切都是对象,那这种特殊情况是什么鬼?
这种情况是由于分配内存时采用了类似C语言中的做法,而非Java中的通常做法,一般发生在使用“本地方法”的情况下。比如,在本地 C 方法中,可能调用了 malloc() 函数系列。
所以喽,一般不要用 finalize 的意思是,没有用本地方法你就基本不要用 finalize。
初始化与清理
1.为什么不能用返回值区分重载方法?
假设可以
void howAreYou(){}
int howAreYou(){
return 0;
}
void whenCanILeave(){
howAreYou();
}
事实上我们经常处于这种情况——不关心返回值是什么,只是需要调用这个函数。这时候编译器就识别不出你要调用的到底是哪个了。所以必须依靠参数来标识一个函数。
2.对象的初始化顺序?
Java 尽力保证所有变量在使用前都能得到恰当的初始化。基于这样的思想,类的内部变量定义,即使散步于方法定义之外,仍旧会在任何方法(包括构造器)被调用前得到初始化。
明白这点,对象的初始化顺序就很容易理解了:
父类静态变量与代码块-->子类静态变量与代码块-->父类非静态变量与代码块-->父类构造器--> 子类非静态变量与代码块-->子类构造器。
复用类
1.类的代码在初次使用时才会加载
每个类的编译代码都存在于它自己的独立文件中,该文件只在需要使用程序代码时才会被加载。
这个原理的常见应用是结合静态内部类实现延迟加载的单例模式:
public class Singleton {
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
2.final的三种情况:数据、方法和类。
final 数据:告知编译器这块数据是恒定不变的。final 修饰基本类型时很好理解,修饰对象的时候又怎么样呢?效果是使得引用不可变,即无法指向另一个对象,但对于正在指向的对象自身的内容是可以改变的。
final 方法:用来锁定方法,确保方法不会被覆盖。在早期 final 方法还可用来提升效率,但现在已经不提倡了。所以,只有在想明确禁止覆盖的时候,才将方法设置为 final。
private 方法默认隐式指定为final, 无法被继承;如果子类定义相同名称和参数的方法等同于生成了新的方法,没有覆盖父类设置了final的方法。
final 类:类不可继承。