初始化
初始化顺序为
静态对象——非静态对象——构造器
构造器
构造器实际上是一个静态方法
既然是方法那就可以重载
在传参数时,如果形参是long类型,实参可以是int类型。此处与计算时小范围向大范围转类似(都是为了避免数据遗失)
小知识点:构造器可以调用重载的构造器(使用this关键字)但是必须在起始位置并且只能调用一个别的构造器
class People{
String name;
int age;
public People() {
this("龟龟侠");
// this(18);//只能调用一个构造
// TODO Auto-generated constructor stub
print();
}
public People(String name){
System.out.println("name:"+name);
}
public People(int age){
System.out.println("age:"+age);
}
public void print(){
System.out.println("我是print方法");
}
}
成员初始化
在类中每个成员变量都会进行初始化,基本数据类型有其默认值,对象则默认为null。
非静态数据(比构造器先执行)
int 默认值为0,name先赋值为"hello"之后再进入构造器
class People{
String name = "hello";
int age;
public People() {
System.out.println(name);
System.out.println(age);
// this(18);
/* 打印
hello
0
*/
}
}
成员初始化还可以写成(使用代码块,静态数据可以使用静态代码块):
class People{
String name;
int age;
{
name = "hello";
age = 18;
}
public People() {
System.out.println(name);
System.out.println(age);
// this(18);
}
/* 打印
hello
18
*/
}
静态数据初始化(比非静态先执行)
使用关键字static,并且static不能作用于局部变量,只能作用于域。
class People{
static String COUNTRY = "国家";
String name;
int age;
{
System.out.println("进入代码块");
System.out.println(COUNTRY);
name = "hello";
age = 18;
}
static{
System.out.println("进入静态代码块");
// System.out.println(age);不能访问非静态资源,可以在此处为静态数据初始化
}
public People() {
System.out.println("进入构造器");
System.out.println(name);
System.out.println(age);
// this(18);
}
}
/*打印结果
进入静态代码块
进入代码块
国家
进入构造器
hello
18
*/
以上可以看出初始化先后顺序应该是
静态数据——> 非静态数据 ——>构造器
静态数据是所有同类对象共享的而非静态数据则是每个对象都有属于自己的成员变量。
静态代码块中的代码只执行一次,代码块中的代码必须每次创建对象都要执行。
清理
finalize()方法的用途
java中的内存释放是由java虚拟机控制的,在发生垃圾回收时先执行finalize方法然后再在下一次垃圾回收时释放资源。所以finalize方法可以在销毁这个对象时做一些事情。
finalize方法的一种用途释放资源——但是既然垃圾回收机制是释放资源的哪finalize方法还能释放什么资源呢?都应该知道在很多时候一个项目有可能不会只用一种语言编写。java中就有本地方法的api和调用js的引擎。java虚拟机就不能释放这些非java程序的资源了。
小知识点:当JVM并未面临内存耗尽的情况它并不会花时间去执行垃圾回收回复内存。(对象可能不被回收)
public class 清理 {
public static void main(String[] args) {
Book novel = new Book(true);
novel.checkIn();
new Book(true);// 意图有一个没有引用的类被视为垃圾
System.gc();// 强制进行终结动作
/*打印结果
Error: checked out
*/
}
}
class Book{
boolean checkedOut = true;
public Book(boolean checkOut) {
checkedOut = checkOut;
}
void checkIn(){
checkedOut = false;
}
protected void finalize(){
// 垃圾回收时先调用finalize方法
if (checkedOut) {
System.out.println("Error: checked out");
}
}
}
垃圾回收机制工作原理
java回收器可以提高创建对象的速度:在某些虚拟机中堆的实现有时候更像是传送带,没分配一个对象就往前移动一格。它工作时,将一边回收空间,一边使堆中的对象紧密排列。通过垃圾回收器对对象重新排列,实现一种高速的、有无限空间可供分配的堆模型。
垃圾回收机制
引用计数(简单但速度很慢):
对象没被引用一次引用计数加一,当引用离开作用域或被置null时减一。当引用计数为0时则释放所占用的空间。
缺陷:
当出现循环引用时可能出现“对象应该被回收但计数不为0”
A a = new A();
B b = new B();
a.instance = b;
b.instance = a;
a = null;
b = null;
// 虽然a、b都置空了但计数不为0
自适应垃圾回收机制
“停止—复制”:先暂停程序,将所有存活的对象从当前堆复制到另一个堆并且紧凑排列,然后还要修正对应引用(因为对象从旧堆移到了新堆)。
缺陷:因为需要维持两个堆,效率变低且维护变困难,为了优化有些虚拟机按需从堆中分配几块较大的内存,将复制动作发生在这些大块之间。
还有就是由于要复制(占用太多资源),引入“标记—清理”的方法。
“标记—清理”(也需要停止程序):先从堆栈和静态存储区域出发,遍历所有的引用,进而找出所有的存活对象,每个存活对象设置一个标记,当全部标记完成后,清理所有被未标记的对象。(因为只是释放了空间,并未整理所以堆中的对象并不紧凑。如果希望得到连续的空间就需要进行整理剩下的对象)
如果所有对象稳定,垃圾回收效率降低就切换到“标记—清理”,如果堆空间出现很多碎片就切换到“停止—复制”。这就是自适应技术。
自适应寻找“活对象”: