java进阶

JAVASE进阶

[toc]

1.内部类

1.成员内部类

  1. 如何创建内部类的对象

    public class Start {
        public static void main(String[] args) {
            outerClass out = new outerClass();  // 外部类创建对象
            outerClass.inner inner = new outerClass().new inner(); //内部类创建对象
            inner.test();
        }
    }
    
  2. 内部类可以方便的直接访问外部类的私有属性

  3. 外部类不能直接访问内部类的私有属性, 可以通过创建对象的方式访问

  4. 外部类和内部类有相同名称属性时, 如果想要使用外部类的属性, 则需要加 外部类.this

    System.out.println(outerClass.this.age);
    

2.匿名内部类

  • 一般是只是用一次的类

3.静态内部类

  1. 使用static关键字修饰的内部类叫做静态内部类

  2. 访问静态内部类的方法和属性

    public static void main(String[] args) {
        // 因为静态的属于类,不属于对象,所以后面不需要创建对象
        jintai jin = new outerClass.jintai(); //把outerClass.jintai()看做一个整体
        jin.test();
    }
    

4.方法内部类

  1. 定义

    将内部类定义在外部类的方法中

  2. 方法内部类只能在方法中创建对象, 因为方法内部类的作用域在当前方法, 且不能使用static修饰符

2.异常处理

1.try/catch/finally

  1. java中的异常处理

    try, catch, finally, throw, throws关键字

    异常关键字.png
  1. 异常输出

    • e.printStackTrace(); 打印异常的堆栈信息
  2. 多重catch异常捕获, 根据不同的异常使用不同的异常捕获类

    package yc;
    
    import java.util.InputMismatchException;
    
    public class testException {
        public static void main(String[] args) {
            try{
                System.out.println(1/0);
            }catch (ArithmeticException e){
                System.out.println("除数不能为0");
            }catch (InputMismatchException e){
                System.out.println("输入的参数数类型不匹配");
            }
        }
    }
    
    
  3. 常用异常类

    常用异常类.png
  1. finally

    ==finally是总是要执行的, 即使是try中有return语句, 也是有限执行finally中的语句==

     public class TryTest{
         public static void main(String[] args){
             System.out.println(test());
         }
     
         private static int test(){
             int num = 10;
             try{
                 System.out.println("try");
                 return num += 80;
             }catch(Exception e){
                 System.out.println("error");
             }finally{
                 if (num > 20){
                     System.out.println("num>20 : " + num);
                 }
                 System.out.println("finally");
                 num = 100;
                 return num;
             }
         }
     }
    // 结果是100
    
  2. ==finally总结==

    try语句在返回前,将其他所有的操作执行完,保留好要返回的值,而后转入执行finally中的语句,而后分为以下三种情况:

    情况一:如果finally中有return语句,则会将try中的return语句”覆盖“掉,直接执行finally中的return语句,得到返回值,这样便无法得到try之前保留好的返回值。

    情况二:如果finally中没有return语句,也没有改变要返回值,则执行完finally中的语句后,会接着执行try中的return语句,返回之前保留的值。

    情况三:如果finally中没有return语句,但是改变了要返回的值,这里有点类似与引用传递和值传递的区别,分以下两种情况,:

    ​ 1)如果return的数据是基本数据类型或文本字符串,则在finally中对该基本数据的改变不起作用,try中的return语句依然会返回进入finally块之前保留的值。

    ​ 2)如果return的数据是引用数据类型,而在finally中对该引用数据类型的属性值的改变起作用,try中的return语句返回的就是在finally中改变后的该属性的值。

2.throws/throw

  1. 声明异常

    * 在异常情况出现的时候,可以使用try...catch...finally的方式对异常进行处理,除此之外,可以将异常向外跑出,由外部的进行处理
    *   1、在方法调用过程中,可以存在N多个方法之间的调用,此时假如每个方法中都包含了异常情况
    *       那么就需要在每个方法中都进行try。。catch,另外一种比较简单的方式,就是在方法的最外层调用处理一次即可
    *       使用throws的方法,对所有执行过程中的所有方法出现的异常进行统一集中处理
    *   2、如何判断是使用throws还是使用try...catch..
    *       最稳妥的方式是在每个方法中都进行异常的处理
    *       偷懒的方式是判断在整个调用的过程中,外层的调用方法是否有对异常的处理,如果有,直接使用throws,如果没有
    *           那么就要使用try...catch...
    
    throws.png
package com.mashibing;

import java.io.File;
import java.io.FileInputStream;

/**
 * @author: 马士兵教育
 * @create: 2019-09-07 15:28
 */
/*
throws:声明异常
* 在异常情况出现的时候,可以使用try...catch...finally的方式对异常进行处理,除此之外,可以将异常向外跑出,由外部的进行处理
*   1、在方法调用过程中,可以存在N多个方法之间的调用,此时假如每个方法中都包含了异常情况
*       那么就需要在每个方法中都进行try。。catch,另外一种比较简单的方式,就是在方法的最外层调用处理一次即可
*       使用throws的方法,对所有执行过程中的所有方法出现的异常进行统一集中处理
*   2、如何判断是使用throws还是使用try...catch..
*       最稳妥的方式是在每个方法中都进行异常的处理
*       偷懒的方式是判断在整个调用的过程中,外层的调用方法是否有对异常的处理,如果有,直接使用throws,如果没有
*           那么就要使用try...catch...
* throw:抛出异常
*
* */
public class Excepton2 {
    public static void main(String[] args) {
        try {
            show();
        } catch (GenderException e) {
            e.printStackTrace();
        }

//        new FileInputStream(new File(""));
        System.out.println("hehe");
    }

    public static void show() throws GenderException{
        String gender = "1234";
        if (gender.equals("man")){
            System.out.println("man");
        }else if(gender.equals("woman")){
            System.out.println("woman");
        }else{
//            throw new Exception("性别出现错误");
            throw new GenderException("gender is wrong");
        }
    }


    public static void test1() throws Exception{
        System.out.println(1/0);
    }
    public static void test2() throws Exception {
        test1();
        System.out.println(100/0);
    }
    public static void test3() throws Exception{
        test2();
    }
    public static void test4() throws Exception{
        test3();
    }
}

  1. 抛出异常

    throw.png

throw要和throws结合使用, 类似于python中的raise

  1. 自定义异常类

    package com.mashibing;
    
    /**
     * @author: 马士兵教育
     * @create: 2019-09-07 15:44
     */
    /*
    * 自定义异常:
    *       在java的api中提供了非常丰富的异常类,但是在某些情况下不太满足我们的需求,此时需要自定义异常
    *       步骤:
    *           1、继承Exception类
    *           2、自定义实现构造方法
    *           3、需要使用的时候,使用throw new 自定义异常的名称;
    *       什么时候需要自定义异常?
    *           一般情况下不需要
    *           但是在公司要求明确,或者要求异常格式规范统一的时候是必须要自己实现的
    *
    * */
    public class GenderException extends Exception {
    
        public GenderException(){
            System.out.println("性别异常");
        }
    
        public GenderException(String msg){
            System.out.println(msg);
        }
    }
    
  2. 异常的继承关系

    异常的分类2.png

3.常用类

1.基本类型的包装类

  1. 定义

    包装类是将基本类型封装到一个类中, 包含属性和方法, 方便对象操作, 包装类位于java.lang中

    包装类1.png
  1. 包装类和基本类型的装换

    包装类转换.png
  1. 装箱和拆箱

    装箱是调用了valueOf方法, 拆箱是调用了intValue方法

    装箱和拆箱.png
  1. ==面试题1==

    package com.comment;
    
    public class integer {
        public static void main(String[] args) {
            Integer a = 100;
            Integer b = 100;
            Integer c = 200;
            Integer d = 200;
            System.out.println(a == b);  //true
            System.out.println(c == d);  //false
            /*
            说明:
            int类型转为Integer类型的时候是调用了Integer中的valueOf方法,100符合>=-128且<=127这个条件,所以返回的是Integer.cache中的100,是个值
            而200不在条件范围内, 所以返回的是一个对象, 对象的地址不一样,所以是false
            valueOf源码:
                public static Integer valueOf(int i) {
                    if (i >= IntegerCache.low && i <= IntegerCache.high)   low=-128,high=127
                return IntegerCache.cache[i + (-IntegerCache.low)];        IntegerCache.cache是一个Integer类型的数组, 里面是-128到127总共256个数
            return new Integer(i);
        }
             */
        }
    }
    
    
  2. ==面试题2==

    package com.comment;
    
    public class integer {
        public static void main(String[] args) {
            Double a = 1.0;
            Double b = 1.0;
            Double c = 2.0;
            Double d = 2.0;
    
            System.out.println(a == b);  //false
            System.out.println(c == d);  //false
            /*
            说明:
                赋值的时候实际上是调用了Double.valueOf这个方法, 而这个方法返回的是个Double对象, 所以不相等
            Double源码:
                public static Double valueOf(double d) {
                    return new Double(d);
                }
             */
        }
    
    }
    
    
  3. ==常量池1.7之后放在堆里面==

2.字符串相关类

  1. String的创建方式

    • String s = "hello world"
    • String s = new String("hello world")
  2. 字符串的本质

    查看源码得知, 字符串的本质是字符数组或字符序列

    String类使用final修饰,不可以被继承
    使用equals方法比较的是字符数组的每一个位置的值
    ==String是一个不可变对象, 指的是字符数组的引用不可变, 里面的值可以变==

  3. String.equals()方法:

    比较两个字符串的值是否相等, 比较方法:

    1. 先比较传入的对象是否相等, 相等的话直接返回true

      if (this == anObject) {
          return true;
      }
      
    2. 如果对象不相等的话, 再比较两个字符串的每一位, 如果都相等则返回true, 否则返回false

    3. equals和==的区别

      ==equals判断字符串值相等,双等号判断字符串对象引用相等==

  4. String.hashCode()方法:

    计算字符串的哈希值

    原理:遍历出字符串的每个字符, 再和 31*h相加, 因为字符和数字相加就是字符的编码值和数字相加, 所以结果是int类型的值

    h的默认值为0, 第一次计算后h的值就是第一个字符的编码

    31是2的5次方

    此方法的哈希值不是一个等长的数

    for (int i = 0; i < value.length; i++) {
        h = 31 * h + val[i];
    }
    hash = h;
    
  5. String.inern()方法

    当字符串调用此方法后, 如果调用这个方法的字符串在常量池里有, 则返回常量池里的地址

    示例:

    String a = "hello";
    String b = new String("hello");
    a.intern();
    此时 a等于b
    
  6. StringBuffer类和StringBuilder类

    StringBuffer是String的增强版,字符串缓冲区,是一个容器,可变字符串

    创建对象:

    ​ StringBuffer sb = new StringBuffer();
    ​ StringBuffer sb = new StringBuffer("aaa");

    ​ sb.append('hello').append('world') # 追加元素

    ​ StringBuffer会将所有的元素拼接成字符串, 数据类型可以是任意

    两个方法:

    System.out.println(sb.length());     //对象的长度
    System.out.println(sb.capacity());   //对象的容量, 最小16
    

    StringBuilder和StringBuffer基本一样, 不同的是线程不安全

  7. 其他常用方法

    char charAt(int index) 返回字符串中第index个字符

    boolean equalsIgnoreCase(String other) 如果字符串与other相等(忽略大小写),则返回true

    String replace(char oldChar,char newChar) 字符串替换

    int indexOf(String str) 返回指定字符的索引

    lastIndexOf(chr) 返回一个字符在字符串中的最后一个位置

    boolean startsWith(String prefix) 如果字符串以prefix开始,则返回true

    boolean endsWith(String prefix) 如果字符串以prefix结尾,则返回true

    String substring(int beginIndex) 切片

    String substring(int beginIndex,int endIndex) 切片

    String toLowerCase() 返回一个新字符串,该串将原始字符串中的所有大写字母改成小写字母

    String toUpperCase() 返回一个新字符串,该串将原始字符串中的所有小写字母改成大写字母

    String trim() 返回一个新字符串,该串删除了原始字符串头部和尾部的空格

    String concat() 拼接字符串

  8. 字符串选用

    String:不可变字符序列
    StringBuilder:可变字符序列、效率高、线程不安全
    StringBuffer:可变字符序列、效率低、线程安全
    String使用陷阱:
    – string s="a"; //创建了一个字符串
    s=s+"b"; //实际上原来的"a"字符串对象已经丢弃了,现在又产生了一个字符串
    s+"b"。如果多次执行这些改变串内容的操作,会导致大量副本字符串对象存留在内
    存中,降低效率。如果这样的操作放到循环中,会极大影响程序的性能

  9. ==面试题==

    public class integer {
        public static void main(String[] args) {
            String a = "abc";
            String b = "def";
            String c = "abcdef";
            String d = a + b;
            String e = "abc" + "def";
            String f = (a + b).intern();
            System.out.println(c == d);  //false
            System.out.println(c == e);   //true
            System.out.println(c == f);   //true
            
            //因为变量指向的是地址, 
        }
    
    }
    

3.时间处理相关类

  1. 日期相关类关系图

    日期相关类.png
  1. 常用的日期类

    • Date()

      Date date = new Date()

      System.out.println(date) //打印时间 Fri Jan 01 20:10:20 CST 2021

      System.out.println(date.getTime()) //打印毫秒

    • SimpleDateFormat

      SimpleDateFormat 是 DateFormat的子类

      格式化时间:

      package yc;
      
              import java.text.DateFormat;
              import java.text.ParseException;
              import java.text.SimpleDateFormat;
              import java.util.Date;
      
      public class StringBufferDemo {
          public static void main(String[] args) throws ParseException {
              Date date = new Date();
              DateFormat dateformate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
              //将日期转换为字符串
              String str = dateformate.format(date);
              System.out.println(str); // 2021-01-01 20:25:21
              //将字符串转换为日期
              Date d = dateformate.parse("2020-10-10 17:22:11");
              System.out.println(d);  // Sat Oct 10 17:22:11 CST 2020
          }
      }
      
      
    • Calendar

      用于设置和获取日期/时间数据的特定部分

      package yc;
      
              import java.text.DateFormat;
              import java.text.ParseException;
              import java.text.SimpleDateFormat;
              import java.util.Calendar;
              import java.util.Date;
      
      public class StringBufferDemo {
          public static void main(String[] args) throws ParseException {
              //Calendar类的使用, 默认获取当前系统时间
              Calendar c = Calendar.getInstance();  //由于Calendar是抽象类, 所以需要访问getInstance方法来创建对象
              System.out.println(c); //java.util.GregorianCalendar[time=1609505728575,areFieldsSet=true,ar ... ...
              System.out.println(c.get(Calendar.YEAR)); //2021
          }
      }
      
      

4.Math类

  1. 说明

    Math类包含了常见的数学运算函数

  2. random

    random()生成[0,1)之间的随机浮点数, 返回的是一个double类型

    生成 0-10 之间的随机数

    int a = (int)(10*Math.random());
    

    生产20-30之间的随机数

    int b = 20 + (int)(10*Math.random());
    
    System.out.println(Math.ceil(3.14));  //向上取整  4.0
    System.out.println(Math.floor(3.14));  // 向下取整 3.0
    System.out.println(Math.pow(2,8));       // 幂运算 256.0
    

5.枚举类

  1. 说明

    1. 枚举指由一组固定的常量组成的类型

    2. 只能够取特定值中的一个

    3. 使用enum关键字

    4. 所有的枚举类型隐性地继承自 java.lang.Enum。(枚举实质上还是类!
      而每个被枚举的成员实质就是一个枚举类型的实例,他们默认都是publi
      c static final的。可以直接通过枚举类型名直接使用它们。)

    5. 强烈建议当你需要定义一组常量时,使用枚举类型

    6. 表枚举类时, 永远不要用equals, 要使用"=="

  2. 创建枚举类

    简单用法:

    package yc;
    
    public enum Gender {
        男,女
    }
    
    
    package yc;
    
    public class Test {
        Gender gen1 = Gender.女;
        Gender gen2 = Gender.男;
    
        public static void main(String[] args) {
            System.out.println(Gender.女);
        }
    }
    
    

    用法2

    package yc;
    
    public enum Gender {
        NAME("hanqieng"), AGE("30");
        String name;
    
        Gender (String name){
            this.name = name;
        }
        public void show(){
            System.out.println(this.name);
        }
    }
    
    
    package yc;
    
    public class Test {
        public static void main(String[] args) {
            Gender g = Gender.NAME;
            Gender g2 = Gender.AGE;
            System.out.println(g.name()); //NAME
            System.out.println(g);         //NAME
            System.out.println(g.name);    //hanqifeng
            System.out.println(g2.name);  //30
            System.out.println(g2.name()); //AGE
        }
    }
    
    

4.JAVA集合框架

1.章节概述

  1. 章节类容

    ▪ 容器的概念
    ▪ 容器 API
    ▪ Collection 接口
    ▪ Iterator 接口
    ▪ Iterable接口
    ▪ Set 接口
    ▪ Comparable 接口
    ▪ List 接口
    ▪ Map 接口

  2. java集合框架包含内容

    java集合框架.png

▪ List 接口存储一组丌唯一,有序(插入顺序)的对象
▪ Set 接口存储一组唯一,无序的对象
▪ Map接口存储一组键值对象,提供key到value的映射

2.List接口

  1. List结构包含但不限于ArryList, LinkedList 实现类

  2. ArryList和LinkedList的特点

    ▪ ==ArrayList实现了长度可变的数组,在内存中分配连续的空间==。

    初始化的时候长度为0, 每次扩容为当前长度的1.5倍

    – 优点:遍历元素和随机访问元素的效率比较高
    – 缺点:添加和删除需要大量移动元素效率低,按照内容查询效
    率低

    ▪ ==LinkedList采用链表存储方式==。
    – 优点:插入、删除元素时效率比较高
    – 缺点:遍历和随机访问元素效率低下

  3. List接口的特有方法

    List独有方法.png
  1. Collection-ArryList代码示例

    package com.mashibing;
    
    import java.util.ArrayList;
    import java.util.Collection;
    
    /**
     * @author: 马士兵教育
     * @create: 2019-09-07 21:21
     */
    /*
    * java集合框架:
    *   Collection:存放的是单一值
    *       特点:
    *           1、可以存放不同类型的数据,而数组只能存放固定类型的数据
    *           2、当使用arraylist子类实现的时候,初始化的长度是10,当长度不够的时候会自动进行扩容操作
    *       api方法:
    *           增加数据的方法
    *           add:要求必须传入的参数是Object对象,因此当写入基本数据类型的时候,包含了自动拆箱和自动装箱的过程
    *           addAll:添加另一个集合的元素到此集合中
    *
    *           删除数据的方法
    *           clear:只是清空集合中的元素,但是此集合对象并没有被回收
    *           remove:删除指定元素
    *           removeAll:删除集合元素
    *
    *           查询数据的方法
    *           contains:判断集合中是否包含指定的元素值
    *           containsAll:判断此集合中是否包含另一个集合
    *           isEmpty:判断集合是否等于空
    *           retainAll:若集合中拥有另一个集合的所有元素,返回true,否则返回false
    *           size:返回当前集合的大小
    *
    *           //集合转数组的操作
    *           toArray:将集合转换成数组
    * */
    public class CollectionDemo {
        public static void main(String[] args) {
            Collection collection = new ArrayList();
            collection.add(1);
            collection.add(true);
            collection.add(1.23);
            collection.add("abc");
            System.out.println(collection);
            ((ArrayList) collection).add(0,"mashibing");
            System.out.println(collection);
            Collection collection1 = new ArrayList();
            collection1.add("a");
            collection1.add("b");
            collection1.add("c");
            collection1.add("d");
            collection.addAll(collection1);
            System.out.println(collection);
    //        collection.clear();
    //        System.out.println(collection);
            System.out.println(collection.contains("a"));
            System.out.println(collection.containsAll(collection1));
            System.out.println(collection.isEmpty());
    //        collection.remove("a");
    //        System.out.println(collection);
            System.out.println(collection1.retainAll(collection));
            Object[] objects = collection.toArray();
            collection.add("a");
            System.out.println(collection);
    
    
        }
    }
    
    
  2. Collection-List接口代码示例

    package com.mashibing;
    
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.List;
    
    /**
     * @author: 马士兵教育
     * @create: 2019-09-07 21:21
     */
    /*
    * java集合框架:
    *   List:存放的是单一值
    *       特点:
    *           1、可以存放不同类型的数据,而数组只能存放固定类型的数据
    *           2、当使用arraylist子类实现的时候,初始化的长度是10,当长度不够的时候会自动进行扩容操作
    *       api方法:
    *           增加数据的方法
    *           add:要求必须传入的参数是Object对象,因此当写入基本数据类型的时候,包含了自动拆箱和自动装箱的过程
    *           addAll:添加另一个集合的元素到此集合中
    *
    *           删除数据的方法
    *           clear:只是清空集合中的元素,但是此集合对象并没有被回收
    *           remove:删除指定元素
    *           removeAll:删除集合元素
    *
    *           查询数据的方法
    *           contains:判断集合中是否包含指定的元素值
    *           containsAll:判断此集合中是否包含另一个集合
    *           isEmpty:判断集合是否等于空
    *           retainAll:若集合中拥有另一个集合的所有元素,返回true,否则返回false
    *           size:返回当前集合的大小
    *
    *           //集合转数组的操作
    *           toArray:将集合转换成数组
    * */
    public class ListDemo {
        public static void main(String[] args) {
            List list = new ArrayList();
            list.add("a");
            list.add(1);
            list.add("a");
            list.add(true);
            System.out.println(list);
    //        System.out.println(list.get(3));
            System.out.println(list.indexOf("a"));
            System.out.println(list.lastIndexOf("a"));
            list.set(0,"mashibing");
            System.out.println(list);
            List list1 = list.subList(0, 2);
            System.out.println(list1);
    //        List of = List.of(1,2,3,4);
    //        System.out.println(of);
        }
    }
    
  3. Collection-LinkedList代码示例

    package com.mashibing;
    
    import java.util.LinkedList;
    
    /**
     * @author: 马士兵教育
     * @create: 2019-09-08 15:18
     */
    /*
    * linkedList拥有更加丰富的方法实,需要用的时候查询api即可,不需要记忆
    *
    * */
    public class LinkedListDemo {
        public static void main(String[] args) {
            LinkedList linkedList = new LinkedList();
            linkedList.add(123);
            linkedList.add(false);
            linkedList.add("abc");
            System.out.println(linkedList);
            linkedList.add(2,"mashibing");
            System.out.println(linkedList);
            linkedList.addFirst("1111");  // 在最前面插入
            System.out.println(linkedList);
            linkedList.addLast("2222");  // 在最后插入
            System.out.println(linkedList);
            System.out.println(linkedList.element());  //获取第一个元素
            linkedList.offer("3333");
            System.out.println(linkedList);
    
    
        }
    }
    
    
  4. Collection-Vector代码示例

    package com.mashibing;
    
    import java.util.Vector;
    
    /**
     * @author: 马士兵教育
     * @create: 2019-09-08 15:34
     */
    /**
     *      1、Vector也是List接口的一个子类实现
     *      2、Vector跟ArrayList一样,底层都是使用数组进行实现的
     *      3、面试经常问区别:
     *          (1)ArrayList是线程不安全的,效率高,Vector是线程安全的效率低
     *          (2)ArrayList在进行扩容的时候,是扩容1.5倍,(使用的是位移操作, 原来的长度加上右移1位),Vector扩容的时候扩容原来的2倍(加法操作,当前加上原来的长度)
     *
     * */
    public class VectorDemo {
        public static void main(String[] args) {
            Vector vector = new Vector();
            vector.add(1);
            vector.add("abc");
            System.out.println(vector);
        }
    }
    

3.Iterator接口

  1. 概览

    ▪ 所有实现了Collection接口的容器类都有一个iterator方法用以返回一个实现了Iterator接口的对象。
    ▪ Iterator对象称作迭代器,用以方便的实现对容器内元素的遍历操作。
    ▪ Iterator接口定义了如下方法

    ​ boolean hasNext(); //判断是否有元素没有被遍历
    ​ Object next(); //返回游标当前位置的元素并将游标移动到下一个位置
    ​ void remove(); //删除游标左面的元素,在执行完next之后该,操作只能执行一次

  2. Iterator与Collection的关系

    1. 所有的集合类都默认实现了Iterable的接口,==实现此接口意味着具备了增强for循环的能力==,也就是for-each, 增强for循环本质上使用的也是iterator的功能

      所以ArryList实例对象也是有.iterator方法的

      Iterable接口中的方法:
      iterator()
      foreach() //增强for循环的实现

    2. 在iterator的方法中,要求返回一个Iterator的接口子类实例对象

      此接口中包含了:

      ​ hasNext()方法

      ​ next()方法

    3. ==注意事项==

      在使用iterator进行迭代的过程中如果删除其中的某个元素会报错,并发操作异常,因此, 如果遍历的同时需要修改元素,建议使用listIterator(),
      ListIterator迭代器提供了向前和向后两种遍历的方式, 始终是通过cursor和lastret的指针来获取元素值及向下的遍历索引 ,当使用向前遍历的时候必须要保证指针在迭代器的结果,否则无法获取结果值

    4. Listerator删除元素原理

      删除元素的时候cursor和lastret都减1, 向上移动

  3. 为什么需要ListIterator

    1. 在迭代过程中准备添加或删除元素

      ArrayList al=new ArrayList();
      1//添加元素
      2 al.add("java3");
      //遍历
      Iterator it=al.iterator();
      while(it.hasNext()){
        Object obj=it.next();
        if (obj.equals("java2")) {
            al.add("java9");
      }
      
    2. ListIterator的作用 --> 解决并发操作异常

      在迭代时,丌可能通过集合对象的方法(al.add(?))操作集合中的元素,会发生并发修改异常

      所以,在迭代时只能通过迭代器的方法操作元素,但是Iterator的方法,是有限的,只能进行判断(hasNext),取出(next),删除(remove)的操作, 如果想要在迭代的过程中进行向集合中添加,修改元素等就需要使用ListIterator接口中的方法

      while(li.hasNext()){
      Object obj=li.next();
      if ("java2".equals(obj)) {
        add("java9994");
        li.set("java002");
      }
      }
      
  4. 代码示例

    package com.mashibing;
    
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.ListIterator;
    
    /**
     * @author: 马士兵教育
     * @create: 2019-09-08 15:42
     */
    /*
    * 在java代码中包含三种循环的方式
    *   do...while
    *   while
    *   for
    * 还有一种增强for循环的方式,可以简化循环的编写
    *
    *
    *   所有的集合类都默认实现了Iterable的接口,实现此接口意味着具备了增强for循环的能力,也就是for-each
    *      增强for循环本质上使用的也是iterator的功能
    *      方法:
    *               iterator()
    *               foreach()
    *   在iterator的方法中,要求返回一个Iterator的接口子类实例对象
    *       此接口中包含了
    *               hasNext()
    *               next()
    *
    *   在使用iterator进行迭代的过程中如果删除其中的某个元素会报错,并发操作异常,因此
    *       如果遍历的同时需要修改元素,建议使用listIterator(),
    *   ListIterator迭代器提供了向前和向后两种遍历的方式
    *       始终是通过cursor和lastret的指针来获取元素值及向下的遍历索引
    *       当使用向前遍历的时候必须要保证指针在迭代器的结果,否则无法获取结果值
    * */
    public class IteratorDemo {
        public static void main(String[] args) {
            ArrayList list= new ArrayList();
            list.add(1);
            list.add(2);
            list.add(3);
            list.add(4);
            for(int i=0;i

4.Set接口

  1. 概述

    Set接口储存一组唯一, 无序的对象, 可以放任意的数据类型

    存入和取出的顺序不一定一致

    操作数据的方法与List类似, Set接口不存在get()方法

  2. 常用的Set实现类

    HashSet-->LinkedHashSet

    TreeSet

  3. HashSet与TreeSet

    • HashSet

      采用HashTable哈希表的存储结构

      优点: 添加速度块, 查询速度快, 删除速度快

      缺点: 无序

    • TreeSet

      采用二叉树(红黑树)的数据结构, 所以只能放相同的数据类型

      优点: 有序(排序后的升序), 查询速度比List快

      缺点: 查询速度没有HashSet快

  4. HashSet总结

    HashSet是如何保证元素的唯一性的呢?

    答:是通过元素的两个方法,hashCode和equals方法来完成

    如果元素的HashCode值相同,才会判断equals是否为true

    如果元素的hashCode值不同,不会调用equals方法

  5. 代码示例

    package com.mashibing;
    
    import java.util.*;
    
    /**
     * @author: 马士兵教育
     * @create: 2019-09-08 16:36
     */
    /*
    *   1、set中存放的是无序,唯一的数据
    *   2、set不可以通过下标获取对应位置的元素的值,因为无序的特点
    *   3、使用treeset底层的实现是treemap,利用红黑树来进行实现
    *   4、设置元素的时候,如果是自定义对象,会查找对象中的equals和hashcode的方法,如果没有,比较的是地址
    *   5、树中的元素是要默认进行排序操作的,如果是基本数据类型,自动比较,如果是引用类型的话,需要自定义比较器
    *       比较器分类:
    *         内部比较器
    *               定义在元素的类中,通过实现comparable接口来进行实现
    *         外部比较器
    *               定义在当前类中,通过实现comparator接口来实现,但是要将该比较器传递到集合中
    *         注意:外部比较器可以定义成一个工具类,此时所有需要比较的规则如果一致的话,可以复用,而
    *               内部比较器只有在存储当前对象的时候才可以使用
    *               如果两者同时存在,使用外部比较器
    *               当使用比较器的时候,不会调用equals方法
    * */
    public class SetDemo implements Comparator {
        public static void main(String[] args) {
    //        Set set = new HashSet();
    //        set.add("123");
    //        set.add(1);
    //        set.add(true);
    //        set.add("123");
    //        System.out.println(set);
    //        Iterator iterator = set.iterator();
    //        while (iterator.hasNext()){
    //            System.out.println(iterator.next());
    //        }
    //        System.out.println("---------");
    //        //将while循环改成for循环,推荐使用
    //        for(Iterator iter = set.iterator(); iter.hasNext();){
    //            System.out.println(iter.next());
    //        }
    
    //        TreeSet treeSet = new TreeSet();
    //        treeSet.add(34);
    //        treeSet.add(1);
    //        treeSet.add(65);
    //        System.out.println(treeSet.ceiling(1));
    //        System.out.println(treeSet);
    //        HashSet hashSet = new HashSet();
    //        hashSet.add(new Person("zhangsan",12));
    //        hashSet.add(new Person("zhangsan",12));
    //        hashSet.add(new Person("lisi",13));
    //        System.out.println(hashSet);
    
            TreeSet treeSet = new TreeSet(new SetDemo());
            treeSet.add(new Person("lisi",15));
            treeSet.add(new Person("wangwu",13));
            treeSet.add(new Person("maliu",12));
            treeSet.add(new Person("zhangsan",19));
            treeSet.add(new Person("zhangsan",12));
            System.out.println(treeSet);
    
    
        }
    
        @Override
        public int compare(Person o1, Person o2) {
            if(o1.getAge()>o2.getAge()){
                return -1;
            }else if(o1.getAge() < o2.getAge()){
                return 1;
            }else{
                return 0;
            }
        }
    }
    
    

5.Comparable接口

问题: TreeSet是根据什么来排序的呢?

所有可以排序的类都实现了java.lang.Comparable接口, Comparable接口中只有一个方法:

​ public int compareTo(Object obj)

​ 返回0表示 this==obj

​ 返回正数表示 this > obj

​ 返回负数表示 this

实现了Comparable 接口的类通过实现 comparaTo 方法从而确定该类对象的排序方式asf

// 内部比较器, 定义在元素的类中, 通过实现compareTo接口来进行实现
@Override
public int compareTo(Object o) {
    Person p  = (Person) o;
    if (p.name.length()>this.name.length()){
        return -1;
    }else if(p.name.length()
@Override
public int compare(Person o1, Person o2) {
    if(o1.getAge()>o2.getAge()){
        return -1;
    }else if(o1.getAge() < o2.getAge()){
        return 1;
    }else{
        return 0;
    }
}


TreeSet treeSet = new TreeSet(new SetDemo());
treeSet.add(new Person("lisi",15));
treeSet.add(new Person("wangwu",13));
treeSet.add(new Person("maliu",12));
treeSet.add(new Person("zhangsan",19));
treeSet.add(new Person("zhangsan",12));
System.out.println(treeSet);

  •     注意:外部比较器可以定义成一个工具类,此时所有需要比较的规则如果一致的话,可以复用,而内部比较器只有在存储当前对象的时候才可以使用
    
  •           如果两者同时存在,使用外部比较器
    
  •           当使用比较器的时候,不会调用equals方法
    

6.泛型

  1. 概述

    ▪ 为什么需要泛型
    ▪ 解决数据类型操作丌统一产生的异常
    ▪ 使用泛型可以更好的去保护数据类型

    当做一些集合的统一操作的时候,需要保证集合的类型是统一的,此时需要泛型来进行限制

    给集合中的元素设置相同的类型就是泛型的基本需求

  2. 泛型对象

    在创建对象的时候指定需要参数的类型

    示例:

    List list = new ArrayList();  //此时就只能往list中添加String类型的元素, List是个带泛型的接口
    list.add("1"); // new Integer(1)
    list.add("abc");//new String("abc)
    list.add("true");//new Boolean(true)
    list.add(new Person("zhangsan",12).toString());
    System.out.println(list);
    
  1. 泛型类

    1. 泛型类的定义1

      package cn.mashibing.demo;
      public class Point2 {// 此处可以随便写标识符号,T 是type 的简称, 也可以写a,b,c, 相当于是给类定义了一个类型不定的参数
      private T var;//var 的类型由T 指写, 由外部指定
      public T getVar() {// 返回值的类型由外部指定
      return var;
      }
      public void setVar(T var) {// 参数的类型由外部指定
      this.var = var;
      }
      }
      
    2. 泛型类的定义2

      public class Notepad {// 此处指定了两个泛型
      private K key;//此变量的类型由外部决定
      private V value;//此变量的类型由外部决定
      }
      
    3. 泛型对象的使用

      Notepadt=null;//指定两个泛型类型的对象
      //Key为String,Value为Integer
      t=new Notepad();
      t.setKey("张三");
      t.setValue(30);
      System.out.println("姓名:"+t.getKey()+"\t年龄:"+t.getValue());
      
  2. 泛型总结

    • 当做一些集合的统一操作的时候,需要保证集合的类型是统一的,此时需要泛型来进行限制

    • 优点:

    • 1、数据安全

    • 2、获取数据时效率比较高

    • 给集合中的元素设置相同的类型就是泛型的基本需求

    • 使用:

    • 在定义对象的时候,通过<>中设置合理的类型来进行实现

    • 泛型的高阶应用:

    • 1、泛型类

    • 在定义类的时候在类名的后面添加,起到占位的作用,类中的方法的返回值类型和属性的类型都可以使用

    • 2、泛型接口

    • 在定义接口的时候,在接口的名称后添加,

    • 1、子类在进行实现的时候,可以不填写泛型的类型,此时在创建具体的子类对象的时候才决定使用什么类型

      public class Fan implements List
      
    • 2、子类在实现泛型接口的时候,只在实现父类的接口的时候指定父类的泛型类型即可,此时,测试方法中的泛型类型必须要跟子类保持一致

      public class Fan implements List
      
    • 3、泛型方法

    • 在定义方法的时候,指定方法的返回值和参数是自定义的占位符,可以是类名中的T,也可以是自定义的Q,只不过在使用Q的时候需要使用定义在返回值的前面

      package com.mashibing;
      
      /**
       * @author: 马士兵教育
       * @create: 2019-09-21 16:44
       */
      public class FanXingMethod {
      
          private T t;
      
          public T getT() {
              return t;
          }
      
          public void setT(T t) {
              this.t = t;
          }
      
          public  void show(Q q){  //需要将Q定义到返回值前面
              System.out.println(q);
              System.out.println(t);
          }
      }
      
      
    • 4、泛型的上限(工作中不用)

      如果父类确定了,所有的子类都可以直接使用

      public ArrayList(Collection c) {  
      
    • 5、泛型的下限(工作中不用)

      如果子类确定了,子类的所有父类都可以直接传递参数使用

       public void forEach(Consumer action) {
      

7. Map

遍历HashMap的两种方式

  1. map.keySet()

    返回一个键的集合

  2. map.values()

    返回一个值的集合

  3. 使用迭代器

  4. map.entrySet()

你可能感兴趣的:(java进阶)