Java 学习笔记(八)面向对象 下

封装

面向对象程序的三大特点:封装,继承,多态

通过封装可以提高程序的安全性,通过继承可以实现代码的复用,通过多态可以提高程序的可扩展性

为什么封装?

允许用户直接修改属性,用户可能会赋值一些无效的值,所以要对属性进行封装

如何封装?

使用 private 修饰属性为私有的,private 私有成员只能在当前类体中使用

提供公共的 getter setter 方法实现对属性的访问,必要时可以在 setter 方法中对参数接收的数据有效性进行验证

/**
 * 封装
 */
public class Person {
    // 使用 private 关键字将属性修饰为私有属性
    private String name;
    private int age;
    private String gender;

    // getter 方法返回属性
    public String getName() {
        return name;
    }

    // setter 方法设置属性
    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        // 对数据有效性进行验证
        if (age >= 0 && age <= 130) {
            this.age = age;
        }else {
            System.out.println(age + "超出类人的年龄范围");
        }
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        // 对数据有效性进行验证
        if ("男".equals(gender) || "女".equals(gender)) {
            this.gender = gender;
        }else {
            System.out.println(gender + "不是合理的性别");
        }

    }

}
public class Test {
    public static void main(String[] args) {
        Person p1 = new Person();

        // setter 方法设置属性
        p1.setName("zhangsan");
        p1.setAge(999);
        p1.setGender("test");

        // getter 方法获取属性
        System.out.println(p1.getName());
        System.out.println(p1.getAge());
        System.out.println(p1.getGender());
    }
}

输出结果:

999超出类人的年龄范围
test不是合理的性别
zhangsan
0
null

以上输入结果中,数据有效性验证失败的数据会输出为默认值

继承

继承使用 extends 关键字

子类继承父类,就自动拥有了父类的实例变量与实例方法

/**
 * 定义宠物类
 */
public class Pet {
    String nickname;
    int age;

    public void eat() {
        System.out.println(nickname + "在吃饭");
    }
}
/**
 * 定义小狗类,继承宠物类
 */
public class Dog extends Pet {
    // 定义子类特有的属性
    boolean specialDog;

    // 定义子类特有的方法
    public void guard() {
        System.out.println(nickname + "在看家");
    }
}
public class Test {
    public static void main(String[] args) {
        Dog dog = new Dog();

        // 子类对象访问继承自父类的属性
        dog.nickname = "小黑";
        dog.age = 5;

        // 子类对象调用继承自父类的方法
        dog.eat();

        // 子类对象访问子类特有的属性
        dog.specialDog = true;

        // 子类对象调用子类特有的方法
        dog.guard();
    }
}

输出结果:

小黑在吃饭
小黑在看家

构造方法不能继承

执行子类的构造方法时,会先调用父类的构造方法

在子类构造方法体中,默认调用父类的无参构造方法,如果父类没有无参构造方法,则语法错误

在子类的构造方法中,可以通过 super() 方法显示的调用指定的构造方法

/**
 * 定义人类
 */
public class Person {
    // 定义属性
    String name;
    int id;
    int age;
    String gender;

    // 定义无参构造方法
    public Person() {
        System.out.println("我是父类的无参构造方法");
    }

    // 定义有参构造方法
    public Person(String name, int id, int age, String gender) {
        System.out.println("我是父类的有参构造方法");
        this.name = name;
        this.id = id;
        this.age = age;
        this.gender = gender;
    }
}
/**
 * 定义学生类,继承自人类
 */
public class Student extends Person {
    // 定义子类特有的属性
    int score;
    String major;

    // 定义无参构造方法
    public Student() {
        // 这里没有使用 super() 来指定调用父类的哪个构造方法,会默认调用父类的无参构造方法
        System.out.println("我是子类的无参构造方法");
    }

    public Student(String name, int id, int age, String gender, int score, String major) {
        // 这里使用 super() 方法指定了调用父类的有参构造方法
        super(name, id, age, gender);
        this.score = score;
        this.major = major;
        System.out.println("我是子类的有参构造方法");
    }
}
public class Test {
    public static void main(String[] args) {
        Student student1 = new Student();
        Student student2 = new Student("小明", 001, 18, "男", 99, "计算机");
    }
}

输出结果:

我是父类的无参构造方法
我是子类的无参构造方法
我是父类的有参构造方法
我是子类的有参构造方法

方法重写,当继承自父类的方法无法满足子类的需求时,可以在子类中重写该方法

/**
 * 定义人类
 */
public class Person {
    // 定义属性
    String name;
    int id;
    int age;
    String gender;

    // 定义无参构造方法
    public Person() {

    }

    // 定义有参构造方法
    public Person(String name, int id, int age, String gender) {
        this.name = name;
        this.id = id;
        this.age = age;
        this.gender = gender;
    }

    // 定义方法显示人的信息
    public void show() {
        System.out.println("name: " + name);
        System.out.println("id: " + id);
        System.out.println("age: " + age);
        System.out.println("gender: " + gender);
    }

}
/**
 * 定义学生类,继承自人类
 */
public class Student extends Person {
    // 定义子类特有的属性
    int score;
    String major;

    // 定义无参构造方法
    public Student() {

    }

    public Student(String name, int id, int age, String gender, int score, String major) {
        // 这里使用 super() 方法指定了调用父类的有参构造方法
        super(name, id, age, gender);
        this.score = score;
        this.major = major;
    }

    // 继承的 show() 方法,可以显示 name,id,age,gender 无法显示 score,major 在这里重写 show() 方法
    @Override // 注解,让编译器验证方法重写是否符合规则
    public void show() {
        // 调用继承的 show() 方法
        super.show();
        // 添加功能
        System.out.println("score: " + score);
        System.out.println("major: " + major);
    }
}
public class Test {
    public static void main(String[] args) {
        Student student = new Student("小明", 002, 19, "男", 100, "java");
        // 通过子类对象调用 show() 方法,会调用子类中重写之后的 show() 方法,这是 java 的就近原则
        student.show();
    }
}

输出结果:

name: 小明
id: 2
age: 19
gender: 男
score: 100
major: java

静态方法不存在继承问题,属于哪个类的静态方法就使用哪个类的命名调用即可

访问权限

类的访问权限

类的访问权限分为两种:公共类和非公共类

如果想要这个类在其他包中使用,需要声明为 public 公共类,公共类的类名和源文件的名称必须一致,一个源文件中只能定义一个公共类

如果类没有使用 public 修饰,则只能在当前包中使用

类成员的访问权限

类成员的访问权限有四种:

访问权限 当前类 当前包 不在当前包的子类 不在当前包也没有继承关系的类
private 私有的 yes no no no
默认权限 yes yes no no
protected 保护的 yes yes yes no
public 公共的 yes yes yes yes
方法覆盖的规则

在子类中重写父类的方法,校验规则:

  • 方法签名必须一致,方法签名就是方法名与参数个数以及参数的类型
  • 方法返回值类型可以一致,也可以是子类型
  • 方法的访问权限可以一致,也可以更大
  • 方法抛出的异常,可以一致,也可以是子异常

Object

Object 类是所有 java 类的根父类

Java 中的类如果没有通过 extends继承父类,则该类默认继承 Object

继承是可传递的,所以 Object 类的中定义的方法,所有类都可以继承到

Object 类中定义的方法:

Modifier and Type Method and Description
protected Object clone() 客隆堆中的对象
boolean equals(Object obj) 判断堆中两个对象的属性值是否一致
Class<?> getClass() 返回对象的类
int hashCode() 返回对象的哈希码
void notify()唤醒等待的线程
String toString() 把对象转换为字符串
void wait()线程等待

实体类的定义规范

实体类是指客观存在的实体,如,人,电脑,书

在定义实体类时,有以下定义规范:

  • 把属性定义为私有的
  • 提供无参构造方法
  • 重写 equals() hashCode()
  • 重写 toString()
  • 提供 getter setter 方法
public class Book {
    // 定义私有属性
    private String name;
    private String author;
    private String press;
    private String isbn;
    private double price;

    // 定义无参构造方法
    public Book() {
    }

    // 重写 equals
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Book book = (Book) o;
        return name.equals(book.name) &&
                isbn.equals(book.isbn);
    }

    // 重写 hashCode
    @Override
    public int hashCode() {
        return Objects.hash(name, isbn);
    }

    // 重写 toString
    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", author='" + author + '\'' +
                ", press='" + press + '\'' +
                ", isbn='" + isbn + '\'' +
                ", price=" + price +
                '}';
    }

    // 定义 getter 和 setter
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public String getPress() {
        return press;
    }

    public void setPress(String press) {
        this.press = press;
    }

    public String getIsbn() {
        return isbn;
    }

    public void setIsbn(String isbn) {
        this.isbn = isbn;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }
}

final 关键字

final 关键字可以修饰类,修饰属性,修饰方法,修饰局部变量,修饰形参

final 修饰的类为最终类,不能被继承

final 修饰的属性(字段)

  • 必须显示初始化,如果没有显示初始化,需要在构造方法中赋值,因为显示初始化在编译时会编译到构造方法中,所以,显示初始化与在构造方法中赋值效果一样
  • 不能重新赋值
  • 经常与 static 关键字一起修饰属性(字段),称为 final 常量,如 static final double PI = 3.14 常量名一般大写

final 修饰的方法为最终方法,不能被重写

final 修饰的局部变量,不能重新赋值

final 修饰的形参,不能重新赋值

多态

多态分为对象多态和行为多态。对象多态是指同一个对象名可以引用不同的对象,行为多态是指调用同一个方法会执行不同的方法体。

对象多态是通过对象转型实现的

行为多态分为静态多态和动态多态。静态多态是通过方法重载实现,在编译阶段就可以根据方法的实参来确定调用哪个方法,又称为编译多态。动态多态是在程序运行过程中,确定要执行哪个对象的方法,又称为运行时多态或者动态绑定。

对象向上转型

对象向上转型是指可以给父类的引用赋值子类对象,这是自动类型转换

动态绑定

实现动态绑定有四个条件:

  • 子类继承父类
  • 子类重写父类方法
  • 给父类的引用赋值子类对象
  • 通过父类的引用调用被重写的方法
对象向下转型

给父类的引用赋值子类的对象,是对象向上转型。在对象向上转型之后,即父类的引用指向了子类在堆中的对象,此时如果想要访问子类特有的属性或者调用子类特有的方法时,就需要对象向下转型。

对象向下转型通过强制类型转换来实现

/**
 * 定义动物类做为父类
 */
public class Animal {
    public void eat(){
    };
}
/**
 * 定义小狗类做为子类
 */
public class Dog extends Animal {
    // 重写父类的 eat() 方法
    @Override
    public void eat() {
        System.out.println("小狗喜欢吃骨头");
    }

    // 给小狗添加特有的方法
    public void guard() {
        System.out.println("小狗可以看家");
    }
}
/**
 * 定义小猫类做为子类
 */
public class Cat extends Animal {
    // 重写父类的 eat() 方法
    @Override
    public void eat() {
        System.out.println("小猫喜欢吃鱼");
    }

    // 给小猫添加特有的方法
    public void catchMouse() {
        System.out.println("小猫可以捉老鼠");
    }
}
/**
 * 对象向上转型
 */
public class Test01 {
    public static void main(String[] args) {
        // 给父类的引用赋值子类 Dog 的对象
        Animal animal = new Dog();
        // 给父类的引用赋值子类 Cat 的对象
        animal = new Cat();
    }
}
/**
 * 动态绑定
 */
public class Test02 {
    public static void main(String[] args) {
        // 给父类引用赋值子类对象
        Animal animal = new Dog();
        // 通过父类引用调用被重写的方法,输出结果:小狗喜欢吃骨头
        animal.eat();

        // 给父类引用赋值子类对象
        animal = new Cat();
        // 通过父类引用调用被重写的方法,输出结果:小猫喜欢吃鱼
        animal.eat();
    }
}
/**
 * 对象向下转型
 */
public class Test03 {
    public static void main(String[] args) {
        Animal animal = new Dog();
        // 父类引用不能直接调用子类对象特有的方法,需要通过强制类型转换实现对象向下转型
        ((Dog)animal).guard();

        animal = new Cat();
        ((Cat)animal).catchMouse();

        doSomething(new Dog());
        doSomething(new Cat());
    }
    
    // 一般情况下,对象向下转型前,会使用 instanceof 运算符判断堆中对象是否为目标类型
    public static void doSomething(Animal animal) {
        if (animal instanceof Dog) {
            ((Dog)animal).guard();
        }else if (animal instanceof Cat) {
            ((Cat)animal).catchMouse();
        }
    }
}
多态的作用

多态可以提供程序的可扩展性,体现面向抽象的编程思想,降低代码的耦合度

/**定义宠物类为父类
 *
 */
public class Pet {
    String name;

    public Pet(String name) {
        this.name = name;
    }
}
/**
 * 定义小狗类为子类
 */
public class Dog extends Pet {
    public Dog(String name) {
        super(name);
    }
}
/**
 * 定义小猫类为子类
 */
public class Cat extends Pet {
    public Cat(String name) {
        super(name);
    }
}
/**
 * 定义宠物医院类
 */
public class PetHospital {
    public void treat(Pet pet) {
        System.out.println(pet.name + "正在宠物医院玩耍");
    }
}
public class Test {
    public static void main(String[] args) {
        PetHospital hospital = new PetHospital();

        hospital.treat(new Dog("小黑"));
        hospital.treat(new Cat("小花"));
    }
}

输出结果:

小黑正在宠物医院玩耍
小花正在宠物医院玩耍

抽象类

什么是抽象类?

使用 abstract 修饰的类,就是抽象类

为什么要定义抽象类?

含有抽象方法的类,必须定义为抽象类。对事物进行更高层级的抽象时,如宠物类,交通工具类等无法具体化的类,就可以定义为抽象类

为什么定义抽象方法?

当类有某个操作,但是无法具体实现时就可以定义为抽象方法

抽象方法的特点:

  • 使用 abstract 修饰,没有方法体

  • 含有抽象方法的类,必须定义为抽象类

抽象类的特点:

  • 只要是由 abstract 修饰的类,就是抽象类
  • 抽象类可以没有抽象方法
  • 子类继承了抽象类,需要重写抽象方法,如果没有重写,则子类也需要定义为抽象类
  • 抽象类不能实例化
  • 抽象类的引用可以赋值子类对象,也可以赋值匿名内部类对象
  • 抽象类中除了可以定义抽象方法,也可以定义普通类的成员,如实例变量,实例方法,静态变量,静态方法,构造方法等

匿名内部类

匿名内部类是一个没有类名的内部类,如果需要一个只使用一次的子类,可以定义为匿名内部类,就不需要再创建一个子类了,匿名内部类只能使用一次

/**
 * 把马戏团的所有动物抽象为动物类
 */
public abstract class Animal {
    // 马戏团所有的动物都会表演
    public abstract void play();

}
/**
 * 定义狗熊类,继承动物类
 */
public class Bear extends Animal {
    @Override
    public void play() {
        System.out.println("狗熊表演跳绳");
    }
/**
 * 定义大象类,继承动物类
 */
public class Elephant extends Animal {
    @Override
    public void play() {
        System.out.println("大象表演跳舞");
    }
}
/**
 * 定义猴子类,继承动物类
 */
public class Monkey extends Animal {
    @Override
    public void play() {
        System.out.println("猴子表演骑自行车");
    }
}
/**
 * 训练师
 */
public class Trainner {
    public void train(Animal animal) {
        System.out.println("训练师请动物出来表演节目");
        animal.play();
    }
}
public class Test {
    public static void main(String[] args) {
        Trainner trainner = new Trainner();
        // 给抽象类传递子类对象
        trainner.train(new Bear());
        trainner.train(new Elephant());
        trainner.train(new Monkey());

        //给抽象类传递匿名内部类
        trainner.train(new Animal() {
            @Override
            public void play() {
                System.out.println("老虎表演跳火圈");
            }
        });
    }
}

执行结果:

训练师请动物出来表演节目
狗熊表演跳绳
训练师请动物出来表演节目
大象表演跳舞
训练师请动物出来表演节目
猴子表演骑自行车
训练师请动物出来表演节目
老虎表演跳火圈

接口

接口是什么

电脑上面有 USB 接口,HDMI 接口,耳机接口等接口,这些接口可以扩展电脑的功能

Java 中的接口可以简单的理解为功能的封装,用来扩展类的功能

接口的定义与实现

定义接口的语法

​ [修饰符] inter 接口名 {

​ 功能用方法表示

​ }

实现接口的语法

​ class 类名 implements 接口名 {

​ 在类中重写接口的抽象方法

​ }

说明

  • 接口可以简单的看作是功能的封装,功能使用方法来表示,接口中的方法默认使用 public abstract 修饰,接口也可以看作是一组操作规范或者说一个操作协议
  • 类实现接口,需要重写接口的抽象方法,如果不重写,则需要将类定义为抽象类
  • 接口也是一种引用数据类型,可以定义变量,但是接口不能实例化对象,接口的引用可以赋值实现类的对象或者匿名内部类对象
  • 通过接口的引用调用抽象方法时,实际执行的是实现类对象的方法,称为接口多态
  • 除了默认的抽象方法,jdk8 在接口中新增了 default 修饰的方法和 static 修饰的方法,这两种方法经常用于项目升级时扩展接口的功能
  • 接口也能继承,并且接口允许多继承
  • 接口允许多实现,即一个类在继承父类的同时,可以实现多个接口,需要重写所有接口的抽象方法

例子1

/**
 * 定义一个飞行接口,封装一个飞行功能
 */
public interface Flyable {
    // 功能用方法表示,接口中的方法,默认为 public abstract 修饰的抽象方法
    void fly();
}
/**
 * 类实现接口
 */
public class RedBird implements Flyable {
    // 类实现接口需要重写接口的抽象方法,如果不重写,那么要把类定义为抽象类
    @Override
    public void fly() {
        System.out.println("红火正常飞行");
    }
}
/**
 * 类实现接口
 */
public class BlueBird implements Flyable {
    // 类实现接口需要重写接口的抽象方法,如果不重写,那么要把类定义为抽象类
    @Override
    public void fly() {
        System.out.println("蓝冰在飞行过程中可以一个变三个");
    }
}
public class Test {
    public static void main(String[] args) {
        // 接口属于引用数据类型,可以定义变量
        Flyable f;
        // 给接口的引用赋值实现类 RedBird 的对象
        f = new RedBird();
        // 调用 RedBird 实现类重写的 fly() 方法
        f.fly();

        // 给接口的引用赋值实现类 BlueBird 的对象
        f = new BlueBird();
        // 调用 BlueBird 实现类重写的 fly() 方法
        f.fly();

        // 也可以赋值匿名内部类对象
        f = new Flyable() {
            @Override
            public void fly() {
                System.out.println("黑风会在飞行过程中爆炸");
            }
        };
        // 调用匿名内部类重写的 fly() 方法
        f.fly();
    }
}

执行结果:

红火正常飞行
蓝冰在飞行过程中可以一个变三个
黑风会在飞行过程中爆炸

例子2

/**
 * 定义接口
 */
public interface MyInterface {
    // 接口中的字段,默认为 public static final 修饰的常量
    int X = 123;
    // 接口中的方法,默认为 public abstract 修饰的抽象方法
    void m1();

    // default 修饰的方法,可以有方法体,在实现类中,可以重写也可以不重写该方法
    default void dm() {
        System.out.println("default修饰的方法,可以有方法体");
    }

    // static 修饰的方法
    static void sm() {
        System.out.println("static 修饰的方法");
    }
}
/**
 * 定义接口的实现类
 */
public class MyclassImpl implements MyInterface {
    @Override
    public void m1() {
        System.out.println("在实现类中重写接口的抽象方法");
    }

    @Override
    public void dm() {
        System.out.println("在实现类中可以重写 default 方法,也可以不重写");
    }
}
public class Test {
    public static void main(String[] args) {
        // 接口中的抽象方法,需要通过接口的引用来调用
        MyInterface ref = new MyclassImpl();
        ref.m1();

        // 接口中的常量,只能通过接口名访问
        System.out.println(MyInterface.X);

        // default 修饰的方法,通过接口的引用调用
        ref.dm();

        // 接口中的静态方法,通过接口名调用
        MyInterface.sm();
    }
}

执行结果:

在实现类中重写接口的抽象方法
123
在实现类中可以重写 default 方法,也可以不重写
static 修饰的方法

抽象类与接口的区别

  • 本质不同,抽象类是对事物的抽象,解决对象到底是什么;接口是对功能的封装,解决对象能做什么
  • 内容不同,抽象类除了抽象方法外,可以定义实例变量,实例方法,静态变量,静态方法,构造方法等;接口除了抽象方法外,可以定义 public static final 常量, default 方法,静态方法
  • 使用方式不同,抽象类需要被 extends 继承,接口需要 implements 实现,类只允许单继承,接口可以多继承
  • 抽象类是由子类对象或者匿名内部类对象作为实参,由父类的引用作为的形参;接口是由实现类对象或者匿名内部类对象作为实参,由接口的引用作为形参

提倡面向接口编程

  • 接口更灵活,一个类在继承另外一个父类的同时,可以实现多个接口
  • 接口体现面向抽象编程的思想,降低类的耦合度,可以提高程序的可扩展性
  • 接口可以使项目分层

对象数组

定义数组

​ 数据类型[] 数组名 = new 数据类型[长度];

数据类型就是数据中存储数据的类型,如果数组存储整数则定义为 int 类型,存储字符串则定义为 String 类型,存储 Person 对象则定义为 Person 类型

如果数组中存储的是引用类型的对象,则该数组称为对象数据

public class Student {
    String name;
    int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name=" + name + ",age=" + age + "}";
    }
}
public class Test {
    public static void main(String[] args) {
        // 定义数组,存储 Student 对象
        Student [] data = new Student[10];
        // 在使用对象数据是,一般会定义一个变量记录数组中元素数量
        int size = 0;

        // 向数组中添加 Student 对象的引用,每添加一个元素,size 的值就会加 1
        data[size] = new Student("小明", 18); size++;
        data[size] = new Student("小花", 18); size++;
        data[size] = new Student("小六", 18); size++;

        // 遍历数组中所有元素
        System.out.println("数组中的所有元素:");
        for (int i = 0; i < size; i++) {
            System.out.println(data[i]);
        }

        // 删除数组中的小刘同学
        // 1. 找出小六的下标
        int x = -1;
        for (int i = 0; i < size; i++) {
            if ("小六".equals(data[i].name)) {
                x = i;
                break;
            }
        }

        // 2. 把数组中从 x+1 开始的每个元素前移
        System.arraycopy(data, x+1, data, x, size-x-1);
        // 3. 元素的数量 size 减 1
        size--;
        // 4. 最后一个元素原来占用的空间现在空出来了,需要释放掉,把最后一个元素赋值为 null
        data[size] = null;

        System.out.println("删除小六同学之后数组中的元素:");
        for (int i = 0; i < size; i++) {
            System.out.println(data[i]);
        }

    }

}

执行结果:

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