javaSE 温故而知新

重温 javaSE

前言:有地基才能有高楼大厦

认识java

  1. java是一门强类型的语言
    1.1 什么叫强类型什么叫弱类型呢?
  2. 强类型:
    强制数据类型定义的语言。也就是说,一旦一个变量被指定了某个数据类型,如果不经过强制转换,那么它就永远是这个数据类型了。举个例子:如果你定义了一个整形变量 a,那么程序根本不可能将 a 当作字符串类型处理。强类型定义语言是类型安全的语言。
  3. 弱类型 数据类型可以被忽略的语言。它与强类型定义语言相反, 一个变量可以赋不同数据类型的值。
    强类型定义语言在速度上可能略逊色于弱类型定义语言,但是强类型定义语言带来的严谨性能够有效的避免许多错误。例如:JavaScript 1.2 强类型和弱类型各有什么优势?
  4. 强类型:
    强类型定义语言严谨性能避免不必要的错误
  5. 弱类型:
    编译速度快,开发敏捷
  6. java是静态语言
    2.1 什么叫静态语言什么叫动态语言?
  7. 静态语言
    (1)变量的类型在编译的时候确定
    (2)变量的类型在运行时不能修改
    (3)这样编译器就可以确定运行时需要的内存总量
  8. 动态语言 (1)变量的类型在运行的时候确定 (2)变量的类型在运行可以修改
  9. java是跨平台的语言
    一套代码跑各个平台
  10. java是面向过程的语言
    4.1 面向过程和面向对象的优缺点
  11. 面向过程性能比面向对象高。 因为类调用时需要实例化,开销比较大,比较消耗资源,所以当性能是最重要的考量因素的时候,比如单片机、嵌入式开发、Linux/Unix 等一般采用面向过程开发。但是,面向过程没有面向对象易维护、易复用、易扩展。
  12. 面向对象 :面向对象易维护、易复用、易扩展。 因为面向对象有封装、继承、多态性的特性,所以可以设计出低耦合的系统,使系统更加灵活、更加易于维护。但是,面向对象性能比面向过程低。

Java基础

1、数据类型

1.1 基本数据类型:

byte short char int float double long boolean

javaSE 温故而知新

注意:整形默认为int,如果数值不属于int范围,会报错,整形后面加L代表是long数据。浮点型显性默认为double,浮点数高精度类型不能直接赋值给低精度类型,会造成精度损失,编译不通过,必须加F,加F代表是float数据

例如:

long value = 9223372036854775807; //错误写法

long value = 9223372036854775807L; //正确写法相等于long value = (long)9223372036854775807L;

float f = 1000.1; // 错误写法编译不通过

float f = 1000.1F; // 正确写法相等于 float f = (float)1000.1;

1.2 引用数据类型

所有的非基本数据类型都是引用数据类型

1.3 基本数据类型的包装类

javaSE 温故而知新
javaSE 温故而知新

1.4 基本类型与包装类互相转换

// 基础类型转成包装类
Long l = new Long(1000L);
Long l2 = Long.valueOf(100L); // 包装类.valueOf(基本数据类型变量)
// 包装类转成基本类型
long basicL = l.longValue(); // 包装类变量.基本数据类型value()

1.5 自动装箱与拆箱

Integer i = 10;  //装箱 相当于Integer i = Integer.valueOf(10)
int n = i;   //拆箱 相当于int n = i.intValue()

1.6 Byte,Short,Integer,Long缓存

对于两个非new生成的Integer对象,进行比较时,如果两个变量的值在区间-128到127之间,是同一个对象则为true,如果不在这区间,则为false

Integer i = 100;
Integer j = 100;
System.out.print(i == j); //true
Integer i = 128;
Integer j = 128;
System.out.print(i == j); //false

答案在源码中很容易找到,装箱是调用的valueOf方法,源码如下

public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i

我们看到如果是在IntegerCache.low和IntegerCache.high之间,都是返回的同一个对象,这些对象在加载类的时候就已经创建好了

注意:Float,Double并没有实现常量池技术。

2、访问修饰符

名称 中文简称 类内部是否可以访问 同包是否可以访问 不同包是否可以访问 子类是否可以访问 privalte 私有的 可以 不可以 不可以 不可以 default 默认不写 可以 可以 不可以 不可以 protected 受保护的 可以 可以 不可以 可以 public 公开的 可以 可以 可以 可以

3、final关键字

  • final类,不可被继承
  • final方法,不可被重写,可以被重载,private 方法是隐式的 final
  • final参数,不可改变参数的指向,如下:
    javaSE 温故而知新
  • final变量,不可改变,被称为常量

4、static关键字

static静态、可以修饰属性,方法,还可以定义代码块,被修饰的元素隶属于类,被类的所有对象共享。

  • static方法:一般称作静态方法,由于静态方法不依赖于任何对象就可以进行访问,因此对于静态方法来说,是没有this的,因为它不依附于任何对象,既然都没有对象,就谈不上this了。并且由于这个特性,在 静态方法中不能访问类的非静态成员变量和非静态成员方法,因为非静态成员方法/变量都是必须依赖具体的对象才能够被调用
  • static变量:也称作静态变量,静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中 只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。
  • static代码块:static代码块可以置于类中的任何地方,类中可以有多个static块。 在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次==。因此,很多时候会将一些只需要进行一次的初始化操作都放在static代码块中进行。
  • static类:static类只能是内部类

5、异常

javaSE 温故而知新

顶层类 Throwable 派生出两个重要的子类, Error 和 Exception
Error:Error的错误是致命的,一但发生Error JVM就会停止
Exeption:Exeption不会停止JVM。

5.1 Exception

异常又分为,运行时异常,和编译异常

5.2 处理异常

  1. try-catch-finaly(捕获)
try (如果有资源需要在代码块执行完释放可以把变量声明在这里,前提是资源要实现AutoCloseable接口) {
            // 可能发生异常的代码
} catch (Exception e ) {
            // 发生异常处理的代码
} finally {
            // 不管发不发生异常都会执行的代码块
}

注意点: 如果catch里面有return,return语句会在finally代码块的最后执行
catch可以有多个
2. throw throws (抛出异常,交给上层处理)

throw主动抛出异常

if () {
    throw new NumberFormatException("主动抛出")
}

throws 定义可能会发生的异常

public Integer test() throws NumberFormatException() {

}

5.3 自定义异常

在我们日常开发中,大部分异常是够用的,但是又些时候需要我们自己去继承RuntimeExecption类定义一个自己的异常来满足需求

6、逻辑运算符

javaSE 温故而知新
  • 逻辑运算符:先走一遍,在判断
    &、|、^、!
  • 短路逻辑运算符:一但符合条件,后面的判断不走
    &&、||

7、泛型

泛型不支持基本数据类型,用包装类代替

为什么要使用泛型?

  1. 保证了类型的安全性。
  2. 消除强制转换
List list = new ArrayList();
list.add("hello");
String s = (String) list.get(0);
// 使用泛型
List list = new ArrayList();
list.add("hello");
String s = list.get(0); // no cast

泛型通配符:

  • 上界通配符: 只能是T或者是T的子类
  • 下界通配符: 只能是T或者是T的父类
  • 无界通配符: 任何类型

8、重载和重写

重载:方法名称都相同,方法参数顺序、参数类型、参数个数不一样

重写:只有继承才会有重写,方法名称,方法参数顺序、参数类型、参数个数都一致。重写的访问修饰符必须大于等于父类

9、abstract关键字

abstract类:天生就是为了规范来被子类继承的,不能被实例化,不能用final修饰(因为可以abstract类就是要用来继承的),与接口不同的是,abstract可以有普通成员变量、方法。

abstract方法:abstract方法必须存在abstract类中,不能用private、static修饰(因为子类必须要重写),abstract方法必须被重写

10、interface关键字(接口)

接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有变量和方法的实现。interface只能用在类上,接口中的所有方法都是abstract的,子类必须重写。

10.1 interface和abstract的区别

interface是强调实现功能可以多实现,interface里面的方法都是abstract的,实现的子类全部要重写,没有构造器

abstract是强调所属关系只能单继承,abstract类可以存在非abstract的方法,子类可以选择是否要重写、有构造器

11、继承

11.1 为什么要使用继承?

  • 提高代码的重用性。
  • 类与类之间产生了关系,是多态的前提

11.2 实现继承

关键字extends,我们可以让一个类和另一个类建立起父子关系.例如

// Student称为子类(派生类),People称为父类(基类或超类)
// 当子类继承父类后,就可以直接使用父类公共的属性和方法了
public class Student extends People {}

注意:
final 的方法子类不可重写
private default 方法、属性、子类不可访问

11.3 this和super

this:是自身的一个对象,代表对象本身

  • 普通直接引用当前对象本身
  • 形参和成员名重名,用this来区分
  • 引用构造方法,this(参数) ,应该为构造函数中的第一条语句,调用的事1本类中另外一种形式的构造方法

super:可以理解为是指向自己超(父)类对象,这个超类指的是离自己最近的一个父类

  • 普通的直接引用,与this类似,只不过它是父类对象,可以通过它调用父类成员
  • 子类中的成员变量或方法与父类中的成员变量或方法同名,可以使用super区分
  • 引用构造方法,super(参数):调用父类中的某一个构造方法(应该为构造方法中的第一条语句)

12、implements

implements用来实现接口,可以多实现,以逗号分割

13、多态

实现多态的条件

  1. 必须要有子类继承父类的继承关系
  2. 子类需要对父类中的一些方法进行重写,然后调用方法时就会调用子类重写的方法而不是原本父类的方法
  3. 在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法

例如:

public class Duo  {
    public void test () {
        System.out.println("Duo");
    }
}
public class Duo2 extends Duo {
    @Override
    public void test() {
        System.out.println("Duo2");
    }
}
public class Demo {
    public static void main(String[] args) {
        Duo duo = new Duo2();
        duo.test(); // 输出 Duo2
        Duo duo = new Duo();
        duo.test(); // 输出 Duo
    }
}

14、String类

String不是基本数据类型,它在内部存储了一个 final char数组

javaSE 温故而知新

String 类是不可改变的,所以你一旦创建了 String 对象,那它的值就无法改变了,如果需要对字符串做很多修改,那么应该选择使用 StringBuffer / StringBuilder

14.1 丰富的构造函数

javaSE 温故而知新

14.2 不可变有什么好处?

  1. 字符串常量池的设计需要
    String常量池是方法区的一个特殊的储存区。当新建一个字符串(双引号方式)的时候,如果此字符串在常量池中早已存在,会返回一个已经存在字符串的引用,而不是新建一个对象。
  2. hashCode不会变
    在开发中,我们经常用String去做Map的Key,String的hashCode不会变,Map就不用重新获取hashCode

14.3 双引号创建方式和其他创建方式的不同

String str1 = "abc";
String str2 = "abc";
String str3 = "abc";
String str4 = new String("abc");
String str5 = new String("abc");

javaSE 温故而知新

双引号这种方式创建String,会判断字符串常量池中,有没有这个常量,如果有的话,直接引用,如果没有创建常量
其他的创建方式会在堆里创建对象,堆再引用常量池的常量,返回堆里的引用

14.4 intern方法

javaSE 温故而知新

我们看到这是个native方法,被native修饰的方法,都是和操作系统的打交道的方法,我们看不到,不能修改

调用intern方法,会判断字符串常量池中是否用,有的话直接返回字符串常量池中的引用,如果没有就创建,返回字符串常量池的引用,证明如下:

String a = "a";
String b = new String("a");
System.out.println(a == b); // false
String c = b.intern();
System.out.println(a == c); // false

14.5 StringBuffer和StringBuilder

这两者相同点:可变字符串类,内部都维护了一个 char[] value;,有扩容机制,capacity()方法可以返回实际的长度

这两者区别:StringBuffer内部使用synchronized 关键字进行修饰,所以是线程安全的,StringBuilder线程不安全

javaSE 温故而知新

15、内部类

public class Demo {
    // 成员内部类
    class inner1 {}
    // 静态内部类
    static class inner2 {}
    public void demoMethod() {
        // 方法内部类
        class inner3 {}
        // 匿名内部类
        new Thread(new Runnable() {
            @Override
            public void run() {
            }
        });
    }
}

1、成员内部类特点:
成员内部类实例需要通过外部类,如 new Demo().new inner1(),成员内部类可以访问外部类的所有属性方法

2、局部内部类特点:
局部内部类:作用域只能是在方法内

3、静态内部类特点:
不依赖外部类实例, 外部类.new 静态内部类()new创建对象,只能访问外部类的静态属性,可以拥有自己的成员属。通俗意思就是,定义了一个类,这个类可以访问外部类static的成员属性和方法

4、匿名内部类特点:
匿名内部类不能定义任何静态成员、方法和类,通常用来实现一个接口,访问局部变量,这个局部变量必须是final

16、java 是值传递

首先看下面代码

public class Employee {
    public String name=null;
    public Employee(String n){
        this.name=n;
    }
    //将两个Employee对象交换
    public static void swap(Employee e1,Employee e2){
        Employee temp = e1;
        e1 = e2;
        e2 = temp;
        System.out.println(e1.name+" "+e2.name); //打印结果:李四 张三
    }
    public static void main(String[] args) {
        Employee worker = new Employee("张三");
        Employee manager = new Employee("李四");
        swap(worker,manager);
        System.out.println(worker.name + " " + manager.name); //打印结果仍然是: 张三 李四
    }
}

通过上面的代码,发现形参上的交换,并没有改变实参,所以一定不是引用传递。实际它是地址copy,在swap方法中,我们实际上是改变了地址值,不会影响原实参的地址引用。

我们再来看看一段代码

public class Employee {
    public StringBuilder name=null;
    public Employee(StringBuilder n){
        this.name=n;
    }
    //将两个Employee对象交换
    public static void swap(Employee e1,Employee e2){
        e1.name.append("交换");
        e2.name.append("交换");
    }

    public static void main(String[] args) {
        Employee worker = new Employee(new StringBuilder("张三"));
        Employee manager = new Employee(new StringBuilder("李四"));
        swap(worker,manager);
        System.out.println(worker.name.toString());
        System.out.println(worker.name.toString()+" "+manager.name.toString()); //张三交换 李四交换
    }
}

结果是改变了实参,用通俗的话就是,相当于有形参实参参数是指向同一个地址的,打个比方就是有两把钥匙,两把钥匙都可以进入房子,备用钥匙进去,把电冰箱换成了洗衣机,然后主要钥匙再进去肯定是电冰箱换成了洗衣机。但是第一段代码的情况是这样的,有两把钥匙,备用钥匙又重新进锅炉,融化,变成了可以打开其他房子的钥匙,把其他房子的电冰箱换成了洗衣机,肯定是不会影响到主要钥匙的房子的。判断是否发生改变的核心就是看看是否发生了地址的改变。

17、类的初始化顺序

  1. 初始化父类的静态成员
  2. 初始化父类的静态代码块
  3. 初始化子类的静态成员
  4. 初始化子类的静态代码块
  5. 初始化父类的非静态成员
  6. 初始化父类的非静态代码块
  7. 初始化父类的构造方法
  8. 初始化子类的非静态成员
  9. 初始化子类的非静态代码块
  10. 初始化子类的构造方法

(静态成员 -> 静态代码块) ->( 非静态成员变量 -> 非静态代码块 – > 构造方法)

18、++a 和 a++

++a:先自己+1,再参与运算

a++:参与运算再自己+1

我们看看++a和a++的操作数栈,上代码:

public class Demo {
    public static void main(String[] args) {
        int a = 1;
        // 1 + 3
        int b = a++ + ++a;
        System.out.println(b); // 4
        System.out.println(a); // 3
    }
}

操作数栈:

 0 iconst_1  // 入栈一个1的值
 1 istore_1  // a存入局部变量表第一个位置
 2 iload_1   // 加载局部变量表第一个位置到栈 a = 1
 3 iinc 1 by 1 // 局部变量表第一个位置自增+1,增加前a=1,增加后a=2
 6 iinc 1 by 1 // 局部变量表第一个位置自增+1,此时 a=2,再自增+1, a=3
 9 iload_1   // 加载局部变量表第一个位置 a=3
10 iadd         // 相加
11 istore_2 // b存入到局部变量表2的位置
12 getstatic #2  //打印
15 iload_2
16 invokevirtual #3
19 return

18、jdk8特性

Lambda

JDK7之前有些情况,我们需要实现一个接口作为参数传入,我们不得不,写一个类来实现接口,而这个接口我们只需要用一次,代码会变得臃肿,lambda的到来,就是为了解决这个问题。

在lamdba没有出现之前,我们想要实现一个接口只有一个方法的时候,从繁到简的演变过程:

@FunctionalInterface
public interface LambdaInterface {
    void test();
}
public interface Run {
    void test(LambdaInterface);
}

1、定义一个专门的类来实现

public class LamdbaImpl implements LambdaInterface {
    @Override
    public void test() {

    }
}
public class LamdbaDemo {
    public static void main(String[] args) {
        Run.test(new LamdbaImpl())
    }
}

2、静态成员内部类

public class LamdbaDemo {
    static class LamdbaInner implements LambdaInterface {
        @Override
        public void test() {

        }
    }
    public static void main(String[] args) {
        Run.test(new LamdbaInner())
    }
}

3、局部内部类

public class LamdbaDemo {
    public static void main(String[] args) {
        class LamdbaInner implements LambdaInterface {
            @Override
            public void test() {

            }
        }
        Run.test(new LamdbaInner())
    }
}

4、匿名内部类

public class LamdbaDemo {
    public void test() {
        LambdaInterface lambdaInterface = new LambdaInterface() {
            @Override
            public void test() {

            }
        };
        Run.test(lambdaInterface)
    }
}

5、lamdba

public class LamdbaDemo {
    public void test() {
        Run.test(()->{

        })
    }
}

使用lamdba会可以让我们的代码简洁很多,但是同时也会降低可读性,阿里巴巴开发手册中,规定了不允许用lamdba。

tips:在接口中添加了 @FunctionalInterface 的接口,只允许有一个抽象方法,否则编译器也会报错,可以拥有若干个默认方法。

注意点:lamdba内部访问外部方法内的变量必须是final的

例如:

public class LamdbaDemo {
    public static void main(String[] args) {
        int i = 1;
        new Thread(()-> {
            i++; // error
            System.out.println(i);
        }).start();
    }
}
lamdba方法引用
  1. 引用静态方法: 引用静态方法,接口 = Class名::静态方法名,如果接口的返回类型为void,静态方法的返回类型可以为任意的,如果接口的返回类型不为void,静态方法的返回类型需要和接口一致。接口和静态方法的参数类型,顺序必须一样。
public class LamdbaDemo {
    public static void main(String[] args) {
        // Person person = food -> {
        //    LamdbaDemo.eat(food);
        // };
        Person person = LamdbaDemo::eat;
        person.eat("1");
    }
    static String eat(String food) {
        System.out.println(food);
        return food;
    }
}

interface Person {
    void eat(String food);
}
  1. 引用实例方法: 引用实例方法,接口 = Class名::成员方法名,如果接口的返回类型为void,成员方法的返回类型可以为任意的,如果接口的返回类型不为void,静态方法的返回类型需要和接口一致。接口和方法的参数类型,从第二开始算起,顺序必须一样,因为第一个参数是实例对象。
public class LamdbaDemo {
    public static void main(String[] args) {
        Person person = LamdbaDemo::eat;
        person.eat(new LamdbaDemo(), "niu");
    }

    public String eat(String food) {
        System.out.println(food);
        return food;
    }
}

interface Person {
    void eat(LamdbaDemo lamdbaDemo, String food);
}
  1. 引用this
    引用this和实例方法的区别就是,实例就是this,可以省略不写
public class LamdbaDemo {
    public void test() {
        Person person = this::eat;
        person.eat("niu");
    }
    public String eat(String food) {
        System.out.println(food);
        return food;
    }
}

interface Person {
    void eat(String food);
}

Stream API

stream是优化集合处理的优化,它是链式的,对于处理数据比较大的时候,效率很高,对于数据量比较小,直接使用普通的for效率比较高

Stream和Collection集合的区别:

  • Collection是一种静态的内存数据结构,而Stream是有关计算的
  • 前者是主要面向内存的,存储在内存中;后者主要是面向CPU,通过CPU实现计算.

  • 集合讲的是数据,Stream讲的是计算

串行Stream:

这位老哥写的还可以,点击跳转

并行Stream:

多个线程来处理流,将一个大任务,分而治之分成很多个线程去执行(fork/join原理)

获取并行流的方式:

  1. 通过已有的串行流获取并行流
List integers = Arrays.asList(1,2,3,4);
Stream stream = integers.stream();
// 通过已有的串行流获取并行流
Stream parallel = stream.parallel();
  1. 直接获取
List integers = Arrays.asList(1,2,3,4);
// 直接获取
Stream stream = integers.parallelStream();

并行流的线程安全问题:

ArrayList integers = new ArrayList<>();
// 添加一万个数据到integers
for (int i = 0; i < 10000; i++) {
  integers.add(new Random().nextInt(1000));
}
ArrayList integers2 = new ArrayList<>();
// 获取integers的并行流
integers.parallelStream().forEach(x -> {
  // Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException
  integers2.add(x);
});
System.out.println(integers2.size());

解决方式:

  1. 加锁
  2. 使用并发容器
  3. 使用collect生成List
并行Stream 原理(frok join pool):

Fork/Join框架是Java 7提供的一个用于并行执行任务的框架, 核心思想就是把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果

Fork/Join框架使用一个巧妙的算法来平衡线程的负载,称为 工作窃取(work-stealing)算法。工作窃取的运行流程图如下:

javaSE 温故而知新

fork join属于并发编程系列:看这篇文章,点击跳转

Optional类

optional类是为了解决我们日常开发中多嵌套判断是否为null而存在的,看一个例子:

if (user != null) {
    Address address = user.getAddress();
    if (address != null) {
        Country country = address.getCountry();
        if (country != null) {
            String isocode = country.getIsocode();
            if (isocode != null) {
                return isocode.toUpperCase();
            }
        }
    }
}

这样的代码非常的难维护,如果我们换成Optional

首先,重构类,使其 getter 方法返回 Optional 引用:

public class User {
    private Address address;

    public Optional getAddress() {
        return Optional.ofNullable(address);
    }

    // ...

}
public class Address {
    private Country country;

    public Optional getCountry() {
        return Optional.ofNullable(country);
    }

    // ...

}

现在我们可以这样写

User user = new User("anna@gmail.com", "1234");
String result = Optional.ofNullable(user)
  .flatMap(u -> u.getAddress())
  .flatMap(a -> a.getCountry())
  .map(c -> c.getIsocode())
  .orElse("default");

方法:

javaSE 温故而知新

日期时间API

简单来说就是。jdk7之前的日期api不健全,线程不安全,不丰富,现在新增了几个类,都是线程安全的

  1. LocalDate
  2. LocalTime
  3. LocalDateTime
  4. Instant
  5. Duration 计算时间差
  6. Period 计算日期差
  7. TemporalAdjuster 时间调节器。比如,获得下个星期日,当月的最后一天或下一年的第一天的日期
  8. ZonedDateTime 支持时区的日期时间类

可以很清晰的看出ZonedDateTime相当于LocalDateTime+ZoneId

javaSE 温故而知新

这篇文章写的很好:点击跳转

19、枚举类

如果我们需要定义一组常量,最好是是使用枚举类
特点:可以进行排序,构造方法是私有的,不能再继承类。

javaSE 温故而知新

java集合

文章太长了,放在我另一篇博客中了,点击跳转

Java多线程

待更新

java IO

待更新

java 反射

待更新

陆续更新…

Original: https://www.cnblogs.com/isyuesen/p/16247492.html
Author: yuesen
Title: javaSE 温故而知新

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/620372/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • java时间戳与Date相互转换、日期格式化、给日期加上指定时长、判断两时间点是否为同一天

    https://blog.csdn.net/heng615975867/article/details/36016617 愿你遍历山河 仍觉人间值得 posted on2019-0…

    Java 2023年5月29日
    089
  • 【声音工厂】微信小程序开发记录 声音播放操作

    以下js 实现了微信小程序播放 停止 暂停等 音频播放。 import { formatTime } from "./index"; /** * 通用声音播放器…

    Java 2023年6月8日
    084
  • 二. 手写SpringMVC框架

    1 新建DispatcherServlet 1.2 在src目录下,新建applicationContext.xml 1.3 在 Dispatcher S ervlet 的构造方法…

    Java 2023年6月16日
    050
  • Java学习 (八)基础篇 运算符

    运算符 基本运算符 1.一元基础运算(重点) 一元运算符 (a++ / ++a) (a– / –a) 2.二元基础运算 基础 计算返回值类型 关系运算 幂运…

    Java 2023年6月8日
    096
  • Spring Boot 入门(十一)使用Schedule

    在启动类上加上@EnableScheduling注解 @SpringBootApplication @EnableScheduling //开启定时功能的注解,放在主入口 publ…

    Java 2023年6月5日
    097
  • ThreadLocal 详解

    一、ThreadLocal 简介 ThreadLocal实例通常作为静态的私有的(private static)字段出现在一个类中,这个类用来关联一个线程。ThreadLocal是…

    Java 2023年6月13日
    070
  • Java实现批量下载《神秘的程序员》漫画

    后来就想下载下来,但是一张一张的点击右键”另存为”,还有很多时候要点击”下一页,”确实让人淡疼。就想着写个程序搞定,自认确实水平一般…

    Java 2023年5月29日
    082
  • 集合框架——LinkedList集合源码分析

    示例代码 底层代码 第1步(初始化集合) 第2步(往集合中添加一个元素) 第3步(往集合中添加第二个元素) 第4步(往集合中添加第三个元素) LinkedList添加元素流程示意图…

    Java 2023年6月15日
    065
  • 如何封装第三方API

    日常开发中,少不了对第三方api的封装。api封装的好坏绝定了后期维护的难度以及使用api的开发人员是否抱怨。比如:有一天第三方api的域名变了。或者自己封装的api没有参数说明,…

    Java 2023年5月29日
    0153
  • docker内的服务无法获取用户真实IP

    背景:MySQL 数据库和Redis运行在宿主机上(Linux),server运行在docker内,web运行在Nginx内(Nginx运行在docker内),获取的用户IP为10…

    Java 2023年6月8日
    092
  • SpringBoot自定义starter

    一、starter的构成 xxx-starter—–>xxx-starter-autoconfigurer 启动器—–>…

    Java 2023年5月30日
    084
  • Java_深度剖析ConcurrentHashMap

    本文基于Java 7的源码做剖析。 多线程环境下,使用Hashmap进行put操作会引起死循环,导致CPU利用率接近100%,所以在并发情况下不能使用HashMap。虽然已经有一个…

    Java 2023年5月29日
    057
  • Spring-Cloud-Alibaba系列教程(一)Nacos初识

    前言 在 2020&#x5E74;即将开启SpringCloudAlibaba的专题,希望2020年共同学习进步。 学习资料 文档 Naco文档 程序猿DD Spring …

    Java 2023年6月10日
    0100
  • Spring注解是如何生效的?

    现在大部分开发已经采用Spring Boot了,少了很多配置文件,方便了许多。以前在使用注解,比如@Autowired、@Resource 或者事务相关的一些注解时,我们会首先在配…

    Java 2023年5月30日
    073
  • JVM内存分配和垃圾回收

    一、JVM堆分代 1、JVM堆被分为了 年轻代和 老年代。年轻代的GC过程称为Yong GC,速度快较频繁。老年代的GC过程称为Full GC,速度较慢应该尽量避免。 2、对象被创…

    Java 2023年6月8日
    093
  • 程序员要知道的22个学习网站

    点击标题即可直达链接网址 GitHub是一个面向开源及私有软件项目的托管以及在线软件开发平台,用于存储、跟踪和协作软件项目,开发者能够上传自己的代码文件,并与其他开发者在开源项目上…

    Java 2023年6月15日
    072
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球