Java_Foundation(四)

简介: Java_Foundation(四)

集合


虚线是实现,实现是继承


20190311161004511.png


1. Collection接口


20190719092502504.png


①. 为什么集合使用什么样的泛型,迭代器就用什么泛型 ? [ 理解 ]


20190721113929655.png


②.迭代器用什么泛型,next()方法就用什么泛型 [ 理解 ]


20190721114819727.png


1>. Collection、Map 接口的概述


是单例集合的顶层接口,它表示一组对象,这些对象也称为Collection的元素


JDK不提供此接口的任何直接实现,它提供更具体的子接口 (如 Set 和 List)实现


set:元素无序、不可重复的集合- - 类似高中集合


List:元素有序,可重复的集合- - "动态"数组


Map接口:具有映射关系"key-value"对的集合 - - 类似于高中的函数 y=f(x)(x1,y1)(x2,y2)


2>.Collection中常用的方法


boolean add(E e):添加元素[ 注意这里的E是泛型类型 ]


boolean addAll(Collection<? extends E> c):将形成中包含的c所有元素添加到当前集合中 [ 向下限定, 固定上边界 ]


boolean remove(Object obj):从集合中移除指定的元素[ 重写了equals方法]


void clear():清除集合中的元素


boolean contains(Object o):判断集合中是否存在指定的元素[ 重写了equals方法]


boolean isEmpty():判断集合是否为空


int size():集合的长度,也就是集合中元素的个数


Iterator<E>iterator( ):返回一个Iterator接口,实现类的对象,进而实现集合的遍历


equal(Object obj):判断两个集合中所有元素是否完全相同


将数组转成集合: Collection coll1 = Arrays.asList(1, 2, 3);


将集合转成数组:Object [ ] obj=coll1.toArray();


//创建集合对象
        Collection<String> c = new ArrayList<String>();
        //boolean add(E e):添加元素
//        System.out.println(c.add("hello"));
//        System.out.println(c.add("world"));
//        System.out.println(c.add("world"));
        c.add("hello");
        c.add("world");
        c.add("java");
        //boolean remove(Object o):从集合中移除指定的元素
//        System.out.println(c.remove("world"));
//        System.out.println(c.remove("javaee"));
        //void clear():清空集合中的元素
//        c.clear();
        //boolean contains(Object o):判断集合中是否存在指定的元素
//        System.out.println(c.contains("world"));
//        System.out.println(c.contains("javaee"));
        //boolean isEmpty():判断集合是否为空
//        System.out.println(c.isEmpty());
        //int size():集合的长度,也就是集合中元素的个数
        System.out.println(c.size());
        //输出集合对象
        System.out.println(c);

     20190718111935965.png


3>. 数组转换成集合 [ 掌握 ]


①. 数组换成成集合,虽然不能增加或减少元素,但是可以用集合的思想操作数组,也就是说可以使用其他集合中的方法 [ 除了增加和减少都能使用 ]


②. 基本数据类型的数组转换成集合,会将整个数组当成一个对象转换


③. 将数组转成集合,数组必须是引用数据类型


       String[]arr={"a","b","c"};

       List<String> list= Arrays.asList(arr);

       System.out.println(list);

       //list.add("d");//UnsupportedOperationException

       //System.out.println(list);

       int[]arr2={11,22,33,44,55};

       //List<int[]ar> listInt=Arrays.asList(arr2);

       List listInt=Arrays.asList(arr2);

       System.out.println(listInt);//输出的是地址值[[I@3578436e]

1

2

3

4

5

6

7

8

9

       //基本数据类型的数组转换成集合,会将整个数组当成一个对象转换

       Integer[]arr={11,22,33,44,55};

       List<Integer>list=Arrays.asList(arr);

       System.out.println(list);//[11, 22, 33, 44, 55]

       //将数组转成集合,数组必须是引用数据类型

1

2

3

4

5

4>. 集合转数组 [ 加泛型的 ]


当集合转换数组时,数组的长度如果<=集合的size,转换后的数组长度等于集合的size


当集合转换数组时,数组的长度如果>=集合的size,分配的数组长度,就和你指定的长度一样[new String[10]]


//谁大集合长度就等于谁
         ArrayList<String>list=new ArrayList<>();
         list.add("a");
         list.add("b");
         list.add("c");
         list.add("d");
         String[]str=list.toArray(new String[0]);
         for(String str2:str){
             System.out.println(str2);
         }


5>.集合的遍历方式 [ 迭代器iterator 和 增强for循环 ].


5.1. Iterator接口的概述


Iterator对象称为迭代器(设计模式的一种),主要用于遍历 Collection 集合中的元素。


Iterator 仅用于遍历集合,Iterator 本身并不提供承装对象的能力。如果需要创建 Iterator 对象,则必须有一个被迭代的集合


Iterator<E> iterator ():返回此集合中元素的迭代器,通过集合的iterator () 方法得到


//迭代器的原理及源码解析
 Iterator<String> iterator=coll.iterator();//是通过多肽的方式得到的Iterator的对象
  /*
        public Iterator<E> iterator() {
            return new ArrayList.Itr();
        }
        private class Itr implements Iterator<E> {
           .......
        }
         */


20190718140955543.png


5.2. 方法


boolean hasNext():如果迭代具有更多的元素,则返回true


E next():返回迭代中的下一个元素,并把指针向下移动一位


20190319115614893.png


while(iterator.hasNext()){
             /*
               Iterator中的常用方法 :
               E next():返回迭代中的下一个元素
               boolean hasNext():如果迭代具有更多的元素,则返回true
             * */
             //System.out.println(iterator.next());
             String s=iterator.next();
             System.out.println(s);//String类实现了toString方法
         }


5.3. 增强for循环


增强for:简化数组和Collection集合遍历


它是JDK5 之后出现的,其内部原理就是一个Iterator迭代器


20190319115631144.png

//使用增强for循环实现数组的便利遍历
  @Test
  public void test3() {
  String[]str=new String[]{"aa","bb","cc"};
  for(String s:str){
    System.out.println(s);
  }
  }
  // 使用增强for循环实现集合的便利遍历
  @Test
  public void test2() {
  Collection coll = new ArrayList();
  coll.add("aa");
  coll.add(11);
  for(Object i:coll){
    System.out.println(i);
  }
  }
  }


5.4>. 普通for循环


for (int i = 0; i <list.size() ; i++) {
            Student s=list.get(i);
            System.out.println(s.getId()+" "+s.getName());
        }


6>. 三种迭代能否删除


①. 普通for循环,可以删除,但是索引要 i- -


②. 迭代器,可以删除,但是必须使用迭代器自身的remove方法,否则会出现并发修改异常


③. 增强for循环不能删除


public void fun1(){
     ArrayList<String> list=new ArrayList<>();
     list.add("AAA");
     list.add("BBB");
     list.add("BBB");
     list.add("CCC");
     list.add("DDD");
     //1.普通for循环进行删除
      /*  for (int i = 0; i < list.size(); i++) {
            String str=list.get(i);
            if("BBB".equals(str)){
                //两个BBB在一起的话,会留住一个BBB
                //两个BBB分割的话,两个都会删除
                //要想删除两个BBB必须使用i--,每次删除后,指针又回到原来的位置
                //list.remove(i);
                list.remove(i--);
            }
        }*/
        //2.迭代器删除
       /* Iterator<String>it=list.iterator();
        while(it.hasNext()){
            if("BBB".equals(it.next())){
                //ConcurrentModificationException
                //list.remove("BBB"):不能用集合的删除方法,因为迭代过程中如果集合修改会出现并发修改异常
                it.remove();
            }
        }*/
     /*  for(Iterator<String>it2=list.iterator();it2.hasNext();){
           if("BBB".equals(it2.next())){
               //ConcurrentModificationException
               //list.remove("BBB"):不能用集合的删除方法,因为迭代过程中如果集合修改会出现并发修改异常
               it2.remove();
           }
       }*/
       //3.增强for循环
        /*
         增强for循环不能删除,因为底层是一个iterator
        * */
        for(String str2:list){
            if("BBB".equals(str2)){
                // list.remove("BBB");
            }
        }
        System.out.println(list);
    }


20190718155919135.png


7>.Collection集合储存学生对象并遍历


20190718151942303.png


2. List接口


1>. List集合的概述


①. 元素都带有索引


②. List集合类中元素有序、且可重复,集合中的每个元素都有其对应的顺序索引


有序:储存 和 取出 的元素顺序一致


可重复:储存元素可以重复


2>. list集合特有方法


①. 增: void add( int index,E element):添加一个元素


②. 删 E remove(int index) 删除指定索引位置的元素,返回被删除的元素


③. 改E set(int index,Object ele):设置指定索引位置的元素,返回被修改的元素


④. 查 E get(int index):获取指定索引的元素


//遍历集合
 for (int i = 0; i <list.size() ; i++) {
            Student s=list.get(i);
            System.out.println(s.getId()+" "+s.getName());
        }


public class ListDemo02 {
    public static void main(String[] args) {
        //创建集合对象
        List<String> list = new ArrayList<String>();
        //添加元素
        list.add("hello");
        list.add("world");
        list.add("java");
        //void add(int index,E element):在此集合中的指定位置插入指定的元素
//        list.add(1,"javaee");
        //IndexOutOfBoundsException
//        list.add(11,"javaee");
        //E remove(int index):删除指定索引处的元素,返回被删除的元素
//        System.out.println(list.remove(1));
        //IndexOutOfBoundsException
//        System.out.println(list.remove(11));
        //E set(int index,E element):修改指定索引处的元素,返回被修改的元素
//        System.out.println(list.set(1,"javaee"));
        //IndexOutOfBoundsException
//        System.out.println(list.set(11,"javaee"));
        //E get(int index):返回指定索引处的元素
//        System.out.println(list.get(1));
        //IndexOutOfBoundsException
//        System.out.println(list.get(11));
        //输出集合对象
//        System.out.println(list);
        //遍历集合
//        System.out.println(list.get(0));
//        System.out.println(list.get(1));
//        System.out.println(list.get(2));
        //用for循环改进遍历
        for (int i=0; i<list.size(); i++) {
            String s = list.get(i);
            System.out.println(s);
        }
    }
}


3>. List并发修改异常


// 需求
我有一个集合: List<String> list=new ArrayList<>();
里面有三个元素:list.add("hello");list.add("world");list.add("java");
遍历集合,得到每一个元素,看有没有 " world "这个元素,如果有,我就添加一个" javaEE" 元素


异常的原因:迭代器遍历的过程中,通过集合对象修改了集合中的元素,造成了迭代器获取元素中判断预期修改值和实际修改值不一致 [ 重点 ]


20190718152311525.png


解决方案:使用for循环进行遍历,list中的get方法不会对 expectedModCount = modCount进行判断,可以添加成功
@Test
    public void fun5(){
     List<String> list=new ArrayList<>();
     list.add("hello");
     list.add("world");
     list.add("java");
     Iterator<String> iterator=list.iterator();
        for (int i = 0; i < list.size(); i++) {
             String s=list.get(i);
             if(s.equals("world")){
                 list.add("javaEE");
             }
        }
    /* while(iterator.hasNext()){
         String s=iterator.next();
         if(s.equals("world")){
             list.add("javaEE"); //遍历的同时在修改元素,并发修改ConCurrentModificationException
         }
     }*/
        System.out.println(list);
    }


20190718153805859.png


4>. 列表迭代器 ListIterator


4.1. ListIterator 的概述


通过list集合的 listIterator()方法得到,所以说它是list集合中特有的迭代器


用于允许程序员沿任一方向遍历列表的迭代器,在迭代期间修改列表,并获取列表中迭代器的当前位置


4.2. ListIterator中的常用方法


E next():返回迭代中的下一个元素


boolean hasNext():如果迭代具有更多的元素,则返回true


E previous():返回列表中的上一个元素


bloolean hasPrevious(): 如果此列表迭代器在相反方向遍历列表时具有更多的元素,则返回true


void add(E e):将制定的元素插入列表[ 重点掌握 ]


①. 列表迭代器的add方法 会让 expectedModCount = modCount,不会出现并发修改异常


②. 而集合中的add方法,会直接把修改的次数加上1,这样expectedModCount != modCount,下次当再次调用next()的方法的时候,会调用checkForComodification()方法,当ExpectedModCo unt != modCount的时候会抛出修改并发异常


// listIterator接口中的add()方法会  expectedModCount = modCount;
 public void add(E e) {
            checkForComodification();
            try {
                int i = cursor;
                ArrayList.this.add(i, e);
                cursor = i + 1;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }


2019071815445973.png


逆向遍历,必须要有正向遍历在前面才能遍历出来;要是没有正向遍历,直接逆向遍历,逆向遍历的指针从0索引开始,这个时候向后遍历便没有要遍历的元素
    @Test
    public void fun6(){
     List<String>list=new ArrayList<>();
     list.add("hello");
     list.add("world");
     list.add("javeEE");
     //通过list集合的listItrator()方法得到
     ListIterator<String> lit=list.listIterator();
        System.out.println("正向遍历:");
     while(lit.hasNext()){
         String s=lit.next();
         System.out.print(s+"\t");//hello world javeEE
     }
        System.out.println();
        System.out.println("逆向遍历:");//一般很少运用
        while(lit.hasPrevious()){
            String s=lit.previous();
            //要是没有正向遍历直接逆向遍历,指针在0的位置,向上找没有元素,所以出打印空
            System.out.print(s+"\t");//javeEE world hello
        }
     //获取列表迭代器
     while(lit.hasNext()){
         String s=lit.next();
         if(s.equals("world")){
             //列表迭代器的add方法 会让 expectedModCount = modCount;
             lit.add("xiaozhi");
         }
     }
        System.out.println(list);//[hello, world, xiaozhi, javeEE]
    }


5>. ArrayList


5.1. 什么是ArrayList


ArrayList<E>:
在所有E的地方我们使用引用数据类型替换即可
举例:ArrayList<String>、ArrayList<Student>


可调节大小的数组实现


< E >: 是一种特殊的数据类型,范型


5.2. ArrayList构造 和 增删改查


public ArrayList():创建一个空的集合对象


public boolean add(E e):将指定的元素追加到此集合的末尾


public void add(int index , E element):在此集合中指定位置插入指定的元素


public boolean remove(Objec o):删除指定的元素,返回删除是否成功 [ 重写了equals方法 ]


public E remove(int index):删除指定索引处的元素,返回被删除的元素 [ <> 返回的是什么,E就是什么类型]


public E set(int index , E element) :修改指定索引处的元素,返回被修改的元素


public E get(int index):返回指定索引处的元素


public int size() :返回集合中的元素的个数


//ArrayList<String> array=new ArrayList<>();
         ArrayList<String> array=new ArrayList<String>();
         //public boolean add(E e)
        array.add("AAA");
        array.add("BBB");
        array.add("CCC");
        //public void add(int index,E element)
        array.add(0,"BeforeAAA");
        System.out.println(array);

   

5.3. 遍历集合 [ 掌握 ]


@Test
    public void fun8(){
        List<String>list=new ArrayList<>();
        list.add("hello");
        list.add("world");
        list.add("xiaozhi");
        //遍历集合的通用格式
        //E get(int i)
        for(int i=0;i<list.size();i++){
            String s=list.get(i);
            System.out.print(s+"\t");
        }

5.4. ArrayList 中去除重复字符串元素方式


1. 基本数据类型的去重


分析 :

1.创建新集合

2.根据传入的集合[ 老集合 ] 获取迭代器

3.遍历老集合

4.通过新集合判断是否包含老集合中的元素,如果包含就不添加,如果不包含就添加


public class DemoInteger {
    public static void main(String[] args) {
        //ArrayList去除集合中字符串的重复值(字符串的内容相同)
        //思路: 创建新集合方式
        /*
         创建新集合将重复的元素去掉
         1.明确返回值类型,返回ArrayList
         2.明确参数类表ArrayList
        * */
        ArrayList<String> list=new ArrayList<>();
        list.add("aa");
        list.add("bb");
        list.add("bb");
        list.add("cc");
        ArrayList<String>arrayList=getSingle(list);
        Iterator<String> iterator = arrayList.iterator();
        while (iterator.hasNext()){
            System.out.print(iterator.next()+"\t");
        }
    }
    public static ArrayList getSingle(ArrayList list){
        ArrayList<String> listNew=new ArrayList<>();
        Iterator<String> iterator = list.iterator();
        while(iterator.hasNext()){
            String str1=iterator.next();
            if(!listNew.contains(str1)){
                listNew.add(str1);
            }
        }
        return listNew;
    }


2. 引用类型的去重


①. contains( ): 方法判断是否包含,依赖的是equals方法。没有重写equals之前比较的是地址值,重写后比较的时候属性值


②. remove( ) :方法的底层也是依赖equals方法。没有重写equals之前比较的是地址值,重写后比较的时候属性值


//Person [ 重点是equals方法的重写 ]
public class Person {
    private String name;
    private int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public Person(){
    }
    //重点是要重写equals方法
    @Override
    public boolean equals(Object o) {
       Person p=(Person)o;
       return this.name.equals(p.name)&&this.age==p.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 +
                '}';
    }
}


public class ArrayListDemo {
    public static void main(String[] args) {
        // 创建集合
        ArrayList list=new ArrayList();
        //添加元素
        list.add(new Person("zhangsan",25));
        list.add(new Person("zhangsan",25));
        list.add(new Person("lisi",23));
        list.add(new Person("lisi",23));
        //去除重复元素
        ArrayList listNew=getSingle(list);
        System.out.println(listNew);
        System.out.println("--------");
        listNew.remove(new Person("zhangsan",25));
        System.out.println(listNew);
    }
    //contains 方法判断是否包含,依赖的是equals方法
    //remove :方法的底层也是依赖equals方法。没有重写equals之前比较的是地址值,重写后比较的时候属性值
    public static ArrayList getSingle(ArrayList list){
        ArrayList listNew=new ArrayList();
        Iterator iterator = list.iterator();
        while(iterator.hasNext()){
            Object obj=iterator.next();
            if(!listNew.contains(obj)){
                listNew.add(obj);
            }
        }
        return listNew;
    }
}


20190719085703935.png

20190719090435610.png

20190719092107705.png


6>. Vector [ 了解 ]


Vector v=new Vector();
        v.addElement("AAA");
        v.addElement("BBB");
        v.addElement("CCC");
        Enumeration en=v.elements();//获取枚举
        while (en.hasMoreElements()){//判断集合中是否有元素
            System.out.println(en.nextElement());//获取集合的元素
        }


3. 数据结构 [ 栈、队列 ]


1>.栈 [先进后出的模型 ]


压/进栈:数据进入栈模式的过程


弹/出栈:数据离开栈模型的过程


20190623155930200.png


2.> 队列 [ 先进先出的模型 ]


入队列:数据从后段进入队列模型的过程


出队列:数据从前端离开队列模型的过程


20190623155938814.png


3>.数组


数组是一种查询快,增删慢的模型

4>. 链表


链表的每个元素称为节点,包含:数据和下一个节点的地址


20190623155958125.png20190623160004732.png


4. 数据结构之数组和链表 [ 掌握 ]


数组:查询快修改也快 [ 能很快找到索引值 ]; 增、删 很慢 [ 不管是增还是删,都会创建一个新数组,拷贝等 ] ;每增加一倍,元素的就扩容一倍


链表:查询修改是慢的 [ 查询只能从两头开始,全部找];增、删很快


20190628235622305.png


5. list的三个子类的特点


1>.ArrayList


底层数据结构是数组,查询快,增删慢


线程不安全,效率高


20190719093750640.png


2>.Vector


底层数据结构是数组,查询快,增删慢


线程安全,效率低


3>.LinkedList


底层数据结构是链表,查询慢,增删快


查修慢的原因是:链表的底层会从两端往中间查询;增删快的原因是:只在一个链表中发生,增加和删除会断开两个地址值,然后指向要添加的元素


线程不安全,效率高


20190724141551772.png


4>. 面试题目[ 重点掌握 ]


1.Vector 和 ArrayList 的区别


Vector 是线程安全的,效率低


ArrayList 是现成不安全的,效率高


共同点:都是数组实现的,增删慢,改查快


2.ArrayList 和 LinkedList的区别


ArrayList 底层是数组结果,查询和修改快


linkedList 底层是链表结构的,增和删比较快,查询和修改比较慢


共同点:都是线程不安全的


5>.List有三个儿子,我们到底使用谁呢?


查询多用 ArrayList


增删多用 LinkedList


如果都多 ArrayList


6. 泛型 [ generic ]


1>.generic概述和基本使用


< > 中放的必须是引用数据类型


泛型使用的注意事项:前后的泛型必须一致, 或者后面的泛型可以省略不写 [ 1.7的新特性 ]


泛型最好不要定义成Object,没有意义


ArrayList<Object>list=new ArrayList<Person>();//报错
ArrayList<Person>list=new ArrayList<Person>();//1.7版本的新特性
ArrayList<Person>list=new ArrayList<>();//1.7版本的新特性


2>. 泛型类 的概述和使用


定义格式:public class 类名 < 泛型类型1....>{ }


注意事项:泛型类型必须是引用类型


public class Tools<Q> {
    private Q q;
    public void setQ(Q q){
        this.q=q;
    }
    public Q getQ(){
        return q;
    }
}


3>. 泛型方法的概述和使用


格式:修饰符<类型> 返回值类型 方法名(类型 变量名){}
public class Tools<Q> {
    private Q q;
    public void setQ(Q q){
        this.q=q;
    }
    public Q getQ(){
        return q;
    }
    //方法泛型最好要与类的泛型一致
    public  void show(Q q){
        System.out.println(q);
    }
    //如果不一致,需要在方法上声明该泛型
    public <T>void show2(T t){
        System.out.println(t);
    }
    //Q 是创建对象的时候才给赋值,静态方法必须声明自己的泛型
   /* public static void print(Q q){   //报错
    }*/
   public static<Q> void  print(Q q){  //这里的Q与类上面的泛型是不同的泛型
   }
}


@Test
    public void fun1(){
         Tools<String>tools=new Tools<>();
         tools.show("abc");//abc
         tools.show2("123");//123
    }


4>.泛型接口的概述和使用


interface Inter<T>{
    public void show(T t);
}
//第一种方式:推荐使用
class Demo implements Inter<String>{
    public void show(String t) {
        System.out.println(t);
    }
}
//第二种方式
/*
class Demo<T> implements Inter<T>{ //没有必要在实现接口的时候给自己类添加泛型
    @Override
    public void show(T t) {
        System.out.println(t);
    }
}*/


5>. 泛型高级之通配符


①. 泛型通配符<?>:任意类型,如果没有明确,那么就是Object以及任意的Java类


②. ?extends E :向下限定,E及其子类 [ 泛型固定上边界 ]


③. ? super E: 向上限定, E及其父类 [ 泛型固定下边界 ]


//当右边的泛型是不确定时,左边可以指定?
        List<?> list=new ArrayList<Integer>();
//?extends E :向下限定,E及其子类  (?是子类,E是父类)
// addAll(Collection < ? extends E >) 括号里面可以放E及其子类
// 因为我们不确定有多少子类,所以我们使用?代替
public class Student extends Person  {
    private String name;
    private int age;
    public Student() {
    }
    public Student(String name, int age) {
        super(name,age);
    }
}


ArrayList<Person>list2=new ArrayList<>();
        list2.add(new Person("张三",23));
        list2.add(new Person("李四",24));
        list2.add(new Person("王五",25));
        ArrayList<Student>list3=new ArrayList<>();
        list2.add(new Person("赵六",26));
        list2.add(new Person("周七",27));
        list2.addAll(list3);
        System.out.println(list2);//把子类放入到父类中是可以的
        //list3.addAll(list2);//在父类放入到子类中是不可以的
        // public boolean addAll(Collection<? extends E> c) {


//TreeSet(Comparator<? super E>comparator)
    TreeMap(Comparator<? super E>comparator)


//类型通配符上限:<? extends 类型>
        //List<? extends Number> list1=new ArrayList<Object>(); 报错
        List<? extends Number> list2=new ArrayList<Number>();
        List<? extends Number> list3=new ArrayList<Integer>();
        //类型通配符下限<? super 类型>
        //List<? super Number> list4=new ArrayList<Integer>();报错
        List<? super Number> list5=new ArrayList<Number>();
        List<? super Number> list4=new ArrayList<Object>();

20190719201927698.png


7. JDK 5的新特性


1>. 增强for循环[ 底层是iterator ]


2>. 可变参数


可变参数概述:定义方法的时候不知道定义多少个参数


格式:修饰符 返回值类型 方法名(数据类型 ... 变量名){ }


注意事项:①. 这里的变量其实是一个数组 ②. 如果一个方法有可变参数,那么,可变参数肯定是最后一个


20190719202353666.png


3>. JDK5 的新特性自动装箱和拆箱


自动装箱:把基本数据类型转换成包装类型


自动拆箱:把包装类型转换为基本数据类型


注意事项: 在使用时,Integer x=null; 代码会出现NullPointerException,建议先判断是否为null,然后使用


Integer i3=null;
        int a=i3+100;
        System.out.println(a);//NullPointerException
        //底层用i3调用的是intValue() ,但是i3是null,null调用方法就会出现空指针异常


8.Set


1>.HashSet [ Set的主要实现类 ]


1.1. HashSet 的概述


①. 无序性!=随机性 [ 正在的无序性是指元素在底层存储的位置是无序的 ]


②. 不可重复性:当向set中添加进相同的元素的时候,后面的这个不能添加进去


③. 没有带索引的方法,所以不能用普通for循环遍历


④. 底层数据结构是哈希表


HashSet<String>hs=new HashSet<>();
        boolean b1=hs.add("a");
        boolean b2=hs.add("a");
  hs.add(null);
        System.out.println(hs);  //HashSet的继承体系中,有重写toString()方法
        System.out.println(b1);
        System.out.println(b2);
        //只要能用迭代器迭代的,就可以使用增强for循环遍历
        for(String str:hs){
            System.out.println(str);//[a]
        }


1.2. 哈希值


1.哈希值的介绍


是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值


Object类中有一个方法可以获取对象的哈希值:public int hashCode():返回对象的哈希码值


特点:①.同一个对象多次调用hashCode() 方法返回的哈希值是相同的


②.默认情况下,不同对象的哈希值是不相同的。而重写hashCode()方法,可以实现让不同对象的哈希值相同


1.3. 哈希值原理 [掌握]


20190719112758383.png


1.4. 自定义对象的唯一性


要求添加进Set中的元素所在的类,一定要重写equal()和 hashCode()方法,进而保存不可重复性 [ 掌握 ]


hashCode():属性相同的对象返回值必须相同,属性不同的返回值尽量不同(提高效率)


equals():属性相同返回true,属性不同返回false,返回false的时候就存储


[ 掌握关于equals方法和hashCode方法底层实现原理 ]
    /*
  public static int hashCode(Object a[]) {
        if (a == null)
            return 0;
        int result = 1;
        for (Object element : a)
            result = 31 * result + (element == null ? 0 : element.hashCode());
        return result;
    }
   为什么是31?
   1.31是质数,质数是能被1和它本身整除的数
   2.31这个数既不大也不小
   3.31这个数好算,2的5次方-1,向左移动5位数-1
  * */
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;//调用的对象和传入的对象是同一个对象,直接返回true
        if (o == null || getClass() != o.getClass()) return false;//传入的对象为空或者字节码文件不相同,返回false
        Person person = (Person) o;//向下转型
        return age == person.age &&
                Objects.equals(name, person.name);
        //如果调用对象的年龄和传入对象的年龄 相同并且 调用对象的姓名和传入对象的姓名相同返回true
    }


public class Person {
    private String name;
    private int age;
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public Person() {
    }
    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;
    }
    public int hashCode() {
        return Objects.hash(name, age);
    }
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;//调用的对象和传入的对象是同一个对象,直接返回true
        if (o == null || getClass() != o.getClass()) return false;//传入的对象为空或者字节码文件不相同,返回false
        Person person = (Person) o;//向下转型
        return age == person.age &&
                Objects.equals(name, person.name);
        //如果调用对象的年龄和传入对象的年龄 相同并且 调用对象的姓名和传入对象的姓名相同返回true
    }
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}


HashSet<Person>hs=new HashSet<>();
    hs.add(new Person("zhangsan",23));
    hs.add(new Person("zhangsan",23));
    hs.add(new Person("zhangsan",23));
    hs.add(new Person("lisi",24));
    hs.add(new Person("lisi",24));
    hs.add(new Person("lisi",24));
    System.out.println(hs.size());//2
        System.out.println(hs);//[Person{name='lisi', age=24}, Person{name='zhangsan', age=23}]
    }

 

1.5. HashSet的原理 [ 掌握 ]


当HashSet调用add()方法储存对象的时候,先调用对象的hashCode方法得到一个哈希值,然后在集合中查找是否有哈希值相同的对象。如果没有哈希值相同的对象就直接存入集合;如果有哈希值相同的对象,就和哈希值相同对象逐个进行equals()比较,比较结果为false就存入,true则不存

2>.LinkedHashSet


①. 哈希表和链表实现的Set接口,具有可预测的迭代次序


②. 由链表保证元素有序,也就是说元素的存储和取出顺序是一致的


③. 由哈希表保证元素唯一,也就是说没有重复的元素


@Test
  public void testLinkHashSet(){
  Set set=new LinkedHashSet();
  set.add(123);
  set.add(456);
  set.add("AAA");
  set.add("BBB");
  set.add(null);
  Iterator iterator=set.iterator();
  while(iterator.hasNext()){
    System.out.println(iterator.next());//123 456 AAA BBB null
  }


3>. Set的练习


①. 编写一个程序,获取10个1-20的随机数,要求随机数不能重复,并把最终的结果打印在控制台上

//编写一个程序,获取10个1-20的随机数,要求随机数不能重复,并把最终的结果打印在控制台上
       //1.有Random类创建随机数对象
        Random random=new Random();
        //2.需要储存10个随机数,而且不能重复,所以我们用hashSet集合
        HashSet<Integer>hs=new HashSet<>();
        //3.如果HashSet的size是<10 就可以不断的储存,如果大于等于10就停止储存
        while(hs.size()<=10){
            //4.4.通过Randeom类中的nextInt(n)方法获取1-20之间的随机数,并将这些数字储存在hashSet中
            int i=random.nextInt(20)+1;
            hs.add(i);
     }
        for(Integer hs2:hs){
            System.out.println(hs2);
        }

   

②.使用Scanner从键盘读取一行输入,去除重复字符,打印不同的那些字符


Scanner sc=new Scanner(System.in);
        System.out.println("请键盘输入字符串");
        String str=sc.nextLine();
        HashSet<Character> hs=new HashSet<>();
        char[] chs = str.toCharArray();
        for (int i = 0; i < chs.length; i++) {
            hs.add(chs[i]);
        }
        Iterator<Character> iterator = hs.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }
        /*for(Character hs2:hs){
            System.out.print(hs2);
        }*/


③.去除list中重复的元素


//将集合中重复的元素去掉
    @Test
    public void fun7(){
    ArrayList<String>list=new ArrayList<>();
    list.add("AAA");
    list.add("AAA");
    list.add("AAA");
    list.add("AAA");
    list.add("AAA");
    list.add("AAA");
    list.add("BBB");
    list.add("BBB");
    list.add("CCC");
    list.add("CCC");
    getSingle(list);
    // 打印
        System.out.println(list);
    }
    public static  void getSingle(ArrayList<String> list) {
        /*LinkedHashSet<String>lhs=new LinkedHashSet<>();
        Iterator<String> iterator = list.iterator();
        while(iterator.hasNext()){
            lhs.add(iterator.next());
        }
        for(String lhs2:lhs){
            System.out.print(lhs2+"\t");
        }*/
       //1.创建一个LinkedHashSet集合
        LinkedHashSet<String>lhs=new LinkedHashSet<>();
        //2.将List集合中所有的元素添加到LinkedHashSet集合
        lhs.addAll(list);
        //3.将List 集合中元素清除
        list.clear();
        //4.将LinkedHashSet集合中的元素添加到List集合中
        list.addAll(lhs);
    }


4>. TreeSet


4.1.TreeSet的特点


①.元素有序,这里的顺序不是指存储和取出的顺序,而是按照一定的规则进行排序,具体排序方式取决于构造方法


TreeSet():根据其元素的自然排序进行排序


TreeSet(Comparator comparator) :根据指定的比较器进行排序


②. 没有带索引的方法,所以不能使用普通for循环遍历


③. 由于是Set集合,所以不包含重复元素的集合


4.2. 自然排序的原理和图解


1. 自然顺序(Comparable)


①. TreeSet 类的add()方法中会把存入的对象提升为Comparable类型


②. 调用对象的CompableTo()方法和集合中的对象比较


③. 根据CompableTo()方法返回的结果进行储存


TreeSet底层是一个二叉树,两个叉。小的存储在左边[ 负数 ],大的存储在右边[ 正数 ],相等就不存 [ 0 ]。CompareTo方法,在TreeSet集合如何存储元素取决于compareTo方法的返回值[ 掌握 ]


①. 返回的0,集合中只有一个元素


②. 返回-1,集合会将存储的元素倒序


③. 返回1,集合会怎么存就怎么取


/ /按照年龄排序
        public int compareTo(Object o) {
        Person p=(Person)o;
        int num=this.age-p.age;//年龄是比较的主要条件
        return num==0?this.name.compareTo(p.name):num;//姓名是比较的次要条件
    }
      TreeSet<Person>ts=new TreeSet<>();
        ts.add(new Person("张三",23));
        ts.add(new Person("李四",13));
        ts.add(new Person("王五",43));
        ts.add(new Person("赵六",33));
        System.out.println(ts);
        //[Person{name='李四', age=13}, Person{name='张三', age=23}, 
        Person{name='赵六', age=33}, Person{name='王五', age=43}]

20190719151533549.png



4.3. TreeSet存储自定义对象并遍历练习 [ 自然排序 ]


public class Person implements Comparable{
    private String name;
    private int age;
    }


①. 按照姓名排序


//按照姓名排序
    public int compareTo(Object o) {
        Person p=(Person)o;
        int num=this.name.compareTo(p.name);
        //姓名是主要条件,年龄是次要条件
        return num==0?this.age-p.age:num;
    }
        TreeSet<Person>ts=new TreeSet<>();
        ts.add(new Person("张三",23));
        ts.add(new Person("张三",25));
        ts.add(new Person("王五",43));
        System.out.println('张'+0);//24352
        System.out.println('李'+0);//26446
        System.out.println('王'+0);//29579
        System.out.println("ts = " + ts);
        //ts = [Person{name='张三', age=23}, Person{name='张三', age=25}, 
        Person{name='王五', age=43}]

 


②. 按照姓名长度进行排序


public int compareTo(Object o) {
      Person p=(Person)o;
      int length=this.name.length()-p.name.length();//比较长度为主要条件
      int num=length==0?this.name.compareTo(p.name):length;//比较内容为次要条件
      return num==0?this.age-p.age:num;//比较年龄也为次要条件
    }
        TreeSet<Person>ts=new TreeSet<>();
        ts.add(new Person("zhangsan",23));
        ts.add(new Person("lisi",25));
        ts.add(new Person("wangwu",43));
        System.out.println("ts = " + ts);
        //ts = [Person{name='lisi', age=25}, Person{name='wangwu', age=43}, Person{name='zhangsan', age=23}]


4.4. 比较器顺序(Comparator)


①. 创建TreeSet的时候可以制定一个Comparator接口


②. 如果传入了Comparator的子类对象,那么TreeSet就会按照比较器中的顺序排序


③. 调用的对象是Comparator接口中compare()方法顺序


调用的对象是compare方法的第一个参数,集合中的对象是compare方法的第二个参数


@Test
    public void fun4(){
        /*
        需求:将字符串按照长度排序
        * */
        //Comparator c=new CompareByLen();
        //new TreeSet(Comparator );
        TreeSet<String>ts=new TreeSet<>(new CompareByLen());
        ts.add("aaaaaaaa");
        ts.add("z");
        ts.add("wc");
        ts.add("nba");
        ts.add("cba");
        System.out.println(ts);//[n, bb, aaa]
    }
    class CompareByLen /* extends Object*/implements Comparator<String>{//
        @Override
        public int compare(String s1, String s2) {
            //按照字符串长度进行比较
            int num=s1.length()-s2.length();//长度为主要条件
            return num==0?s1.compareTo(s2):num;//内容为次要条件
        }
    }

 

20190719154508913.png


4.5. TreeSet原理 [ 掌握 ]


1. 自然顺序(Comparable)


①. TreeSet 类的add()方法中会把存入的对象提升为Comparable类型


②. 调用对象的CompableTo()方法和集合中的对象比较


③. 根据CompableTo()方法返回的结果进行储存


2. 比较器顺序(Comparator)


①. 创建TreeSet的时候可以制定一个Comparator接口


②. 如果传入了Comparator的子类对象,那么TreeSet就会按照比较器中的顺序排序


③. 调用的对象是Comparator接口中compare()方法顺序


调用的对象是compare方法的第一个参数,集合中的对象是compare方法的第二个参数


3. 两种方式的区别


TreeSet 如果传入Comparator,就优先按照Comparator .


TreeSet构造函数什么都不传,默认按照类中Comparable的顺序(没有就报错ClassCastE xception)


//java.lang.ClassCastException: com.itheima.TreeSetDemo4.Person cannot be cast to java.base/java.lang.Comparable
public class Person {
    private String name;
    private int age;
    public Person(){}
    public Person(String name, int age) {
        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 +
                '}';
    }
}


@Test
    public void fun1(){
        //1.按照年龄来排序
        TreeSet<Person>ts=new TreeSet<>();
        ts.add(new Person("张三",23));
        ts.add(new Person("张三",23));
        ts.add(new Person("张三",23));
        ts.add(new Person("李四",24));
        ts.add(new Person("王五",24));
        System.out.println("ts = " + ts);
    }


4.6. 练习 [ 掌握 ]


①. 在一个集合中储存了无序并且重复的字符串,定义一个方法,让其有序(字典顺序)而且重复的输出


/*
     分析:
     1.定义一个List集合,并储存重复的无序的字符串
     2.定义方法对其排序保留重复
     3.打印list集合
     * */
        //1.定义一个List集合,并储存重复的无序的字符串
        ArrayList<String>list=new ArrayList<>();
        list.add("aaa");
        list.add("aaa");
        list.add("ccc");
        list.add("bbb");
        list.add("ccc");
        list.add("ddd");
        list.add("ddd");
        list.add("aaa");
        list.add("aaa");
        //2.定义方法对其排序保留重复
        sort(list);
        //3.打印list
        System.out.println(list);
    }
    /**
      定义方法,排序并保留重复
      分析:
     1.创建TreeSet集合对象,因为String本身就具备比较功能,但是重复的不会保留,所以我们用比较器
     2.将list集合中所有的元素添加到TreeSet集合中,对其排序保留重复
     3.清空list集合
     4.将TreeSet集合中排好序的元素添加到list集合中
     * */
    public static void sort(List<String> list){
    // 1.创建TreeSet集合对象,因为String本身就具备比较功能,但是重复的不会保留,所以我们用
        TreeSet<String>ts=new TreeSet<>(new Comparator<String>() {
            public int compare(String s1, String s2) {
                int num=s1.compareTo(s2);//比较内容为主要条件
                return num==0?1:num;//返回1就不让你返回1  //保留重复
            }
        });
        //2.将list集合中所有的元素添加到TreeSet集合中,对其排序保留重复
        ts.addAll(list);
        //3.清空list集合
        list.clear();
        //4.将TreeSet集合中排好序的元素添加到list集合中
        list.addAll(ts);
    }


②. 从键盘接收一个字符串,程序对其中所有字符进行排序 [ 例如键盘输入: helloitcase程序打印: aceehillost ] [ 重点掌握 ]


//注意这里的自动装箱和拆箱的过程
          // 1.键盘录入字符串,Scanner
          Scanner sc=new Scanner(System.in);
          System.out.println("请键盘输入一个字符串");
          String str=sc.nextLine();
          //2.将字符串转换为字符数组,可以拿到每一个字符
          char[] chars = str.toCharArray();
          //3.定义TreeSet集合,传入比较器对字符排序并保留重复
          TreeSet<Character>ts=new TreeSet<>(new Comparator<Character>() {
              @Override
              public int compare(Character s1, Character s2) {
                 // int num=s1-s2; //自动拆箱
                  int num=s1.compareTo(s2);
                  return num==0?1:num;
              }
          });
          //4.遍历字符数组,将每一个字符储存到TreeSet集合中
        for (int i = 0; i < chars.length; i++) {
            ts.add(chars[i]); //自动装箱: 会使得char基本数据类型转成包装类型
        }
        //5.遍历TreeSet集合,打印每一个字符
        for(Character c:ts){
            System.out.print(c);
        }

     

③. 程序启动后,可以从键盘接收多个整数,直到输入quit时结束输入,把所有输入的整数倒序排列打印


//1.创建Scanner对象,键盘录入
    Scanner sc=new Scanner(System.in);
    //2.创建TreeSet集合对象,TreeSet集合中传入比较器
    TreeSet<Integer>ts=new TreeSet<>(new Comparator<Integer>() {
        @Override
        public int compare(Integer i1, Integer i2) {
            int num=i2-i1;//这叫自动拆箱,使用i2-i1就是倒序了
            //int num=i2.compareTo(i1)
            return num==0?1:num;
        }
    });
    //3.无限循环不断接收整数,遇到quit退出,因为退出是quit,所以键盘录入的时候应该都以字符串的形式录入
    while(true){
       String str=sc.nextLine();//将键盘录入的字符储存在str中
       if("quit".equals(str)){
           break;
       }
        //4.判断是quit就退出,不是就将其转换成Integer,并添加到集合中
        Integer i=Integer.parseInt(str);//本来这里变成int的,发生了自动装箱 int---Integer
        ts.add(i);
    }
    //5.遍历TreeSet集合并打印每一个元素
    for(Integer integer:ts){
        System.out.print(integer);
    }

 

9. Map接口


1>.Map接口的概述


Map [ 双列集合 ]与 Collection [ 单列集合 ] 并列存在


Map <K, V> 这里的K 、V 都应该是引用数据类型


HashSet底层依赖HashMap,单列底层依赖双列集合[ 理解 ]


20190706204111896.png20190721123520705.png


2>. Map 集合的功能概述


2.1 添加功能.


V put(K key ,V value): 添加元素,返回的是以前的值


如果键是第一次储存,就直接储存元素,返回null;如果键不是第一次存在,就用值把以前的值替换掉,返回以前的值


Map<String,Integer> map=new HashMap<>();
        Integer i1=map.put("张三",23);
        Integer i2=map.put("李四",23);
        Integer i3=map.put("王五",24);
        Integer i4=map.put("赵六",25);
        Integer i5=map.put("张三",26);//相同的键不储存,把原来的值覆盖 把被覆盖的值返回
        System.out.println(map);//{李四=23, 张三=26, 王五=24, 赵六=25}
        //这里的i1--i4 都是null是因为开始的时候[张三,23][李四,23]....
        // 在集合中没有,这样把原来的值覆盖了,返回的是原来的值
        System.out.println(i1);//null
        System.out.println(i2);//null
        System.out.println(i3);//null
        System.out.println(i4);//null
        System.out.println(i5);//23


删除功能


void clear():移除所有的键值对元素
V remove(Object key):根据键删除键值对元素,并把值返回
       Map<String,Integer> map=new HashMap<>();
       map.put("张三",23);
       map.put("李四",23);
       map.put("王五",24);
       map.put("赵六",25);
       //根据键删除元素,返回键对应的值
       Integer value=map.remove("张三");
       System.out.println(value);//23


2.3. 判断功能


boolean containsKey(Objecct key):判断是否包含指定的键
boolean containsValue(Objecct value):判断是否包含指定的值
       //判断是否包含传入的键
       System.out.println(map.containsKey("张三"));//true
       //判断是否包含传入的值
       System.out.println(map.containsValue(23));//true


2.4. 长度功能 [ 掌握 ]


int size():返回集合中的键值对的个数
       Map<String,Integer> map=new HashMap<>();
       map.put("张三",26);
       map.put("李四",23);
       map.put("王五",24);
       map.put("赵六",25);
       Collection<Integer>coll=map.values();
       System.out.println(coll);//[23, 23, 24, 25]
       System.out.println(map.size());//4


2.5. 获取功能 [ 掌握 ]


V get(Object key):根据键获取值


Set<K> keySet():获取集合中所有的键集合


Collection<V>values:获取集合中所有值集合


Set<Map.Entry<K,V>> entrySet():拿到所有的键值对对象


①. K getKey():得到entrySet中的键


②. V getValue():得到entrySet中的值


Map<String, Integer> map = new HashMap<>();
        map.put("张三", 23);
        map.put("李四", 24);
        map.put("王五", 25);
        map.put("赵六", 23);
        //V get(Object key):根据键获取值
        Integer i = map.get("张三");//26
        Integer i2=map.get("小智");//没有的话返回null
        //1.获取所有的键
        Set<String> keySet = map.keySet();
        //iterator遍历
        Iterator<String> iterator = keySet.iterator();
        while (iterator.hasNext()) {
            String key = iterator.next();//获取每一个键
            Integer value = map.get(key); //根据键获取值
            System.out.println(key + "=" + value);
        }
        System.out.println("--------------");
        //使用增强for循环
        for (String key : map.keySet()) {
           Intger value=map.get(key);
            System.out.println(key + "=" +value );
        }

20190721110457596.png


interface Inter{
    interface Inter2{
        public void show();
    }
}
//这里的Inter.Inter2 和Map.Entry一样的
class Demo implements Inter.Inter2{
    @Override
    public void show() {
    }
}


//2.根据键值对对象,获取键和值
        //Map.Entry说明Entry是Map的内部接口,将键和值封装成了Entry对象,并储存在Set集合中
        Set<Map.Entry<String,Integer>>entrySet=map.entrySet();
        //获取每一个对象
        Iterator<Map.Entry<String,Integer>>it=entrySet.iterator();
        while(it.hasNext()){
            //获取每一个Entry对象
            //static  class Entry<K,V> implements Map.Entry<K,V>{}
            Map.Entry<String,Integer>en=it.next();//父类引用指向子类对象
            //Entry<String,Integer>en=it.next(); 子类对象
            //根据键值对对象获取键
            String key=en.getKey();
            //根据键值对对象获取值
            Integer value=en.getValue();
            System.out.println(key+"="+value);
        }
        //增强for循环
        for(Map.Entry<String,Integer> en:map.entrySet()){
            System.out.println(en.getKey()+"="+en.getValue());
        }
       for(Entry<String,Integer> en:map.entrySet()){
            System.out.println(en.getKey()+"="+en.getValue());
        }

20190721112515256.png


3>.HashMap [ Map实现类之一 ]


①. Map 中的 key 用 Set 来存放,不允许重复,即同一个 Map 对象所对应的类,须重写hashCode( )和equals( )方法


②. HashMap 判断两个 key 相等的标准是:两个 key 通过 equals() 方法返回 true,hashCod e 值也相等


③. HashMap 判断两个 value相等的标准是:两个 value 通过 equals() 方法返回 true。


注意:两个HashMap的hashcode相同,则他们的equal()方法不一定相同,若两个HashMap的equal()相同,则他们的hashcode一定相同


允许使用null键和null值,与HashSet一样,不保证映射的顺序


20190315185009456.png


4>. 练习


①. HashMap集合键是Student值是String的案例[ 掌握 ]


// HashMap集合键是Student值是String的案例
public class Student {
    private String name;
    private int age;
    public Student() {
    }
    public Student(String name, int age) {
        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 boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age &&
                Objects.equals(name, student.name);
    }
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}


HashMap<Student,String>hm=new HashMap<>();
        hm.put(new Student("张三",23),"北京");
        String i=hm.put(new Student("张三",23),"上海");
        hm.put(new Student("李四",24),"广州");
        hm.put(new Student("王五",25),"深圳");
        System.out.println(i);
        //没有重写equals方法之前,调用的是Object类的,会比较地址值
        //没有重写equals方法和 hashCode方法的时候map中的元素有4个,重写后只有3个
        //注意这里的张三对应的值是上海,因为把北京覆盖了
        System.out.println(hm);//北京
        //{Student{name='张三', age=23}=上海, Student{name='李四', age=24}=广州, Student{name='王五',


②. 统计字符串中每个字符出现的次数 [ 掌握 ]


思路:

1.键盘随机输入一个字符串

2.将字符串转换成字符数组

3.定义双列集合,存储字符串中字符以及字符出现的次数

4.遍历字符数组,获取每一个字符并将字符存储在双列集合中

5.存储过程做判断,如果集合中不包含这个键,就将该字符当做键,值为1存储

如果集合中包含这个键,就将值+1存储

6.打印双列集合获取字符出现的次数


//1.键盘随机输入一个字符串
        Scanner sc=new Scanner(System.in);
        System.out.println("请输入一个字符串");
        String line = sc.nextLine();
        //2.将字符串转换成字符数组
        char[] chars = line.toCharArray();
        //3.定义双列集合,存储字符串中字符以及字符出现的次数
        HashMap<Character,Integer>hm=new HashMap<>();
        //4.遍历字符数组,获取每一个字符并将字符存储在双列集合中
        for(char c:chars){
            //5.如果不包含这个键,就将该字符当做键,值为1存储
           /* if(!hm.containsKey(c)){
              hm.put(c,1);
            }else{
              hm.put(c,hm.get(c)+1); //这里发生了自动装箱
            }*/
            //这里先发生自动拆箱,后发生自动装箱
           hm.put(c,!hm.containsKey(c)?1:hm.get(c)+1);
        }
        //6.打印双列集合获取字符出现的次数
        Set<Map.Entry<Character,Integer>> en=hm.entrySet();
        //①.迭代器答应
       /* Iterator<Map.Entry<Character,Integer>> iterator=en.iterator();
        while(iterator.hasNext()){
            Map.Entry<Character,Integer> entry=iterator.next();
            System.out.println("字母-->"+entry.getKey()+"在字符串中出现的次数是-->"+entry.getValue());
        }*/
        //②. 增强for
       /* for(Map.Entry<Character,Integer> en2:en){
            System.out.println("字母-->"+en2.getKey()+"在字符串中出现的次数是-->"+en2.getValue());
        } */
       //③. Set<K> keySet(); 调用 V get(K) 调用键得到值
       for(Character c2:hm.keySet()){
           System.out.println("字母-->"+c2+"在字符串中出现的次数是-->"+hm.get(c2));
       }


③. 单列集合嵌套双列集合


//需求:创建一个ArrayList集合,存储三个元素,每一个元素都是HashMap,每一个HashMap的键和值都是String,并遍历
public class ArrayListDemo {
    public static void main(String[] args) {
        //创建ArrayList集合
        ArrayList<HashMap<String,String>> list=new ArrayList<>();
        //创建HashMap集合并添加键值对元素
        HashMap<String,String>hs=new HashMap<>();
        hs.put("唐智","岳阳");
        hs.put("洋洋","广州");
        hs.put("小幸","长沙");
        HashMap<String,String>hs2=new HashMap<>();
        hs2.put("诸葛亮","三国");
        hs2.put("黄盖","三国");
        hs2.put("卢布","三国");
        HashMap<String,String>hs3=new HashMap<>();
        hs3.put("孙悟空","西游");
        hs3.put("猪八戒","西游");
        hs3.put("沙僧","西游");
        //将HashMap添加到ArrayList
        list.add(hs);
        list.add(hs2);
        list.add(hs3);
        //遍历ArrayList
        Iterator<HashMap<String, String>> iterator = list.iterator();
        while(iterator.hasNext()){
            //得到每一个HashMap中的对象
            HashMap<String,String> hss=iterator.next();
            //对得到的每一个HashMap对象进行遍历
            for(String key:hss.keySet()){
             String value=hss.get(key);
                System.out.println(key+"="+value);
            }
        }
    }
}


20190721152140758.png


④. 双列集合嵌套单列集合


public class HashMapDemo2 {
    public static void main(String[] args) {
        //创建HashMap集合
        HashMap<ArrayList<String>,String>hm=new HashMap<>();
        //创建ArrayList集合,添加元素
        ArrayList<String>list=new ArrayList<>();
        list.add("小智");
        list.add("小幸");
        list.add("洋洋");
        ArrayList<String>list2=new ArrayList<>();
        list2.add("诸葛亮");
        list2.add("黄盖");
        list2.add("卢布");
        ArrayList<String>list3=new ArrayList<>();
        list3.add("鹏翔");
        list3.add("碰翔");
        list3.add("朋翔");
        //将ArrayList添加进HashMap集合中
        hm.put(list,"岳阳");
        hm.put(list2,"三国");
        hm.put(list3,"湖南");
        //遍历HashMap集合
        for(ArrayList<String> key:hm.keySet()){
            System.out.println(hm.get(key));
            //遍历ArrayList 得到每一个HashMap中的
            Iterator<String> iterator = key.iterator();
            while(iterator.hasNext()){
                String str=iterator.next();
                System.out.println("\t"+str);
            }
        }
    }
}


5>. LinkedHashMap


LinkedHashMap:使用链表维护添加进Map中的顺序, 故遍历Map时,是按添加的顺序遍历的


LinkedHashMap<String,Integer>lhm=new LinkedHashMap<>();
        lhm.put("张三",23);
        lhm.put("李四",24);
        lhm.put("王五",25);
        lhm.put("赵六",26);
        System.out.println(lhm);//{张三=23, 李四=24, 王五=25, 赵六=26}


6>.TreeMap [ 和TreeSet一样 ]


自然排序:TreeMap 的所有的 Key 必须实现 Comparable 接口,调用对象的comparaTo()方法和集合中的对象进行比较,根据CompableTo()方法返回的结果进行储存 [ 所有的 Key 应该是同一个类的对象,否则将会抛出 ClasssCastException ]


选择器排序:创建 TreeMap 时,传入一个 Comparator 对象,该对象负责对 TreeMap 中的所有 key 进行排序。此时不需要 Map 的 Key 实现 Comparable 接口


TreeMap集合键是Student值是String的案例


//自然排序
public class Student implements Comparable<Student> {
    private String name;
    private int age;
    public Student() {
    }
    public Student(String name, int age) {
        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 "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    @Override
    public int compareTo(Student s) {
        //以年龄为主要条件,姓名为次要条件
        int num=this.age-s.age;
        return num==0?this.name.compareTo(s.name):num;
    }
}


TreeMap<Student,String> tm=new TreeMap<>();
         tm.put(new Student("张三",23),"北京");
         tm.put(new Student("李四",13),"上海");
         tm.put(new Student("王五",33),"广州");
         tm.put(new Student("赵六",43),"北京");
         System.out.println(tm);
         //{Student{name='李四', age=13}=上海, Student{name='张三', age=23}=北京,
        // Student{name='王五', age=33}=广州, Student{name='赵六', age=43}=北京}


/

//选择器排序
  TreeMap<Student,String> tm=new TreeMap<>(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("张三",23),"北京");
        tm.put(new Student("李四",13),"上海");
        tm.put(new Student("王五",33),"广州");
        tm.put(new Student("赵六",43),"北京");
        System.out.println(tm);
        //{Student{name='张三', age=23}=北京, Student{name='李四', age=13}=上海,
        //Student{name='王五', age=33}=广州, Student{name='赵六', age=43}=北京}


7>. Hashtable


面试题目 [ 掌握 ]


HashMap和Hashtable的区别


  • 共同点:


底层都是哈希算法,都是双列集合


  • 区别

1.HashMap是线程不安全的,效率高,jdk1.2版本


 Hashtable是现场安全的,效率低,jdk1.0版本


2.HashMap可以存储null键和null值


 Hashtable不可以存储null键和null值



8>. 操作集合的工具类:Collections [是一个类]


1. Collections中的概述


Collections 是一个操作 Set、List 和 Map 等集合的工具类


Collections中都是静态方法


①. public static <T> void sort(List<T>list):对集合进行升序


②. public static <T> reverse(List<?> list):将集合顺序反转


③. public static <T> shuffle(List<?> list):随机置换,可以用来洗牌


ArrayList<String> list=new ArrayList<>();
        list.add("b");
        list.add("a");
        list.add("d");
        list.add("c");
        System.out.println(list);//[b, a, d, c]
        Collections.sort(list);
        System.out.println(list);//[a, b, c, d]
        //根据默认排序结果获取集合中最大值
        System.out.println("max:"+Collections.max(list));//d
        System.out.println("开始的时候的排序是"+list);//[b, a, d, c]
        Collections.reverse(list);
        System.out.println("反转后时候的排序是"+list);//[c, d, a, b]
        System.out.println(list);//[b, a, d, c]
        Collections.shuffle(list);//反转集合
        System.out.println(list); //[d, c, b, a] [a, d, b, c] [a, b, d, c]....


ArrayList<String>list=new ArrayList<>();
        list.add("b");
        list.add("c");
        list.add("a");
        list.add("d");
        System.out.println(list);
        //如果索引包含在列表中,则返回搜索的索引,否则返回(-(插入点)-1)
        System.out.println(Collections.binarySearch(list,"c"));//1
        System.out.println(Collections.binarySearch(list,"e"));//-5


20190721165659643.png


2. Collection的练习


ArrayList存储学生对象,使用Collections对ArrayList进行排序

       要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序


思路:

       1:定义学生类

       2:创建ArrayList集合对象

       3:创建学生对象

       4:把学生添加到集合

       5:使用Collections对ArrayList集合排序

       6:遍历集合


public class CollectionsDemo02 {
    public static void main(String[] args) {
        //创建ArrayList集合对象
        ArrayList<Student> array = new ArrayList<Student>();
        //创建学生对象
        Student s1 = new Student("linqingxia", 30);
        Student s2 = new Student("zhangmanyu", 35);
        Student s3 = new Student("wangzuxian", 33);
        Student s4 = new Student("liuyan", 33);
        //把学生添加到集合
        array.add(s1);
        array.add(s2);
        array.add(s3);
        array.add(s4);
        //使用Collections对ArrayList集合排序
        //sort(List<T> list, Comparator<? super T> c)
        Collections.sort(array, new Comparator<Student>() {
            @Override
            public int compare(Student s1, Student s2) {
                //按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
                int num = s1.getAge() - s2.getAge();
                int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
                return num2;
            }
        });
        //遍历集合
        for (Student s : array) {
            System.out.println(s.getName() + "," + s.getAge());
        }
    }
}


String、StringBuffer、StringBuilder


1. String类


1>.String类的概述


String 类在java.lang包下,所以使用的时候不需要导包


String类代表字符串,JAVA程序中所有的双引号字符串,都是String类的对象,包括 " " [ 就算没有new,也照样是 ]


如果在编程的过程中每次感觉字符串的内容发生了改变,那么一定是产生了一个新的字符串对象


2>. 字符串的特点


字符串不可变,它们在值在创建后不能被更改


虽然String的值是不可变的,但是它们可以被共享


字符串效果上相当于字符数组(char[ ]) ,但是底层原理是字节数组(byte[ ])


注意:在jdk1.8前是用char[ ] 数组存储的,JDK1.9中是用byte[ ] 数组存储的


3>. Stirng类的构造方法


public String():创建一个空白字符对象,不含有任何内容


public String (char[ ]chs):根据字符数组的内容,来创建字符串对象


public String(byte [ ]bys):根据字节数组的内容,来创建字符串对象


String s=" abc ":直接赋值的方式创建字符串对象,内容就是abc [ 推荐 ]


注意:直接写上双引号,就是字符串对象


String  s1=new String();
        System.out.println("s1"+s1);
        //public String(char[]chs):根据字符数组的内容,来创建字符串对象
        char[] chs={'a','b','c'};
        String s2=new String(chs);
        System.out.println("s2\t"+s2);
        //public String(byte[]bys):根据字节数组的内容,来创建字符串对象
        byte[] bys={97,98,99};
        String s3=new String(chs);
        System.out.println("s3\t"+s3);
        //String s="abc":直接赋值的方式创建字符串对象,内容就是abc
        String s4="abc";
        System.out.println("s4\t"+s4);


4>. String对象的特点


①. 字符串常量池 [ 在方法区中 ]:程序当中直接写上的双引号字符串,就在字符串常量池中


②. 通过new创建的字符串对象,每一次new都会申请一个内存空间,虽然内容相同,但是地址值不同


重点掌握


String str1="abc";
        String str2="abc";
        char[]charArray={'a','b','c'};
        String str3=new String(charArray);
        System.out.println(str1==str2);//true
        System.out.println(str1==str3);//fasle
        System.out.println(str2==str3);//fasle


20190625190747142.png


5>. 字符串的比较


1. 使用 == 做比较


基本类型:比较的是数据值是否相同


引用类型:比较的是地址值是否相同


2. equals方法


public boolean equals (Object anObject): 参数可以是任何对象,只有参数是一个字符串并且内容相同才会给true;否则返回false


public boolean equalsIgnoreCase(String str):忽略大小写,进行内容比较


3. 注意事项


①.任何对象都能用Object进行接收


②.equals 方法具有对称性,也就是a.equals(b)和 b.equals(a)效果一样


③.如果比较双方是一个常量一个变量,推荐把常量字符串写在前面


推荐:“abc”.eqauls(str) 不推荐:str.equals(“hello”)


       char[] chs={'a','b','c'};

       String s1=new String(chs);

       String s2=new String(chs);


       String s3="abc";

       String s4="abc";


       //比较字符串对象地址值是否相同

       System.out.println(s1==s2);//false

       System.out.println(s1==s3);//false

       System.out.println(s3==s4);//true

       System.out.println("=======");


       //比较字符串内容是否相同

       System.out.println(s1.equals(s2));//true

       System.out.println(s1.equals(s3));//true

       System.out.println(s1.equals(s4));//true

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

6>. String类的常见面试题


       //1.判断定义为Stirng类型的str1和str1是否相等

        //常量池中没有这个字符串对象,就创建一个,如果有,就直接引用

       String str1="abc";

       String str2="abc";

       System.out.println(str1 == str2);//true

       System.out.println(str1.equals(str2));//true

1

2

3

4

5

6

       //2.下面这句话在内存中创建了几个对象

       //创建了两个对象,一个在堆内存中,一个在常量池中

       String str3=new String("abc");

1

2

3

20190627124516718.png


       //3.判断定义为String类型的str4和str5是否相等

       //str4 中的地址是堆内存中的,而str5的地址是常量池中的

       String str4=new String("abc");

       String str5="abc";

       System.out.println(str4==str5);/false

       System.out.println(str4.equals(str5));//true

1

2

3

4

5

6

      Java语言有常量优化机制

      //4.判断定义为Stirng类型的str6和str7是否相等

      //byte b=3+4   在编译的时候就变成了7,把7赋值给b,常量优化机制

       String str6="a"+"b"+"c"; //这是三个常量字符相加

       String str7="abc";

       System.out.println(str6==str7);//true,java中有常量优化机制

       System.out.println(str6.equals(str7));//true

1

2

3

4

5

6

7

       //5. 判断定义为Stirng类型的str8、str9、str10是否相等

        //str10 的地址值是堆内存的,而str9的地址值是常量池的

       //变量和常量去串连:在StringBuffer[StringBuilder] 通过append()方法把元素添加进去,在通过toString转成String。

所以s3记录的地址值是ox222

       String  str8="ab";

       String  str9="abc";

       String  str10=str8+"c";

       System.out.println(str10==str9);//fasle

       System.out.println(str10.equals(str9)); //true

1

2

3

4

5

6

7

8

920190627125949240.png



7>.字符串的常用方法 [ 掌握 ]


①. str.length():获取字符串长度(包括空格)


②. int indexOf(String s) : 返回s字符串在当前字符串中首次出现的位置。若没有,返回-1,下标从0开始


③. int lastIndexOf(String s):返回s字符串最后一次在当前字符串中出现的位置。若无,返回-1,下标从0开始


注意:如果lastIndexOf()方法参数中是空字符""(没有空格),那么结果和length()结果一样


④. char charAt(int index):获取指定索引位置的字符,下标从0开始


⑤. String subString():截取字符串,空格占用一个索 引位置


str.subString(int begin):从指定的索引位置截取到最后


str.subString(int begin,int end):从索引位置开始,包括前面,不包括后面


⑥. public String replace(charSequence oldString,charSequence newString):将所有出现的老字符串替换成新的字符串,返回替换之后的结果新字符串


charSequence的意思就是说可以接受字符串类型


⑦. 字母大小写转换


String toLowerCase():转小写


String toUpperCase():转大写


⑧. str.trim():去除两端的空格


⑨. String [ ] split(String regex):按照regex将当前字符串拆分,拆分为多个字符串,整体返回值为String [ ]


注意事项:split 方法的参数其实是一个 “正则表达式”; 今天要注意:如果要按照英文句点进行切分,必须写"\\."


⑩. public char[] toCharArray():将当前字符串拆分为字符数组作为返回值


11. public byte[] getBytes():获取当前字符串底层的字节数组


public byte[ ] getBytes(Charset charset):默认是utf-8


20190724111859388.png


12. static String valueOf(char [ ] chs):将字符数组转换成字符串


13. static String valueOf(int i):将int类型的数据转成字符串;


注意:String类的valueOf()方法可以把任意类型的数据转成字符串


       char[]chars="Hello".toCharArray();

       //转换称为字符数组

       for(int i=0;i<chars.length;i++){

       System.out.print(chars[i]+"\t");//H e l l o

       }

       System.out.println("======");

       //转换成字节数组

       byte[]bytes="abc".getBytes();

       for (int i = 0; i < bytes.length; i++) {

           System.out.print(bytes[i]+"\t");

       }

       System.out.println("======");

       //把o换成*号

       String str1="How do you do?";

       String str2=str1.replace("o","*");

       System.out.println("把o换成*号str2: "+str2);


       System.out.println("======");

       //String[]split()

       String str3="aaa,bbb,ccc";

       String[]str4=str3.split(",");

       for(String str5:str4){

           System.out.println(str5);

       }

       System.out.println("======");

       String str6="aaa.bbb.ccc";

       //String[]arrStr=str6.split(".");

       String[]arrStr=str6.split("\\.");

       for (int i = 0; i < arrStr.length; i++) {

           System.out.println(arrStr[i]);

       }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

       //重点掌握

       //1.byte[ ]getBytes():将字符串转换成字节数组

       String s1="abc";

       byte[]ch=s1.getBytes();

       for (int i = 0; i < ch.length; i++) {

           //System.out.print(ch[i]+"\t");

       }

       System.out.println("\n"+"--------");

       String s2="你好你好";

       //通过gbk码表将字符串转换成字节数组-- 编码的过程

       //编码:把我们看的懂的转换成计算机看得懂的

       //gbk中一个中文代表两个字节

       //gbk码表的特点:中文的第一个字节,肯定是负数

       byte[]arr2=s2.getBytes();

       for (int i = 0; i < arr2.length; i++) {

           //System.out.print(arr2[i]+"\t"); //97 98 99

       }

     

       //2.char[ ]toCharArray():把字符串转换成字符数组

       char[]chs=s1.toCharArray();

       for (int i = 0; i < chs.length; i++) {

           //System.out.print(chs[i]+"\t");//a b c

       }

     

       //3.static String valueOf(char[]ch)

       //底层是由String类的构造方法完成的

       char[]ch1={'a','b','c'};

       String str5=String.valueOf(ch1);

       System.out.println("valueOf():"+str5);

       String str6=String.valueOf(100);

       System.out.println("将int 100 变成 字符串100:"+str6);

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

8>. String类的判断功能


1. String类的判断功能


boolean equals(Object obj):比较字符串的内容是否相同,区分大小写


boolean equalsIgnoreCase(String str):比较字符串的内容是否相同,忽略大小写写


boolean contains(String str):判断大字符串中是否包含小字符串


boolean startsWith(String str):判断字符串是否以某个指定的字符串开头


boolean endsWith(String str):判断字符串是否以某个指定的字符结束


boolean isEmpty(): 判断字符串是否为空


2. " " 和 null 的区别 [ 重点 ]


" "是字符串常量,也是一个String类的对象,既然是对象可以调用String类中的方法


null 是空常量,不能调用任何的方法,否则会出现空指针异常,null可以给任意的引用数据类型赋值


    String s1="heima";

    String s2="heima";

    String s3="heiMa";

    System.out.println(s2.equals(s3));//false

    System.out.println(s2.equalsIgnoreCase(s3));//true


   String s4="heimaxiaozhi";

   boolean contains=s4.contains(s2);

   System.out.println("s4中是否包含了s2的内容"+contains);

1

2

3

4

5

6

7

8

9

   //重点知识点

   System.out.println("-----");

   String str1="heima";

   String str2="";

   String str3=null;

   System.out.println(str1.isEmpty());//false

   System.out.println(str2.isEmpty());//true

   System.out.println(str3.isEmpty());//java.lang.NullPointerExceptioon

1

2

3

4

5

6

7

8

9>. String类的其他方法


String replace(char old , char new)


String replace(String old , String new)


String trim():String 类的去除字符串两端的空格 案例


int compareTo(String str):String的按字典顺序比较两个字符串及案例演示


int comareToIgnoreCase(String str)[了解 ]


       String s = "heima";

       String s2 = s.replace('e', 'x');

       System.out.println(s2);//hxima

       String s3 = s.replace('o', 'z');//z 不存在,保留原字符不改变

       System.out.println(s3);//heima


       String s4 = s.replace("ei", "aa");

       System.out.println(s4);//haama


       String s5 = " abc  defg ";

       String s6 = s5.trim();

       System.out.println(s6);//abc  defg


       String s7 = "abc";

       String s8 = "bcd";

       int num = s7.compareTo(s8);

       System.out.println(num); //-3 按照码表值比较


       String s9 = "黑";

       String s10 = "马";


       int num2 = s9.compareTo(s10);

       System.out.println(num2);


       String s11 = "heima";

       String s12 = "HEIMA";

       int num3 = s11.compareToIgnoreCase(s12);

       System.out.println(num3);//0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

10>. 遍历字符串 [ 掌握 ]


需求:键盘录入一个字符串,使用程序实现在控制台遍历该字符串


思路:①.键盘录入一个字符串,用Scanner实现


②.遍历字符串,首先要能够获取到字符串中的每一个字符


public char charAt(int index):返回指定索引出的char值,字符串的索引也是从0开始的


③.遍历字符串,其次要能够获取到字符串长度


public int length():返回字符串的长度


       Scanner sc=new Scanner(System.in);

       System.out.println("请随机输入一个字符串:");

       String str=sc.nextLine();

       for (int i = 0; i <str.length() ; i++) {

           System.out.println(str.charAt(i));

       }

1

2

3

4

5

6

       String str="asdasfsa";

       char[]chs=str.toCharArray();

       for (int i = 0; i < chs.length; i++) {

           System.out.print(chs[i]);

       }

1

2

3

4

5

11>. 字符串练习


①. 统计字符次数

public static void main(String[] args) {

       //键盘输入一个字符串,用Scanner实现

       Scanner sc=new Scanner(System.in);

       System.out.println("请输入一个字符串:");

       String line = sc.nextLine();


       //要统计三中类型的字符个数,需要定义三个统计变量,初始值都是0

       int bigCount=0;

       int smallCount=0;

       int numberCount=0;

       int  otherCount=0;

     

       //遍历字符串,得到每一个字符

       for (int i = 0; i < line.length(); i++) {

           char ch=line.charAt(i);


           //判断该字符属于哪种类型,然后对应类型的统计变量+1

           if(ch>='A' && ch<='Z'){

               bigCount++;

           }else if(ch>='a' && ch<='z'){

               smallCount++;

           }else if(ch>='0'&&ch<='9' ){

               numberCount++;

         }else{

               otherCount++;

           }

       }


       System.out.println("大些字母:"+bigCount+"个");

       System.out.println("小些字母:"+smallCount+"个");

       System.out.println("数字有:"+numberCount+"个");

   }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

②. 字符串反转

public class Demo4 {

   public static void main(String[] args) {


       Scanner sc=new Scanner(System.in);

       System.out.println("请输入一个字符串");

       String str = sc.nextLine();

       String strT=reverse(str);

       System.out.println("反转后的顺序是:"+strT);


   }

   public static String reverse(String s){


       //在方法中把字符串倒着遍历,然后把每一个得到的字符拼接成一个字符串并返回

       String ss="";

       for(int i=s.length()-1;i>=0;i--){

        ss+=s.charAt(i);

       }

       return ss;

   }

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

③. 按照制定的格式拼接字符串

/*

定义一个方法,把数组{1,2,3} 按照制定格式拼接成一个字符串。参考按照如下:[word1#word2#word3]

格式:[word1#word2#word3]

用到:  for 循环、字符串拼接、每个数组元素之前都有一个word字样、分割使用的是#、区分一下是不是最后一个

* */

public class DemoString {

   public static void main(String[] args) {


       int [] arr={1,2,3};

       String strNew=fromArrayToString(arr);

       System.out.println(strNew);


   }

   public static String fromArrayToString(int[]arr){

       String str="[";


        for(int i=0;i<arr.length;i++){


            if(i==arr.length-1){

                str+="word"+arr[i]+"]";

            }else{

                str+="word"+arr[i]+"#";

            }

        }

      return  str;

   }

}


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

   @Test

   public void fun3(){

       /*

       需求: 把数组中的数据按照指定的格式拼接成一个字符串

       如: int[ ] arr={1,2,3};

       输出结果: [1,2,3]

       * */

       int[ ] arr={1,2,3};

       String str="[";


       for (int i = 0; i < arr.length; i++) {

           if(i==arr.length-1){

               str+=arr[i]+"]";

           }else {

               str+=arr[i]+",";

           }

       }


       System.out.println(str);

   }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

④. 将一个字符串的首字母转成大写,其余为小写

       // 链式编程 :只要保证每次调用完方法返回的是对象,就可以继续调用

       // 将一个字符串的首字母转成大写,其余为小写

       // 链式编程 :只要保证每次调用完方法返回的是对象,就可以继续调用

       String str="aFDSFfdsrg";

       String str2=str.substring(0,1).toUpperCase().concat(str.substring(1,str.length()).toLowerCase());

       System.out.println("str2 = " + str2);

1

2

3

4

5

6

⑤. 常见对象(在大串中查找小串出现的次数代码实现)

      //定义大串

       String strMax = "woaiheima,heimabutongyubaodu,heimajiayou";

       //定义小串

       String strMin = "heima";

       //定义计数器变量

       int count = 0;

       //定义索引

       int index = 0;

       //定义循环,判断小串是否在大串中出现

       while ((index = strMax.indexOf(strMin)) != -1) {

           count++; //计算器自增

           strMax = strMax.substring(index + strMin.length());

       }

       System.out.println("小串在大串中出现的次数是" + count);

1

2

3

4

5

6

7

8

9

10

11

12

13

14

⑥. 随机获取4个英文大写字母和一个数字

定义String getStr()方法

 功能描述:

  获取长度为5的随机字符串

  字符串由随机的4个大写英文字母和1个0-9之间(包含0和9)的整数组成

  英文字母和数字的顺序是随机的

1

2

3

4

5

//定义一个随机的数字看是否和循环时候是不是相同

public class StringTe {

   public static void main(String[] args) {

       String str=getStr5();

       System.out.println("str = " + str);

 

   }

   public static String getStr5(){

       //先随机的生成一个0-5之间的数据,如果种子是5,那么实际产生的数据就是0-4

       Random r=new Random();

       int j = r.nextInt(5);//就的数就是0-4中间的某一个

       StringBuilder sb=new StringBuilder();

       for(int i=0;i<5;i++){

           if(i==j){

               sb.append(r.nextInt(10));

           }else {

               //随机的产生大写字母字符

               int bigNum = r.nextInt(26) + 65;

               char ch=(char)bigNum;

               sb.append(ch);

           }

       }

       String s=sb.toString();

       return s;

   }

}


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

public class StringDemoax {

   public static void main(String[] args) {

       String str=getStr5();

       System.out.println("str = " + str);

             

   }


   public static String getStr5() {

       StringBuilder sb=new StringBuilder();

       Random r=new Random();

       int randomNum=r.nextInt(10);

       for(int i=0;i<5;i++){

         

           if(i==randomNum/2){

           sb.append(randomNum);

           }else{

               char ch=(char)(r.nextInt(26)+65);

               sb.append(ch);

           }

       }

     return sb.toString();

   }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

⑦.将第一个大写,其他的小写

已知字符串如下:

 "good good study day day up"

 请定义方法将字符串中每一个单词的首字母大写,其余的小写

    最后打印的结果如下: (各位,千万别 sout("Good Good Study Day Day Up"); 哟)

  "Good Good Study Day Day Up"

1

2

3

4

5

public class StringDemo {

   public static void main(String[] args) {

       String str="good good study day day up";

       String string=getChange(str);

       System.out.println("string = " + string);

   }


   private static String getChange(String str) {

       StringBuilder sb=new StringBuilder();

       //1.将字符串转成数组

       String[] split = str.split(" ");

       //2.遍历数组,将每一个字符

       for (int i = 0; i < split.length; i++) {

           //3.将字符串第一个字母大写,其他的转小写

           String string=split[i].substring(0,1).toUpperCase().concat(split[i].substring(1).toLowerCase());

           //4.创建StringBulider对象,把新的字符串添加进去

           sb.append(string).append(" ");

       }

       //5.最后会有一个空格,最后把空格去掉

       return sb.toString().trim();

   }

}


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

   public static String change2(String str) {

           StringBuilder sb=new StringBuilder();

           String str2=" ";

           int index=0;

           while((index=str.indexOf(str2))!=-1){

               String strN=str.substring(0,index);

               sb.append(strN.substring(0,1).toUpperCase().concat(strN.substring(1).toLowerCase())).append(" ");

               str=str.substring(index+1);

               if(!str.contains(str2)){

                   sb.append(str.substring(0,1).toUpperCase().concat(str.substring(1).toLowerCase()));

               }

           }


           return sb.toString();

       }

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

2. StirngBuffer


1>. StringBuffer的概述


java.lang.StringBuffer代表可变的字符序列,线程安全可变的字符序列 [ 线程安全,所以效率低 ]


很多方法与String相同,但StingBuffer是可变长度的。


StringBuffer是一个容器。


2>. StringBuffer的构造方法


public StringBuffer():无惨构造方法


public StringBuffer(String str):指定字符串内容的字符串缓冲区对象


public StringBuffer(int capacity):指定容量的字符缓冲区对象


public int capacity():返回当前容量 [ 理论值 ]


public int length( ):返回长度(字符数) [ 实际值 ]


       StringBuffer sb = new StringBuffer();

       System.out.println(sb.length());//0

       System.out.println(sb.capacity());//容器初始容量,理论值 16


       StringBuffer sb2 = new StringBuffer("xiaozhi");

       System.out.println(sb2.length());//7

       System.out.println(sb2.capacity());//16+7=23

1

2

3

4

5

6

7

3>. StringBuffer 的添加功能


public StringBuffer append(String str):可以把任意类型数据添加到字符串缓冲区里面,并返回字符串缓冲区本身


public StringBuffer insert(int offset,String str):在指定位置把任意类型的数据插入到字符串缓冲区里面,并返回字符串缓冲区本身


StirngBuffer 是将字符串缓冲区,当new 的时候是在堆内存创建了一个对象, 底层是一个长度为16的字符数组,当调用添加方法时,不会再创建对象,在不断向原缓冲区添加字符


       StringBuffer str=new StringBuffer("xiaozhi");

       StringBuffer str2=str.append("6");

       System.out.println(str2);//xiaozhi6

       StringBuffer str3=str.insert(0,false);

       System.out.println(str3);//falsexiaozhi6

1

2

3

4

5

4>. StringBuffer的删除功能 [ 了解 ]


public StringBuffer deleteCharAt(int index) : 删除指定位置的字符,并返回本身


public StringBuffer delete(int start,int end):删除从指定位置开始指定位置结束的内容,并返回本身[ )


       StringBuffer sb=new StringBuffer("xiaozhi");

       //删除a这个元素

       sb.deleteCharAt(2);

       System.out.println(sb);//xiozhi

       //删除o这个字符

       sb.delete(2,3);

       System.out.println(sb);//xizhi

       //清空缓冲区

       sb.delete(0,sb.length());

       System.out.println("清空缓冲区"+sb);

1

2

3

4

5

6

7

8

9

10

5>. StringBuffer的替换和反转功能


public StringBuffer replace(int start,int end,String str):从start开始到end用str替换


public StringBuffer reverse():反转


       StringBuffer sb=new StringBuffer("heima");

       sb.replace(0,3,"ttt");

       System.out.println(sb);//tttma


       sb.reverse();

       System.out.println("反转后的顺序是:"+sb);//amttt

1

2

3

4

5

6

6>. StringBuffer 的截取功能


public String subString(int start):从指定位置截取到末尾


public String subString(int start,int end):截取从指定位置开始到结束位置,包括开始位置,不包括结束位置


注意事项:返回值类型不再是StringBuffer,要拿String去接收


      StringBuffer sb=new StringBuffer("xiaozhi");

       //截取zhi

       String str1=sb.substring(4);

       System.out.println("str1 = " + str1);

       //截取xiao

       String str2=sb.substring(0,4);

       System.out.println("str2 = " + str2);

1

2

3

4

5

6

7

7>. StringBuffer 和 String相互转换 [ 掌握 ]


1. String — StringBuffer


①. 通过带参构造方法


②. 通过无参构造方法 和 通过append()方法


      //通过构造方法将字符串转换成StringBuffer对象

       StringBuffer sb=new StringBuffer("heima");

       System.out.println(sb);//这是一个StringBuffer对象了

       StringBuffer sb2=new StringBuffer();

       sb2.append("heima");

       System.out.println(sb2);

1

2

3

4

5

6

2. StringBuffer – String


①. 通过构造方法


②. 通过toString()方法


③. 通过subString(0,length)


       String s1=new String(sb2);

       String s3=sb2.toString();

       String s4=sb2.substring(0,sb2.length());

1

2

3

3. StringBuilder


1>.StringBuilder的概述


StringBuilder 是一个可变的字符串类,我们可以把它看成一个容器


String和 StringBuilder的区别


String:内容是不可变的


StringBuilder:内容是可变的


2>. StringBuilder的构造方法


public StringBuilder():创建一个空白可变字符串对象,不含有任何内容


public StringBuilder(String str):根据字符串的内容,来创建可变字符串对象


3>. StringBuilder的添加和反转方法


public StringBuilder append(任意类型):添加数据,并返回对象本身


public StringBuilder reverse():返回相反的字符序列


4>. StringBuilder 和String 相互转换


①. StringBuilder 转换为String


public String toString():通过toString()就可以实现把StringBuilder转换为String


②. String 转换为 StringBuilder


public StringBuilder(String s):通过构造方法就可以现在把String 转换为StringBuilder


       //StringBuffer-->string

       StringBuilder sbf=new StringBuilder();

       sbf.append("hello");

       String str = sbf.toString();

       System.out.println(str);


       //String-->StringBuffer

       String  str1="helloStr";

       StringBuilder sb=new StringBuilder(str1);

       System.out.println(sb);

1

2

3

4

5

6

7

8

9

10

public class Demo4 {

   public static void main(String[] args) {

       //定义一个int类型的数组,用静态初始化完成数组元素的初始化

       int[]arr=new int[]{1,2,3};

       String strT=arrayToString(arr);

       System.out.println("输出的结果是:"+strT);

   }

   public static String arrayToString(int[]arr){

       //在方法中用StringBuilder 按照要求进行拼接,并把结果转成String返回

       StringBuilder sb=new StringBuilder();


       sb.append("[");


       for (int i = 0; i <arr.length ; i++) {


           if(i==arr.length-1){

           sb.append(arr[i]);

           }else{

           sb.append(arr[i]).append(",");

           }


       }

       sb.append("]");

       String s=sb.toString();

       return s;

   }

}


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

4. StirngBuffer 、StringBuilder 和 String


StirngBuffer 和 StringBuilder 是一样的

1. StringBuffer 和 StringBuilder 的区别


StirngBuffer 是jdk1.0版本的,是线程安全的,效率低


StringBuilder 是jdk1.5 版本的,是线程不安全的,效率高


2. StirngBuffer 、StringBuilder 和 String 的区别


String是一个可变的字符序列


StirngBuffer 、StringBuilder 是可变的字符序列


5. StringBuilder的扩容 [ 掌握 ]


20190729224911650.png


①.第一种方式:空惨构造

public class Capacity1 {

   public static void main(String[] args) {

       System.out.println("-----------第一种-----------");

       //可变的字符序列

       //StringBuilder() 构造一个不带任何字符的字符串生成器,其初始容量为 16 个字符。

       StringBuilder sb = new StringBuilder();

       // int length() 返回长度(字符数)

       System.out.println("实际存储字符的个数:"+sb.length());    //0


       // int capacity() 返回当前容量。

       System.out.println("容量"+sb.capacity());  //16

       System.out.println("----------添加数据-----------");


       sb.append("aaaaaaaaaaaaaaa");  //字符串的长度是15

       System.out.println("实际存储字符的个数:"+sb.length());    //15

       System.out.println("容量"+sb.capacity());  //16


       sb.append("a");

       System.out.println("----------当SB的长度为15的时候,又添加了一个字符----------");

       System.out.println("实际存储字符的个数:"+sb.length());    //16

       System.out.println("容量"+sb.capacity());  //16


       sb.append("a");

       System.out.println("----------当SB的长度为16的时候,又添加了一个字符----------");

       System.out.println("实际存储字符的个数:"+sb.length());    //17

       System.out.println("容量"+sb.capacity());  //34  ? 几倍


       //int newCapacity = (value.length << 1) + 2;  // 原来容器数据的长度 * 2 + 2

       //value.length << 1  相当于 16 * 2

   }

}


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

20190729224005699.png



②. StringBuilder(int capacity):在创建sb的时候直接指定容量,一般很少用

       System.out.println("-----------第二种--------------");

       //StringBuilder(int capacity)

       //在创建SB的时候直接指定容量,一般很少用

       StringBuilder sb1 = new StringBuilder(30);

       System.out.println("容量"+sb1.capacity());    //30

       System.out.println("长度"+sb1.length());      //0

1

2

3

4

5

620190729224204674.png



③. 在构造方法中添加字符串

       System.out.println("-----------第三种--------------");

       StringBuilder sb2 = new StringBuilder("str");

       /*

           扩容的源码:super(str.length() + 16);

           根据构造方法中添加元素的长度+ 默认的容量  == 19

        */

       System.out.println("容量"+sb2.capacity());    //19

       System.out.println("长度"+sb2.length());      //3

1

2

3

4

5

6

7

820190729224703229.png20190729224502910.png




异常

1>. 异常的概述和分类


20190716162839261.png

20190716162853714.png



2>. Jvm默认是如何处理异常的


①. Jvm有一个默认的异常处理机制,就将该异常进行处理。并将该异常的名称,异常的信息,异常出现的位置打印在了控制台上


②. 同时将程序停止运行


//看异常从后往前看,先看这里的 java:6  再看 java:14

public class JvmException {

   public static void main(String[] args) {

       DemoJvm d=new DemoJvm();

       int x=d.div(1,0);

       System.out.println(x);//ArithmeticException: / by zero

   }

}

class DemoJvm{

   public int div(int a,int b){//a=10 b=0

       // 10/0 被除数是10,除数是0当除数是0的时候违背了算数运算法则,抛出异常

       // new ArithmeticExcpetion("/ by zero")

       return a/b;

   }

}

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15



3>. try–catch的方式处理异常


try:用来检测异常的;catch:用来捕获异常的;finally:用来释放资源的

异常处理的两种方式

try.....catch.....finally

1.try.....catche

2.try.....catche.....finally

3.try.....finally

throws

1

2

3

4

5

6

7

世界上最真情的相依就是你在try 我在catch,无论你发神马脾气,我都静静接受,默默处理


①.当通过trycatch将问题处理了,程序会继续执行


20190708103450459.png


②. try后面如果跟多个catch,那么小的异常放前面,大的异常放后面,根据多肽的原理,如果大的放前面,就会将所有的子类对象接受,后面的catch就没有意义了


20190708110154334.png

4>. 编译期异常和运行期异常的区别


所有的RuntimeException类及其子类的实例被称为运行时异常,其他的异常就是编译时异常


编译时异常:Java程序必须显示处理,否则程序就会发生错误,无法通过编译


运行时异常:无需显示处理,也可以和编译时异常一样处理


20190708115857227.png


5. Throwable的集中常见方法


String getMessage():获取异常信息,返回字符串


String toString():获取异常类和异常信息,返回字符串


void printStackTrace():获取异常类名和异常信息,以及异常出现在程序中的位置,返回值为void [ Jvm 默认这种方式 ]


   try{

       System.out.println(1/0);

   }catch (Exception e){

       //Exception e =new ArithmeticException("/ by zero");

       System.out.println(e.getMessage());//获取异常信息 / by zero

       //toString():打印异常类名和异常信息

       System.out.println(e.toString());//java.lang.ArithmeticException: / by zero

       System.out.println(e);//java.lang.ArithmeticException: / by zero

       //printStackTrance():JVM 默认这样方式处理

       e.printStackTrace();

       //at day08.ExcepetionDemo.main(ExcepetionDemo.java:8)

       //java.lang.ArithmeticException: / by zero

   }

1

2

3

4

5

6

7

8

9

10

11

12

13

6>. throws的方式处理异常


①. 编译时异常的抛出,必须对其进行处理


②. 运行时异常的抛出,可以处理也可以不处理


20190716170858126.png20190716171741248.png



throw:在功能方法内部出现某种情况,程序不能继续运行,需要进行跳转时,就用throw把异常对象抛出

//掌握

throws:

1. 用在方法声明后面,跟的是异常类名

2. 可以跟多个异常类名,用逗号隔开

3. 表示抛出异常,由该方法的调用者来处理

throw:

1. 用在方法体内,跟的是异常对象名

2. 只能抛出一个异常类对象名

3. 表示抛出异常,由方法体内的语句处理

  Exception e=new Exception("年龄非法");

  throw e;

1

2

3

4

5

6

7

8

9

10

11

7>. finally


1. finally的特点


被finally控制的语句体一定会执行


特殊情况:在执行到finally之前jvm退出了(比如:System.exit(0))


//return语句相当于是方法的最后一口气,那么在它将死之前会看一

//看有没有finally帮其完成遗愿。如果有就将finally执行后切底返回

try{

        System.out.println(10/0);

    }catch (Exception e){

        System.out.println("除数为0了");

        return;

    }finally {

        System.out.println("一定会执行的");

    }

1

2

3

4

5

6

7

8

9

10

2. 面试题 [ 掌握 ]


1.final,finally和finalize的区别


final:

final可以修饰类,不能为继承

final修饰方法,不能被重写

final修饰变量,只能赋值一次


finally:

finally是try语句中的一个语句体,不能单独使用,用来释放资源


finalize:

是一个方法,当垃圾回收器确定不存在对该对象的更多引用时,

由对象的垃圾回收器调用次方法


2.如果catch里面有return语句,请问finally的代码还会执行吗?如果会,请问在return前还是retrun后

会执行,在return前执行

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

1620190709163106252.png20190709163413428.png



8>. 自定义异常概述和基本使用


1. 异常的注意事项


①. 子类重写父类方法时,要求子类抛出的异常要小于父类抛出的异常


②. 如果被重写的方法没有异常抛出,那么子类的方法绝对不可以抛出异常,如果子类方法内部有异常发生,那么子类只能try,不能throws


2. 如何使用异常处理


原则:如果该功能类部可以将问题处理,用try,如果处理不了,交由调用者处理,这里用throws


20190716224226165.png

//Exception是编译时异常

//RuntimeException时运行时异常

public class ScoreException extends Exception/*RuntimeException*/ {

    public ScoreException(){

    }

    public ScoreException(String message){

        super(message);

    }

}

1

2

3

4

5

6

7

8

9

public class Teacher {


   public void checkScore(int score)throws ScoreException{

       if(score<0||score>100){

           //throw new ScoreException();

           throw new ScoreException("你输入的数字有误");

       }else{

           System.out.println("正确");

       }

   }

}

1

2

3

4

5

6

7

8

9

10

11

public class Demo {

   public static void main(String[] args) {

       Scanner sc=new Scanner(System.in);

       System.out.println("请输入你的成绩:");

       int score=sc.nextInt();

      Teacher t=new Teacher();

       try {

           t.checkScore(score);

       } catch (ScoreException e) {

           e.printStackTrace();

       }

   }

}

20190716225409205.png20190716225814410.png

相关文章
|
安全 Java
Java_Foundation(三)
Java_Foundation(三)
151 0
Java_Foundation(三)
|
存储 算法 Java
Java_Foundation(二)
Java_Foundation(二)
171 0
Java_Foundation(二)
|
存储 SQL 移动开发
Java_Foundation(一)
Java_Foundation(一)
318 0
Java_Foundation(一)
|
3天前
|
安全 Java API
java如何请求接口然后终止某个线程
通过本文的介绍,您应该能够理解如何在Java中请求接口并根据返回结果终止某个线程。合理使用标志位或 `interrupt`方法可以确保线程的安全终止,而处理好网络请求中的各种异常情况,可以提高程序的稳定性和可靠性。
26 6
|
18天前
|
设计模式 Java 开发者
Java多线程编程的陷阱与解决方案####
本文深入探讨了Java多线程编程中常见的问题及其解决策略。通过分析竞态条件、死锁、活锁等典型场景,并结合代码示例和实用技巧,帮助开发者有效避免这些陷阱,提升并发程序的稳定性和性能。 ####
|
16天前
|
存储 监控 小程序
Java中的线程池优化实践####
本文深入探讨了Java中线程池的工作原理,分析了常见的线程池类型及其适用场景,并通过实际案例展示了如何根据应用需求进行线程池的优化配置。文章首先介绍了线程池的基本概念和核心参数,随后详细阐述了几种常见的线程池实现(如FixedThreadPool、CachedThreadPool、ScheduledThreadPool等)的特点及使用场景。接着,通过一个电商系统订单处理的实际案例,分析了线程池参数设置不当导致的性能问题,并提出了相应的优化策略。最终,总结了线程池优化的最佳实践,旨在帮助开发者更好地利用Java线程池提升应用性能和稳定性。 ####
|
18天前
|
缓存 Java 开发者
Java多线程编程的陷阱与最佳实践####
本文深入探讨了Java多线程编程中常见的陷阱,如竞态条件、死锁和内存一致性错误,并提供了实用的避免策略。通过分析典型错误案例,本文旨在帮助开发者更好地理解和掌握多线程环境下的编程技巧,从而提升并发程序的稳定性和性能。 ####
|
11天前
|
安全 算法 Java
Java多线程编程中的陷阱与最佳实践####
本文探讨了Java多线程编程中常见的陷阱,并介绍了如何通过最佳实践来避免这些问题。我们将从基础概念入手,逐步深入到具体的代码示例,帮助开发者更好地理解和应用多线程技术。无论是初学者还是有经验的开发者,都能从中获得有价值的见解和建议。 ####
|
11天前
|
Java 调度
Java中的多线程编程与并发控制
本文深入探讨了Java编程语言中多线程编程的基础知识和并发控制机制。文章首先介绍了多线程的基本概念,包括线程的定义、生命周期以及在Java中创建和管理线程的方法。接着,详细讲解了Java提供的同步机制,如synchronized关键字、wait()和notify()方法等,以及如何通过这些机制实现线程间的协调与通信。最后,本文还讨论了一些常见的并发问题,例如死锁、竞态条件等,并提供了相应的解决策略。
33 3
|
12天前
|
监控 Java 开发者
深入理解Java中的线程池实现原理及其性能优化####
本文旨在揭示Java中线程池的核心工作机制,通过剖析其背后的设计思想与实现细节,为读者提供一份详尽的线程池性能优化指南。不同于传统的技术教程,本文将采用一种互动式探索的方式,带领大家从理论到实践,逐步揭开线程池高效管理线程资源的奥秘。无论你是Java并发编程的初学者,还是寻求性能调优技巧的资深开发者,都能在本文中找到有价值的内容。 ####