Initialization & Cleanup
Agenda
•   概述
•   构造器命名 & 默认构造器
•   含参数构造器
•   this关键字
•   RE - static关键字
•   垃圾回收 - 引用计数&内存泄露
•   垃圾回收 - finalize方法
•   垃圾回收 - System.gc()
•   static块
•   non-static块
•   变长参数
•   枚举类型
概述
• 初始化和清理是仸何编程语言中都需要处
  理的两个问题, 正确的初始化保证了对象能
  够被使用, 而清理则确保了不被使用的对象
  被回收, 与之相关的内存/文件操作符等系统
  资源也会释放;
• 在Java中, 对象的初始化沿用了C++中的构造
  器(Constructor)方式, 并且引入了垃圾回收
  (Garbage Collect)机制来实现对象的回收.
构造器的命名
                      &默认构造器
• Java中构造器(constructor)的命名与类名相同, 可以有多
  个构造器(重载), 只是这些构造器的参数不同; 示例:
Class Rock {
   Rock() {
        System.out.println(“This is Rock”);
   }
}
• 无参构造器在java被称为默认构造器(default constructor),
  如果一个类没有定义任何构造器, 则会自动引入一个默
  认构造器.
• 构造器的命名不遵循”方法的第一个字母小写”的编码风
  格;
• 示例: demo/Demo1.java
带参数构造器
• Java中构造器与方法一样也可以指定形参.
  示例:
class Rock {
    Rock (int i) {
         System.out.print("Rock " + i + " ");
    }
}

• 示例: demo/Demo2.java
this关键字
•   访问某个对象上的属性或方法时, Java会默认传入该对象的引用; 可以使用
    this关键字访问该对象的引用, this可以理解为”当前对象”. 示例:
Class Demo {
    int String name = “Bosh”;
    private void sayHello() {
             System.out.println(name); // 等价于this.name
    }
    public void say() {
             /**比如Demo demo = new Demo(); demo.say();
              **this即表示demo **/
             sayHello(); // 等价于this.sayHello()
    }
}
•   可以看到this关键字并不是必须的, 但是在某些特殊的情况下必须使用该
    关键字, 比如:
public void setName(String name) {
    this.name = name; // name是对象的属性, 这里使用输入的参数进行赋值
}
•   this指向的是对象, 不能使用在static方法中, 因为调用static方法不需要创建
    对象.
•   示例: demo/Demo4.java
this关键字
                                              构造器调用
•   this关键字可以用于调用另一个构造器, 这样的好处在于避免了重复代码, 符合DRY原则.
    示例:
Flower(int petals) { // 构造器1
      petalCount = petals;
      print("Constructor w/ int arg only, petalCount= " + petalCount);
}
Flower(String ss) {         // 构造器2
      print("Constructor w/ String arg only, s = " + ss);
      s = ss;
}
Flower(String s, int petals) {             // 构造器3
      this(petals);                       // 调用构造器1
      print("String & int args");
}
Flower() {
      this("hi", 47);                    // 调用构造器3
      print("default constructor (no args)");
}
•   this构造器的调用必须是构造器方法体中的第一条语句, 并且只能有一次
    this调用, 否则会爆出编译错误;
•   示例: demo/Demo5.java
RE - static关键字
• static可以理解为non-this, 因为不需要创建
  对象; 在static方法中不能调用non-static方法,
  反之在non-static方法中则可以调用static方
  法;
• static被认为是non-OOP的, 如果你的设计中
  出现了过多的static那么应该重新思考你的
  设计了.
垃圾回收
            引用计数 & 内存泄露
• Java中的垃圾回收(GC)是基于引用计数机制的, 所谓引用计数是指Java
    会自动计算指向所有对象的引用的个数, 如果某个对象的引用计数为0,
    那么该对象将在JVM下一次的GC操作中被释放;
• Java中的内存泄露(Memory Leak)不同于C++, 后者是指没有调用对象的
    destructor方法导致不再被使用对象的内存没有被释放; Java的内存泄
    露是指对象仍然是可访问的(引用计数大于0), 但是不会被使用. 示例:
Vector v=new Vector(10);
for (int i=1;i<100; i++) {
    Object o=new Object();
    v.add(o);
    o=null; // 虽然o不再指向Object对象, 但v然保存了这些对象的引
      // 用如果v不再被使用那么这些Object对象就造成了内存泄露
}
Solution:
设置v=null; 可以避免这里的内存泄露问题
垃圾回收
          finalize方法
• finalize方法定义在Object类中, 子类可以覆
  盖该方法实现资源的释放, 该方法在对象被
  垃圾回收(GC)之前被调用;
• 但是尽量不要依赖finalize方法来实现对内存
  等资源的释放, GC会处理好这一切. 如果需
  要释放比如文件句柄, 数据库连接等资源则
  应当编写相应的方法.
垃圾回收
           System.gc()
• 可以调用System.gc()来提示JVM进行垃圾回
  收, 但是该调用不能保证GC操作被立即执行;
  建议是如果基于JVM内存调优需要永远不要
  调用此方法, 而应该从其他方面进行调优;
• Runtime.getRuntime().gc()调用等价于
  System.gc()
成员初始化
• 类成员的初始化区分于static成员和非static成员: 前
   者在该类被加载时初始化, 之后不会再次初始化; 后
   者在每次创建对象时(new)初始化;
• 对象成员的初始化分为两步:
1, 执行成员声明语句的初始化, eg:
private int i = 1; // 声明成员i, 在创建对象时首先执行初始化操作
注意: 在成员声明语句中可以不指定初始值, 将会使用默认值
进行初始化, 参考: demo/Demo6.java
2, 执行构造函数中的成员初始化操作, 在构造函数中可
   以对成员进行初始化
• 示例: demo/Demo7.java
• 示例: demo/Demo8.java
static块
• static块的执行时机与static成员的初始化相
  同, 都是在被加载时执行; 写法:
  static {
    ......
  }
• 示例: demo/Demo9.java
non-static块
• Java提供了非static块用于实现对非static成
  员的初始化, 写法: {......} ; 相比static块是没
  有static关键字.
• 示例: demo/Demo10.java
变长参数
• JDK5对方法的变长参数提供了支持, eg:
// 方法声明
void printArray(Object... args)
// 调用
printArray(47, 3.14F, 11.11);
printArray("one", "two", "three");
printArray(new A(), new A(), new A());
printArray((Object[])new Integer[]{ 1, 2, 3, 4 });
printArray(); // Empty list is OK
• 示例: demo/Demo11.java
变长参数
                       可选参数
• 可以看到, 变长参数是允许为空的, 这就为可
  选参数的实现提供了一种方式, eg:
void f(int required, String... trailing) // trailing可选
• 示例: demo/Demo12.java
枚举类型
                            Enumerated Type
•   JDK5引入了枚举类型用于定义枚举值, eg:
public enum Spiciness {
     NOT, MILD, MEDIUM, HOT, FLAMING
}
• 如何使用?
1, 赋值
Spiciness howHot = Spiciness.MEDIUM;
2, print
System.out.println(howHot); // 输出MEDIUM
3, 顺序
howHot.oridnal(); // 返回2, 从0开始
4, 使用在switch语句中
Spiciness degree ...;
switch(degree) {
     case NOT: System.out.println("not spicy at all."); break;
    ......
     default: System.out.println("maybe too hot.");
}
• 示例: demo/Demo13.java
END

5, initialization & cleanup

  • 1.
  • 2.
    Agenda • 概述 • 构造器命名 & 默认构造器 • 含参数构造器 • this关键字 • RE - static关键字 • 垃圾回收 - 引用计数&内存泄露 • 垃圾回收 - finalize方法 • 垃圾回收 - System.gc() • static块 • non-static块 • 变长参数 • 枚举类型
  • 3.
    概述 • 初始化和清理是仸何编程语言中都需要处 理的两个问题, 正确的初始化保证了对象能 够被使用, 而清理则确保了不被使用的对象 被回收, 与之相关的内存/文件操作符等系统 资源也会释放; • 在Java中, 对象的初始化沿用了C++中的构造 器(Constructor)方式, 并且引入了垃圾回收 (Garbage Collect)机制来实现对象的回收.
  • 4.
    构造器的命名 &默认构造器 • Java中构造器(constructor)的命名与类名相同, 可以有多 个构造器(重载), 只是这些构造器的参数不同; 示例: Class Rock { Rock() { System.out.println(“This is Rock”); } } • 无参构造器在java被称为默认构造器(default constructor), 如果一个类没有定义任何构造器, 则会自动引入一个默 认构造器. • 构造器的命名不遵循”方法的第一个字母小写”的编码风 格; • 示例: demo/Demo1.java
  • 5.
    带参数构造器 • Java中构造器与方法一样也可以指定形参. 示例: class Rock { Rock (int i) { System.out.print("Rock " + i + " "); } } • 示例: demo/Demo2.java
  • 6.
    this关键字 • 访问某个对象上的属性或方法时, Java会默认传入该对象的引用; 可以使用 this关键字访问该对象的引用, this可以理解为”当前对象”. 示例: Class Demo { int String name = “Bosh”; private void sayHello() { System.out.println(name); // 等价于this.name } public void say() { /**比如Demo demo = new Demo(); demo.say(); **this即表示demo **/ sayHello(); // 等价于this.sayHello() } } • 可以看到this关键字并不是必须的, 但是在某些特殊的情况下必须使用该 关键字, 比如: public void setName(String name) { this.name = name; // name是对象的属性, 这里使用输入的参数进行赋值 } • this指向的是对象, 不能使用在static方法中, 因为调用static方法不需要创建 对象. • 示例: demo/Demo4.java
  • 7.
    this关键字 构造器调用 • this关键字可以用于调用另一个构造器, 这样的好处在于避免了重复代码, 符合DRY原则. 示例: Flower(int petals) { // 构造器1 petalCount = petals; print("Constructor w/ int arg only, petalCount= " + petalCount); } Flower(String ss) { // 构造器2 print("Constructor w/ String arg only, s = " + ss); s = ss; } Flower(String s, int petals) { // 构造器3 this(petals); // 调用构造器1 print("String & int args"); } Flower() { this("hi", 47); // 调用构造器3 print("default constructor (no args)"); } • this构造器的调用必须是构造器方法体中的第一条语句, 并且只能有一次 this调用, 否则会爆出编译错误; • 示例: demo/Demo5.java
  • 8.
    RE - static关键字 •static可以理解为non-this, 因为不需要创建 对象; 在static方法中不能调用non-static方法, 反之在non-static方法中则可以调用static方 法; • static被认为是non-OOP的, 如果你的设计中 出现了过多的static那么应该重新思考你的 设计了.
  • 9.
    垃圾回收 引用计数 & 内存泄露 • Java中的垃圾回收(GC)是基于引用计数机制的, 所谓引用计数是指Java 会自动计算指向所有对象的引用的个数, 如果某个对象的引用计数为0, 那么该对象将在JVM下一次的GC操作中被释放; • Java中的内存泄露(Memory Leak)不同于C++, 后者是指没有调用对象的 destructor方法导致不再被使用对象的内存没有被释放; Java的内存泄 露是指对象仍然是可访问的(引用计数大于0), 但是不会被使用. 示例: Vector v=new Vector(10); for (int i=1;i<100; i++) { Object o=new Object(); v.add(o); o=null; // 虽然o不再指向Object对象, 但v然保存了这些对象的引 // 用如果v不再被使用那么这些Object对象就造成了内存泄露 } Solution: 设置v=null; 可以避免这里的内存泄露问题
  • 10.
    垃圾回收 finalize方法 • finalize方法定义在Object类中, 子类可以覆 盖该方法实现资源的释放, 该方法在对象被 垃圾回收(GC)之前被调用; • 但是尽量不要依赖finalize方法来实现对内存 等资源的释放, GC会处理好这一切. 如果需 要释放比如文件句柄, 数据库连接等资源则 应当编写相应的方法.
  • 11.
    垃圾回收 System.gc() • 可以调用System.gc()来提示JVM进行垃圾回 收, 但是该调用不能保证GC操作被立即执行; 建议是如果基于JVM内存调优需要永远不要 调用此方法, 而应该从其他方面进行调优; • Runtime.getRuntime().gc()调用等价于 System.gc()
  • 12.
    成员初始化 • 类成员的初始化区分于static成员和非static成员: 前 者在该类被加载时初始化, 之后不会再次初始化; 后 者在每次创建对象时(new)初始化; • 对象成员的初始化分为两步: 1, 执行成员声明语句的初始化, eg: private int i = 1; // 声明成员i, 在创建对象时首先执行初始化操作 注意: 在成员声明语句中可以不指定初始值, 将会使用默认值 进行初始化, 参考: demo/Demo6.java 2, 执行构造函数中的成员初始化操作, 在构造函数中可 以对成员进行初始化 • 示例: demo/Demo7.java • 示例: demo/Demo8.java
  • 13.
    static块 • static块的执行时机与static成员的初始化相 同, 都是在被加载时执行; 写法: static { ...... } • 示例: demo/Demo9.java
  • 14.
    non-static块 • Java提供了非static块用于实现对非static成 员的初始化, 写法: {......} ; 相比static块是没 有static关键字. • 示例: demo/Demo10.java
  • 15.
    变长参数 • JDK5对方法的变长参数提供了支持, eg: //方法声明 void printArray(Object... args) // 调用 printArray(47, 3.14F, 11.11); printArray("one", "two", "three"); printArray(new A(), new A(), new A()); printArray((Object[])new Integer[]{ 1, 2, 3, 4 }); printArray(); // Empty list is OK • 示例: demo/Demo11.java
  • 16.
    变长参数 可选参数 • 可以看到, 变长参数是允许为空的, 这就为可 选参数的实现提供了一种方式, eg: void f(int required, String... trailing) // trailing可选 • 示例: demo/Demo12.java
  • 17.
    枚举类型 Enumerated Type • JDK5引入了枚举类型用于定义枚举值, eg: public enum Spiciness { NOT, MILD, MEDIUM, HOT, FLAMING } • 如何使用? 1, 赋值 Spiciness howHot = Spiciness.MEDIUM; 2, print System.out.println(howHot); // 输出MEDIUM 3, 顺序 howHot.oridnal(); // 返回2, 从0开始 4, 使用在switch语句中 Spiciness degree ...; switch(degree) { case NOT: System.out.println("not spicy at all."); break; ...... default: System.out.println("maybe too hot."); } • 示例: demo/Demo13.java
  • 18.