Java基础补充(三)—— 泛型&正则表达式

365 阅读3分钟

泛型

  • 使用泛型

    • 代码简写

      编译器看到List<Number>可以自动推断后面的泛型类型

      List<Number> list = new ArrayList<>();
      

      知识补充

      1. 为什么用List list = new ArrayList()而不直接ArrayList?
        1. 依赖于抽象不依赖于实现。 2. 提高灵活性(如改LinkedList,只需改一行代码)
      2. 向上转型后对方法、变量的使用
        1. 调用子类同名方法时,使用子类方法
        2. 不能直接调用子类独有方法,只能使用自己的内部方法
        3. 父类中的变量无法被子类覆盖或重写
        4. 可以通过向下转型来调用子类特有的方法和变量
    • 泛型接口

      public interface Comparable<T> {
          int compareTo(T o);
      }
      
    • 静态泛型方法

      public class Pair<T> {
          public static <K> Pair<K> create(K first, K last) {
              return new Pair<K>(first, last);
          }
      }
      
  • 擦拭法

    虚拟机对泛型一无所知,所有的工作都是编译器做的。

    1. 编译器把<T>视为Object
    2. 编译器根据<T>实现安全的强制转型
    • Java泛型局限:
      • <T>不能是基本类型,例如int,因为实际类型是ObjectObject类型无法持有基本类型
      • 无法取得带泛型的Class
      • 无法判断带泛型的Class
  • extends通配符

    首先,Pair<Integer>不是Pair<Number>的子类,但是可以通过Pair<? extends Number>使得方法接收所有泛型类型为NumberNumber子类的Pair类型

    public class Main {
        public static void main(String[] args) {
            Pair<Integer> p = new Pair<>(123, 456);
            int n = add(p);
            System.out.println(n);
        }
        static int add(Pair<? extends Number> p) {
            Number first = p.getFirst();
            Number last = p.getLast();
            return first.intValue() + last.intValue();
        }
    }
    
    • 限制T类型

      public class Pair<T extends Number> {}
      

      则只能定义:

      Pair<Number> p1 = null;
      Pair<Integer> p2 = new Pair<>(1, 2);
      Pair<Double> p3 = null;
      
    • 允许调用方法T get()

  • super通配符

    Pair<? super Integer>表示,方法参数接受所有泛型类型为IntegerInteger父类的Pair类型。

    • 允许调用方法set(T)

    • PECS原则: Producer Extends Consumer Super

    • 无限定通配符

      因为<?>通配符既没有extends,也没有super,因此:

      • 不允许调用set(T)方法并传入引用(null除外);
      • 不允许调用T get()方法并获取T引用(只能获取Object引用)。

正则表达式

  • 匹配规则

    单个字符的匹配规则如下:

    正则表达式 规则 可以匹配
    A 指定字符 A
    \u548c 指定Unicode字符
    . 任意字符 ab&0
    \d 数字0~9 0~9
    \w 大小写字母,数字和下划线 a~zA~Z0~9_
    \s 空格、Tab键 空格,Tab
    \D 非数字 aA&_,……
    \W 非\w &@,……
    \S 非\s aA&_,……

    多个字符的匹配规则如下:

    正则表达式 规则 可以匹配
    A* 任意个数字符 空,AAAAAA,……
    A+ 至少1个字符 AAAAAA,……
    A? 0个或1个字符 空,A
    A{3} 指定个数字符 AAA
    A{2,3} 指定范围个数字符 AAAAA
    A{2,} 至少n个字符 AAAAAAAAA,……
    A{0,3} 最多n个字符 空,AAAAAA

    复杂匹配规则主要有:

    正则表达式 规则 可以匹配
    ^ 开头 字符串开头
    $ 结尾 字符串结束
    [ABC] […]内任意字符 A,B,C
    [A-F0-9xy] 指定范围的字符 A,……,F0,……,9xy
    [^A-F] 指定范围外的任意字符 A~F
    AB|CD|EF AB或CD或EF ABCDEF
  • 分组匹配

    按括号提取子串:引入java.util.regex,用Pattern对象匹配,匹配后获得一个Matcher对象,如果匹配成功可以直接从Matcher.group(index)返回子串。

    public class Main {
        public static void main(String[] args) {
            Pattern p = Pattern.compile("(\\d{3,4})\\-(\\d{7,8})");
            Matcher m = p.matcher("010-12345678");
            if (m.matches()) {
              	String g0 = m.group(0); // 010-12345678
                String g1 = m.group(1); // 010
                String g2 = m.group(2); // 12345678
            } else {
                System.out.println("匹配失败!");
            }
        }
    }
    
  • 非贪婪匹配

    贪婪匹配:任何一个规则,它总是尽可能多地向后匹配

    非贪婪匹配:尽可能少的匹配,使用?

    如:正则表达式:(\d+)(0*),将"123000"提取为"123000"""

    ​ 正则表达式:(\d+?)(0*),将"123000"提取为"123""000"

  • 搜索和替换

    • 分割字符串

      "a b c".split("\\s"); // { "a", "b", "c" }
      "a b  c".split("\\s"); // { "a", "b", "", "c" }
      "a, b ;; c".split("[\\,\\;\\s]+"); // { "a", "b", "c" }
      
    • 搜索字符串(matcher.find()

      public class Main {
          public static void main(String[] args) {
              String s = "the quick brown fox jumps over the lazy dog.";
              Pattern p = Pattern.compile("\\wo\\w");
              Matcher m = p.matcher(s);
              while (m.find()) {
                  String sub = s.substring(m.start(), m.end());
                  System.out.println(sub);
              }
          }
      }
      // row fox dog
      
    • 反向引用

      使用replaceAll()的时候,我们传入的第二个参数可以使用$1$2来反向引用匹配到的子串。例如:

      public class Main {
          public static void main(String[] args) {
              String s = "the quick brown fox jumps over the lazy dog.";
              String r = s.replaceAll("\\s([a-z]{4})\\s([a-z]{3})", " <b>$1</b>$2 ");
              System.out.println(r);
          }
      }
      
      // the quick brown fox jumps <b>over</b>the  <b>lazy</b>dog .