Java复习之集合框架


俗话说:温故而知新。想想学过的知识,就算是以前学得很不错,久不用了,就会忘记,所以温习一下以前学习的知识我认为是非常有必要的。而本篇文件温习的是 Java基础中的集合框架。

  • 为什么会有集合框架?

    • 平时我们用数组存储一些基本的数据类型,或者是引用数据类型,但是数组的长度是固定的,当添加的元素超过了数组的长度时,需要对数组进行重新的定义,这样就会显得写程序太麻烦,所以Java内部为了我们方便,就提供了集合类,能存储任意对象,长度是可以改变的,随着元素的增加而增加,随着元素的减少而减少。
    • 数组可以存储基本数据类型,也可以存储引用数据类型,基本数据类型存储的是值,引用数据类型存储的是地址,而集合只能存储引用数据类型(也就是对象),其实集合中也可以存储基本数据类型,但是在存储的时候会自动装箱变成对象。
    • 有了集合不意味着我们要抛弃数组,如果需要存储的元素个数是固定的,我们可以使用数组,而当存储的元素不固定,我们使用集合。
  • 集合的种类

    • 集合分为单列集合和双列集合。单列集合的根接口为Collection,双列结合的根接口为Map,两种集合都有基于哈希算法的集合类(HashMap和HashSet),现在我们可能会有疑问,到底是双列集合基于单列集合还是单列集合基于双列集合呢,下面我们来看往集合HashMap和HashSet添加元素的源码:
/*
*HashMap的put 方法 
*/
 public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }

/*
* HashSet  的add 方法
*/
public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }
// PRESENT是一个Object 对象
 private static final Object PRESENT = new Object();
  • 由上源码,我们可以看出,双列集合的put方法源码中并没有出现add方法,而单列集合的add源码只能怪出现了put;我们可以知道单列集合是基于双列集合实现的。其实道理很简单,单列集合每次添加元素,只要添加key就可以,而key也是双列集合元素的唯一标识,而其值value则由一个Object对象代替并且隐藏,每次加入,输出元素都是隐藏单列结合的这个值, 底层基于双列集合,隐藏一列是很好实现的,而如果是单列集合要变成双列集合估计就会有很大的难度,就好比魔术师变魔术,魔术师变东西前肯定事先准备好要变的东西,只是将其隐藏,但是如果魔术师变魔术是真的从无到有,那我估计他就是神仙了,想要什么就变出来什么便是。

单列集合

  • 首先我们看单列结合的继承图,单列集合的根接口是Collection,而List的实现类为ArrayList、LinkedList、Vector,Set接口的实现类是HashSet和TreeSet。
集合框架 单列集合.jpg
  • 其次我们来看看各个集合的功能
List集合的特有功能概述
    * void add(int index,E element) //集合中添加元素
    * E remove(int index) //删除集合中index位置上的元素
    * E get(int index)  //获取集合中index位置上的元素
    * E set(int index,E element) 将index位置上的元素替换成 element

Vector类特有功能
    * public void addElement(E obj)  添加元素
    * public E elementAt(int index)  //获取元素
    * public Enumeration elements()  //获取元素的枚举(迭代遍历的时候用到)

LinkedList类特有功能
    * public void addFirst(E e)及addLast(E e)  //集合头添加元素或者集合尾添加元素
    * public E getFirst()及getLast() //获取头元素 获取尾元素
    * public E removeFirst()及public E removeLast() //删除头元素删除尾元素
    * public E get(int index);//获取index元素
根据上述LinkedList的功能,我们可以模拟栈获取队列的数据结构,栈是先进后出,队列为先进先出。

/**
 * 模拟的栈对象
 * @author 毛麒添
 * 底层还是使用LinkedList实现
 * 如果实现队列只需要将出栈变为 removeFirst 
 */
public class Stack {

    private LinkedList linklist=new LinkedList();
    
    /**
     * 进栈的方法
     * @param obj
     */
    public void in(Object obj){
        linklist.addLast(obj);
    }
    
    /**
     * 出栈
     */
    public Object out(){
        return linklist.removeLast();
    }
    /**
     * 栈是否为空
     * @return
     */
    public boolean isEmpty(){
        return linklist.isEmpty();
    }
}


//集合的三种迭代(遍历集合)删除
ArrayList<String> list=new ArrayList();
        list.add("a");
        list.add("b");
        list.add("c");
        list.add("world");
//1,普通for循环删除元素
for(int i=0;i<list,size();i++){//删除元素b
     if("b".equals(list.get(i))){
        list.remove(i--);// i-- 当集合中有重复元素的时候保证要删除的重复元素被删除
  }
}
//2.使用迭代器遍历集合
Iterator<String> it=list.iterator();
while(it.hasNext){
   if("b".equals(it.next())){
     it.remove();//这里必须使用迭代器的删除方法,而不能使用集合的删除方法,否则会出现并发修改异常(ConcurrentModificationException)
  }
}

//使用增强for循环来进行删除
for (String str:list){
     if("b".equals(str)){
       list.remove("b");//增强for循环底层依赖的是迭代器,而这里删除使用的依旧是集合的删除方法,同理肯定是会出现并发修改异常(ConcurrentModificationException),所以增强for循环一直能用来遍历集合,不能对集合的元素进行删除。
  }
}
  • 接下里我们看Set集合,我们知道Set 集合存储无序,无索引,不可以存储重复的对象;我们使用Set集合都是需要去掉重复元素的, 如果在存储的时候逐个equals()比较, 效率较低,哈希算法提高了去重复的效率, 降低了使用equals()方法的次数,其中HashSet底层基于哈希算法,当HashSet调用add方法存储对象,先调用对象的hashCode()方法得到一个哈希值, 然后在集合中查找是否有哈希值相同的对象,如果没有哈希值相同的对象就直接存入集合,如果有哈希值相同的对象, 就和哈希值相同的对象逐个进行equals()比较,比较结果为false就存入, true则不存。下面给出HashSet存储自定义对象的一个例子,自定义对象需要重写hashCode()和equals()方法。
/**
 * 自定义对象
 * @author 毛麒添
 * HashSet 使用的bean  重写了equals和HashCode方法
 */
public class Person1 {
    private String name;
    private int age;
    public Person1() {
        super();
        // TODO Auto-generated constructor stub
    }
    public Person1(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Person1 [name=" + name + ", age=" + age + "]";
    }
    
    //使HashSet存储元素唯一
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        System.out.println("equals调用了");
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Person1 other = (Person1) obj;
        if (age != other.age)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }   
}

public class Demo1_Hashset {

    public static void main(String[] args) {
        HashSet<Person1> hs=new HashSet<Person1>();
        hs.add(new Person1("张三", 23));
        hs.add(new Person1("张三", 23));
        hs.add(new Person1("李四", 24));
        hs.add(new Person1("李四", 24));
        hs.add(new Person1("李四", 24));
        hs.add(new Person1("李四", 24));
        System.out.println(hs);
    }

运行结果如图,达到了不存储重复自定义对象的目的。其实HashSet的下面还有一个LinkedHashSet,底层是链表实现的,是set中唯一一个能保证怎么存就怎么取的集合对象,是HashSet的子类,保证元素唯一,与HashSet原理一样,这里就不多说了。

HashSet 例子运行结果截图.png
  • 最后是TreeSet集合,该集合是用来进行排序的,同样也可以保证元素的唯一,可以指定一个顺序, 对象存入之后会按照指定的顺序排列。
    指定排序有两种实现:
    • Comparable:集合加入自定义对象的时候,自定义对象需要实现Comparable接口,
      • 实现接口的抽象方法中返回0,则集合中只有一个元素
      • 返回正数,则集合中怎么存则怎么取,
      • 返回负数,集合倒序存储
    • Comparator(比较器):
      • 创建TreeSet的时候可以制定 一个Comparator
      • 如果传入了Comparator的子类对象, 那么TreeSet就会按照比较器中的顺序排序
      • add()方法内部会自动调用Comparator接口中compare()方法排序
      • 调用的对象是compare方法的第一个参数,集合中的对象是compare方法的第二个参数
    • 原理:
      • TreeSet底层二叉排序树
      • 返回小的数字存储在树的左边(负数),大的存储在右边(正数),相等则不存(等于0)
      • 在TreeSet集合中如何存取元素取决于compareTo()方法的返回值

下面来看例子:

/**
 * 自定义对象 用于TreeSet
 * @author 毛麒添
 *
 */
public class Person implements Comparable<Person>{

    private String name;
    private int age;
    
    public Person(){
        super();
    }
    public Person(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
    
    @Override
    public boolean equals(Object obj) {
        Person p=(Person) obj;
        return this.name.equals(p.name)&&this.age==p.age;
    }
    
    @Override
    public int hashCode() {
        // TODO Auto-generated method stub
        return 1;
    }
    
    /*//按照年龄进行排序(TreeSet)
    @Override
    public int compareTo(Person o) {
        int number=this.age-o.age;//年龄是比较的主要条件
        //当年龄一样的时候比较名字来确定排序
        return number==0?this.name.compareTo(o.name):number;
    }*/
    
    //按照姓名进行排序(TreeSet)
        @Override
        public int compareTo(Person o) {
            int number=this.name.compareTo(o.name);//姓名是比较的主要条件
            //当姓名一样的时候比年龄来确定排序
            return number==0?this.age- o.age:number;
        }
        
        //按照姓名长度进行排序(TreeSet)
                /*@Override
                public int compareTo(Person o) {
                    int length=this.name.length()-o.name.length();//姓名长度比较的次要条件
                    int number=length==0?this.name.compareTo(o.name):length;//姓名是比较的次要条件
                    //比年龄也是次要条件
                    return number==0?this.age- o.age:number;
                }*/
}

/**
 * 
 * @author 毛麒添
 * TreeSet集合
 * 集合加入自定义对象的时候,自定义对象需要实现Comparable接口,
 * 实现接口的抽象方法中返回0,则集合中只有一个元素
 * 返回正数,则集合中怎么存则怎么取,
 * 返回负数,集合倒序存储
 * 
 * 将字符按照长度来进行排序在TreeSet中,需要使用有比较的构造方法进行比较。
 */
public class Demo_TreeSet {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        demo1();//整数存取排序
        demo2();//自定义对象排序
        
        //将字符按照长度来进行排序在TreeSet中
        TreeSet<String> strLenset=new TreeSet<String>(new compareByLen());
        strLenset.add("aaaaa");
        strLenset.add("lol");
        strLenset.add("wrc");
        strLenset.add("wc");
        strLenset.add("b");
        strLenset.add("wnnnnnnnnnnn");
        
        System.out.println(strLenset);
    }

    private static void demo2() {
        TreeSet<Person> ptreeSet=new TreeSet<Person>();
        
        ptreeSet.add(new Person("李四",12));
        ptreeSet.add(new Person("李四",16));
        ptreeSet.add(new Person("李青",16));
        ptreeSet.add(new Person("王五",19));
        ptreeSet.add(new Person("赵六",22));
        
        System.out.println(ptreeSet);
    }

    private static void demo1() {
        TreeSet< Integer> treeSet=new TreeSet<Integer>();
        treeSet.add(1);
        treeSet.add(1);
        treeSet.add(1);
        treeSet.add(3);
        treeSet.add(3);
        treeSet.add(3);
        treeSet.add(2);
        treeSet.add(2);
        treeSet.add(2);
        
        System.out.println(treeSet);
    }

}

//TreeSet 构造器,实现compare对需要存储的字符串进行比较
class compareByLen implements Comparator<String>{

    //按照字符串的长度进行比较,该方法的返回值和继承Comparable的compareTo方法返回值同理。
    @Override
    public int compare(String o1, String o2) {
        int num=o1.length()-o2.length();//以长度为主要条件
        return num==0?o1.compareTo(o2):num;//内容为次要条件
    }
    
}


  • 下面是运行截图,其中compareTo的实现方法对几种条件排序进行了实现,具体可以查看Person自定义类中的实现。
TreeSet 例子运行截图.png

单列集合复习就到这里吧。


双列集合

  • 同样的,在复习双列结合之前我们先看看双列集合的继承图。
集合框架 双列集合.jpg
  • Map集合的功能梳理:

    • 添加功能
      • V put(K key,V value):添加元素。
      • 如果键是第一次存储,就直接存储元素,返回null
      • 如果键不是第一次存在,就用值把以前的值替换掉,返回以前的值
    • 删除功能
      • void clear():移除所有的键值对元素
      • V remove(Object key):根据键删除键值对元素,并把值返回
    • 判断功能
      • boolean containsKey(Object key):判断集合是否包含指定的键
      • boolean containsValue(Object value):判断集合是否包含指定的值
      • boolean isEmpty():判断集合是否为空
    • 获取功能
      • Set<Map.Entry<K,V>> entrySet():
      • V get(Object key):根据键获取值
      • Set<K> keySet():获取集合中所有键的集合
      • Collection<V> values():获取集合中所有值的集合
    • 长度功能
      • int size():返回集合中的键值对的个数
  • Map类集合也有三种遍历方式:

    • 使用迭代器进行遍历
    • 使用增强For循环来进行遍历
    • 使用Map.Entry来遍历集合中的元素
  • 下面我们来看看如何实现上面三种遍历方式

/**
 * 
 * @author 毛麒添
 * Map 集合的遍历
 */
public class Demo {

    public static void main(String[] args) {
        Map<String ,Integer> map=new HashMap<String, Integer>();
        map.put("张三", 18);
        map.put("李四", 19);
        map.put("王五", 20);
        map.put("赵六", 21);
        
        //使用迭代器进行遍历
        /*Set<String> keySet = map.keySet();//获取所有key的集合
        Iterator<String> iterator = keySet.iterator();
        while(iterator.hasNext()){
            String key = iterator.next();
            Integer i=map.get(key);
            System.out.println(i);
        }*/
        //使用增强For循环来进行遍历
        for (String key :map.keySet()) {
            Integer integer = map.get(key);
            System.out.println(integer);
        }
/*---------------------------使用Map.Entry来遍历集合中的元素--------------------------*/
        Set<Map.Entry<String,Integer>> en=map.entrySet();////获取所有的键值对象的集合
        /*//使用迭代器来遍历
        Iterator<Entry<String, Integer>> iterator = en.iterator();
        while(iterator.hasNext()){
            Entry<String, Integer> e=iterator.next();//获取键值对对象
            String key = e.getKey();//根据键值对对象获取键
            Integer value = e.getValue();//根据键值对对象获取值
            System.out.print(key);
            System.out.println(value);
        }*/
        //使用增强for循环来遍历
        for (Entry<String, Integer> entry : en) {
            String key = entry.getKey();
            Integer value = entry.getValue();
            System.out.print(key);
            System.out.println(value);
        }
/*---------------------------使用Map.Entry来遍历集合中的元素--------------------------*/
    }
}
  • LinkedHashMap与LinkedHashSet一样,怎么存怎么取,保证元素唯一(key 是唯一判定值),由于保证元素唯一,其性能肯定会低一些,这里就不细说了。

  • TreeMap是双列集合,其实他和TreeSet是很像的,但是双列集合的键是唯一标识,所以TreeMap排序的是每个元素的键。对于存储自定义对象排序,它也有Comparable和Comparator,下面我们来看例子

/**
 * 
 * @author 毛麒添
 * TreeMap
 *  通TreeSet 原理,存取自定义对象也需要继承Comparable结构,
 *  或者实现比较器Comparator
 */
public class Demo6_TreeMap {

    public static void main(String[] args) {
        TreeMap<Student, String> tm=new TreeMap<Student, String>(new Comparator<Student>() {

            @Override
            public int compare(Student s1, Student s2) {
                int num=s1.getName().compareTo(s2.getName());//以姓名作为主要比较条件
                return num==0?s1.getAge()-s2.getAge():num;
            }
        });
        tm.put(new Student("张三",13),"杭州");
        tm.put(new Student("张三",14), "贺州");
        tm.put(new Student("王五",15), "广州");
        tm.put(new Student("赵六",16), "深圳");
        
        System.out.println(tm);
    }

}

/**
 * 自定义对象
 * @author 毛麒添
 * HashMap 存储对象 与 HashSet 同理  需要重写 hashcode 和equals 方法 
 * TreeMap 实现 Comparable接口
 */
public class Student implements Comparable<Student>{

    private int age;
    private String name;
    
    public Student(){
        super();
    }
    public Student(String name,int age){
        this.name=name;
        this.age=age;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    
    
    @Override
    public String toString() {
        return "Student [age=" + age + ", name=" + name + "]";
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Student other = (Student) obj;
        if (age != other.age)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }
    @Override
    public int compareTo(Student o) {
        int num =this.age-o.age;//以年龄为主要条件
        return num==0?this.name.compareTo(o.name):num;//姓名作为次要条件
    }   
}

到这里,Java集合框架的复习基本完成,最后来一个斗地主的例子对集合框架做一个综合应用,只是实现斗地主洗牌和发牌,至于怎么打牌,逻辑复杂,这里不做实现。

/**
 * 
 * @author 毛麒添
 * 模拟斗地主洗牌和发牌,牌排序
 * 买一副扑克
 * 洗牌
 * 发牌
 * 看牌
 */
public class Doudizhu_progress {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        //构造一副扑克牌
        String[] number={"3","4","5","6","7","8","9","10","J","Q","K","A","2"};
        String[]color={"黑桃","红桃","梅花","方块"};
        HashMap<Integer, String> pokerMap=new HashMap<Integer, String>();//存放牌的map
        ArrayList<Integer> list=new ArrayList<Integer>();//存放牌的索引
        int index=0; //索引
        for (String s1 : number) {
            for (String s2 : color) {
                pokerMap.put(index,s2.concat(s1));
                list.add(index);
                index++;
            
            }
        }
        //加入大小王
        pokerMap.put(index,"小王");
        list.add(index);
        index++;
        pokerMap.put(index,"大王");
        list.add(index);
        
        //洗牌
        Collections.shuffle(list);
        //System.out.println(list);
       
        //发牌,3个人玩 加上底牌3张 使用TreeSet 来存放索引,并自动对索引排好序
        TreeSet<Integer> mao=new TreeSet<Integer>();
        TreeSet<Integer> li=new TreeSet<Integer>();
        TreeSet<Integer> huang=new TreeSet<Integer>();
        TreeSet<Integer> dipai=new TreeSet<Integer>();
        
        for(int i=0;i<list.size();i++){
            if(i>=list.size()-3){//最后三张牌,作为底牌
               dipai.add(list.get(i));  
            }else if(i%3==0){
                mao.add(list.get(i));
            }else if(i%3==1){
                li.add(list.get(i));
            }else {
                huang.add(list.get(i));
            }
        }
        
        //看牌
        lookPoker(pokerMap,mao,"mao");
        lookPoker(pokerMap,li,"li");
        lookPoker(pokerMap,huang,"huang");
        lookPoker(pokerMap,dipai,"底牌");
    }

    /**
     * 看牌的方法
     * @param pokerMap 存放牌的map
     * @param mao  该玩家的牌的索引集合
     * @param name 玩家名字
     */
    private static void lookPoker(HashMap<Integer, String> pokerMap,
            TreeSet<Integer> mao, String name) {
        if(name.equals("底牌")){
            System.out.print("地主"+name+"的牌是:");
        }else{
            System.out.print("玩家"+name+"的牌是:");
        }
        for (Integer integer : mao) {
            System.out.print(pokerMap.get(integer)+" ");
        }
        
        System.out.println();
        
    }

}

运行截图:

斗地主程序运行截图.png

写在最后:
如果你看到这里,估计你也温故知新了吧,那就这样吧,这篇又臭又长的文章就到这里啦。文章中如果有错误,请大家给我提出来,大家一起学习进步,如果觉得我的文章给予你帮助,也请给我一个喜欢。

本系列文章:
Java复习之集合框架
Java复习之IO流(上)
Java复习之IO流(下)
Java 复习之多线程

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

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,654评论 18 399
  • 一、集合框架的概述 1、概述: 1、简述:所谓集合,就是为方便对多个对象的操作,对对象进行存储。集合就是存储对象最...
    玉圣阅读 512评论 0 4
  • 上一篇文章介绍了Set集合的通用知识。Set集合中包含了三个比较重要的实现类:HashSet、TreeSet和En...
    Ruheng阅读 15,650评论 3 57
  • 人的时间精力是有限的,大脑的运作模式也是由基因进化决定的能省就省,因为从生理上大脑维持日常的工作需要消耗大量的能量...
    尘世知行者阅读 495评论 0 0
  • 为你我用了半年的积蓄, 漂洋过海的来看你, 为了这次相聚, 我连见面时的呼吸都曾反复练习。 身边有一部分朋友是异地...
    喜欢木子阅读 343评论 0 0