当前位置: 首页 > news >正文

Java接口(二)

1. 接口使用实例

给对象数组排序

// 步骤1:定义学生类(需要排序的对象)
class Student {
    String name;    // 学生姓名
    int age;        // 学生年龄
    double score;   // 考试成绩

    // 构造方法:创建学生对象时初始化数据
    public Student(String name, int age, double score) {
        this.name = name; // 给name字段赋值
        this.age = age;// 给age字段赋值
        this.score = score;// 给score字段赋值
    }
    // 重写toString方法:方便打印学生信息
    @Override
    public String toString() {
        return "[" + this.name + "|" + this.age + "|" + this.score + "]";

    }
}

再给定一个学生对象数组, 对这个对象数组中的元素进行排序(按分数降序).

Student[] students = {
                new Student("张三", 20, 88.5),
                new Student("李四", 19, 92.0),
                new Student("王五", 22, 85.0),
                new Student("赵六", 25, 96.5)
        };

数组我们有一个现成的 sort 方法, 能否直接使用这个方法排序呢?

Arrays.sort(students);
System.out.println(Arrays.toString(students));
 
// 运行出错, 抛出异常.
Exception in thread "main" java.lang.ClassCastException: Student cannot be cast to java.lang.Comparable

发现不能,和普通的整数不一样, 两个整数是可以直接比较的, 大小关系明确. 而两个学生对象的大小关系怎么确定?

方法一:额外让Student实现Comparator接口,并实现其中的compare方法。

// 步骤1:定义学生类(需要排序的对象)
class Student {
    String name;    // 学生姓名
    int age;        // 学生年龄
    double score;   // 考试成绩

    // 构造方法:创建学生对象时初始化数据
    public Student(String name, int age, double score) {
        this.name = name; // 给name字段赋值
        this.age = age;// 给age字段赋值
        this.score = score;// 给score字段赋值
    }
    // 重写toString方法:方便打印学生信息
    @Override
    public String toString() {
        return "[" + this.name + "|" + this.age + "|" + this.score + "]";

    }
}
// 步骤2:创建比较器(实现Comparator接口)
// 比较器1:年龄比较器,按年龄从小到大排序
import java.util.Comparator;
class AgeComparator implements Comparator<Student> {
    //实现Comparator接口,必须要实现compare方法
    @Override
    public int compare(Student s1, Student s2) {
        //compare方法	核心比较逻辑,返回负/零/正数决定排序顺序
        /* 比较规则说明:
           如果s1的年龄 < s2的年龄 → 返回负数 → s1排在前面
           如果s1的年龄 > s2的年龄 → 返回正数 → s2排在前面
           如果年龄相同 → 返回0 */

        // 年龄差比较法(升序)
        // 示例:s1.age=20,s2.age=19 → 20-19=1(正数)→ s1排在s2后面
        return s1.age - s2.age; // 直接相减实现升序
    }
}
// 比较器2:成绩比较器,按成绩从高到低排序
import java.util.Comparator;
class ScoreComparator implements Comparator<Student> {
    @Override
    public int compare(Student s1, Student s2) {
        /* 比较规则说明:
           使用Double.compare比较两个double值
           Double.compare(a, b) 返回:
               -1 如果a < b
                1 如果a > b
                0 如果相等
           添加负号使排序方向反转 */

        // 使用Double类自带的比较方法
        // 例如:Double.compare(88.5, 92.0) → 返回-1
        // 添加负号反转顺序 → 返回1 → 实现降序
        return -Double.compare(s1.score, s2.score);
    }
}
// 比较器3:姓名比较器,按姓名拼音顺序排序
import java.util.Comparator;
class NameComparator implements Comparator<Student> {
    @Override
    public int compare(Student s1, Student s2) {
        // 使用String的compareTo方法
        // "张三".compareTo("李四") → 正数("张"的拼音在"李"之后)
        return s1.name.compareTo(s2.name);
    }
}

测试类

import java.util.Arrays;
public class Main {
    public static void main(String[] args) {
        // 初始化学生数组
        Student[] students = {
                new Student("张三", 20, 88.5),
                new Student("李四", 19, 92.0),
                new Student("王五", 22, 85.0),
                new Student("赵六", 25, 96.5)
        };

        // 打印原始数据
        System.out.println("========== 原始数据 ==========");
        printStudents(students);

        // 使用不同比较器进行排序演示
        System.out.println("\n====== 按年龄升序排列 ======");
        Arrays.sort(students, new AgeComparator());//创建比较器对象 new AgeComparator()
        //Arrays.sort()	通用排序方法,通过传入不同的Comparator实现不同排序规则
        //允许通过接口类型(Comparator)操作不同的比较器实现类 --多态
        printStudents(students);

        System.out.println("\n===== 按成绩降序排列 =====");
        Arrays.sort(students, new ScoreComparator());
        printStudents(students);

        System.out.println("\n===== 按姓名拼音排序 =====");
        Arrays.sort(students, new NameComparator());
        printStudents(students);
    }

    // 辅助方法:打印学生数组
    private static void printStudents(Student[] students) {
        for (Student s : students) {
            System.out.println(s);// 自动调用toString()方法
        }
    }
}
/*
========== 原始数据 ==========
        [张三|20|88.5]
        [李四|19|92.0]
        [王五|22|85.0]
        [赵六|25|96.5]

        ====== 按年龄升序排列 ======
        [李四|19|92.0]
        [张三|20|88.5]
        [王五|22|85.0]
        [赵六|25|96.5]

        ===== 按成绩降序排列 =====
        [赵六|25|96.5]
        [李四|19|92.0]
        [张三|20|88.5]
        [王五|22|85.0]

        ===== 按姓名拼音排序 =====
        [张三|20|88.5]
        [李四|19|92.0]
        [王五|22|85.0]
        [赵六|25|96.5]

*/

方法二额外指定Student 类实现 Comparable 接口, 并实现其中的 compareTo 方法。

// 学生类实现Comparable接口
class Student implements Comparable<Student>{
    String name;    // 学生姓名
    int age;        // 学生年龄
    double score;   // 考试成绩

    // 构造方法:创建学生对象时初始化数据
    public Student(String name, int age, double score) {
        this.name = name; // 给name字段赋值
        this.age = age;// 给age字段赋值
        this.score = score;// 给score字段赋值
    }
    // 重写toString方法:方便打印学生信息
    @Override
    public String toString() {
        return "[" + this.name + "|" + this.age + "|" + this.score + "]";
    }
    // 实现Comparable接口的compareTo方法
    @Override
    public int compareTo(Student o) {
        return this.age - o.age;
    }
}

测试类

import java.util.Arrays;
public class Main {
    public static void main(String[] args) {
        Student[] students = {
                new Student("张三", 20, 88.5),
                new Student("李四", 19, 92.0),
                new Student("王五", 22, 85.0),
                new Student("赵六", 25, 96.5)
        };
        Arrays.sort(students);// 调用排序
        for (Student s : students) {
            System.out.println(s);// 打印每个学生信息
        }
    }
}
/*输出:
        [李四|19|92.0]
        [张三|20|88.5]
        [王五|22|85.0]
        [赵六|25|96.5]*/

混合使用两种方式

class Student implements Comparable<Student> {
    String name;    // 学生姓名
    int age;        // 学生年龄
    double score;   // 考试成绩

    // 构造方法:创建学生对象时初始化数据
    public Student(String name, int age, double score) {
        this.name = name; // 给name字段赋值
        this.age = age;// 给age字段赋值
        this.score = score;// 给score字段赋值
    }

    // 重写toString方法:方便打印学生信息
    @Override
    public String toString() {
        return "[" + this.name + "|" + this.age + "|" + this.score + "]";
    }

    @Override
    // 实现Comparable接口的compareTo方法
    public int compareTo(Student o) {
        return this.age - o.age;
    }
}
// 额外定义成绩比较器
import java.util.Comparator;
class ScoreComparator implements Comparator<Student> {
    @Override
    public int compare(Student s1, Student s2) {
        return -Double.compare(s1.score, s2.score);
    }
}

测试类

public class Main {

    public static void main(String[] args) {
        Student[] students = {
                new Student("张三", 20, 88.5),
                new Student("李四", 19, 92.0),
                new Student("王五", 22, 85.0),
                new Student("赵六", 25, 96.5)
        };
        System.out.println("-- 自然排序(年龄升序)--");
        Arrays.sort(students); // 使用Comparable
        print(students);

        System.out.println("\n-- 自定义排序(成绩降序)--");
        Arrays.sort(students, new ScoreComparator()); // 使用Comparator
        print(students);
    }

    public static void print(Student[] students) {
        for (Student s : students) {
            System.out.println(s);// 自动调用toString()方法
        }
    }
}
/*
运行:
        -- 自然排序(年龄)--
        [李四|19|92.0]
        [张三|20|88.5]
        [王五|22|85.0]
        [赵六|25|96.5]

        -- 自定义排序(成绩)--
        [赵六|25|96.5]
        [李四|19|92.0]
        [张三|20|88.5]
        [王五|22|85.0]
*/

两种方式区别

对比ComparableComparator
接口位置在类内部实现独立的外部比较器类
排序方法compareTo(Student o)compare(Student s1, Student s2)
调用方式Arrays.sort(数组)Arrays.sort(数组,比较器实例)
排序规则数量只能定义一种自然排序规则可以定义多个不同的排序规则

Comparable:内置于被比较类中

class Student implements Comparable<Student> { ... }

Comparator:独立于被比较类外

class ScoreComparator implements Comparator<Student> { ... }

Comparable 的 compareTo 方法:

public int compareTo(Student other) {
    // 比较当前对象(this)和另一个对象(other)
}

Comparator 的 compare 方法:

public int compare(Student s1, Student s2) {
    // 比较两个独立对象s1和s2
}

2. Clonable 接口和浅拷贝深拷贝

Java 中内置了一些很有用的接口, Clonable 就是其中之一。Object 类中存在一个 clone 方法, 调用这个方法可以创建一个对象的 “拷贝”. 但是要想合法调用 clone 方法, 必须要先实现 Clonable 接口, 否则就会抛出 CloneNotSupportedException 异常.

2.1 浅拷贝

【定义】

  1. 复制对象本身及其基本类型字段。
  2. 新旧对象共享同一引用对象。
  3. 修改引用字段会影响原对象。
// Person类实现Cloneable接口(允许克隆)
class Person implements Cloneable {
    String name;// 基本类型字段(直接复制值)
    String[] hobbies;  // 引用类型字段

    public Person(String name, String[] hobbies) {
        this.name = name;
        this.hobbies = hobbies;
    }

    // 重写 clone() 方法实现浅拷贝
    @Override
    protected Object clone() throws CloneNotSupportedException {
    	// 调用Object类的默认克隆方法(浅拷贝)
        // 仅复制Person对象本身,hobbies数组仍共享同一引用
        return super.clone();
    }

    @Override
    public String toString() {
        return name + "-" +  Arrays.toString(hobbies);
    }
}

测试类

public class Main {
    public static void main(String[] args) throws CloneNotSupportedException {
        String[] hobbies = {"打球","阅读"};
        // 原始对象
        Person original = new Person("赵六",hobbies);
        System.out.println("原始对象:"+ original);
        //克隆对象
        Person cloned = (Person) original.clone();
        System.out.println("克隆对象:" + cloned);
        // 修改克隆对象的字段
        cloned.name = "王五"; // 修改基本类型字段(仅影响克隆对象)
        cloned.hobbies[0] = "打游戏";// 修改引用类型字段(影响原始对象)
        System.out.println("----------修改克隆对象后----------");
        System.out.println("原始对象:"+ original);
        System.out.println("修改克隆对象: " + cloned);
    }
}
/*
输出:
        原始对象:赵六-[打球, 阅读]
        克隆对象:赵六-[打球, 阅读]
        ----------修改克隆对象后----------
        原始对象:赵六-[打游戏, 阅读]
        修改克隆对象: 王五-[打游戏, 阅读]
*/

【关键问题】
修改 cloned.hobbies 导致 original.hobbies 同步变化
原因:数组 hobbies 是引用类型,浅拷贝仅复制其内存地址。修改引用类型字段会影响所有共享该引用的对象。

2.2 深拷贝

【定义】

  1. 递归复制对象及其所有引用指向的子对象,生成完全独立的对象树。
  2. 克隆对象与原始对象不共享任何引用类型数据。
  3. 修改拷贝后的对象不会影响原对象。
// 地址类(实现Cloneable接口)
class Address implements Cloneable {
    String city;
    String street;

    public Address(String city, String street) {
        this.city = city;
        this.street = street;
    }
	// 重写浅拷贝方法
    @Override
    public Object clone() throws CloneNotSupportedException {
        return super.clone(); // Address类只有基本类型字段,浅拷贝已足够
    }

    @Override
    public String toString() {
        return city + "市" + street + "路";
    }
}
class DeepPerson implements Cloneable {
    String name; // 基本类型字段(直接复制值)
    String[] hobbies; // 引用类型字段(数组)
    Address address;  // 嵌套引用类型字段(对象)

    public DeepPerson(String name, String[] hobbies, Address address) {
        this.name = name;
        this.hobbies = hobbies;
        this.address = address;
    }

    //实现深拷贝
    @Override
    protected Object clone() throws CloneNotSupportedException {
		 // 1. 先调用Object.clone()进行浅拷贝(复制name字段)
        DeepPerson cloned = (DeepPerson) super.clone();
         // 2. 深拷贝数组:创建新数组并复制元素
        cloned.hobbies = Arrays.copyOf(this.hobbies, this.hobbies.length); 
        // 3. 深拷贝嵌套对象:调用Address的clone方法
        cloned.address = (Address) this.address.clone(); 
        return cloned;
    }

    @Override
    public String toString() {
        return name + "- 爱好:" +  String.join(",", hobbies) + "" + "-" + "地址:" + address;
    }
}

测试类

public class Main {
    public static void main(String[] args) throws CloneNotSupportedException {
    	// 初始化数据
        String[] hobbies = {"打球", "阅读"};
        Address address = new Address("北京", "长安");
         // 创建原始对象
        DeepPerson original = new DeepPerson("赵六", hobbies, address);
        System.out.println("原始对象:" + original);
        // 执行深拷贝
        DeepPerson cloned = (DeepPerson) original.clone();
        System.out.println("克隆对象:" + cloned);
        // 修改克隆对象的所有类型字段
        cloned.name = "王五";// 修改基本类型字段(不影响原对象)
        cloned.hobbies[0] = "游戏";// 修改数组字段(不影响原对象)
        cloned.address.city = "上海"; // 修改嵌套对象字段(不影响原对象)
        System.out.println("----------修改克隆对象后----------");
        System.out.println("原始对象: " + original);
        System.out.println("修改克隆对象: " + cloned);
    }
}
/*
输出:
        原始对象:赵六- 爱好:打球,阅读-地址:北京市长安路
        克隆对象:赵六- 爱好:打球,阅读-地址:北京市长安路
        ----------修改克隆对象后----------
        原始对象: 赵六- 爱好:打球,阅读-地址:北京市长安路
        修改克隆对象: 王五- 爱好:游戏,阅读-地址:上海市长安路*/

【相对于浅拷贝关键改进】

  1. 修改 cloned.hobbies 和 cloned.address 不会影响原对象
  2. 原因:数组和 Address 对象均被完全复制

2.3 一个简单易懂区别浅拷贝深拷贝示例

【浅拷贝】

// Money类:包含一个公有字段的简单数据类
class Money {
    // 公有字段,存储金额数值
    public double m = 88.8; // 初始值为88.8
}
// Person类:实现Cloneable接口表示支持克隆
class Person implements Cloneable {
    // 公有字段,持有Money对象的引用
    public Money money = new Money(); // 初始化时创建Money对象

    // 重写clone方法(浅拷贝)
    @Override
    protected Object clone() throws CloneNotSupportedException {
        // 调用Object类的clone方法(浅拷贝)
        // 仅复制Person对象本身,不会复制其引用的Money对象
        return super.clone();
    }
}
public class Main {
    public static void main(String[] args) throws CloneNotSupportedException {
        // 创建原始Person对象
        // person1.money指向Money对象A(地址假设0x100)
        Person person1 = new Person();

        // 克隆对象(浅拷贝)
         // person2.money仍指向Money对象A(地址0x100)
        Person person2 = (Person) person1.clone();

        // 打印克隆操作前的数据
        System.out.println("通过person2修改前的结果");
        System.out.println(person1.money.m); // 输出Money对象A的值:88.8
        System.out.println(person2.money.m); // 输出Money对象A的值:88.8

        //  修改克隆对象的数值
        person2.money.m = 99.9; // 修改的是Money对象A的值

        // 打印修改后的数据
        System.out.println("通过person2修改后的结果");
        System.out.println(person1.money.m); // 输出Money对象A的新值:99.9
        System.out.println(person2.money.m); // 输出Money对象A的新值:99.9
    }
}

发现:修改 person2.money.m 会影响 person1.money.m
【深拷贝】

// Money类:包含一个公有字段的简单数据类
class Money {
    // 公有字段,存储数值
    public double m = 88.8; // 初始值为 88.8
}
// Person类:实现Cloneable接口表示支持克隆
class Person implements Cloneable {
    public String name;//基本类型字段
    public Money money = new Money(); // 引用类型字段

    // 构造函数:初始化姓名
    public Person(String name) {
        this.name = name;
    }

    // 重写clone方法(实现深拷贝)
    @Override
    protected Object clone() throws CloneNotSupportedException {
        // 1. 调用Object.clone()进行浅拷贝:复制name字段(基本类型),money字段(引用类型)仍指向原对象
        Person cloned = (Person) super.clone();
        // 2. 深拷贝核心操作--处理每个引用类型字段:为克隆对象创建新的Money实例
        cloned.money = new Money();  // 创建新的Money对象
        cloned.money.m = this.money.m;  // 复制数值(值相同)
        return cloned;//返回深拷贝后的对象
    }
}

测试类

public class Main {
    public static void main(String[] args) throws CloneNotSupportedException {
        // 创建原始Person对象

        // person1.money指向内存中的Money对象A(地址假设为0x100)
        Person person1 = new Person("张三");

        // 克隆对象(触发深拷贝)
        // person2.money指向新Money对象B(地址0x200)
        Person person2 = (Person) person1.clone();

        // 打印克隆操作前的数据
        System.out.println("通过person2修改前的结果");
        System.out.println(person1.money.m); // 输出原对象A的值:88.8
        System.out.println(person2.money.m); // 输出新对象B的值:88.8(值复制)

        // 修改克隆对象数值
        person2.money.m = 99.9;//修改对象B的值

        // 验证深拷贝结果
        System.out.println("通过person2修改后的结果");
        System.out.println(person1.money.m); // 输出:88.8  --原对象A,person1保持原值88.8
        System.out.println(person2.money.m); // 输出:99.9  --克隆对象B,person2变为99.9
    }
}

在这里插入图片描述

2.4 深拷贝与浅拷贝的区别

区别浅拷贝深拷贝
复制范围仅复制对象本身递归复制对象及所有引用对象
内存关系引用类型字段共享所有字段独立
适用场景不可变对象或无需独立副本时需要完全独立副本的场景
代码实现简单(super.clone())复杂(需要手动处理所有引用字段)

3. 抽象类和接口的区别

抽象类和接口都是 Java 中多态的常见使用方式。
核心区别: 抽象类中可以包含普通方法和普通字段, 这样的普通方法和字段可以被子类直接使用(不必重写), 而接口中的抽象方法, 子类必须重写所有的抽象方法。

区别抽象类接口
实现单继承(一个类只能继承一个抽象类)多实现(一个类可实现多个接口,弥补了单继承,类似于多继承)
设计原则是什么(is - a 关系)能做什么(has - a 或 can-do关系)
子类使用使用extends关键字继承抽象类使用implements关键字实现接口
成员变量可定义普通成员变量只能定义常量(默认public static final)
构造方法可以定义不能定义
关系一个抽象类可以实现若干接口接口不能继承抽象类,但是接口可以使用extends关键字继承多个父接口
适用场景为子类提供通用代码实现和共性行为定义行为规范(多态扩展)

【抽象类和接口混合使用】
抽象类为基,管理公共属性和基础行为
接口为翼,通过多实现扩展多样化能力

下面代码的 Animal被设置为抽象类,是因为Animal类中包含一个 age 这样的属性, 这个属性在任何子类中都是存在的, 因此此处的 Animal 只能作为一个抽象类, 而不应该成为一个接口。
抽象类存在的意义是为了让编译器更好的校验, 像Animal 这样的类一般不会直接使用, 而是使用它的子类,万一不小心创建了 Animal 的实例, 编译器会及时提醒我们。

// 抽象类:定义动物的公共属性(age)和基础行为eat();
public abstract class Animal {
    public int age;// 公共属性,所有子类共享

    //抽象类的构造方法(强制子类必须初始化age属性)
    public Animal(int age) {
        this.age = age;
    }
    // 强制子类实现的基础行为
    public abstract void eat();
}

// 接口:定义飞行能力(特殊能力)
public interface Flyable {
    void fly();
}
// 接口:定义跑步能力(特殊能力
public interface Runable {
    void run();
}
// 接口:定义游泳能力(特殊能力)
public interface Swimmable {
    void swim();
}
// Bird:继承Animal的公共属性,实现Flyable能力
public class Bird extends Animal implements Flyable{

    // 必须显式调用父类构造方法(抽象类控制子类初始化过程)
    public Bird(int age) {
        super(age);
    }
    // 实现抽象方法:定义鸟类具体的进食方式
    @Override
    public void eat() {
        System.out.println("鸟吃鸟粮");
    }

    // 实现接口方法:定义飞行能力的具体实现
    @Override
    public void fly() {
        System.out.println("鸟有飞行能力");
    }
}

// Duck:继承Animal的公共属性,实现Swimmable和Runnable能力
public class Duck extends Animal implements Swimmable, Runable {
    //必须显式调用父类构造方法,因为是抽象类父类Animal控制子类构造过程
    public Duck(int age) {
        super(age);
    }
    // 实现抽象方法:定义鸭子具体的进食方式
    @Override
    public void eat() {
        System.out.println("鸭子吃饲料");
    }
    // 实现Swimmable接口方法:游泳能力的具体实现
    @Override
    public void swim() {
        System.out.println("鸭子有游泳能力");
    }

    @Override
    public void run() {
        System.out.println("鸭子可以跑步");
    }
}

测试类

public class Main {
    // 面向接口编程:接收任何具有飞行能力的对象
    public static void flying(Flyable flyable) {
        flyable.fly();// 多态调用
    }
    // 面向接口编程:接收任何具有游泳能力的对象
    public static void swimming(Swimmable swimmable) {
        swimmable.swim();
    }
    // 面向接口编程:接收任何具有跑步能力的对象
    public static void running(Runable runnable) {
        runnable.run();
    }
    public static void main(String[] args) {
        // 创建具体动物实例
        Bird bird = new Bird(2);
        Duck duck = new Duck(5);
        // 调用基础行为方法
        bird.eat();//输出:鸟吃鸟粮(继承自Animal)
        duck.eat();//输出:鸭子吃饲料(继承自Animal)

        // 通过接口调用特殊能力
        flying(bird);//输出:鸟有飞行能力(Flyable接口)
        //flying(duck);  // 编译错误:Duck未实现Flyable接口
        swimming(duck);//输出:鸭子有游泳能力(Swimmable接口)
        running(duck);//输出:鸭子可以跑步(Runnable接口)
    }
}

如果再添加一个机器人类,这个类不继承Animal

//机器人类:体现了接口在跨类层次定义行为的能力
public class Robot implements Runable {
    //Runnable接口不再局限于Animal继承体系。无论是生物(如Duck)还是非生物(如Robot),只要实现Runnable接口即可具备跑步能力。

    @Override
    public void run() {
        System.out.println("机器人有跑步能力");
    }
}

测试类调用

//因为running()方法原本设计为接收Runnable接口类型参数
//所以新增的Robot可直接调用,无需任何调整
Robot robot = new Robot();
running(robot);  // 输出:机器人有跑步能力

相关文章:

  • dp4-ai 安装教程
  • 化繁为简解决leetcode第1289题下降路径最小和II
  • 深度解剖 TCP 三次握手 四次挥手
  • LXC 导入多Linux系统
  • mybatis-genertor(代码生成)源码及扩展笔记
  • stm32F103C8T6引脚定义
  • python 的gui开发示例
  • MySQL Online DDL:演变、原理与实践
  • RAG 文档嵌入到向量数据库FAISS
  • 前沿科技:具身智能(Embodied Intelligence)详解
  • 利用cusur+claude3.7 angent模式一句提示词生成一个前端网站
  • 阿里拟收购两氢一氧公司 陈航将出任阿里集团钉钉 CEO
  • 【CV/NLP/生成式AI】
  • 二月公开赛Web-ssrfme
  • 4月1号.
  • Redis:主从复制
  • 机器学习+EEG熵进行双相情感障碍诊断的综合评估
  • Git基本操作
  • ThreadLocal用法详解
  • 聊一聊缓存如何进行测试
  • 解放日报:服务国家战略,加快建成科技创新高地
  • 上海:以税务支持鼓励探索更多的创新,助力企业出海
  • 央行就《关于规范供应链金融业务引导供应链信息服务机构更好服务中小企业融资有关事宜的通知》答问
  • 共绘“彩色上海”,IP SH艺术共创沙龙首期圆满举办
  • “女乘客遭顺风车深夜丢高速服务区”续:滴滴永久封禁两名涉事司机账号
  • 华夏幸福:去年营业收入237.65亿元,同比减亏12亿元