黑马程序员技术交流社区

标题: “第三贴”之Object类主要涉及的问题 [打印本页]

作者: 黄茂霖    时间: 2013-5-5 21:37
标题: “第三贴”之Object类主要涉及的问题
本帖最后由 shenqi 于 2013-5-6 12:32 编辑

基于面向对象编程思想,因为所有类都具备相同的方法,所以把共同的方法抽取到Object类当中, Object类就是Java中的所有类的超类。无论是sun公司提供的类还是程序员自定义的类Java都隐式的继承了Object类,下面让我们来逐一分析该类的方法以及注意事项:
clone()方法:创建并返回此对象的一个副本。返回Object.
问题: 如下代码:
packagecom.itcast.itheima;
publicclass CloneTest {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Table table = new Table();
        table = (Table) table.clone();
    }
}
//定义表类
classTable{
   
}
为什么table.clone()编译不过呢?
分析:
1.首先先了解一下clone()方法的作用,提到这个方法就不得不说一下23种设计模式之一 ---- 原型模式,什么是原型模式呢?顾名思义就是创建一个和原来一模一样的新对象。例如:日常开发中经常用到的复制功能,用户建立一张财务凭证后,以后会有类似的凭证,只是金额要修改,其他内容都相同,此时用户就没有必要重新将凭证的内容逐一输入。只需复制一下即可。
2.通过API文档查询要使用该方法就的对象必须实现Cloneable的接口,Cloneable接口里面什么方法都没有定义,是一个标示接口,类似于java.io.Serializable。否则会报CloneNotSupportedException异常,前面的编译不通过是因为该方法默认的修饰符是protected的,所以必须覆盖把修饰符修改成public的.
修改以上代码如下:
package com.itcast.itheima;
public class CloneTest {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Table table = new Table();
        table = (Table) table.clone();
    }
}
//定义表类
class Table implementsCloneable{
        publicObject clone(){
            Objectobj = null;
        try {
            obj = super.clone();
        } catch (CloneNotSupportedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return obj;
    }
}



作者: 黄茂霖    时间: 2013-5-5 21:37
equals() : 该方法用于比较某个对象是否与本对象相等。返回boolean值
查看equals()方法的源代码:
        public boolean equals(Object obj) {
                return (this == obj);
}
问题:
        我们可以清楚的看到是比较对象与对象之间是否相等,这与我们之前在String类中看到的==才是比较内存中的对象值、而equals()方法才是真正的比较字符串中的内容的说法显然不符合。
分析:在前面提到Object类是所有类的超类,那么String类作为它的子类当然也可以对重载、覆盖等动作。显然String类是对equlas()方法进行覆盖才会有这种现象出现。
先看一段代码:
package com.itheima;
public class ObjectTest {
        public static void main(String[] args) {
                String s1 = "a";
                String s2 = new String("a");
                String s3 =  "a";
                System.out.println("s1.equals(s2) :" + s1.equals(s2));
                System.out.println("s1 == s2 :" + (s1 == s2));
                System.out.println("-----------------------");
                System.out.println("s1.equals(s3) :" + s1.equals(s3));
                System.out.println("s1 == s3 :" + (s1 == s3));
        }
}
输出结果:
s1.equals(s2) :true
s1 == s2 :false
-----------------------
s1.equals(s3) :true
s1 == s3 :true
1.由于定义了String s1 = "a"; "a"就会存放在内存中的常量池,当String s3 = "a";并不会生成一个新的"a",而是直接指向内存中常量池的值"a".所以固然s1 == s3 为true。
2.由于s2是new String("a"),我们知道new这个动作一出现就表示出现新的对象,那s1 == s2 显示是false.
3.由于以上的知识不难理解,重点在于equals()方法,查看String类中equals()方法的源代码:
public boolean equals(Object anObject) {
        //假如传来的对象与本对象相等,那么其值肯定相等.(这点没问题吧?)
        if (this == anObject) {
            return true;
        }
        //如果传来的对象不是本对象的那么判断一下是不是String这种类型,如果是的话                //那么开始取出该值逐一与本对象的值判断。注意:使用关键字instanceof判断对                //象是否String类型,不是判断对象与对象之间的判断.搞清楚这点对于该问题就                        //迎刃而解。具体的逻辑自己看,不难.
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = count;
            if (n == anotherString.count) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = offset;
                int j = anotherString.offset;
                while (n-- != 0) {
                    if (v1[i++] != v2[j++])
                        return false;
                }
                return true;
            }
        }
        return false;
}

作者: 黄茂霖    时间: 2013-5-5 21:38
HashCode()方法: 返回该对象的哈希码值。返回int值
有许多人学了很长时间的Java,但一直不明白hashCode方法的作用,之前我也一直搞不懂有什么用途,学了Java中的集合(Collection)之后才明白HashCode的作用.
Java中的集合(Collection)有两类:一类是List,再有一类是Set。
它们的区别:前者集合内的元素是有序的,元素可以重复;后者元素无序,但元素不可重复。

问题:
        要想保证元素不重复,可两个元素是否重复应该依据什么来判断呢?可以使用Object.equals()方法。但是,如果每增加一个元素就检查一次,那么当元素很多时,后添加到集合中的元素比较的次数就非常多了。
例如:集合中现在已经有1000个元素,那么第1001个元素加入集合时,它就要调用1000次equals方法。这显然会大大降低效率。于是,Java采用了哈希表的原理。哈希(Hash)实际上是个人名,由于他提出一哈希算法的概念,所以就以他的名字命名了。(对于哈希值的设置修改参考毕老师的视频的集合类: http://edu.csdn.net/news/2012822/f21877d69403.shtml)
所以,Java对于hashCode方法是这样规定的:
1、如果两个对象相同,那么它们的hashCode值一定要相同。
2、反过来如果两个对象的hashCode相同,它们并不一定相同。

总结equals()方法和hashCode()方法:
1.        在定义类时,为了保证equals()方法和hashCode()方法跟我们需求相符的情况下,最后一开始就重写它,因为要防止可能在继承其他类或者实现接口时改变了这两个方法。

toString()方法:返回该对象的字符串表示。
问题:在定义数组并往里数组里存数据然时,通过System.out.println()方式打印出来的为什么是一段内存地址。
代码如下:
package com.itcast.itheima;
public class ToStringTest {
                public static void main(String[] args) {
                        int arr[] = {1,5,6,8,9,7,4,6};
                        System.out.println(arr);
                }
}
输出结果:
[I@de6ced
分析:
“[I@de6ced”  ----“[”表示该类型是数据
----“I”表示该数据存储int类型
                                   ----“@de6ced”是栈指向堆的地址。
System.out.println()底层就是调用arr.toString()就是打印出该对象在内存中的地址。
System.out 返回的PrintStream对象,通过查看源代码查到println()方法:
public void println(Object x) {
        //再追加查看valueOf()方法源代码
        String s = String.valueOf(x);
        synchronized (this) {
            print(s);
            newLine();
        }
}

valueOf源代码:
  public static String valueOf(Object obj) {
        return (obj == null) ? "null" : obj.toString();
}
这样就不难解释为什么打印出内存地址,同时也供大家提供一种学习方法。多看源代码学习。

wait(),wait(long timeout),wait(long timeout,int nanos),notify(),notifyAll()方法是跟线程通信有关的。可以参考毕老师的视频进行学习:http://edu.csdn.net/news/2012822/f21877d69403.shtml

作者: 曹睿翔    时间: 2013-5-5 22:28
很不错,基本满足要求,其他几个方法也大致说下,另外把帖子中关键的地方用其他颜色标注,方便查看




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2