【面试题解析--Java基础】回顾与加深,浅浅回顾JAVA常规八股,利用起碎片化时间。

【深度学习新浪潮】手把手教你不花一分的token钱,纯本地部署openclaw 本地轻量开源AI智能体框架Windows 11 + WSL2 + Ollama + OpenClaw 一键部署零代码配置,直接用上本地模型工具调用未来方向:轻量化、插件化、本地生态成熟如果你喜欢本地AI、厌倦了云端限制、想真正拥有一个“听话又能干”的本地助手,OpenClaw 绝对值得现在就上手玩一玩。 阅读详情

一、Java基础

1. final 关键字的作用:

  • 修饰类时,被修饰的类无法被继承。
  • 修饰方法时,被修饰的方法无法被重写。
  • 修饰变量时,变量为常量,初始化后无法重新赋值。

2. static 关键字的作用:

  • 修饰变量和方法时,被修饰的变量和方法是静态的,可以直接通过类来引用,而不需要创建实例。
  • 修饰代码块时,是静态代码块,在类加载时自动加载,只执行一次。
  • 修饰内部类时,是静态内部类,只能访问外部类的静态成员变量和方法。静态内部类可以单独创建。
  • 修饰导入包中的静态方法或变量时,可以直接使用被修饰的方法和变量,而不需要加上所属的类。

3. 基本类型和引用类型的区别:

在Java编程语言中,数据类型可以分为两大类:基本数据类型(又称原始数据类型)和引用数据类型。这两者的区别主要体现在以下几个方面:

存储内容:

  • 基本数据类型:直接存储实际值在栈(Stack)中,例如数值、字符或布尔值。
  • 引用数据类型:存储堆(Heap)内存地址在栈中,该地址指向实际数据所在的位置。

内存分配:

  • 基本数据类型:在变量声明时,系统会在栈上为其分配空间并直接存储值。
  • 引用数据类型:声明引用变量时,栈上分配的空间存放的是对象的内存地址,对象本身的数据存储在堆上。

数据类型种类:

  • 基本数据类型:包括整数类型(byte、short、int、long)、浮点类型(float、double)、字符类型(char)和布尔类型(boolean)。
  • 引用数据类型:包括类(Class)、接口(Interface)、数组(Array)、枚举(Enum)、注解(Annotation)和字符串(String)等。

使用方式:

  • 基本数据类型:可以直接使用算术运算符进行操作,比如加减乘除。
  • 引用数据类型:不能直接使用算术运算符(除了==和!=比较地址),但可以调用其方法和属性。

传递方式:

  • 基本数据类型:作为方法参数传递时,传递的是数据的值(值传递)。
  • 引用数据类型:作为方法参数传递时,传递的是内存地址(引用传递),因此方法内部对对象的修改会影响原始对象。

默认值:

  • 基本数据类型:具有默认值,例如整型的默认值是0,布尔型的默认值是false。
  • 引用数据类型:默认值是null。

性能:

  • 基本数据类型:由于存储在栈上,访问速度相对较快。
  • 引用数据类型:存储在堆上,需要通过栈上的引用访问,速度相对较慢-

注意:在Java中,当谈到引用数据类型的参数传递时,通常指的是“引用传递”(pass by reference),但这可能会引起一些误解。

在Java中,所有参数传递都是按值传递(pass by value),包括引用数据类型。

这意味着当我们将一个引用数据类型的变量传递给方法时,实际上传递的是该变量存储的值的副本,即对象的引用。以下是这个过程的具体解释:

按值传递的本质: 传递的是值的副本。对于基本数据类型,这个值就是数据本身;对于引用数据类型,这个值是对象的引用。

误解引用传递: 有人可能会认为,因为引用数据类型的参数可以改变原始对象的状态,所以Java使用的是引用传递。

举例说明:
假设有一个对象 Person p 存储在堆上,其引用存储在栈上的变量 p 中。
当我们将 p 作为参数传递给方法时,栈上会创建一个引用的副本。
方法内部使用这个副本引用来访问和修改堆上的对象。

示例代码:

public class Person {
    String name;
 
    public Person(String name) {
        this.name = name;
    }
}
 
public void changeName(Person p) {
    p.name = "New Name";
}
 
public static void main(String[] args) {
    Person person = new Person("Original Name");
    changeName(person);
    // person.name 现在是 "New Name"
}

在这个例子中,changeName 方法接收了一个 Person 对象的引用。虽然看起来像是引用传递,但实际上是按值传递了这个引用的副本。这个副本指向与原始引用相同的 Person 对象,所以修改是通过引用副本进行的,但影响到了原始对象。

总结: 在Java中,引用数据类型的参数传递是按值传递的,传递的是对象引用的副本,但由于这个副本和原始引用指向同一个对象,所以看起来像是引用传递。

真正的引用传递(pass by reference)是指将变量的引用传递给方法或函数,且按引用传递传递的不是值的副本,而是实际的引用本身。

4. String是值传递还是引用传递?

在Java中,String是一种特殊的引用数据类型。对于String类型的参数传递,可以认为是按值传递的,但情况稍微有些复杂。

String的特殊性: String是不可变(immutable)的,这意味着一旦创建了一个String对象,其内容就不能改变。因此,任何试图修改String对象内容的操作都会返回一个新的String对象。

参数传递行为: 当我们将一个String对象作为参数传递给方法时,传递的是该String对象的引用的副本。然而,由于String是不可变的,所以方法内部无法直接修改原始的String对象。任何修改操作都会创建一个新的String对象,并将引用副本指向这个新对象。

示例:

public class Main {
   public static void main(String[] args) {
       String original = "Hello";
       changeString(original);
       System.out.println(original);  // 输出仍然是 "Hello"
   }
 
   public static void changeString(String str) {
       str = "World";  // 这不会改变原始的String对象
       System.out.println(str);  // 输出 "World"
   }
}

在这个例子中,changeString方法试图修改传入的String参数。然而,由于String是不可变的,str = "World";实际上是在栈上创建了一个新的String引用,并将其指向一个新的String对象。原始的String对象仍然保持不变,所以main方法中的original变量打印出来的仍然是"Hello"。

总结: 虽然String的参数传递看起来像是引用传递,但由于String是不可变的,所以方法内部无法修改原始的String对象。因此,在某种意义上,String的参数传递可以被认为是按值传递。

5. 接口和抽象类的区别:

  • 相同点:都是上层的抽象层,不能被实例化,都能包含抽象方法。
  • 不同点:
    • 抽象类可以包含非抽象方法,而接口中只能包含抽象方法。
    • 抽象类可以包含普通和静态的成员变量,接口只能包含 public static final 修饰的常量。
    • 一个类只能继承一个抽象类,但可以实现多个接口。
    • 抽象类可以包含构造方法,接口不能包含构造方法。
interface MyInterface {
    void method1(); // Abstract method
}

abstract class MyAbstractClass {
    abstract void method2(); // Abstract method

    void method3() {
        // Concrete method
    }
}

6. 反射是在运行时获取类的相关信息。可以通过 Class 类来获取字段、方法等信息,从而对类进行操作。

在Java中,反射允许我们在运行时获取类的相关信息,并且可以动态地操作类的字段、方法、构造函数等。通过使用Class类,我们可以获取类的各种信息并对其进行操作。

下面是一个简单的示例来说明如何使用反射来获取类的信息:

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class ReflectionExample {
    public static void main(String[] args) throws Exception {
        Class<?> myClass = Class.forName("com.example.MyClass"); // 获取类的 Class 对象

        // 获取类的字段信息
        Field[] fields = myClass.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field.getName());
        }

        // 获取类的方法信息
        Method[] methods = myClass.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method.getName());
        }

        // 创建类的实例并调用方法
        Object obj = myClass.getDeclaredConstructor().newInstance();
        Method myMethod = myClass.getDeclaredMethod("myMethod");
        myMethod.invoke(obj);
    }
}

在这个示例中,我们使用Class.forName方法来获取指定类的Class对象,然后通过该对象可以获取类的字段和方法信息。我们还演示了如何通过反射来创建类的实例,并调用其方法。

需要注意的是,反射是一种功能强大但也复杂的机制,应该谨慎使用。过度依赖反射会导致代码可读性和性能上的问题。因此,在使用反射时需要权衡利弊,并尽量避免滥用。

7. Java 中创建实例对象的初始化顺序:

在Java中,创建实例对象的初始化顺序通常按照以下步骤进行:

  1. 父类的静态变量和静态代码块初始化
  2. 子类的静态变量和静态代码块初始化
  3. 父类的实例变量和代码块按照在类中的声明顺序初始化
  4. 父类的构造函数
  5. 子类的实例变量和代码块按照在类中的声明顺序初始化
  6. 子类的构造函数

这个顺序确保了在创建对象时,各个部分都能够按照正确的顺序得到初始化。这个过程对于理解Java对象创建和初始化非常重要,特别是在涉及到继承关系和多态性的情况下。

8. 获取反射的几种方式:

在Java中,获取反射的几种方式包括使用Class.forName()、对象.getClass()和直接通过类名.class来获取Class对象。这些方式都可以用于获取反射对象并进行动态操作。

  1. Class.forName():
    使用Class.forName()方法可以根据类的全限定名(包括包名)来获取对应的Class对象。

    Class clazz = Class.forName("com.example.YourClass");
    
  2. 对象.getClass():
    在已经存在对象的情况下,可以通过调用对象的getClass()方法来获取对应的Class对象。

    YourClass obj = new YourClass();
    Class clazz = obj.getClass();
    
  3. 直接通过类名.class:
    可以直接通过类名后加上.class来获取对应的Class对象。

    Class clazz = YourClass.class;
    

这些方式都可以用于获取Class对象,然后通过Class对象进行反射操作,例如创建对象、调用方法、访问字段等。根据具体的情况选择合适的方式来获取反射对象,以便实现灵活的编程和动态的操作。

9. 类加载双亲委派模型:

当然可以,以下是完整的内容,包括了9.1和9.2的部分:

9什么是双亲委派模型

在双亲委派模型中,类加载器收到类加载请求时,会按照以下步骤操作:

  1. 检查该类是否已被加载:首先检查这个类是否已经被当前类加载器加载过,如果已经加载过,则直接返回已加载的类。

  2. 委派给父类加载器:如果该类尚未被加载,则当前类加载器会将请求委派给其父类加载器去处理。这一过程会一直上溯到启动类加载器(Bootstrap Class Loader)。

  3. 尝试加载:只有当父类加载器无法完成这个类的加载请求时(例如,该类不在父类加载器的搜索路径中),当前类加载器才会尝试自己加载这个类。

为什么叫双亲委派模型

这个模型被称为“双亲委派”是因为每个类加载器都有一个“父”类加载器,它首先将加载请求委托给这个“父”加载器。这里的“双亲”并不是指生物学上的双亲,而是指在类加载器层次结构中的“父辈”。

双亲委派模型的好处

双亲委派模型有以下几个好处:

  • 避免类的重复加载:通过委派给父类加载器,可以避免同一个类被不同的类加载器多次加载,确保每个类在JVM中只存在一个副本。
  • 保证Java核心API不被篡改:由于Bootstrap Class Loader是位于委派链的最顶端,负责加载Java的核心类库,因此可以确保这些核心类库不会被自定义的类加载器加载,从而保护了Java核心API的安全性和稳定性。

如何打破双亲委派模型

在某些特殊情况下,可能需要打破双亲委派模型。可以通过以下方式实现:

  • 自定义类加载器:通过定义自己的类加载器并重写其loadClass方法,可以改变委派逻辑,实现自定义的类加载行为。
  • 场景举例:例如,在Java EE容器或者某些Web服务器(如Tomcat)中,由于需要实现容器的隔离性或者热替换等特性,会实现自己的类加载器,并不完全遵循双亲委派模型。

综上所述,双亲委派模型是Java类加载机制中的一个重要概念,它通过委派的方式提高了类加载的效率和安全性,但在特定场景下,也可以根据需要进行适当的打破和调整。

public class ClassLoadingExample {
    public static void main(String[] args) {
        ClassLoadingExample example = new ClassLoadingExample();
        ClassLoader appClassLoader = ClassLoader.getSystemClassLoader();
        System.out.println("Application ClassLoader: " + appClassLoader);
        System.out.println("Extension ClassLoader: " + appClassLoader.getParent());
        System.out.println("Bootstrap ClassLoader: " + appClassLoader.getParent().getParent());
    }
}

10. 在重写 equals 方法时通常需要重写 hashCode 方法,以确保相等的对象具有相同的 hashCode 值,避免在集合类中可能出现的问题。

在Java中,如果一个类重写了equals方法以改变两个对象相等的定义,通常也需要重写hashCode方法。以下是需要同时重写这两个方法的原因:

10.1 equals和hashCode方法的关系

在Java中,equals和hashCode方法之间有一个重要的契约,这个契约在java.lang.Object类的文档中有详细的描述:

  • 如果两个对象根据equals(Object)方法返回的结果是相等的,那么调用这两个对象各自的hashCode()方法必须返回相同的整数结果。
  • 如果两个对象根据equals(Object)方法返回的结果是不相等的,那么调用这两个对象各自的hashCode()方法通常(不是必须)应该返回不同的整数结果。

10.2 为什么需要重写hashCode

  • 一致性:当对象的状态没有改变时,多次调用同一个对象的hashCode()方法应该返回相同的值。
  • 相等对象必须有相同的hashCode:如果两个对象相等(即equals方法返回true),它们必须有相同的hashCode值,这是为了保证在使用哈希表(如HashSet、HashMap等)时,这两个对象能够被存储在同一个桶(bucket)中。
  • 不相等对象应该有不同的hashCode:虽然不是必须的,但如果两个对象不相等,它们有不同的hashCode值可以提高哈希表的性能,因为这样可以减少哈希冲突的可能性。

10.3 不遵守契约的问题

如果不遵守这个契约,在集合类(如HashSet、HashMap等)中可能会出现以下问题:

  • 如果两个相等的对象具有不同的hashCode值,那么在哈希表中它们可能会被存储在不同的桶中,这将导致equals方法不会被调用,从而无法正确处理这两个对象(例如,无法删除其中一个对象)。
  • 如果多个不相等的对象具有相同的hashCode值,那么它们都会被映射到同一个桶中,这将增加哈希表的冲突率,导致性能下降。

10.4 如何正确重写hashCode

为了遵守上述契约,重写hashCode方法时,以下是一些通用的指导原则:

  • 确保相同的对象总是返回相同的hashCode值。
  • 确保如果两个对象根据equals方法相等,它们也必须有相同的hashCode值。
  • 尽量使不相等的对象的hashCode值不同,以减少哈希冲突。
  • 通常,hashCode方法会基于对象中用于确定相等性的所有字段来计算哈希值,并且计算方式应该尽可能简单和高效。很多IDE都提供了自动生成hashCode和equals方法的功能,这通常是一个安全且高效的方式。
public class Person {
    private String name;
    private int age;

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        Person person = (Person) obj;
        return age == person.age && Objects.equals(name, person.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

11. 面向对象的特征:

- 封装:将对象的属性和行为封装在一起,隐藏内部细节,提供对外的接口。
- 继承:允许子类继承父类的属性和方法,实现代码复用。
- 多态:同一方法在不同对象上表现出不同的行为。

当然可以,下面是带有英文缩写的设计原则:

1. 抽象

  • 过程抽象:将复杂的操作或行为抽象为一个简单的函数或方法调用。
  • 数据抽象:定义数据类型和可以对这些类型执行的操作,而无需关心数据的具体表示。

2. 封装

  • 封装(Encapsulation):隐藏对象的内部细节,仅对外暴露需要公开的接口。这有助于保护对象的状态不被外部干扰和不恰当的使用。

3. 继承

  • 继承(Inheritance):允许某个类(子类)继承另一个类(父类)的属性和方法,实现代码重用并添加新功能。

4. 多态

  • 多态(Polymorphism):允许不同类的对象对同一消息做出响应,实现同一操作通过不同对象执行不同行为。

扩展的特征和设计原则

  • 单一职责原则(SRP - Single Responsibility Principle):一个类应该只有一个改变的理由。
  • 开放封闭原则(OCP - Open/Closed Principle):软件实体应该对扩展开放,对修改封闭。
  • 里氏替换原则(LSP - Liskov Substitution Principle):子类必须能够替换其父类在程序中的任何位置。
  • 合成/聚合原则(C/A - Composition/Aggregation Principle):优先使用对象组合,而不是类继承。
  • 迪米特法则(LoD - Law of Demeter):一个对象应当对其他对象有尽可能少的了解。

12. StringBufferStringBuilder 的区别:

  • StringBuffer 是线程安全的,使用 synchronized 关键字来保证线程安全,效率较低。
  • StringBuilder 是非线程安全的,效率较高。
public class StringBuilderExample {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder("Hello");
        sb.append(" World");
        System.out.println(sb.toString());
    }
}

13. 浅拷贝和深拷贝:

- 浅拷贝:复制对象时只复制对象本身和其内部基本类型属性的值,而不复制引用类型属性指向的对象。
- 深拷贝:复制对象时会递归地复制所有引用类型属性指向的对象,使得新对象和原对象完全独立。
public class DeepCopyExample {
    public static void main(String[] args) {
        List<String> list1 = new ArrayList<>();
        list1.add("item1");
        list1.add("item2");

        // Shallow copy
        List<String> list2 = new ArrayList<>(list1);
        list2.add("item3");

        // Deep copy
        List<String> list3 = new ArrayList<>(list1.size());
        for (String item : list1) {
            list3.add(new String(item));
        }
        list3.add("item4");

        System.out.println("List1: " + list1);
        System.out.println("List2 (Shallow Copy): " + list2);
        System.out.println("List3 (Deep Copy): " + list3);
    }
}
DOTS 性能基石:为什么传统 Unity 代码难以满足现代游戏需求?(DOTS 系列教程 · 第1篇) 本文探讨了Unity游戏开发中的性能优化问题,指出性能问题不应在最后才考虑,而应贯穿整个开发过程。文章分析了性能问题的三大表现(渲染开销、物理模拟、游戏逻辑),并解释了依赖硬件升级的不可行性。重点剖析了传统Unity代码性能低下的六大根源:垃圾回收卡顿、编译器优化不足、多核利用不足、数据结构和代码缓存不友好、过度抽象等问题。最后指出Unity项目中常见的反模式,如主线程垄断、内存碎片化等,为后续学习DOTS高性能架构解决方案奠定基础 阅读详情

相关推荐

Python内置函数zip()——《Python内置函数手册》Python老吕编著

zip()函数是 Python 中的一个内置函数,用于将多个可迭代对象(如列表、元组、字符串等)中对应的元素打包成一个个元组,然后返回由这些元组组成的迭代器。zip()函数常用于将多个序列并行迭代,或者用于数据对齐。zip()它返回一个迭代器,这意味着你可以逐个获取打包后的元素,而不是一次性将所有元素加载到内存中。如果输入的可迭代对象长度不一致,zip()会以最短的可迭代对象为准,只打包到最短对象的末尾。它可以用来并行迭代多个序列,使得代码更加简洁和高效。在接下来的章节中,我们将详细介绍。

Python老吕的博客 636

面试题解析--JAVA内存】回顾加深浅浅回顾JAVA常规八股利用碎片化时间

在G1垃圾回收器的并发标记阶段,对象引用的修改是正常现象,因为这一阶段允许应用程序的线程垃圾回收器线程同时运行。JMM,即Java内存模型(Java Memory Model),是一个抽象的概念,它描述了Java虚拟机(JVM)在运行Java程序时,如何处理内存中的变量,以及线程如何通过内存进行交互。类的加载过程发生在元数据区,而对象实例的创建发生在堆内存中。通过这种方式,G1垃圾回收器能够有效处理并发标记阶段对象引用的修改,保持垃圾回收的高效性和准确性,也是G1在减少停顿时间方面的优势之一。

Z70769691的博客 985

破盾实录|Vueling航空阿卡迈防护逆向:从503挑战到Cookie生成的全流程拆解

摘要:文章分享了作者在爬取西班牙伏林航空(Vueling)机票数据时,遭遇阿卡迈(Akamai)防护系统的实战经历。起初简单的请求被拦截返回503错误,分析发现阿卡迈通过混淆JS代码实施"挑战-验证"机制,需模拟真实浏览器环境才能获取有效Cookie。作者详细拆解了逆向过程:从抓包分析JS挑战流程,到破解代码混淆和控制流平坦化,最终用Python+Pyppeteer成功模拟浏览器特征,突破防护获取数据。整个过程涉及JS反混淆、环境检测绕过和Cookie生成验证等关键技术点,为类似防护系统

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 1605

Spring 源码系列(23): SpringApplication.run() 启动全流程

本文深入解析了SpringApplication.run()的核心流程,通过源码拆解揭示了从启动到容器就绪的完整生命周期。文章重点分析了三个关键阶段:prepareEnvironment的配置加载逻辑(系统属性>环境变量>配置文件)、createApplicationContext的容器类型推断机制(基于classpath判断Web/Reactive/普通应用),以及callRunners的启动后回调特性(按@Order执行初始化任务)。同时澄清了常见误区,如内嵌Tomcat实际在refresh阶段的onR

不才不才不不才的博客 427

Java 并发灵魂拷问:notify/signal 唤醒顺序是规范还是实现?

本文探讨了Java中Object.notify()和Condition.signal()唤醒线程的顺序问题。关键结论如下: Object.notify(): JVM规范未规定唤醒顺序,HotSpot实现虽采用FIFO(从WaitSet头部取线程),但这属于实现细节而非规范要求 由于synchronized是非公平锁,被唤醒线程需重新竞争锁,最终执行顺序无法保证 严禁业务代码依赖该顺序 Condition.signal(): 严格按FIFO顺序唤醒(AQS等待队列头部线程) 是设计约定,业务可合理依赖该特性

weixin_68315058的博客 364

[Java]-微服务面试题

服务降级是服务自我保护的一种方式,或者保护下游服务的一种方式,用于确保服务不会受请求突增影响变得不可用,确保服务不会崩溃。微服务的负载均衡主要使用了一个组件Ribbon,比如,我们在使用feign远程调用的过程中,底层的负载均衡就是。2,我们还在skywalking设置了告警规则,特别是在项目上线以后,如果报错,我们分别设置了可以给相关负责人。简历上写的微服务,只要是发生了多个服务之间的写操作,都需要进行分布式事务控制。2,在客户端的配置文件中,可以配置某一个服务调用的负载均衡策略(局部)

. 625

Java Spring 批量修改,实体、接口、方法的定义

本文描述了一个批量更新车辆类型的接口实现。该功能通过Controller层接收包含出库单ID列表和车辆类型的请求参数,调用Service层进行处理。实现层采用事务管理,首先验证参数有效性,然后查询对应出库单数据并批量更新车辆类型字段,最后返回操作结果(成功更新记录数或错误信息)。该接口主要用于快递业务中其他出库单的车辆类型批量修改操作,包含完整的参数校验、异常处理和事务管理机制。

LYBWWP 61

简单聊聊 OpenFeign 框架源码

骨架:JDK 动态代理 + 方法元数据 + handler 分发,和 MyBatis 同一套路;主线:调用 → 填 RequestTemplate → 拦截器 → 负载均衡选实例 → Client 执行 → Decoder 解码,异常走 ErrorDecoder/Retryer/fallback;Spring 整合三件事扫描注册 FactoryBean、懒构建代理、给每个客户端独立配置;面试主线。

weixin_47626220的博客 392

并发 13 · 异步编排

摘要:本文探讨了异步编排在秒杀下单场景中的应用,分析了传统Future的局限性,并介绍了CompletableFuture如何通过链式调用解决任务依赖并行问题。文章详细讲解了创建异步任务、串联任务(thenApply/thenCompose)、合并任务(thenCombine/allOf)以及异常处理等核心方法,强调使用独立线程池避免阻塞公共资源。最后结合秒杀案例,展示了如何构建高效、清晰的异步流水线,优化响应时间。全文提供代码示例和选型建议,帮助开发者实现高性能异步流程编排。

记录后端技术的深水区:MySQL、并发、JVM、分布式。原理为主,实战为辅,能少踩一个坑是一个。 406

LangChain4J

Prompt:好比UI层,进行用户交互Langchain4j, Spring AI:好比Controller,调用AI大模型各类AI大模型:好比Service,提供人工智能服务向量数据库:好比Mapper,进行数据存储。

渔阳的博客 194

Spring Boot 实现数据脱敏:自定义注解 + Jackson 序列化器

加了它之后,@Sensitive 就等价于 @JsonSerialize(using = SensitiveJsonSerializer.class) ,Jackson才能识别并触发我们的序列化器。Jackson默认不认识我们自定义的 @Sensitive 注解,@JacksonAnnotationsInside 的作用是:允许把 @JsonSerialize 组合进自定义注解。时,数据库里存的一直是完整值,脱敏是一个展示的动作,而存储层要保护数据应该使用。的这一层比较好,下面是具体实现。

sjkflw121150的博客 215

Spring配置文件

本文系统介绍了配置文件的作用、Spring Boot支持的配置文件格式及其特点。首先阐述了配置文件解决硬编码问题、实现程序灵活配置的核心价值,并以手机字体大小为例说明其应用场景。接着详细讲解了Spring Boot支持的三种配置文件格式(.properties、.yml、.yaml),包括它们的加载优先级和共存规则。最后分别深入分析了properties配置文件的键值对语法、@Value注解读取方式及其冗余信息缺点,以及yml配置文件的基本语法、引号使用规则和优缺点对比,为开发者选择合适的配置文件格式提供参

qq_71356343的博客 258

家政派单系统开发实战:架构设计派单算法指南

家政派单系统是连接用户需求上门服务人员的核心调度平台,其开发难点并不在于简单的CRUD,而是在于如何设计一套能支撑“多角色、多任务类型、高并发抢单”的架构,以及一套能让订单和师傅效率化的派单算法。一旦师傅手动拒绝系统派单,近1小时的接单权重下降50%,防止师傅只接高价单而忽略普通单,导致用户体验受损。建议优先搭建一个可配置化的规则引擎,将派单距离、服务类目、师傅等级做成后台可调整的配置项,这样后期运营调整策略时,无需修改代码。师傅接单后的轨迹追踪,是提升用户体验的关键,也是开发的难点。

zww8949111的博客 324

Java 并发编程筑基篇

Java并发编程基础摘要 本文档系统介绍Java并发编程核心知识,分为基础概念、进阶原理和实战三部分。基础部分涵盖: 进程/线程/协程:操作系统资源分配调度的不同层级单位 并发概念:区分并发/并行、同步/异步等关键术语 线程原理:生命周期、状态转换、上下文切换开销 创建方式:Thread/Runnable/Callable/线程池四种实现 线程安全:可见性、原子性、有序性问题及解决方案 进阶部分深入synchronized、volatile、线程池等核心机制,最后通过实战巩固。适合Java基础复习、面试准

2201_75455813的博客 328

零信任架构实战:基于天远企业年报信息核验构建自动化供应商准入网关

破解供应商准入核查痛点:从传统人工资质初筛到自动化数据穿透 在大型 B2B 供应链采购平台的微服务架构中,供应商准入尽职调查(KYC)是保障平台交易生态健康的核心防线。传统的准入流程往往依赖业务人员手工收取企业营业执照、年度审计报告等纸质或电子扫描件,并登录多平台逐一核对。这种模式不仅流程繁琐、效率极低,而且难以实时防范非存续异常主体或信息不匹配资质的问题,

2501_94042197的博客 227

全国计算机二级Java选择题高频真题20道精选试题解析

全国计算机等级考试二级Java语言程序设计选择题20道高频真题标准试题解析,深度剖析二叉树度数计算、异常捕获匹配、多态向上转型、位运算、集合框架多线程接口。

qq_39121450的博客 218

@Value@ConfigurationProperties注解使用记录

本文探讨了从YAML配置文件中获取Map类型数据的两种方案:使用@Value注解和@ConfigurationProperties注解。作者首先尝试@Value方案,发现其无法直接注入Map且扩展性差,只能获取单个键值。随后转向@ConfigurationProperties方案,但遇到Map键中的冒号被自动过滤的问题。最终解决方案是调整YAML结构为列表形式,并创建包含key-value对的内部类Item,通过转换方法toMap()获取所需Map结构。文章强调了YAML配置项需采用kebab-case(短

AlickLbc的博客 157

Semaphore 源码解析

摘要: Semaphore是Java并发编程中的计数信号量工具,基于AQS(AbstractQueuedSynchronizer)实现,提供共享模式下的线程同步功能。其核心特性包括: 通过acquire/release方法获取/释放许可,许可数量可动态调整; 支持公平/非公平两种模式(FairSync/NonfairSync),公平模式保证先到先得; 内部使用CAS操作和自旋机制保证线程安全; 提供tryAcquire、drainPermits等扩展方法; 任何线程均可释放许可,不要求先获取许可。

赵丙双的博客 202

【DOCKER容器实战】-1Nginx Tomcat

docker容器应用实战

ordinary的博客 363

Java微服务接大模型:3层架构、5个生产问题怎么答

脉脉上有一则Java后端面试复盘:问题从“微服务怎么接大模型”一路追到Agent分层、会话状态、流式响应、工具失败、可观测性和安全。真正的考点不是会不会调用Spring AI,而是能否把不稳定、昂贵且慢的模型调用纳入工程治理。

HanaYao的博客 188

Deep Java Library (DJL) 使用

将 PyTorch 模型转换为 TorchScriptDJL 加载 PyTorch 模型,要求模型必须是格式(.pt或.pth文件)。这是因为 TorchScript 是一种序列化的、可独立于 Python 运行的模型表示。

有的话没说出来之前,你是他的主人,一旦说出来你就成了他的奴隶||想要干好事,别太把自己当人,别把别人太不当人||认识这个人就是开了一扇窗户,就能看到不一样的东西,听到不一样的声音,能让你思考、觉悟,这已经够了 237

AQS深度解析

AQS 是一个抽象类,无法被实例化。它的设计采用了模板方法模式,将获取/释放锁的复杂逻辑(如同步队列的维护、线程的阻塞唤醒)封装在内部,而将“具体同步状态”判断相关的逻辑(如tryAcquiretryRelease)抽象出来,留给子类去实现。核心思想:如果共享资源空闲,则请求线程直接获取锁;否则,将请求线程封装成一个Node节点,加入一个 FIFO 的同步队列中排队等待。// 1. 自定义一个互斥锁,实现 Lock 接口// 2. 内部类继承 AQS// 3. 实现 tryAcquire(独占)

weixin_52056853的博客 203

C#在线客服源码 网站在线客服聊天系统源码数据库 SQL2008源码类型 WebForm

在线客服源码 网站在线客服聊天系统源码一、源码介绍 1、此在线客服系统源码,支持PC端,只需要嵌入一段html代码就可以快速接入客服系统。 2、适用于商城,快递,机构等等需要在线客服功能的站点。接入简单方便。 3、支持多客服不限坐席数,自动分配客服。支持表情包。二、注意事项 1、开发环境为Visual Studio 2010,数据库为SqlServer2008R2,使用.net 4.5开发。 2、数据库文件在DB文件夹中,附加即可 3、客户端地址 Default.aspx,需要接入的朋友可以到时候把Default.aspx的在线客服点击图标代码放入到您的网站中,写好链接即可。

stm32小车红外循迹+超声波避障停车,基于stm32的超声波避障小车,C,C++

智能小车使用红外探头避障,适应不同颜色标志

上一篇: 【面试题解析】当面试官问你如何基于Redisson,实现分布式锁
下一篇: 【面试题解析--JAVA内存】回顾与加深,浅浅回顾JAVA常规八股,利用起碎片化时间。
鄒彬
博客等级 码龄6年 933粉丝 76原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值