引用

https://zhuanlan.zhihu.com/p/74229762
https://baike.baidu.com/item/JIT%E7%BC%96%E8%AF%91%E5%99%A8
https://www.runoob.com/java/java-regular-expressions.html

基础

java 编译相关

  • Java程序从源文件创建到程序运行要经过两大步骤:
  1. 源文件由编译器编译成字节码(ByteCode),Java编译一个类时,如果这个类所依赖的类还没有被编译,编译器就会先编译这个被依赖的类,然后引用,否则直接引用
  2. 字节码由java虚拟机解释运行,大致视为类的加载,类的执行两个步骤。JVM主要在程序第一次主动使用类的时候,才会去加载该类
  • JIT是一种提高程序运行效率的方法。通常,程序有两种运行方式:静态编译与动态解释。静态编译的程序在执行前全部被翻译为机器码,而动态解释执行的则是一句一句边运行边翻译。

java 正则表达式

捕获组概念:通过()从左往右表示捕获组,例如,表达式((A)(B(C)))有四个捕获组,整个表达式是第一个捕获组。

  1. ((A)(B(C)))
  2. (A)
  3. (B(C))
  4. (C)
public static void main( String[] args ){
        // 按指定模式在字符串查找
        String line = "This order was placed for QT3000! OK?";
        String pattern = "(\\D*)(\\d+)(.*)";

        // 创建 Pattern 对象
        Pattern r = Pattern.compile(pattern);

        // 现在创建 matcher 对象
        Matcher m = r.matcher(line);
        System.out.println(m.groupCount());
        if (m.find( )) {
            System.out.println("Found value: " + m.group(0) );
            System.out.println("Found value: " + m.group(1) );
            System.out.println("Found value: " + m.group(2) );
            System.out.println("Found value: " + m.group(3) );
        } else {
            System.out.println("NO MATCH");
        }
    }

m.groupCount()用以获取捕获组数量,代表整个表达式的m.group(0)不计入

3
Found value: This order was placed for QT3000! OK?
Found value: This order was placed for QT
Found value: 3000
Found value: ! OK?
  • Pattern类
    pattern(模式)对象是一个正则表达式的编译表示,用来保存正则表达式和生成Matcher等。
// 创建 Pattern 对象
Pattern r = Pattern.compile(pattern,0);
public static Pattern compile(String regex, int flags)
/*后面的flags代表匹配模式,包含
CASE_INSENSITIVE:不区分大小写
MULTILINE:多行模式
DOTALL:匹配任意字符,包括行终止符
LITERAL:文字分析模式
COMMENTS:允许空格和注释符`#`,#行后的与空格将被忽略
*/
  • Matcher类
    Matcher 对象是对输入字符串进行解释和匹配操作的引擎
// 创建 matcher 对象
Matcher m = r.matcher(line);

lambda 并行运算

  • parallelStream()并行流,通过函数式编程,轻松实现并行运算
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i <= 10; i++) {
            list.add(i);
        }
        list.parallelStream().forEach(System.out::println);
    }

结果

6
7
5
10
2
1
0
3
9
8
4

为什么重写equals还要重写hashcode

  • HashMap中,如果要比较key是否相等,要同时使用这两个函数!HashMap中的比较key是这样的,先求出key的hashcode(),比较其值是否相等,若相等再比较equals(),若相等则认为他们是相等的
    重载hashCode()是为了对同一个key,能得到相同的Hash Code,这样HashMap就可以定位到我们指定的key上。重载equals()是为了向HashMap表明当前对象和key上所保存的对象是相等的,这样我们才真正地获得了这个key所对应的这个键值对。
    ps:(==在原始数据时比较值,对象比较地址)

六原则一法则

  1. 单一职责原则:一个类只做它该做的事情(高内聚)
  2. 开闭原则:对扩展开放,对修改关闭(抽象是关键,封装要可变)
  3. 依赖倒转原则:面向接口编程,尽可能使用抽象类型而不用具体类型(低耦合)
  4. 里氏替换原则:子类可以扩展父类功能,但不能改变其原有功能(前置宽松,后置严格)
  5. 接口隔离原则:接口要小而专,绝不能大而全(高内聚)
  6. 合成聚合复用原则:优先使用聚合或合成关系复用代码
  7. 迪米特法则:一个对象应当对其他对象有尽可能少的了解,只用接口?

Static Nested Class 和 Inner Class的不同

  • Inner Class内部类分为四种:成员内部类、局部内部类、匿名内部类和静态内部类
内部类就是在一个类的内部定义的类
内部类中不能定义静态成员(可定义静态常量,因为内部类依赖于外部类实例,非静态内部类并不随外部类一起加载,只有在实例化外部类之后才会加载。)
内部类可以直接访问外部类中的成员变量
内部类可以定义在外部类的方法外面,也可以定义在外部类的方法体中
在方法体外面定义的内部类的访问类型可以是public,protecte,默认的,private等4种类型
方法内部定义的内部类前面不能有访问类型修饰符,可以使用 final 或 abstract 修饰符
创建内部类的实例对象时,一定要先创建外部类的实例对象,然后用这个外部类的实例对象去创建内部类的实例对象
内部类里还包含匿名内部类,即直接对类或接口的方法进行实现,不用单独去定义内部类

StringBuffer和StringBuilder的区别

  • StringBufferd类是线程安全的,支持并发操
  • StringBuilder类不是线程安全的,但其在单线程中的性能比StringBuffer高。
  • StringBufferd类中很多方法使用synchronized 修饰

String是否能能继承?

public final class String ...{
...
    private final char value[];
...
}
  • String 是用final修饰的,故不能,其内部数组也是,故String不可变(1.9以后用byte实现)

String为什么不可变?

  • String 类被声明为一个 final 类,且类内部的 value 字节数组也是 final 的
  • 不同的字符串变量都指向池中的同一个字符串
  • 因为字符串是不可变的所以在它创建的时候 hashcode 就被缓存了,不变性也保证了 hash 码的唯一性,不需要重新计算,这就使得字符串很适合作为 Map 的键,字符串的处理速度要快过其它的键对象,因为字符串是不可变的,所以是多线程安全的。

Java中是否可以覆盖(override)一个static的方法?

  • Java中static方法不能被覆盖,因为方法覆盖是基于运行时动态绑定的,而static方法是编译时静态绑定的。

集合

  • List以特定索引来存取元素,可以有重复元素
  • Set不能存放重复元素(用对象的equals()方法来区分元素是否重复)
  • Map保存键值对(key-value pair)映射,映射关系可以是一对一或多对一,键不能重复

Collection 和 Collections的区别

  • Collection是集合类的上级接口,继承与他的接口主要有Set 和List.
  • Collections是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。

快速失败(fail-fast)和安全失败(fail-safe)的区别

  • 快速失败
    在用迭代器遍历一个集合对象时,如果遍历过程中对集合对象的内容进行了修改(增加、删除、修改),则会抛出Concurrent Modification Exception。
    集合在被遍历期间如果内容发生变化,就会改变modCount的值。每当迭代器使用hashNext()/next()遍历下一个元素之前,都会检测modCount变量是否为expectedmodCount值,是的话就返回遍历;否则抛出异常,终止遍历。
    java.util包下的集合类都是快速失败的,不能在多线程下发生并发修改(迭代过程中被修改)
  • 安全失败
    采用安全失败机制的集合容器,在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历。
    基于拷贝内容的优点是避免了Concurrent Modification Exception,但同样地,迭代器并不能访问到修改后的内容,即:迭代器遍历的是开始遍历那一刻拿到的集合拷贝,在遍历期间原集合发生的修改迭代器是不知道的。
    java.util.concurrent包下的容器都是安全失败,可以在多线程下并发使用,并发修改。

Iterator和ListIterator的区别

  • Iterator可用来遍历Set和List集合,但是ListIterator只能用来遍历List。
  • Iterator对集合只能是前向遍历,ListIterator既可以前向也可以后向。

ArrayList是否会越界

public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

多线程同时增加时,可能会越界

hashMap的key是一个自定义的类,怎么办?

  • 使用HashMap,如果key是自定义的类,就必须重写hashcode()和equals()。

在ArrayLIst和LinkedList尾部加元素,谁的效率高?

  • ArrayLIst时间损耗在于扩容
  • LinkedList时间损耗在于new Node
    故而小数据时LinkedList优,大数据时ArrayLIst优