java基礎之 超類Object


一、概述:

      Object類是所有Java類的祖先。每個類都使用 Object 作為超類。所有對象(包括數組)都實現這個類的方法。
      在不明確給出超類的情況下,Java會自動把Object作為要定義類的超類。
      可以使用類型為Object的變量指向任意類型的對象。
      Object類是Java中唯一沒有父類的類
      Object類有一個默認構造方法pubilc Object(),在構造子類實例時,都會先調用這個默認構造方法。

 二、API預覽

    Object()
    默認構造方法

    clone()
    創建並返回此對象的一個副本。
    equals(Object obj)
    指示某個其他對象是否與此對象“相等”。
    finalize()
    當垃圾回收器確定不存在對該對象的更多引用時,由對象的垃圾回收器調用此方法。
    getClass()
    返回一個對象的運行時類。
    hashCode()
    返回該對象的哈希碼值。
    notify()
    喚醒在此對象監視器上等待的單個線程。
    notifyAll()
    喚醒在此對象監視器上等待的所有線程。
    toString()
    返回該對象的字符串表示。
    wait()
    導致當前的線程等待,直到其他線程調用此對象的 notify() 方法或 notifyAll() 方法。
    wait(long timeout)
    導致當前的線程等待,直到其他線程調用此對象的 notify() 方法或 notifyAll() 方法,或者超過指定的時間量。
    wait(long timeout, int nanos)
    導致當前的線程等待,直到其他線程調用此對象的 notify() 方法或 notifyAll() 方法,或者其他某個線程中斷當前線程,或者已超過某個實際時間量。

三、方法使用說明
equals() (判斷兩個對象是否相等)

 1)基本數據類型,也稱原始數據類型。byte,short,char,int,long,float,double,boolean   他們之間的比較,用雙等號(==),比較的是他們的值。

 2)復合數據類型(類)   當他們用(==)進行比較的時候,比較的是他們在內存中的存放地址,所以,除非是同一個new出來的對象,他們的比較后的結果為true,否則比較后結果為false。equals()這個方法的初始行為是比較對象的內存地址,但在一些類庫當中這個方法被覆蓋掉了,如String,Integer,Date在這些類當中equals有其自身的實現,而不再是比較類在堆內存中的存放地址了。

例:

        People p=new People();
        p.setName("234");
        
        People p2=new People();
        p2.setName("234");
        
        System.out.println(p.equals(p2)); //false
        System.out.println(p==p2);//false

        String s="123";
        String s1=new String("123");
        String s2=new String("123");
        
       
        System.out.println(s==s1);//false
        System.out.println(s.equals(s1));//true
        System.out.println(s1==s2);//false
        System.out.println(s1.equals(s2));//true
View Code

Java語言規范要求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

 hashCode()( 返回該對象的哈希碼值)

  hashCode 的常規協定是(重寫equals()時,必須重hashcode()並保證此協定):

  • 如果調用equals方法得到的結果為true,則兩個對象的hashcode值必定相等
  • 如果equals方法得到的結果為false,則兩個對象的hashcode值不一定不同
  • 如果兩個對象的hashcode值不等,則equals方法得到的結果必定為false
  • 如果兩個對象的hashcode值相等,則equals方法得到的結果未知

我們會有這樣的協定,舉個例子:

 

class User {
    String name;
    public User(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public boolean equals(Object o) {
        User u = (User) o;
        return name.equals(u.getName());
    }
}

 

 public static void main(String[] args) {
        List<User> list = new ArrayList<User>();
        list.add(new User("lily"));
        Map<User, String> map = new HashMap<User, String>();
        map.put(new User("lily"), "11");

        System.out.println(list.contains(new User("lily"))); //true
        System.out.println(map.containsKey(new User("lily")));//false
    }

原因就不寫了 。。自己領悟叭

 

toString()(返回該對象的字符串表示)

Object類中的toString()方法會打印出類名和對象的內存位置。幾乎每個類都會覆蓋該方法,以便打印對該對象當前狀態的表示。大多數(非全部)toString()方法都遵循如下格式:類名[字段名=值,字段名=值...],當然,子類應該定義自己的toString()方法。該方法是非常重要的調試工具,很多標准類庫中的類都定義了toString()方法,以便程序員獲得有用的調試信息

clone()(創建並返回此對象的一個副本

克隆的分類:
  (1)淺克隆(shallow clone),淺拷貝是指拷貝對象時僅僅拷貝對象本身和對象中的基本變量,而不拷貝對象包含的引用指向的對象。
  (2)深克隆(deep clone),深拷貝不僅拷貝對象本身,而且拷貝對象包含的引用指向的所有對象。
克隆的實現:
  1. 讓該類實現java.lang.Cloneable接口;
  2. 重寫(override)Object類的clone()方法。
該方法是淺克隆,如果需要實現深克隆,則需要重寫clone方法)
為什么克隆是淺拷貝:
1) 效率和簡單性,簡單的copy一個對象在堆上的的內存比遍歷一個對象網然后內存深copy明顯效率高並且簡單。
2 ) 不給別的類強加意義。如果A實現了Cloneable,同時有一個引用指向B,如果直接復制內存進行深copy的話,意味着B在意義上也是支持Clone的,但是這個是在使用B的A中做的,B甚至都不知道。破壞了B原有的接口。
3) 有可能破壞語義。如果A實現了Cloneable,同時有一個引用指向B,該B實現為單例模式,如果直接復制內存進行深copy的話,破壞了B的單例模式。
4) 方便且更靈活,如果A引用一個不可變對象,則內存deep copy是一種浪費。Shadow copy給了程序員更好的靈活性。
克隆滿足的條件:
clone()方法將對象復制了一份並返還給調用者。所謂“復制”的含義與clone()方法是怎么實現的。一般而言,clone()方法滿足以下的描述:
(1)對任何的對象x,都有: x.clone()!=x。換言之,克隆對象與原對象不是同一個對象
(2)對任何的對象x,都有: x.clone().getClass() == x.getClass(),換言之,克隆對象與原對象的類型一樣。
(3)如果對象x的equals()方法定義其恰當的話,那么 x.clone().equals(x)應當成立的。
在JAVA語言的API中,凡是提供了clone()方法的類,都滿足上面的這些條件。JAVA語言的設計師在設計自己的clone()方法時,也應當遵守着三個條件。一般來說,上面的三個條件中的前兩個是必需的,而第三個是可選的。

創建對象的幾種方式:

  1)new
     new操作符的本意是分配內存。程序執行到new操作符時, 首先去看new操作符后面的類型,因為知道了類型,才能知道要分配多大的內存空間。 分配完內存之后,再調用構造函數,填充對象的各個域,這一步叫做對象的初始化,構造方法返回后,一個對象創建完畢
  2)反射
   a: Student stu = (Student)Class.forName("根路徑.Student").newInstance()
   b: Student stu = Student.class.newInstance()
區別:
> Class類的newInstance只能觸發無參數的構造方法創建對象,而構造器類的newInstance能觸發有參數或者任意參數的構造方法來創建對象。
> Class類的newInstance需要其構造方法是共有的或者對調用方法可見的,而構造器類的newInstance可以在特定環境下調用私有構造方法來創建對象。
> Class類的newInstance拋出類構造函數的異常,而構造器類的newInstance包裝了一個InvocationTargetException異常。
  3)clone
       先分配內存,將原來對象內存里的內容copy一份。不會調用構造方法
  4)反序列化
 
 wait() & notify()
wait():
作用於持有該對象鎖的當前線程,使線程從運行態,進入到等待阻塞狀態,釋放對象鎖,釋放cpu控制權,調用該方法的前提是獲得對象鎖
notify()/notifyAll:
作用於持有該對象鎖的線程(其中一個/全部),使線程從等待阻塞狀態,進入到鎖池阻塞狀態,調用該方法的前提是獲得對象鎖
舉個栗子
生產者消費者模型
倉庫
class Store {
    public static List<String> store = new ArrayList<String>();
    public static int limitSize = 5;
}
View Code

生產者

class Producer implements Runnable {
    @Override
    public void run() {
        while (true) {
            synchronized (Store.store) {
                while (Store.store.size() == Store.limitSize) {
                    try {
                        Store.store.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("創建一個商品");
                Store.store.add(UUID.randomUUID().toString());
                Store.store.notifyAll();
            }
        }
    }
}
View Code

消費者

class Consumer implements Runnable {
    @Override
    public void run() {
        while (true) {
            synchronized (Store.store) {
                while (Store.store.size() == 0) {
                    try {
                        Store.store.wait();
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
                System.out.println("消費一個商品");
                Store.store.remove(0);
                Store.store.notifyAll();
            }
        }
    }
}
View Code

啟動生產者,消費者

public static void main(String[] args) {
        Thread producer = new Thread(new Producer());
        Thread consumer = new Thread(new Consumer());
        producer.start();
        consumer.start();
    }
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM