Java之运算符,位运算(源码反码补码)和基本数据类型

1 java运算符

1.1 各个运算符一览

序号 符号 名称 结合性(与操作数) 对目 说明
1 . 从左到右 双目
2 () 圆括号 从左到右
3 [ ] 方括号 从左到右
4 + 正号 从右到左 单目
5 - 负号 从右到左 单目
6 ++ 自增 从右到左 单目 前缀增,后缀增
7 -- 自减 从右到左 单目 前缀减,后缀减
8 ~ 按位非/取补运算 从右到左 单目
9 ! 逻辑非 从右到左 单目 “!”不可以与“=”联用
10 * 从左到右 双目
11 / 从左到右 双目 整数除法:
取商的整数部分,小数部分去掉,不四舍五入
12 % 取余 从左到右 双目
13 + 从左到右 双目
14 - 从左到右 双目
15 << 左移位运算符 从左到右 双目
16 >> 右移位运算符 从左到右 双目
17 >>> 无符号右移位运算符 从左到右 双目
18 < 小于 从左到右 双目
19 <= 小于或等于 从左到右 双目
20 > 大于 从左到右 双目
21 >= 大于或等于 从左到右 双目
22 instanceof 确定某对象是否属于指定的类 从左到右 双目
23 == 等于 从左到右 双目
24 != 不等于 从左到右 双目
25 & 按位与 从左到右 双目
26 | 按位或 从左到右 双目
27 ^ 按位异或 从左到右 双目
28 && 短路与 从左到右 双目
29 || 短路或 从左到右 双目
30 ?: 条件运算符 从右到左 三目
31 = 赋值运算符 从右到左 双目
32 += 混合赋值运算符 从右到左 双目
33 -= 混合赋值运算符 从右到左 双目
34 *= 混合赋值运算符 从右到左 双目
35 /= 混合赋值运算符 从右到左 双目
36 %= 混合赋值运算符 从右到左 双目
37 |= 混合赋值运算符 从右到左 双目
38 ^= 混合赋值运算符 从右到左 双目
39 <<= 混合赋值运算符 从右到左 双目
40 >>= 混合赋值运算符 从右到左 双目
41 >>>= 混合赋值运算符 从右到左 双目

1.2 部分运算符说明

部分运算符说明:
算数运算符:+ :加法,- :减法,* :乘法,/ :除法,% :取余运算
关系运算符:

  • <:只能比较基本类型数据之间的关系,不能比较对象之间的关系;
  • > : (同关系运算符<);
  • <=: (同关系运算符<);
  • >=: (同关系运算符<);
  • == :若使用该运算符比较两个对象的引用(变量),则实质上是比较两个变量是否引用了相同的对象。所谓相同的对象是指,是否是在堆栈(Heap)中开辟的同一块儿内存单元中存放的对象。
    若比较两个对象的引用(变量)所引用的对象的内容是否相同,则应该使用equals()方法,该方法的返回值类型是布尔值。需要注意的是:若用类库中的类创建对象,则对象的引用调用equals()方法比较的是对象的内容;若用自定义的类来创建对象,则对象的引用调用equals()方法比较的是两个引用是否引用了同一个对象,因为第二种情况equals()方法默认的是比较引用。
  • !=:(同关系运算符==)

逻辑运算符 (操作符只能是布尔类型的)&&||!

 public class Demo {
     public static void main(String[] args) {
 //        System.out.println((!'1'||'1')+5);//编译错误
 //        System.out.println(!5);//编译错误
 //        System.out.println(('1'||'1')+5);//编译错误
//        System.out.println(1||2);//编译错误
//        System.out.println(5-3||4-2);//编译错误 8   
      System.out.println(5<3||4>3);//true 9     }
 }

位运算符:&|^!:不可以与=联用,因为!是一元操作符;不可以对布尔类型的数据进行按位非运算
移位运算符(只能处理整数运算符):Charbyteshort类型,在进行移位之前,都将被转换成int类型,移位后的结果也是int类型;移位符号右边的操作数只截取其二进制的后5位(目的是防止因为移位操作而超出int类型的表示范围:25次方是32,int类型的最大范围是32位);对long类型进行移位,结果仍然是long类型,移位符号右边的操作符只截取其二进制的后6位。

>> :若符号位为正,则在最高位插入0;若符号位为,则在最高位插入1
>>>:无论正负,都在最高位插入0

1.3 java基本位操作

1.3.1 位操作符号

基本位操作符号:

  • ~按位非(NOT)
    公式:~n=-n-1
  • & 按位与(AND)
  • |按位或(OR)
  • ^按位异或(XOR)
  • >> 右移
  • >>> 无符号右移
  • <<左移

前面几个都非常简单,主要是移位操作比较容易出错.
首先要搞清楚参与运算的数的位数,如int的是32位,long的是64位。
int i = 1; i的二进制原码表示为: 00000000000000000000000000000001
long l = 1;l的二进制原码表示为: 0000000000000000000000000000000000000000000000000000000000000001

1.3.2 原码反码补码

1.3.2.1 相关定义

各个相关概念定义如下:

  • 机器数:一个数在计算机中的二进制表示形式, 叫做这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号, 正数为0, 负数为1
    比如,十进制中的数 +3 ,计算机字长为8位,转换成二进制就是00000011。如果是 -3 ,就是 10000011 。那么,这里的 0000001110000011 就是机器数。

  • 真值:因为第一位是符号位,所以机器数的形式值就不等于真正的数值。例如上面的有符号数 10000011,其最高位1代表,其真正数值是 -3 而不是形式值13110000011转换成十进制等于131)。所以,为区别起见,将带符号位的机器数对应的真正数值称为机器数真值。
    例:0000 0001的真值 = +000 0001 = +1,1000 0001的真值 = –000 0001 = –1

  • 原码:原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值.
    比如:如果是8位二进制:[+1]原 = 0000 0001[-1]原 = 1000 0001
    第一位是符号位. 因为第一位是符号位, 所以8位二进制数的取值范围就是:[1111 1111 , 0111 1111],即:[-127 , 127]
    原码是人脑最容易理解和计算的表示方式.

  • 反码:反码的表示方法是: 正数的反码跟原码一样负数 的反码是在其原码的基础上, 符号位不变 ,其余各位取反
    比如:[+1] = [00000001]原 = [00000001]反
    [-1] = [10000001]原 = [11111110]反
    可见如果一个反码表示的是负数, 人脑无法直观的看出来它的数值. 通常要将其转换成原码再计算

  • 补码:补码的表示方法是: 正数的补码就是其本身负数 的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)
    比如:[+1] = [00000001]原 = [00000001]反 = [00000001]补
    [-1] = [10000001]原 = [11111110]反 = [11111111]补
    对于负数, 补码表示方式也是人脑无法直观看出其数值的. 通常也需要转换成原码在计算其数值

如果有运算得话,负数都是用补码参与运算的,得到的结果也是补码,需要减1取反获得原码

1.3.2.2 为何要使用原码, 反码和补码

在开始深入学习前, 先死记硬背上面的原码, 反码和补码的表示方式以及计算方法.
现在我们知道了计算机可以有三种编码方式表示一个数. 对于正数因为三种编码方式的结果都相同:
[+1] = [00000001]原 = [00000001]反 = [00000001]补
所以不需要过多解释. 但是对于负数:
[-1] = [10000001]原 = [11111110]反 = [11111111]补

可见原码, 反码和补码是完全不同的. 既然原码才是被人脑直接识别并用于计算表示方式, 为何还会有反码和补码呢?
首先, 因为人脑可以知道第一位是符号位, 在计算的时候我们会根据符号位, 选择对真值区域的加减. 但是对于计算机, 加减乘数已经是最基础的运算, 要设计的尽量简单. 计算机辨别符号位显然会让计算机的基础电路设计变得十分复杂! 于是人们想出了将符号位参与运算的方法. 我们知道, 根据运算法则减去一个正数等于加上一个负数, 即: 1-1 = 1 + (-1) = 0, 所以机器可以只有加法而没有减法, 这样计算机运算的设计就更简单了.
于是人们开始探索 将符号位参与运算, 并且只保留加法的方法. 首先来看原码。计算十进制的表达式:

1-1=0
1 - 1 = 1 + (-1) 
= [00000001]原 + [10000001]原 
= [10000010]原 = -2

如果用原码表示, 让符号位也参与计算, 显然对于减法来说, 结果是不正确的.这也就是为何计算机内部不使用原码表示一个数.

为了解决原码做减法的问题, 出现了反码。计算十进制的表达式:

1-1=0
1 - 1 = 1 + (-1)
= [0000 0001]原 + [1000 0001]原
= [0000 0001]反 + [1111 1110]反
= [1111 1111]反 = [1000 0000]原
= -0

发现用反码计算减法, 结果的真值部分是正确的. 而唯一的问题其实就出现在0这个特殊的数值上. 虽然人们理解上+0-0是一样的, 但是0带符号是没有任何意义的. 而且会有[0000 0000]原和[1000 0000]原两个编码表示0.
于是补码的出现, 解决了0的符号以及两个编码的问题:

1-1 = 1 + (-1)
= [0000 0001]原 + [1000 0001]原
= [0000 0001]补 + [1111 1111]补
= [0000 0000]补=[0000 0000]原

这样0[0000 0000]表示, 而以前出现问题的-0则不存在了.而且可以用[1000 0000]表示-128:

(-1) + (-127) = [1000 0001]原 + [1111 1111]原
= [1111 1111]补 + [1000 0001]补
= [1000 0000]补

-1-127的结果应该是-128, 在用补码运算的结果中, [1000 0000]补 就是-128. 但是注意因为实际上是使用以前的-0的补码来表示-128, 所以-128没有原码和反码表示.(对-128的补码表示[1000 0000]补算出来的原码是[0000 0000]原, 这是不正确的)

使用补码, 不仅仅修复了0的符号以及存在两个编码的问题, 而且还能够多表示一个最低数. 这就是为什么8位二进制, 使用原码或反码表示的范围为[-127, +127], 而使用补码表示的范围为[-128, 127].
因为机器使用补码, 所以对于编程中常用到的32int类型, 可以表示范围是: [-2^{31}, 2^{31}-1] 因为第一位表示的是符号位.而使用补码表示时又可以多保存一个最小值.

1.3.2.3 负数运算

负数参与的运算,得到的是 补码,需要将补码先减1,然后逐位取反,得到原码,即为运算结果
0例外,如果得到的是0,则不需减1和取反。
另外,两个正数运算后得到的就是原码,不需减1和取反。
举例:

1^-1, 
-1 :
10000000000000000000000000000001--原码 
11111111111111111111111111111110--反码 
11111111111111111111111111111111--补码 
1 
00000000000000000000000000000001`--原码 
则1^-1等于 
11111111111111111111111111111111^ 
00000000000000000000000000000001= 
11111111111111111111111111111110--补码 
11111111111111111111111111111101--反码 
10000000000000000000000000000010--原码==-2 
即1^-1=-2

举例:

1^-2 
-2 
10000000000000000000000000000010--原码 
01111111111111111111111111111101--反码 
01111111111111111111111111111110--补码 
1 
00000000000000000000000000000001--原码 
则1^-2等于 
01111111111111111111111111111110^ 
00000000000000000000000000000001= 
01111111111111111111111111111111--补码 
01111111111111111111111111111110--反码 
10000000000000000000000000000001--原码==-1 

1.3.2.4 转换16进制为什么需要 &0xff

例如:把汉字转为16进制需要如下:

@Test
    public void testEnHex() throws UnsupportedEncodingException {
        String s = "严";
        byte[] bytes = s.getBytes("utf-8");
        StringBuffer sb = new StringBuffer();
        for (int i = 0;i<bytes.length;i++){
            String s1 = Integer.toHexString(bytes[i] & 0x0ff).toUpperCase();
            if(s1.length()<2){
                sb.append(0);
            }
            sb.append(s1);
        }
        System.out.println(sb.toString());
    }

如上的为什么需要 &0x0ff呢
先看下添加和去掉结果:
&0x0ff是E4B8A5,没有时是FFFFFFE4FFFFFFB8FFFFFFA5
没有&0x0ff转换后多了一串FF

这是因为Integer.toHexString()的接收参数是int,不是byte,于是运算是会先把byte强制转换为int
由于java中强制转换是保持值不变,而在计算机中数都是用 补码 表示的,javaint32位4个byte, 正数补码是正数本身,这样不会有问题,强转为32位时前面24位会填充0,
而负数的补码是将其对应正数二进制表示所有位取反(原码符号位除外,0变1,1变0)后加1,于是32位的0x00 00 00 80(0000 ... 0000 1000 0000)补码是0xFF FF FF 80(1111 ... 1111 1000 0000),前面是填充的1
所以Integer.toHexString()后就会变成前面多了一串F
所以要得到正确的结果,需要用 Integer.toHexString(card[i] & 0xff),这样会只取最后8位(1byte=8位二进制),前面都置0,这样转换出来就是正确的了

为什么非要添加&0x0ff,不加也有结果,只是长点而已嘛
如果不加&0x0ff,那么保存的字符长度难以统一 ,字符串长度太长。
并且byte的取值范围在[-128,127]之间,16进制表示用两个符号就够了0x00—0xff。负数如果用这么多字符,造成正负数符号长度不统一怎么保存呢?从16进制还原成2进制时怎么按长度区分各个数字呢?

所以我们把byte与运算&0xff。以-1为例:1111 1111 1111 1111 1111 1111 1111 1111 & 0xff 得到0000 0000 0000 0000 0000 0000 1111 11110xff。这个数结果依然是-1。用这种方式处理后,byte不论正负,得到的都是二位的16进制数。以两位存储,两位还原,很方便

还原代码如下,使用E4B8A5(用&0xff)能得到正确值,但是使用FFFFFFE4FFFFFFB8FFFFFFA5(没有用&0xff)就不能得到正确的值

public void testHanzi() {
        String hexStr = "E4B8A5";
        String str =  "0123456789ABCDEF" ;
        char [] hexs = hexStr.toCharArray();
        byte [] bytes =  new  byte [hexStr.length() /  2 ];
        int  n;
        for  ( int  i =  0 ; i < bytes.length; i++) {
            n = str.indexOf(hexs[ 2  * i]) *  16 ;
            n += str.indexOf(hexs[ 2  * i +  1 ]);
            bytes[i] = ( byte ) (n & 0xff );
        }
        System.out.println(new String(bytes));
    }

按照16进制两位两位判断,在进行byte强转时高于127时,溢出转为负值

1.3.3 常用的位运算符运算

常用的位运算符--0在位运算中是比较特殊的
^ 异或:相同为0,相异为1; 任何数与0异或都等于原值。 
& 与: 全1为1, 有0为0;任何数与0异或都等于0。
| 或: 有1为1, 全0为0。任何数与0或都等于原值。
<<左移: 补0。
>> 右移:符号位是0补0,是1补1。
>>>无符号右移:补0。
~ 非:逐位取反

1.3.3.1 左右位移

<<:逻辑左移,右边补0,符号位和其他位一样.
正数: x<<1一般相当于2x,但是可能溢出.
溢出范围: 2^{30} ~ (2^{31}-1) 二进制表示 010000...000到01111....1111,移位后最高为变为1了,变成负数了.
负数:
1111111111111111111111111111111 this is 2^31
1000000000000000000000000000000 this is 2^30

x<<1一般也相当于2x,也有可能溢出.所以, x*32可以写成x<<5
溢出范围: -2^{31}~-(2^{30}+1)二进制表示10000...000101111...1111,移位后最高为变成0了,变成正数了.
>> :算术右移,和上面的不对应,为正数时左边补0,为负数时左边补1.
x>>1,相当于x/2,余数被舍弃,因为这个是缩小,所以不会溢出.
不过有一点要注意: -1右移多少位都是-1.
另外舍弃的余数是正的, 3>>1=1 舍弃的余数是1.
-3>>1=-2 舍弃的余数也是1,而不是-1.
对于正数 x>>1和x/2相等
对于负数x>>1x/2不一定相等.
>>> :逻辑右移,这个才是和<<对应的
这个把符号位一起移动,左边补0
对于正数,>>>>>是一样的
对于负数,右移之后就变成正数了.
可以使用Integer.toBinaryString(int i)来看01比特,更加直观.
考虑下面的代码:
for (val = 0; val < 100000; val +=5) { alterX = val * 8; myResult = val * 2; }
用移位操作替代乘法操作可以极大地提高性能。下面是修改后的代码:
for (val = 0; val < 100000; val += 5) { alterX = val << 3; myResult = val << 1; }
修改后的代码不再做乘以8的操作,而是改用等价的左移3位操作,每左移1位相于乘以2。相应地,右移1位操作相当于除以2。值得一提的是,虽然移位操作速度快,但可能使代码比较难于理解,所以最好加上一些注释。

无符号右移位操作符>>>在将bit串右移位时,从bit串的最左边填充0,这和带符号右移位操作符>>不同。>>在将bit串右移位时,从bit串的最左边填充原来最左边的位。也就是说,bit串原来最左边的位是符号位,如果为1,则在带符号右移时最左边始终填充1;如果为0,则在带符号右移时最左边始终填充0。
移位操作符的例子见下表。

操作 结果 说明
00110010<< 2 11001000 右边始终填充0
00110010 >> 2 00001100 结果和>>>一样
00110010 >>> 2 00001100 结果和>>一样
10110010 >> 2 11101100 结果和>>>不一样
10110010 >>> 2 100101100 结果和>>不一样

按位与操作符&对两个bit串按位进行逻辑与,按位或操作符|对两个bit串按位进行逻辑或,按位异或操作符^对两个bit串按位进行异或操作。运算规则如下表所示。

按位与 按位或 按位异或
0 & 0 = 0 0 | 0 = 0 0 ^ 0 = 0
0 & 1 = 0 0 | 1 = 1 0 ^ 1 = 1
1 & 0 = 0 1 | 0 = 1 1 ^ 0 = 1
1 & 1 = 1 1 | 1 = 1 1 ^ 1 = 0

2 基本数据类型

基本类型,或者叫做内置类型,是JAVA中不同于类的特殊类型。它们是我们编程中使用最频繁的类型
基本类型共有八种,它们分别都有相对应的包装类。关于它们的详细信息请如下:
基本类型可以分为三类,字符类型char,布尔类型boolean以及数值类型byte、short、int、long、float、double
数值类型又可以分为整数类型byte、short、int、long和浮点数类型float、doubleJAVA中的数值类型不存在无符号的,它们的取值范围是固定的,不会随着机器硬件环境或者操作系统的改变而改变。实际上,JAVA中还存在另外一种基本类型void,它也有对应的包装类java.lang.Void,不过我们无法直接对它们进行操作。对于数值类型的基本类型的取值范围,我们无需强制去记忆,因为它们的值都已经以常量的形式定义在对应的包装类中了。请看下面的例子:

public class PrimitiveTypeTest {  
    public static void main(String[] args) {  
        // byte  
        System.out.println("基本类型:byte 二进制位数:" + Byte.SIZE);  
        System.out.println("包装类:java.lang.Byte");  
        System.out.println("最小值:Byte.MIN_VALUE=" + Byte.MIN_VALUE);  
        System.out.println("最大值:Byte.MAX_VALUE=" + Byte.MAX_VALUE);  
        System.out.println();  
        // short  
        System.out.println("基本类型:short 二进制位数:" + Short.SIZE);  
        System.out.println("包装类:java.lang.Short");  
        System.out.println("最小值:Short.MIN_VALUE=" + Short.MIN_VALUE);  
        System.out.println("最大值:Short.MAX_VALUE=" + Short.MAX_VALUE);  
        System.out.println();  
       // int  
        System.out.println("基本类型:int 二进制位数:" + Integer.SIZE);  
        System.out.println("包装类:java.lang.Integer");  
        System.out.println("最小值:Integer.MIN_VALUE=" + Integer.MIN_VALUE);  
        System.out.println("最大值:Integer.MAX_VALUE=" + Integer.MAX_VALUE);  
        System.out.println();  
        // long  
        System.out.println("基本类型:long 二进制位数:" + Long.SIZE);  
        System.out.println("包装类:java.lang.Long");  
        System.out.println("最小值:Long.MIN_VALUE=" + Long.MIN_VALUE);  
        System.out.println("最大值:Long.MAX_VALUE=" + Long.MAX_VALUE);  
        System.out.println();   
        // float  
        System.out.println("基本类型:float 二进制位数:" + Float.SIZE);  
        System.out.println("包装类:java.lang.Float");  
        System.out.println("最小值:Float.MIN_VALUE=" + Float.MIN_VALUE);  
        System.out.println("最大值:Float.MAX_VALUE=" + Float.MAX_VALUE);  
        System.out.println();  
     // double  
        System.out.println("基本类型:double 二进制位数:" + Double.SIZE);  
        System.out.println("包装类:java.lang.Double");  
        System.out.println("最小值:Double.MIN_VALUE=" + Double.MIN_VALUE);  
        System.out.println("最大值:Double.MAX_VALUE=" + Double.MAX_VALUE);  
        System.out.println();    
        // char  
        System.out.println("基本类型:char 二进制位数:" + Character.SIZE);  
        System.out.println("包装类:java.lang.Character");  
        // 以数值形式而不是字符形式将Character.MIN_VALUE输出到控制台  
        System.out.println("最小值:Character.MIN_VALUE="  
                + (int) Character.MIN_VALUE);  
        // 以数值形式而不是字符形式将Character.MAX_VALUE输出到控制台  
        System.out.println("最大值:Character.MAX_VALUE="  
                + (int) Character.MAX_VALUE);  
    }  
}  

运行结果:

基本类型:byte 二进制位数:8
包装类:java.lang.Byte
最小值:Byte.MIN_VALUE=-128
最大值:Byte.MAX_VALUE=127

基本类型:short 二进制位数:16
包装类:java.lang.Short
最小值:Short.MIN_VALUE=-32768
最大值:Short.MAX_VALUE=32767

基本类型:int 二进制位数:32
包装类:java.lang.Integer
最小值:Integer.MIN_VALUE=-2147483648
最大值:Integer.MAX_VALUE=2147483647

基本类型:long 二进制位数:64
包装类:java.lang.Long
最小值:Long.MIN_VALUE=-9223372036854775808
最大值:Long.MAX_VALUE=9223372036854775807

基本类型:float 二进制位数:32
包装类:java.lang.Float
最小值:Float.MIN_VALUE=1.4E-45
最大值:Float.MAX_VALUE=3.4028235E38

基本类型:double 二进制位数:64
包装类:java.lang.Double
最小值:Double.MIN_VALUE=4.9E-324
最大值:Double.MAX_VALUE=1.7976931348623157E308

基本类型:char 二进制位数:16
包装类:java.lang.Character
最小值:Character.MIN_VALUE=0
最大值:Character.MAX_VALUE=65535

FloatDouble的最小值和最大值都是以科学记数法的形式输出的,结尾的E+数字表示E之前的数字要乘以10的多少倍。比如3.14E3就是3.14×1000=31403.14E-3就是3.14/1000=0.00314

大家将运行结果与上表信息仔细比较就会发现floatdouble两种类型的最小值与Float.MIN_VALUEDouble.MIN_VALUE的值并不相同,这是为什么呢?实际上Float.MIN_VALUEDouble.MIN_VALUE分别指的是floatdouble类型所能表示的最小正数。也就是说存在这样一种情况,0±Float.MIN_VALUE之间的值float类型无法表示,0±Double.MIN_VALUE之间的值double类型无法表示。这并没有什么好奇怪的,因为这些范围内的数值超出了它们的精度范围。

需要注意基本类型存储在栈中,因此它们的存取速度要快于存储在堆中的对应包装类的实例对象。从Java5.0(1.5)开始,JAVA虚拟机(Java Virtual Machine)可以完成基本类型和它们对应包装类之间的自动转换。因此我们在赋值、参数传递以及数学运算的时候像使用基本类型一样使用它们的包装类,但这并不意味着你可以通过基本类型调用它们的包装类才具有的方法。另外,所有基本类型(包括void)的包装类都使用了final修饰,因此我们无法继承它们扩展新的类,也无法重写它们的任何方法。
附:Java中二进制,八进制,十六进制,十进制间进行相互转

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容