夯實(shí)Java基礎(chǔ)系列9:深入理解Class類和Object類

目錄

- Object類

本系列文章將整理到我在GitHub上的《Java面試指南》倉庫,更多精彩內(nèi)容請(qǐng)到我的倉庫里查看

https://github.com/h2pl/Java-Tutorial

喜歡的話麻煩點(diǎn)下Star哈

文章首發(fā)于我的個(gè)人博客:

www.how2playlife.com

本文是微信公眾號(hào)【Java技術(shù)江湖】的《夯實(shí)Java基礎(chǔ)系列博文》其中一篇蒸甜,本文部分內(nèi)容來源于網(wǎng)絡(luò)重窟,為了把本文主題講得清晰透徹工三,也整合了很多我認(rèn)為不錯(cuò)的技術(shù)博客內(nèi)容划栓,引用其中了一些比較好的博客文章恤煞,如有侵權(quán)术幔,請(qǐng)聯(lián)系作者示启。
該系列博文會(huì)告訴你如何從入門到進(jìn)階,一步步地學(xué)習(xí)Java基礎(chǔ)知識(shí)蒋失,并上手進(jìn)行實(shí)戰(zhàn)返帕,接著了解每個(gè)Java知識(shí)點(diǎn)背后的實(shí)現(xiàn)原理,更完整地了解整個(gè)Java技術(shù)體系篙挽,形成自己的知識(shí)框架荆萤。為了更好地總結(jié)和檢驗(yàn)?zāi)愕膶W(xué)習(xí)成果,本系列文章也會(huì)提供每個(gè)知識(shí)點(diǎn)對(duì)應(yīng)的面試題以及參考答案铣卡。

如果對(duì)本系列文章有什么建議链韭,或者是有什么疑問的話,也可以關(guān)注公眾號(hào)【Java技術(shù)江湖】聯(lián)系作者煮落,歡迎你參與本系列博文的創(chuàng)作和修訂敞峭。

Java中Class類及用法

Java程序在運(yùn)行時(shí),Java運(yùn)行時(shí)系統(tǒng)一直對(duì)所有的對(duì)象進(jìn)行所謂的運(yùn)行時(shí)類型標(biāo)識(shí)蝉仇,即所謂的RTTI旋讹。

這項(xiàng)信息紀(jì)錄了每個(gè)對(duì)象所屬的類。虛擬機(jī)通常使用運(yùn)行時(shí)類型信息選準(zhǔn)正確方法去執(zhí)行轿衔,用來保存這些類型信息的類是Class類沉迹。Class類封裝一個(gè)對(duì)象和接口運(yùn)行時(shí)的狀態(tài),當(dāng)裝載類時(shí)害驹,Class類型的對(duì)象自動(dòng)創(chuàng)建胚股。

說白了就是:

Class類也是類的一種,只是名字和class關(guān)鍵字高度相似裙秋。Java是大小寫敏感的語言琅拌。

Class類的對(duì)象內(nèi)容是你創(chuàng)建的類的類型信息,比如你創(chuàng)建一個(gè)shapes類摘刑,那么进宝,Java會(huì)生成一個(gè)內(nèi)容是shapes的Class類的對(duì)象

Class類的對(duì)象不能像普通類一樣,以 new shapes() 的方式創(chuàng)建枷恕,它的對(duì)象只能由JVM創(chuàng)建党晋,因?yàn)檫@個(gè)類沒有public構(gòu)造函數(shù)

    /*
     * Private constructor. Only the Java Virtual Machine creates Class objects.
     * This constructor is not used and prevents the default constructor being
     * generated.
     */
     //私有構(gòu)造方法,只能由jvm進(jìn)行實(shí)例化
    private Class(ClassLoader loader) {
        // Initialize final field for classLoader.  The initialization value of non-null
        // prevents future JIT optimizations from assuming this final field is null.
        classLoader = loader;
    }

Class類的作用是運(yùn)行時(shí)提供或獲得某個(gè)對(duì)象的類型信息,和C++中的typeid()函數(shù)類似未玻。這些信息也可用于反射灾而。

Class類原理

看一下Class類的部分源碼

//Class類中封裝了類型的各種信息。在jvm中就是通過Class類的實(shí)例來獲取每個(gè)Java類的所有信息的扳剿。

public class Class類 {
    Class aClass = null;

//    private EnclosingMethodInfo getEnclosingMethodInfo() {
//        Object[] enclosingInfo = getEnclosingMethod0();
//        if (enclosingInfo == null)
//            return null;
//        else {
//            return new EnclosingMethodInfo(enclosingInfo);
//        }
//    }

    /**提供原子類操作
     * Atomic operations support.
     */
//    private static class Atomic {
//        // initialize Unsafe machinery here, since we need to call Class.class instance method
//        // and have to avoid calling it in the static initializer of the Class class...
//        private static final Unsafe unsafe = Unsafe.getUnsafe();
//        // offset of Class.reflectionData instance field
//        private static final long reflectionDataOffset;
//        // offset of Class.annotationType instance field
//        private static final long annotationTypeOffset;
//        // offset of Class.annotationData instance field
//        private static final long annotationDataOffset;
//
//        static {
//            Field[] fields = Class.class.getDeclaredFields0(false); // bypass caches
//            reflectionDataOffset = objectFieldOffset(fields, "reflectionData");
//            annotationTypeOffset = objectFieldOffset(fields, "annotationType");
//            annotationDataOffset = objectFieldOffset(fields, "annotationData");
//        }

        //提供反射信息
    // reflection data that might get invalidated when JVM TI RedefineClasses() is called
//    private static class ReflectionData<T> {
//        volatile Field[] declaredFields;
//        volatile Field[] publicFields;
//        volatile Method[] declaredMethods;
//        volatile Method[] publicMethods;
//        volatile Constructor<T>[] declaredConstructors;
//        volatile Constructor<T>[] publicConstructors;
//        // Intermediate results for getFields and getMethods
//        volatile Field[] declaredPublicFields;
//        volatile Method[] declaredPublicMethods;
//        volatile Class<?>[] interfaces;
//
//        // Value of classRedefinedCount when we created this ReflectionData instance
//        final int redefinedCount;
//
//        ReflectionData(int redefinedCount) {
//            this.redefinedCount = redefinedCount;
//        }
//    }
        //方法數(shù)組
//    static class MethodArray {
//        // Don't add or remove methods except by add() or remove() calls.
//        private Method[] methods;
//        private int length;
//        private int defaults;
//
//        MethodArray() {
//            this(20);
//        }
//
//        MethodArray(int initialSize) {
//            if (initialSize < 2)
//                throw new IllegalArgumentException("Size should be 2 or more");
//
//            methods = new Method[initialSize];
//            length = 0;
//            defaults = 0;
//        }

    //注解信息
    // annotation data that might get invalidated when JVM TI RedefineClasses() is called
//    private static class AnnotationData {
//        final Map<Class<? extends Annotation>, Annotation> annotations;
//        final Map<Class<? extends Annotation>, Annotation> declaredAnnotations;
//
//        // Value of classRedefinedCount when we created this AnnotationData instance
//        final int redefinedCount;
//
//        AnnotationData(Map<Class<? extends Annotation>, Annotation> annotations,
//                       Map<Class<? extends Annotation>, Annotation> declaredAnnotations,
//                       int redefinedCount) {
//            this.annotations = annotations;
//            this.declaredAnnotations = declaredAnnotations;
//            this.redefinedCount = redefinedCount;
//        }
//    }
}

我們都知道所有的java類都是繼承了object這個(gè)類旁趟,在object這個(gè)類中有一個(gè)方法:getclass().這個(gè)方法是用來取得該類已經(jīng)被實(shí)例化了的對(duì)象的該類的引用,這個(gè)引用指向的是Class類的對(duì)象庇绽。

我們自己無法生成一個(gè)Class對(duì)象(構(gòu)造函數(shù)為private)锡搜,而 這個(gè)Class類的對(duì)象是在當(dāng)各類被調(diào)入時(shí),由 Java 虛擬機(jī)自動(dòng)創(chuàng)建 Class 對(duì)象瞧掺,或通過類裝載器中的 defineClass 方法生成耕餐。

//通過該方法可以動(dòng)態(tài)地將字節(jié)碼轉(zhuǎn)為一個(gè)Class類對(duì)象
protected final Class<?> defineClass(String name, byte[] b, int off, int len)
    throws ClassFormatError
{
    return defineClass(name, b, off, len, null);
}

我們生成的對(duì)象都會(huì)有個(gè)字段記錄該對(duì)象所屬類在CLass類的對(duì)象的所在位置。如下圖所示:

[外鏈圖片轉(zhuǎn)存失敗(img-ZfMJTzO4-1569074134147)(http://dl.iteye.com/upload/picture/pic/101542/0047a6e9-6608-3c3c-a67c-d8ee95e7fcb8.jpg)]

如何獲得一個(gè)Class類對(duì)象

請(qǐng)注意辟狈,以下這些方法都是值肠缔、指某個(gè)類對(duì)應(yīng)的Class對(duì)象已經(jīng)在堆中生成以后,我們通過不同方式獲取對(duì)這個(gè)Class對(duì)象的引用哼转。而上面說的DefineClass才是真正將字節(jié)碼加載到虛擬機(jī)的方法桩砰,會(huì)在堆中生成新的一個(gè)Class對(duì)象。

第一種辦法释簿,Class類的forName函數(shù)

public class shapes{}
Class obj= Class.forName("shapes");
第二種辦法,使用對(duì)象的getClass()函數(shù)

public class shapes{}
shapes s1=new shapes();
Class obj=s1.getClass();
Class obj1=s1.getSuperclass();//這個(gè)函數(shù)作用是獲取shapes類的父類的類型

第三種辦法硼莽,使用類字面常量

Class obj=String.class;
Class obj1=int.class;
注意庶溶,使用這種辦法生成Class類對(duì)象時(shí),不會(huì)使JVM自動(dòng)加載該類(如String類)懂鸵。==而其他辦法會(huì)使得JVM初始化該類偏螺。==

使用Class類的對(duì)象來生成目標(biāo)類的實(shí)例

生成不精確的object實(shí)例

==獲取一個(gè)Class類的對(duì)象后,可以用 newInstance() 函數(shù)來生成目標(biāo)類的一個(gè)實(shí)例匆光。然而套像,該函數(shù)并不能直接生成目標(biāo)類的實(shí)例,只能生成object類的實(shí)例==

Class obj=Class.forName("shapes");
Object ShapesInstance=obj.newInstance();
使用泛化Class引用生成帶類型的目標(biāo)實(shí)例

Class<shapes> obj=shapes.class;
shapes newShape=obj.newInstance();
因?yàn)橛辛祟愋拖拗浦障ⅲ允褂梅夯疌lass語法的對(duì)象引用不能指向別的類夺巩。

Class obj1=int.class;
Class<Integer> obj2=int.class;
obj1=double.class;
//obj2=double.class; 這一行代碼是非法的,obj2不能改指向別的類

然而周崭,有個(gè)靈活的用法柳譬,使得你可以用Class的對(duì)象指向基類的任何子類。
Class<? extends Number> obj=int.class;
obj=Number.class;
obj=double.class;

因此续镇,以下語法生成的Class對(duì)象可以指向任何類美澳。
Class<?> obj=int.class;
obj=double.class;
obj=shapes.class;
最后一個(gè)奇怪的用法是,當(dāng)你使用這種泛型語法來構(gòu)建你手頭有的一個(gè)Class類的對(duì)象的基類對(duì)象時(shí),必須采用以下的特殊語法

public class shapes{}
class round extends shapes{}
Class<round> rclass=round.class;
Class<? super round> sclass= rclass.getSuperClass();
//Class<shapes> sclass=rclass.getSuperClass();
我們明知道制跟,round的基類就是shapes舅桩,但是卻不能直接聲明 Class < shapes >,必須使用特殊語法

Class < ? super round >

這個(gè)記住就可以啦雨膨。

Object類

這部分主要參考http://ihenu.iteye.com/blog/2233249

Object類是Java中其他所有類的祖先擂涛,沒有Object類Java面向?qū)ο鬅o從談起。作為其他所有類的基類哥放,Object具有哪些屬性和行為歼指,是Java語言設(shè)計(jì)背后的思維體現(xiàn)。

Object類位于java.lang包中甥雕,java.lang包包含著Java最基礎(chǔ)和核心的類踩身,在編譯時(shí)會(huì)自動(dòng)導(dǎo)入。Object類沒有定義屬性社露,一共有13個(gè)方法挟阻,13個(gè)方法之中并不是所有方法都是子類可訪問的,一共有9個(gè)方法是所有子類都繼承了的峭弟。

先大概介紹一下這些方法

1.clone方法
保護(hù)方法附鸽,實(shí)現(xiàn)對(duì)象的淺復(fù)制,只有實(shí)現(xiàn)了Cloneable接口才可以調(diào)用該方法瞒瘸,否則拋出CloneNotSupportedException異常坷备。
2.getClass方法
final方法,獲得運(yùn)行時(shí)類型情臭。
3.toString方法
該方法用得比較多省撑,一般子類都有覆蓋。
4.finalize方法
該方法用于釋放資源俯在。因?yàn)闊o法確定該方法什么時(shí)候被調(diào)用竟秫,很少使用。
5.equals方法
該方法是非常重要的一個(gè)方法跷乐。一般equals和==是不一樣的肥败,但是在Object中兩者是一樣的。子類一般都要重寫這個(gè)方法愕提。
6.hashCode方法
該方法用于哈希查找馒稍,重寫了equals方法一般都要重寫hashCode方法。這個(gè)方法在一些具有哈希功能的Collection中用到浅侨。
一般必須滿足obj1.equals(obj2)==true筷黔。可以推出obj1.hash- Code()==obj2.hashCode()仗颈,但是hashCode相等不一定就滿足equals佛舱。不過為了提高效率椎例,應(yīng)該盡量使上面兩個(gè)條件接近等價(jià)。
7.wait方法
wait方法就是使當(dāng)前線程等待該對(duì)象的鎖请祖,當(dāng)前線程必須是該對(duì)象的擁有者订歪,也就是具有該對(duì)象的鎖。wait()方法一直等待肆捕,直到獲得鎖或者被中斷刷晋。wait(long timeout)設(shè)定一個(gè)超時(shí)間隔,如果在規(guī)定時(shí)間內(nèi)沒有獲得鎖就返回慎陵。
調(diào)用該方法后當(dāng)前線程進(jìn)入睡眠狀態(tài)眼虱,直到以下事件發(fā)生。
(1)其他線程調(diào)用了該對(duì)象的notify方法席纽。
(2)其他線程調(diào)用了該對(duì)象的notifyAll方法捏悬。
(3)其他線程調(diào)用了interrupt中斷該線程。
(4)時(shí)間間隔到了润梯。
此時(shí)該線程就可以被調(diào)度了过牙,如果是被中斷的話就拋出一個(gè)InterruptedException異常。
8.notify方法
該方法喚醒在該對(duì)象上等待的某個(gè)線程纺铭。
9.notifyAll方法
該方法喚醒在該對(duì)象上等待的所有線程寇钉。

類構(gòu)造器public Object();

大部分情況下,Java中通過形如 new A(args..)形式創(chuàng)建一個(gè)屬于該類型的對(duì)象舶赔。其中A即是類名扫倡,A(args..)即此類定義中相對(duì)應(yīng)的構(gòu)造函數(shù)。通過此種形式創(chuàng)建的對(duì)象都是通過類中的構(gòu)造函數(shù)完成竟纳。

為體現(xiàn)此特性撵溃,Java中規(guī)定:在類定義過程中,對(duì)于未定義構(gòu)造函數(shù)的類蚁袭,默認(rèn)會(huì)有一個(gè)無參數(shù)的構(gòu)造函數(shù),作為所有類的基類石咬,Object類自然要反映出此特性揩悄,在源碼中,未給出Object類構(gòu)造函數(shù)定義鬼悠,但實(shí)際上删性,此構(gòu)造函數(shù)是存在的。

當(dāng)然焕窝,并不是所有的類都是通過此種方式去構(gòu)建蹬挺,也自然的,并不是所有的類構(gòu)造函數(shù)都是public它掂。

registerNatives()方法;

private static native void registerNatives();

registerNatives函數(shù)前面有native關(guān)鍵字修飾巴帮,Java中溯泣,用native關(guān)鍵字修飾的函數(shù)表明該方法的實(shí)現(xiàn)并不是在Java中去完成,而是由C/C++去完成榕茧,并被編譯成了.dll垃沦,由Java去調(diào)用。

方法的具體實(shí)現(xiàn)體在dll文件中用押,對(duì)于不同平臺(tái)肢簿,其具體實(shí)現(xiàn)應(yīng)該有所不同。用native修飾蜻拨,即表示操作系統(tǒng)池充,需要提供此方法,Java本身需要使用缎讼。

具體到registerNatives()方法本身收夸,其主要作用是將C/C++中的方法映射到Java中的native方法,實(shí)現(xiàn)方法命名的解耦休涤。

既然如此咱圆,可能有人會(huì)問,registerNatives()修飾符為private功氨,且并沒有執(zhí)行序苏,作用何以達(dá)到?其實(shí)捷凄,在Java源碼中忱详,此方法的聲明后有緊接著一段靜態(tài)代碼塊:

private static native void registerNatives();  
static {  
     registerNatives();  
}  

Clone()方法實(shí)現(xiàn)淺拷貝

protected native Object clone() throwsCloneNotSupportedException;

看,clode()方法又是一個(gè)被聲明為native的方法跺涤,因此匈睁,我們知道了clone()方法并不是Java的原生方法,具體的實(shí)現(xiàn)是有C/C++完成的桶错。clone英文翻譯為"克隆"航唆,其目的是創(chuàng)建并返回此對(duì)象的一個(gè)副本。

形象點(diǎn)理解院刁,這有一輛科魯茲糯钙,你看著不錯(cuò)双揪,想要個(gè)一模一樣的吏砂。你調(diào)用此方法即可像變魔術(shù)一樣變出一輛一模一樣的科魯茲出來。配置一樣苗胀,長相一樣狡刘。但從此刻起享潜,原來的那輛科魯茲如果進(jìn)行了新的裝飾,與你克隆出來的這輛科魯茲沒有任何關(guān)系了嗅蔬。

你克隆出來的對(duì)象變不變完全在于你對(duì)克隆出來的科魯茲有沒有進(jìn)行過什么操作了剑按。Java術(shù)語表述為:clone函數(shù)返回的是一個(gè)引用疾就,指向的是新的clone出來的對(duì)象,此對(duì)象與原對(duì)象分別占用不同的堆空間吕座。

明白了clone的含義后虐译,接下來看看如果調(diào)用clone()函數(shù)對(duì)象進(jìn)行此克隆操作。

首先看一下下面的這個(gè)例子:

package com.corn.objectsummary;  
  
import com.corn.Person;  
  
public class ObjectTest {  
  
    public static void main(String[] args) {  
  
        Object o1 = new Object();  
        // The method clone() from the type Object is not visible  
        Object clone = o1.clone();  
    }  
  
}  

例子很簡單吴趴,在main()方法中漆诽,new一個(gè)Oject對(duì)象后,想直接調(diào)用此對(duì)象的clone方法克隆一個(gè)對(duì)象锣枝,但是出現(xiàn)錯(cuò)誤提示:"The method clone() from the type Object is not visible"

why? 根據(jù)提示厢拭,第一反應(yīng)是ObjectTest類中定義的Oject對(duì)象無法訪問其clone()方法∑踩回到Object類中clone()方法的定義供鸠,可以看到其被聲明為protected,估計(jì)問題就在這上面了陨闹,protected修飾的屬性或方法表示:在同一個(gè)包內(nèi)或者不同包的子類可以訪問楞捂。

顯然,Object類與ObjectTest類在不同的包中趋厉,但是ObjectTest繼承自O(shè)bject寨闹,是Object類的子類,于是君账,現(xiàn)在卻出現(xiàn)子類中通過Object引用不能訪問protected方法繁堡,原因在于對(duì)"不同包中的子類可以訪問"沒有正確理解。

"不同包中的子類可以訪問"乡数,是指當(dāng)兩個(gè)類不在同一個(gè)包中的時(shí)候椭蹄,繼承自父類的子類內(nèi)部且主調(diào)(調(diào)用者)為子類的引用時(shí)才能訪問父類用protected修飾的成員(屬性/方法)。 在子類內(nèi)部净赴,主調(diào)為父類的引用時(shí)并不能訪問此protected修飾的成員绳矩。!(super關(guān)鍵字除外)

于是玖翅,上例改成如下形式翼馆,我們發(fā)現(xiàn),可以正常編譯:

    public class clone方法 {
    public static void main(String[] args) {

    }
    public void test1() {

        User user = new User();
//        User copy = user.clone();
    }
    public void test2() {
        User user = new User();
//        User copy = (User)user.clone();
    }
}

是的烧栋,因?yàn)榇藭r(shí)的主調(diào)已經(jīng)是子類的引用了写妥。

上述代碼在運(yùn)行過程中會(huì)拋出"java.lang.CloneNotSupportedException",表明clone()方法并未正確執(zhí)行完畢拳球,問題的原因在與Java中的語法規(guī)定:

clone()的正確調(diào)用是需要實(shí)現(xiàn)Cloneable接口审姓,如果沒有實(shí)現(xiàn)Cloneable接口,并且子類直接調(diào)用Object類的clone()方法祝峻,則會(huì)拋出CloneNotSupportedException異常魔吐。

Cloneable接口僅是一個(gè)表示接口扎筒,接口本身不包含任何方法,用來指示Object.clone()可以合法的被子類引用所調(diào)用酬姆。

于是嗜桌,上述代碼改成如下形式,即可正確指定clone()方法以實(shí)現(xiàn)克隆辞色。

public class User implements Cloneable{
public int id;
public String name;
public UserInfo userInfo;

public static void main(String[] args) {
    User user = new User();
    UserInfo userInfo = new UserInfo();
    user.userInfo = userInfo;
    System.out.println(user);
    System.out.println(user.userInfo);
    try {
        User copy = (User) user.clone();
        System.out.println(copy);
        System.out.println(copy.userInfo);
    } catch (CloneNotSupportedException e) {
        e.printStackTrace();
    }
}
//拷貝的User實(shí)例與原來不一樣骨宠,是兩個(gè)對(duì)象。
//    com.javase.Class和Object.Object方法.用到的類.User@4dc63996
//    com.javase.Class和Object.Object方法.用到的類.UserInfo@d716361
        //而拷貝后對(duì)象的userinfo引用對(duì)象是同一個(gè)相满。
    //所以這是淺拷貝
//    com.javase.Class和Object.Object方法.用到的類.User@6ff3c5b5
//    com.javase.Class和Object.Object方法.用到的類.UserInfo@d716361
}

總結(jié):
clone方法實(shí)現(xiàn)的是淺拷貝层亿,只拷貝當(dāng)前對(duì)象,并且在堆中分配新的空間立美,放這個(gè)復(fù)制的對(duì)象匿又。但是對(duì)象如果里面有其他類的子對(duì)象,那么就不會(huì)拷貝到新的對(duì)象中建蹄。

==深拷貝和淺拷貝的區(qū)別==

淺拷貝
淺拷貝是按位拷貝對(duì)象碌更,它會(huì)創(chuàng)建一個(gè)新對(duì)象,這個(gè)對(duì)象有著原始對(duì)象屬性值的一份精確拷貝洞慎。如果屬性是基本類型痛单,拷貝的就是基本類型的值;如果屬性是內(nèi)存地址(引用類型)拢蛋,拷貝的就是內(nèi)存地址 桦他,因此如果其中一個(gè)對(duì)象改變了這個(gè)地址,就會(huì)影響到另一個(gè)對(duì)象谆棱。

深拷貝
深拷貝會(huì)拷貝所有的屬性,并拷貝屬性指向的動(dòng)態(tài)分配的內(nèi)存快压。當(dāng)對(duì)象和它所引用的對(duì)象一起拷貝時(shí)即發(fā)生深拷貝。深拷貝相比于淺拷貝速度較慢并且花銷較大垃瞧。
現(xiàn)在為了要在clone對(duì)象時(shí)進(jìn)行深拷貝蔫劣, 那么就要Clonable接口,覆蓋并實(shí)現(xiàn)clone方法个从,除了調(diào)用父類中的clone方法得到新的對(duì)象脉幢, 還要將該類中的引用變量也clone出來。如果只是用Object中默認(rèn)的clone方法嗦锐,是淺拷貝的嫌松。

那么這兩種方式有什么相同和不同呢?

new操作符的本意是分配內(nèi)存奕污。程序執(zhí)行到new操作符時(shí)萎羔, 首先去看new操作符后面的類型,因?yàn)橹懒祟愋吞寄拍苤酪峙涠啻蟮膬?nèi)存空間贾陷。

分配完內(nèi)存之后缘眶,再調(diào)用構(gòu)造函數(shù),填充對(duì)象的各個(gè)域髓废,這一步叫做對(duì)象的初始化巷懈,構(gòu)造方法返回后,一個(gè)對(duì)象創(chuàng)建完畢慌洪,可以把他的引用(地址)發(fā)布到外部顶燕,在外部就可以使用這個(gè)引用操縱這個(gè)對(duì)象。

而clone在第一步是和new相似的冈爹, 都是分配內(nèi)存割岛,調(diào)用clone方法時(shí),分配的內(nèi)存和源對(duì)象(即調(diào)用clone方法的對(duì)象)相同犯助,然后再使用原對(duì)象中對(duì)應(yīng)的各個(gè)域癣漆,填充新對(duì)象的域,

填充完成之后剂买,clone方法返回惠爽,一個(gè)新的相同的對(duì)象被創(chuàng)建,同樣可以把這個(gè)新對(duì)象的引用發(fā)布到外部瞬哼。

==也就是說婚肆,一個(gè)對(duì)象在淺拷貝以后,只是把對(duì)象復(fù)制了一份放在堆空間的另一個(gè)地方坐慰,但是成員變量如果有引用指向其他對(duì)象较性,這個(gè)引用指向的對(duì)象和被拷貝的對(duì)象中引用指向的對(duì)象是一樣的。當(dāng)然结胀,基本數(shù)據(jù)類型還是會(huì)重新拷貝一份的赞咙。==

getClass()方法

4.public final native Class<?> getClass();

getClass()也是一個(gè)native方法,返回的是此Object對(duì)象的類對(duì)象/運(yùn)行時(shí)類對(duì)象Class<?>糟港。效果與Object.class相同攀操。

首先解釋下"類對(duì)象"的概念:在Java中,類是是對(duì)具有一組相同特征或行為的實(shí)例的抽象并進(jìn)行描述秸抚,對(duì)象則是此類所描述的特征或行為的具體實(shí)例速和。

作為概念層次的類,其本身也具有某些共同的特性剥汤,如都具有類名稱颠放、由類加載器去加載,都具有包吭敢,具有父類碰凶,屬性和方法等。

于是,Java中有專門定義了一個(gè)類痒留,Class,去描述其他類所具有的這些特性蠢沿,因此伸头,從此角度去看,類本身也都是屬于Class類的對(duì)象舷蟀。為與經(jīng)常意義上的對(duì)象相區(qū)分恤磷,在此稱之為"類對(duì)象"。

public class getClass方法 {
    public static void main(String[] args) {
        User user = new User();
        //getclass方法是native方法野宜,可以取到堆區(qū)唯一的Class<User>對(duì)象
        Class<?> aClass = user.getClass();
        Class bClass = User.class;
        try {
            Class cClass = Class.forName("com.javase.Class和Object.Object方法.用到的類.User");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        System.out.println(aClass);
        System.out.println(bClass);
//        class com.javase.Class和Object.Object方法.用到的類.User
//        class com.javase.Class和Object.Object方法.用到的類.User
        try {
            User a = (User) aClass.newInstance();

        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }
} 

此處主要大量涉及到Java中的反射知識(shí)

equals()方法

5.public boolean equals(Object obj);

與equals在Java中經(jīng)常被使用扫步,大家也都知道與equals的區(qū)別:

==表示的是變量值完成相同(對(duì)于基礎(chǔ)類型,地址中存儲(chǔ)的是值匈子,引用類型則存儲(chǔ)指向?qū)嶋H對(duì)象的地址)河胎;

equals表示的是對(duì)象的內(nèi)容完全相同,此處的內(nèi)容多指對(duì)象的特征/屬性虎敦。

實(shí)際上游岳,上面說法是不嚴(yán)謹(jǐn)?shù)模嗟闹皇浅R娪赟tring類中其徙。首先看一下Object類中關(guān)于equals()方法的定義:

public boolean equals(Object obj) {  
     return (this == obj);  
}  

由此可見胚迫,Object原生的equals()方法內(nèi)部調(diào)用的正是==,與==具有相同的含義唾那。既然如此访锻,為什么還要定義此equals()方法?

equals()方法的正確理解應(yīng)該是:判斷兩個(gè)對(duì)象是否相等闹获。那么判斷對(duì)象相等的標(biāo)尺又是什么期犬?

如上,在object類中避诽,此標(biāo)尺即為==哭懈。當(dāng)然,這個(gè)標(biāo)尺不是固定的茎用,其他類中可以按照實(shí)際的需要對(duì)此標(biāo)尺含義進(jìn)行重定義遣总。如String類中則是依據(jù)字符串內(nèi)容是否相等來重定義了此標(biāo)尺含義。如此可以增加類的功能型和實(shí)際編碼的靈活性轨功。當(dāng)然了旭斥,如果自定義的類沒有重寫equals()方法來重新定義此標(biāo)尺,那么默認(rèn)的將是其父類的equals()古涧,直到object基類垂券。

如下場景的實(shí)際業(yè)務(wù)需求,對(duì)于User bean,由實(shí)際的業(yè)務(wù)需求可知當(dāng)屬性u(píng)id相同時(shí)菇爪,表示的是同一個(gè)User算芯,即兩個(gè)User對(duì)象相等。則可以重寫equals以重定義User對(duì)象相等的標(biāo)尺凳宙。

ObjectTest中打印出true熙揍,因?yàn)閁ser類定義中重寫了equals()方法,這很好理解氏涩,很可能張三是一個(gè)人小名届囚,張三豐才是其大名,判斷這兩個(gè)人是不是同一個(gè)人是尖,這時(shí)只用判斷uid是否相同即可意系。

如上重寫equals方法表面上看上去是可以了,實(shí)則不然饺汹。因?yàn)樗茐牧薐ava中的約定:重寫equals()方法必須重寫hasCode()方法蛔添。

hashCode()方法;

  1. public native int hashCode()

hashCode()方法返回一個(gè)整形數(shù)值,表示該對(duì)象的哈希碼值兜辞。

hashCode()具有如下約定:

1).在Java應(yīng)用程序程序執(zhí)行期間作郭,對(duì)于同一對(duì)象多次調(diào)用hashCode()方法時(shí),其返回的哈希碼是相同的弦疮,前提是將對(duì)象進(jìn)行equals比較時(shí)所用的標(biāo)尺信息未做修改夹攒。在Java應(yīng)用程序的一次執(zhí)行到另外一次執(zhí)行,同一對(duì)象的hashCode()返回的哈希碼無須保持一致胁塞;

2).如果兩個(gè)對(duì)象相等(依據(jù):調(diào)用equals()方法)咏尝,那么這兩個(gè)對(duì)象調(diào)用hashCode()返回的哈希碼也必須相等;

3).反之啸罢,兩個(gè)對(duì)象調(diào)用hasCode()返回的哈希碼相等编检,這兩個(gè)對(duì)象不一定相等。

即嚴(yán)格的數(shù)學(xué)邏輯表示為: 兩個(gè)對(duì)象相等 <=>  equals()相等  => hashCode()相等扰才。因此允懂,重寫equlas()方法必須重寫hashCode()方法,以保證此邏輯嚴(yán)格成立衩匣,同時(shí)可以推理出:hasCode()不相等 => equals()不相等 <=> 兩個(gè)對(duì)象不相等蕾总。
 
可能有人在此產(chǎn)生疑問:既然比較兩個(gè)對(duì)象是否相等的唯一條件(也是沖要條件)是equals,那么為什么還要弄出一個(gè)hashCode()琅捏,并且進(jìn)行如此約定生百,弄得這么麻煩?
 
其實(shí)柄延,這主要體現(xiàn)在hashCode()方法的作用上蚀浆,其主要用于增強(qiáng)哈希表的性能。
 
以集合類中,以Set為例市俊,當(dāng)新加一個(gè)對(duì)象時(shí)杨凑,需要判斷現(xiàn)有集合中是否已經(jīng)存在與此對(duì)象相等的對(duì)象,如果沒有hashCode()方法摆昧,需要將Set進(jìn)行一次遍歷撩满,并逐一用equals()方法判斷兩個(gè)對(duì)象是否相等,此種算法時(shí)間復(fù)雜度為o(n)据忘。通過借助于hasCode方法,先計(jì)算出即將新加入對(duì)象的哈希碼搞糕,然后根據(jù)哈希算法計(jì)算出此對(duì)象的位置勇吊,直接判斷此位置上是否已有對(duì)象即可。(注:Set的底層用的是Map的原理實(shí)現(xiàn))

在此需要糾正一個(gè)理解上的誤區(qū):對(duì)象的hashCode()返回的不是對(duì)象所在的物理內(nèi)存地址窍仰。甚至也不一定是對(duì)象的邏輯地址汉规,hashCode()相同的兩個(gè)對(duì)象,不一定相等驹吮,換言之针史,不相等的兩個(gè)對(duì)象,hashCode()返回的哈希碼可能相同碟狞。

因此啄枕,在上述代碼中,重寫了equals()方法后族沃,需要重寫hashCode()方法频祝。

public class equals和hashcode方法 {
    @Override
    //修改equals時(shí)必須同時(shí)修改hashcode方法,否則在作為key時(shí)會(huì)出問題
    public boolean equals(Object obj) {
        return (this == obj);
    }
    
    @Override
    //相同的對(duì)象必須有相同hashcode脆淹,不同對(duì)象可能有相同hashcode
    public int hashCode() {
        return hashCode() >> 2;
    }
}

toString()方法

7.public String toString();

toString()方法返回該對(duì)象的字符串表示常空。先看一下Object中的具體方法體:

 public String toString() {  
    return getClass().getName() + "@" + Integer.toHexString(hashCode());  
}  

toString()方法相信大家都經(jīng)常用到,即使沒有顯式調(diào)用盖溺,但當(dāng)我們使用System.out.println(obj)時(shí)漓糙,其內(nèi)部也是通過toString()來實(shí)現(xiàn)的。

getClass()返回對(duì)象的類對(duì)象烘嘱,getClassName()以String形式返回類對(duì)象的名稱(含包名)昆禽。Integer.toHexString(hashCode())則是以對(duì)象的哈希碼為實(shí)參,以16進(jìn)制無符號(hào)整數(shù)形式返回此哈希碼的字符串表示形式蝇庭。

如上例中的u1的哈希碼是638为狸,則對(duì)應(yīng)的16進(jìn)制為27e,調(diào)用toString()方法返回的結(jié)果為:com.corn.objectsummary.User@27e遗契。

因此:toString()是由對(duì)象的類型和其哈希碼唯一確定辐棒,同一類型但不相等的兩個(gè)對(duì)象分別調(diào)用toString()方法返回的結(jié)果可能相同。

wait() notify() notifAll()

8/9/10/11/12. wait(...) / notify() / notifyAll()

一說到wait(...) / notify() | notifyAll()幾個(gè)方法,首先想到的是線程漾根。確實(shí)泰涂,這幾個(gè)方法主要用于java多線程之間的協(xié)作。先具體看下這幾個(gè)方法的主要含義:

wait():調(diào)用此方法所在的當(dāng)前線程等待辐怕,直到在其他線程上調(diào)用此方法的主調(diào)(某一對(duì)象)的notify()/notifyAll()方法逼蒙。

wait(long timeout)/wait(long timeout, int nanos):調(diào)用此方法所在的當(dāng)前線程等待,直到在其他線程上調(diào)用此方法的主調(diào)(某一對(duì)象)的notisfy()/notisfyAll()方法寄疏,或超過指定的超時(shí)時(shí)間量是牢。

notify()/notifyAll():喚醒在此對(duì)象監(jiān)視器上等待的單個(gè)線程/所有線程。

wait(...) / notify() | notifyAll()一般情況下都是配套使用陕截。下面來看一個(gè)簡單的例子:

這是一個(gè)生產(chǎn)者消費(fèi)者的模型驳棱,只不過這里只用flag來標(biāo)識(shí)哪個(gè)線程需要工作

public class wait和notify {
    //volatile保證線程可見性
    volatile static int flag = 1;
    //object作為鎖對(duì)象,用于線程使用wait和notify方法
    volatile static Object o = new Object();
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                //wait和notify只能在同步代碼塊內(nèi)使用
                synchronized (o) {
                    while (true) {
                        if (flag == 0) {
                            try {
                                Thread.sleep(2000);
                                System.out.println("thread1 wait");
                                //釋放鎖农曲,線程掛起進(jìn)入object的等待隊(duì)列社搅,后續(xù)代碼運(yùn)行
                                o.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        System.out.println("thread1 run");
                        System.out.println("notify t2");
                        flag = 0;
                        //通知等待隊(duì)列的一個(gè)線程獲取鎖
                        o.notify();
                    }
                }
            }
        }).start();
        //解釋同上
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    synchronized (o) {
                        if (flag == 1) {
                            try {
                                Thread.sleep(2000);
                                System.out.println("thread2 wait");
                                o.wait();
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                        }
                        System.out.println("thread2 run");
                        System.out.println("notify t1");
                        flag = 1;
                        o.notify();
                    }
                }
            }
        }).start();
    }

    //輸出結(jié)果是
//    thread1 run
//    notify t2
//    thread1 wait
//    thread2 run
//    notify t1
//    thread2 wait
//    thread1 run
//    notify t2
//不斷循環(huán)
}

從上述例子的輸出結(jié)果中可以得出如下結(jié)論:

1、wait(...)方法調(diào)用后當(dāng)前線程將立即阻塞乳规,且適當(dāng)其所持有的同步代碼塊中的鎖形葬,直到被喚醒或超時(shí)或打斷后且重新獲取到鎖后才能繼續(xù)執(zhí)行;

2暮的、notify()/notifyAll()方法調(diào)用后笙以,其所在線程不會(huì)立即釋放所持有的鎖,直到其所在同步代碼塊中的代碼執(zhí)行完畢冻辩,此時(shí)釋放鎖源织,因此,如果其同步代碼塊后還有代碼微猖,其執(zhí)行則依賴于JVM的線程調(diào)度谈息。

在Java源碼中,可以看到wait()具體定義如下:

public final void wait() throws InterruptedException {  
     wait(0);  
}  

且wait(long timeout, int nanos)方法定義內(nèi)部實(shí)質(zhì)上也是通過調(diào)用wait(long timeout)完成凛剥。而wait(long timeout)是一個(gè)native方法侠仇。因此,wait(...)方法本質(zhì)上都是native方式實(shí)現(xiàn)犁珠。

notify()/notifyAll()方法也都是native方法逻炊。

Java中線程具有較多的知識(shí)點(diǎn),是一塊比較大且重要的知識(shí)點(diǎn)犁享。后期會(huì)有博文專門針對(duì)Java多線程作出詳細(xì)總結(jié)余素。此處不再細(xì)述。

finalize()方法

  1. protected void finalize();

finalize方法主要與Java垃圾回收機(jī)制有關(guān)炊昆。首先我們看一下finalized方法在Object中的具體定義:

protected void finalize() throws Throwable { }  

我們發(fā)現(xiàn)Object類中finalize方法被定義成一個(gè)空方法桨吊,為什么要如此定義呢威根?finalize方法的調(diào)用時(shí)機(jī)是怎么樣的呢?

首先视乐,Object中定義finalize方法表明Java中每一個(gè)對(duì)象都將具有finalize這種行為洛搀,其具體調(diào)用時(shí)機(jī)在:JVM準(zhǔn)備對(duì)此對(duì)形象所占用的內(nèi)存空間進(jìn)行垃圾回收前,將被調(diào)用佑淀。由此可以看出留美,此方法并不是由我們主動(dòng)去調(diào)用的(雖然可以主動(dòng)去調(diào)用,此時(shí)與其他自定義方法無異)伸刃。

CLass類和Object類的關(guān)系

Object類和Class類沒有直接的關(guān)系谎砾。

Object類是一切java類的父類,對(duì)于普通的java類捧颅,即便不聲明景图,也是默認(rèn)繼承了Object類。典型的隘道,可以使用Object類中的toString()方法症歇。

Class類是用于java反射機(jī)制的郎笆,一切java類谭梗,都有一個(gè)對(duì)應(yīng)的Class對(duì)象,他是一個(gè)final類宛蚓。Class 類的實(shí)例表示激捏,正在運(yùn)行的 Java 應(yīng)用程序中的類和接口。

轉(zhuǎn)一個(gè)知乎很有趣的問題
https://www.zhihu.com/question/30301819

Java的對(duì)象模型中:
1 所有的類都是Class類的實(shí)例凄吏,Object是類远舅,那么Object也是Class類的一個(gè)實(shí)例。

2 所有的類都最終繼承自O(shè)bject類痕钢,Class是類图柏,那么Class也繼承自O(shè)bject。

3 這就像是先有雞還是先有蛋的問題任连,請(qǐng)問實(shí)際中JVM是怎么處理的蚤吹?

這個(gè)問題中,第1個(gè)假設(shè)是錯(cuò)的:java.lang.Object是一個(gè)Java類随抠,但并不是java.lang.Class的一個(gè)實(shí)例裁着。后者只是一個(gè)用于描述Java類與接口的、用于支持反射操作的類型拱她。這點(diǎn)上Java跟其它一些更純粹的面向?qū)ο笳Z言(例如Python和Ruby)不同二驰。

而第2個(gè)假設(shè)是對(duì)的:java.lang.Class是java.lang.Object的派生類,前者繼承自后者秉沼。雖然第1個(gè)假設(shè)不對(duì)桶雀,但“雞蛋問題”仍然存在:在一個(gè)已經(jīng)啟動(dòng)完畢矿酵、可以使用的Java對(duì)象系統(tǒng)里,必須要有一個(gè)java.lang.Class實(shí)例對(duì)應(yīng)java.lang.Object這個(gè)類背犯;而java.lang.Class是java.lang.Object的派生類坏瘩,按“一般思維”前者應(yīng)該要在后者完成初始化之后才可以初始化…

事實(shí)是:這些相互依賴的核心類型完全可以在“混沌”中一口氣都初始化好,然后對(duì)象系統(tǒng)的狀態(tài)才叫做完成了“bootstrap”漠魏,后面就可以按照J(rèn)ava對(duì)象系統(tǒng)的一般規(guī)則去運(yùn)行倔矾。JVM、JavaScript柱锹、Python哪自、Ruby等的運(yùn)行時(shí)都有這樣的bootstrap過程。

在“混沌”(boostrap過程)里禁熏,JVM可以為對(duì)象系統(tǒng)中最重要的一些核心類型先分配好內(nèi)存空間壤巷,讓它們進(jìn)入[已分配空間]但[尚未完全初始化]狀態(tài)。此時(shí)這些對(duì)象雖然已經(jīng)分配了空間瞧毙,但因?yàn)闋顟B(tài)還不完整所以尚不可使用胧华。

然后,通過這些分配好的空間把這些核心類型之間的引用關(guān)系串好宙彪。到此為止所有動(dòng)作都由JVM完成矩动,尚未執(zhí)行任何Java字節(jié)碼。然后這些核心類型就進(jìn)入了[完全初始化]狀態(tài)释漆,對(duì)象系統(tǒng)就可以開始自我運(yùn)行下去悲没,也就是可以開始執(zhí)行Java字節(jié)碼來進(jìn)一步完成Java系統(tǒng)的初始化了。

參考文章

https://www.cnblogs.com/congsg2016/p/5317362.html
https://www.jb51.net/article/125936.htm
https://blog.csdn.net/dufufd/article/details/80537638
https://blog.csdn.net/farsight1/article/details/80664104
https://blog.csdn.net/xiaomingdetianxia/article/details/77429180

微信公眾號(hào)

Java技術(shù)江湖

如果大家想要實(shí)時(shí)關(guān)注我更新的文章以及分享的干貨的話男图,可以關(guān)注我的公眾號(hào)【Java技術(shù)江湖】一位阿里 Java 工程師的技術(shù)小站示姿,作者黃小斜,專注 Java 相關(guān)技術(shù):SSM逊笆、SpringBoot栈戳、MySQL、分布式难裆、中間件子檀、集群、Linux差牛、網(wǎng)絡(luò)命锄、多線程,偶爾講點(diǎn)Docker偏化、ELK脐恩,同時(shí)也分享技術(shù)干貨和學(xué)習(xí)經(jīng)驗(yàn),致力于Java全棧開發(fā)侦讨!

Java工程師必備學(xué)習(xí)資源: 一些Java工程師常用學(xué)習(xí)資源驶冒,關(guān)注公眾號(hào)后苟翻,后臺(tái)回復(fù)關(guān)鍵字 “Java” 即可免費(fèi)無套路獲取。

我的公眾號(hào)

個(gè)人公眾號(hào):黃小斜

作者是 985 碩士骗污,螞蟻金服 JAVA 工程師崇猫,專注于 JAVA 后端技術(shù)棧:SpringBoot、MySQL需忿、分布式诅炉、中間件、微服務(wù)屋厘,同時(shí)也懂點(diǎn)投資理財(cái)涕烧,偶爾講點(diǎn)算法和計(jì)算機(jī)理論基礎(chǔ),堅(jiān)持學(xué)習(xí)和寫作汗洒,相信終身學(xué)習(xí)的力量议纯!

程序員3T技術(shù)學(xué)習(xí)資源: 一些程序員學(xué)習(xí)技術(shù)的資源大禮包,關(guān)注公眾號(hào)后溢谤,后臺(tái)回復(fù)關(guān)鍵字 “資料” 即可免費(fèi)無套路獲取瞻凤。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市世杀,隨后出現(xiàn)的幾起案子阀参,更是在濱河造成了極大的恐慌,老刑警劉巖玫坛,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件结笨,死亡現(xiàn)場離奇詭異包晰,居然都是意外死亡湿镀,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門伐憾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來勉痴,“玉大人,你說我怎么就攤上這事树肃≌裘” “怎么了?”我有些...
    開封第一講書人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵胸嘴,是天一觀的道長雏掠。 經(jīng)常有香客問我,道長劣像,這世上最難降的妖魔是什么乡话? 我笑而不...
    開封第一講書人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮耳奕,結(jié)果婚禮上绑青,老公的妹妹穿的比我還像新娘诬像。我一直安慰自己,他們只是感情好闸婴,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開白布坏挠。 她就那樣靜靜地躺著,像睡著了一般邪乍。 火紅的嫁衣襯著肌膚如雪降狠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,950評(píng)論 1 291
  • 那天庇楞,我揣著相機(jī)與錄音喊熟,去河邊找鬼。 笑死姐刁,一個(gè)胖子當(dāng)著我的面吹牛芥牌,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播聂使,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼壁拉,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了柏靶?” 一聲冷哼從身側(cè)響起弃理,我...
    開封第一講書人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎屎蜓,沒想到半個(gè)月后痘昌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡炬转,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年辆苔,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片扼劈。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡驻啤,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出荐吵,到底是詐尸還是另有隱情骑冗,我是刑警寧澤,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布先煎,位于F島的核電站贼涩,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏薯蝎。R本人自食惡果不足惜遥倦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望良风。 院中可真熱鬧谊迄,春花似錦闷供、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至粮呢,卻和暖如春婿失,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背啄寡。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來泰國打工豪硅, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人挺物。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓懒浮,卻偏偏與公主長得像,于是被迫代替她去往敵國和親识藤。 傳聞我的和親對(duì)象是個(gè)殘疾皇子砚著,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容