第一章 基础 - Java源码笔记

1 String,Long源码解析

1.1 String

  • 不可变性,源于String类和类属性value[]都是用final修饰。类不可继承,属性赋值后其内存地址不可修改。
  • 字符串乱码 ,字符串做二进制转化,由于不同系统默认的编码,所以出现乱码,解决方式是指定编码。
  • 首字母大小写,name.substring(0, 1).toLowerCase() + name.substring(1);name.substring(0, 1).toUpperCase() + name.substring(1)。
  • 相等判断,方法有equals()和equalsIgnoreCase(), 判断两个String是否相登,挨个判断字符是否相等。
  • 替换、删除,方法有replace,replaceAll和replaceFirst。
  • 拆分和合并,Guava工具的Splitter和Joiner。

1.2 Long

  • 缓存问题
    缓存了-128到127. 如果是这个范围的值,从此处取值。内部静态类缓存数据。
private static class LongCache {
    private LongCache(){}
    // 缓存,范围从 -128 到 127,+1 是因为有个 0
    static final Long cache[] = new Long[-(-128) + 127 + 1];

    // 容器初始化时,进行加载
    static {
        // 缓存 Long 值,注意这里是 i - 128 ,所以再拿的时候就需要 + 128
        for(int i = 0; i < cache.length; i++)
            cache[i] = new Long(i - 128);
    }
}

1.3 面试

  • 3.1 为什么使用 Long 时,大家推荐多使用 valueOf 方法,少使用 parseLong 方法
    答:因为 Long 本身有缓存机制,缓存了 -128 到 127 范围内的 Long,valueOf 方法会从缓存中去拿值,如果命中缓存,会减少资源的开销,parseLong 方法就没有这个机制。

2 Java常用关键字

2.1 static

静态,修饰类变量,方法,方法块。静态类变量需要注意并发安全问题。
初始化时机

public class Parent {
    public static List<String> PARENT_LIST = new ArrayList() {{
        System.out.println("parent 静态变量初始化");
    }};

    static {
        System.out.println("parent 静态代码块初始化");
    }

    public Parent(){
        System.out.println("parent 构造器初始化");
    }

    public void testStatic(){
        System.out.println("parent 静态方法执行");
    }
}

public class Son extends Parent {
    public static List<String> LIST = new ArrayList() {{
        System.out.println("son 静态变量初始化");
    }};

    static {
        System.out.println("son 静态代码块初始化");
    }

    public Son() {
        System.out.println("son 构造器初始化");
    }

    public void testSonStatic(){
        System.out.println("son 静态方法执行");
    }

    public static void main(String[] args) {
        System.out.println("main 执行");
        new Son();
    }
}

打印结果:
parent 静态变量初始化
parent 静态代码块初始化
son 静态变量初始化
son 静态代码块初始化
main 执行
parent 构造器初始化
son 构造器初始化
结论

  • 父类静态变量和静态代码块比子类优先初始化;
  • 静态变量和静态代码块比构造器优先初始化;
  • 父类构造器优先比子类初始化。

2.2 final

  • 被final修饰的类,类不可被继承;
  • 被final修饰的方法,表示方法不可覆写;
  • 被final修饰的变量,表示变量在声明的必须初始化,且内存地址不可改变。注意是内存地址不可改变,不是值不可改变,对于如List,Map对象,可以改变其值。

2.3 try catch finally

public class TryCatchFinally {
    public static void main(String[] args) {
        TryCatchFinally tryCatchFinally = new TryCatchFinally();
        tryCatchFinally.test();
    }

    public void test(){
        try {
            System.out.println("log try");
            if (true) {
                throw new RuntimeException("try exception");
            }
        } catch (Exception e) {
            System.out.println("log catch");
            if (true) {
                throw new RuntimeException("catch exception");
            }
        } finally {
            System.out.println("log finally");
        }
    }
}

结果
og try
log catch
log finally
Exception in thread “main” java.lang.RuntimeException: catch exception

  • finally先执行,后抛异常;

2.4 volatile

volatile,英文解释:likely to change suddenly and unexpectedly, especially by getting worse,意为易变的。用来共享修饰变量。
**底层原理:**当多个线程在多个cpu分别执行时,为加快速度,线程并不是从内存中读取共享变量,而是从cpu缓存读取,那么就有一个问题,当线程A改变变量X的值时,由于cpu缓存的存在,线程B并不知道变量X已经被修改,这导致变量X值不一致的问题
解决方法:用volatile修饰变量X,当线程A改变变量X的值时,内存会通知其他cpu其cpu缓存的变量X无效,其他线程则重新从内存读取变量X,保证数据一致性。
在这里插入图片描述

2.5 transient

修饰类变量,表示类进行序列化时,忽略此变量。

2.6 default

用来修饰接口方法,表示该方法子类无效实现,但接口必须有默认实现。

public interface ParentInterface {
    default void testMy() {
        System.out.println("do something");
    }
}

2.7 面试题

  1. 如何证明 static 静态变量和类无关?
  • 无需初始化类,可以直接使用静态变量;
  • 在类中写main方法,即使不初始化类的代码,静态变量都会自动初始化;
  • 静态变量只初始化一次,后面无论new多少个类,静态变量只初始化一次。

3 Arrays、Collections、Objects 常用方法源码解析

3.1 工具类通用特征

  1. 构造器私有,无需new出来;
  2. 方法通常被static和final修饰。

3.2 Arrays

Arrays主要用于处理数组,比如排序,查找,填充等等

3.2.1 排序

支持很多参数类型,来个demo:

package demo.two;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.ImmutableList;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;

@Slf4j
public class MyArraysDemoTest {
    @Test
    public void testSort() {
        List<MySort> list = ImmutableList.of(
                new MySort("100"),
                new MySort("200"),
                new MySort("600"),
                new MySort("220"),
                new MySort("150")
        );
        MySort[] mySorts = new MySort[list.size()];
        list.toArray(mySorts);
        log.info("before mySorts={}", JSON.toJSONString(mySorts));
        Arrays.sort(mySorts, Comparator.comparing(MySort::getValue));
        log.info("after mySorts={}", JSON.toJSONString(mySorts));
    }

    @Data
    class MySort {
        private String value;
        public MySort(String value) {
            this.value = value;
        }
    }

}

3.2.2 二分法查找

在这里插入图片描述

3.2.3 拷贝

copyOf(),copyOfRange()(部分拷贝)。

3.3 Collections

集合使用的工具类。

3.3.1 求最大最小值

Collections.max() 和 min()方法。
在这里插入图片描述
特别的:<T extends Object & Comparable<? super T>> 意思是要求T继承Object类并且实现Comparable接口。

3.3.2 多种类型的集合

有线程安全集合(Synchronized开头)和不可变集合(Unmodifiable开头),看底层实现。
在这里插入图片描述
在这里插入图片描述
可以看到操作都是加锁的。
不可变集合是从原集合得到一个新集合,只能读,不能写。
在这里插入图片描述

3.4 Objects

主要用于判断相等和判断空。

3.4.1 相等判断

Objects 有提供 equals 和 deepEquals 两个方法来进行相等判断,前者是判断基本类型和自定义类的,后者是用来判断数组的。

3.4.2 判空

Objects 提供了各种关于空的一些判断,isNull 和 nonNull 对于对象是否为空返回 Boolean 值,requireNonNull 方法更加严格,如果一旦为空,会直接抛出异常。

发布了97 篇原创文章 · 获赞 3 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_39530821/article/details/105084269