两个程序的说明

1、程序1的结果是:
class A{
static{
System.out.println("load a");
}
A(){
System.out.println("create a");
}
}
class B extends A{
static{
System.out.println("load b");
}
B(){
System.out.println("create b");
}
}
public class TestABDemo{
public static void main(String args[]){
new B();
}
}

程序运行的结果入下:
[color=blue]load a
load b
create a
create b[/color]

结果说明:
该程序主要涉及到静态初始化块和构造器的执行顺序。

(1)构造器的执行顺序:[b]创建任何Java对象总是从该类所在继承树的最顶层类的构造器开始执行,然后依次向下执行,最后才执行本类的构造器。[/b]也就是说,创建任何Java对象,最先执行的总是java.lang.Object类的构造器。

(2)初始化块:是Java类里可出现的第四种成员(其他三种为属性、方法和构造器),一个类里可以有多个初始化块,相同类型的初始化块之间有顺序:前面定义的初始化块先执行,后面定义的初始化块后执行。

初始化块的修饰符只能是static,使用static修饰的初始化块称为静态初始化块。初始化块里的代码可以包含任何可执行语句,包括定义局部变量、调用其他对象的方法、使用分支、循环语句等。

初始化块虽然也是Java类的一种成员,但它没有名字,也就没有标识,因此无法通过类、对象来调用初始化块。初始化块只在创建Java对象时隐式执行,而且在执行构造器之前执行。

注意:当Java创建一个对象时,系统先为该对象的所有实例属性分配内存(前提是该类已经被加载过了),接着程序开始对这些实例属性执行初始化,其初始化顺序是:先执行初始化块或声明属性时指定的初始值,再执行构造器里指定的初始值。

[b]当创建一个Java对象时,不仅会执行该类的普通初始化块和构造器,系统会一直上溯到java.lang.Object类,先执行java.lang.Object类的初始化块,开始执行java.lang.Object类的构造器,依次向下执行其父类的初始化块,开始执行其父类的构造器……最后才执行该类的初始化块和构造器,返回该类的对象。[/b]

静态初始化块是类相关的,系统将在类初始化阶段执行静态初始化块,而不是在创建对象时才执行。因此[b]静态初始化块总是比普通初始化块先执行[/b]。

静态初始化块是类相关的,用于对整个类进行初始化处理,通常用于对类属性执行初始化处理。静态初始化块不能对实例属性进行初始化处理。

与普通初始化块类似的是,[b]系统在类初始化阶段执行静态初始化块时,不仅会执行本类的静态初始化块,还会一直上溯到java.lang.Object类(如果它包含静态初始化块),先执行java.lang.Object类的静态初始化块,然后执行其父类的静态初始化块……最后才执行该类的静态初始化块,经过这个过程,才完成了该类的初始化过程。[/b]只有当类初始化完成后,才可以在系统中使用这个类,包括访问这个类的类方法、类属性,或者用这个类来创建实例。

例程1:
class Root{
static{
System.out.println("Root的静态初始化块");
}
{
System.out.println("Root的普通初始化块");
}
public Root(){
System.out.println("Root的无参构造器");
}
}
class Mid extends Root{
static{
System.out.println("Mid的静态初始化块");
}
{
System.out.println("Mid的普通初始化块");
}
public Mid(){
System.out.println("Mid的无参构造器");
}
public Mid(String msg){
//通过this调用同一个类中重载的构造器
this();
System.out.println("Mid的带参构造器,其参数值是:"+msg);
}
}
class Leaf extends Mid{
static{
System.out.println("Leaf的静态初始化块");
}
{
System.out.println("Leaf的普通初始化块");
}
public Leaf(){
//通过super调用父类中有一个字符串参数的构造器
super("Think in Java");
System.out.println("执行Leaf的构造器");
}
}
public class Test{
public static void main(String args[]){
new Leaf();
//new Leaf();
}
}


[b]程序的运行结果1(注释掉后面一个new Leaf();):[/b]
[color=blue]Root的静态初始化块
Mid的静态初始化块
Leaf的静态初始化块
Root的普通初始化块
Root的无参构造器
Mid的普通初始化块
Mid的无参构造器
Mid的带参构造器,其参数值是:Think in Java
Leaf的普通初始化块
执行Leaf的构造器[/color]

[b]程序的运行结果2(去掉后面一个new Leaf();的注释):[/b]
[color=blue]Root的静态初始化块
Mid的静态初始化块
Leaf的静态初始化块
Root的普通初始化块
Root的无参构造器
Mid的普通初始化块
Mid的无参构造器
Mid的带参构造器,其参数值是:Think in Java
Leaf的普通初始化块
执行Leaf的构造器
Root的普通初始化块
Root的无参构造器
Mid的普通初始化块
Mid的无参构造器
Mid的带参构造器,其参数值是:Think in Java
Leaf的普通初始化块
执行Leaf的构造器[/color]

从结果可以看出:[b]类的初始化阶段,先执行最顶层父类的静态初始化块,依次向下,最后执行当前类的静态初始化块;接着,对象的初始化阶段,先执行最顶层父类的初始化块、构造器,依次向下,最后执行当前类的初始化块、构造器。[/b]

注意:[b]静态初始化块只执行一次[/b]。

2、程序2的结果是:
import java.util.*;
public class TestSet{
public static void main(String args[]){
Set<String> books = new HashSet<String>();
books.add(new String("Think in Java"));
boolean result = books.add(new String("Think in Java"));
System.out.println(result);
System.out.println(books);
System.out.println(books.size());
}
}

程序的运行结果如下:
[color=blue]false
[Think in Java]
1[/color]
结果说明:

Set集合不允许包含相同的元素,如果试图把两个相同的元素加入到同一个Set集合中,则添加操作失败,add()方法返回false,且新元素不会被加入。

Set集合判断两个对象是否相同,不是使用==运算符,而是使用equals()方法。也就是说,[b]如果只要两个对象用equals()方法比较返回true,Set就不会接受这两个对象;反之,只要两个对象用equals()方法比较返回false,Set就会接受这两个对象[/b](甚至着两个对象是同一个对象,Set也可以把它们当成两个对象处理)。

例程2:
源代码:Person.java
public class Person{
private String number;
public Person(String n){
this.number = n;
}
public String getNumber(){
return number;
}
public void setNumber(String n){
this.number = n;
}
//public int hashCode(){//重新实现hashCode()方法
// return number.hashCode();
//}
public boolean equals(Object obj){//重新实现equals()方法
Person p = (Person)obj;
return number.equals(p.number);
}
}

源代码:TestSet.java
import java.util.*;
public class TestSet{
public static void main(String args[]){

Person p1= new Person("张三");
Person p2= new Person("张三");
System.out.println("p1 == p2的值为:"+(p1 == p2));
System.out.println("p1.equals(p2)的值为:"+(p1.equals(p2)));

System.out.println("----------");

HashSet<Person> set = new HashSet<Person>();
set.add(new Person("张三"));
boolean result = set.add(new Person("张三"));
System.out.println("又添加一个张三是否成功:"+result);
set.add(new Person("李四"));
System.out.println("Set集合中的元素如下:");
Iterator<Person> it = set.iterator();
while(it.hasNext()){
Person p = it.next();
System.out.println(p.getNumber());
}
System.out.println("个数为:"+set.size());
}
}


[b]程序的运行结果1(注释掉hashCode()方法):[/b]
[color=blue]p1 == p2的值为:false
p1.equals(p2)的值为:true
----------
又添加一个张三是否成功:true
Set集合中的元素如下:
张三
张三
李四
个数为:3[/color]

[b]程序的运行结果2(去掉hashCode()方法的注释):[/b]
[color=blue]p1 == p2的值为:false
p1.equals(p2)的值为:true
----------
又添加一个张三是否成功:false
Set集合中的元素如下:
张三
李四
个数为:2[/color]

结果说明:

[b]public int hashCode()[/b]

返回该对象的哈希码值。支持此方法是为了提高哈希表(例如 java.util.Hashtable 提供的哈希表)的性能。
hashCode 的常规协定是:
[b]在 Java 应用程序执行期间,在对同一对象多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是将对象进行 equals 比较时所用的信息没有被修改。[/b]从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。
如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么对这两个对象中的任一对象上调用 hashCode 方法不 要求一定生成不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同整数结果可以提高哈希表的性能。
实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。)

[b]public boolean equals(Object obj)[/b]

指示其他某个对象是否与此对象“相等”。
equals 方法在非空对象引用上实现相等关系:
自反性:对于任何非空引用值 x,x.equals(x) 都应返回 true。
对称性:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应返回 true。
传递性:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 应返回 true。
一致性:对于任何非空引用值 x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回 false,前提是对象上 equals 比较中所用的信息没有被修改。
对于任何非空引用值 x,x.equals(null) 都应返回 false。
Object 类的 equals 方法实现对象上差别可能性最大的相等关系;即,对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一个对象时,此方法才返回 true(x == y 具有值 true)。
[b][color=red]注意:当此方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。[/color][/b]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值