• [技术干货] Java内功修炼——并发的四重境界:单例之固、生产消费之衡、定时之准、池化之效
    1.单例模式1.1 概述单例模式(Singleton Pattern):是一种常用的设计模式,主要用于确保一个类在整个应用程序中只有一个实例,并提供一个全局访问点 核心作用 1.控制资源访问:常用于管理共享资源,可以避免多线程竞争或重复创建资源导致的性能问题2.全局状态管理:当某些对象需要被多个模块或组件共享时,单例模式提供统一的访问入口3.保证数据一致性:避免多个实例导致的数据不一致问题常见实现方式 饿汉模式:在类加载时就创建实例,避免了线程安全问题,但可能会造成资源浪费,尤其是当实例初始化过程复杂或占用较多资源时懒汉模式:一种延迟初始化的单例实现方式。实例在第一次被使用时才创建,而非在类加载时就创建。这种方式可以节省资源,但需要考虑线程安全问题1.2 饿汉模式public class Singleton {//类加载时进行实例化    private static final Singleton hungry = new Singleton();    //全局唯一获取实例的接口    public static Singleton getInstance(){        return hungry;    }    //构造方法私有化    private Singleton(){}}AI运行代码java 特点: 类加载时进行实例化不存在运行时实例化过程,所以不存在线程安全问题缺点: 即使后面的场景中没有使用到该实例,也会将该实例创建出来,可能会造成不必要的资源浪费1.3 懒汉模式class Singleton{//volatile:禁止指令重排序    private static volatile Singleton lazy = null;    //创建锁对象    private static final Object object = new Object();    //全局唯一获取实例的接口    public static Singleton getInstance(){        //外层if判断:优化,提高性能        if (lazy == null) {            //避免多线程时实例化多个对象            synchronized (object) {                if (lazy == null) {                    lazy = new Singleton();                }            }        }        return lazy;    }    //构造方法私有化    private Singleton(){}}AI运行代码java 实现细节: 1.通过synchronized加锁解决线程安全问题2.外层if判断,减少锁的开销3.volatile防止指令重排序(避免半初始化对象)特点: 只有在真正需要时才创建实例,减少系统启动时的资源占用,资源利用率高缺点: 若未正确使用同步机制(如synchronized或volatile),可能导致多线程环境下实例被多次创建,线程安全实现复杂1.4 懒汉模式半初始化Java对象初始化流程 1.内存分配阶段:当使用new关键字创建对象时,JVM会在堆内存中为该对象分配空间2.对象初始化阶段:对象内存分配完成后,开始执行初始化3.引用赋值阶段:内存分配完成后,JVM将分配的内存地址赋值给引用变量Java对象初始化流程(指令重排序后) 1.内存分配阶段:当使用new关键字创建对象时,JVM会在堆内存中为该对象分配空间2.引用赋值阶段:内存分配完成后,JVM将分配的内存地址赋值给引用变量3.对象初始化阶段:对象内存分配完成后,开始执行初始化 1.5 懒汉/饿汉优缺点对比特性 懒汉模式 饿汉模式实例化时机 第一次使用时 类加载时资源消耗 节省资源 可能浪费资源线程安全 需要额外同步机制 天然线程安全实现复杂度 较复杂 简单适用场景 实例化开销大,延迟加载 实例化开销小,不需要延迟加载2.生产者/消费者模式2.1 概述生产者/消费者模式(Producer/consumer model):用于协调多个线程或进程之间的任务分配与数据处理。生产者负责生成数据或任务,消费者负责处理这些数据或任务,二者通过共享的缓冲区(队列)进行解耦,避免直接依赖 核心作用 1.解耦生产与消费逻辑:生产者仅负责生成数据并放入缓冲区,消费者仅从缓冲区获取数据并处理。两者无需直接交互,降低代码复杂度,提高模块化程度2.平衡处理速率差异:生产者与消费者通常以不同速度运行。缓冲区作为中间层,允许生产者持续写入数据,消费者按自身能力消费,避免互相阻塞3.削峰填谷:通过缓冲队列平滑流量波动,避免系统因瞬时高负载崩溃。当生产者突然产生大量请求时,缓冲区暂时存储这些请求,消费者按照自身处理能力逐步消费;当生产者速度降低时,缓冲区逐步释放积压的请求,保持消费者稳定工作2.2 实现阻塞队列class MyBlockingQueue{    private int head = 0;    private int tail = 0;    private int useSize = 0;    private final String[] array;     public MyBlockingQueue(int capacity){        array = new String[capacity];    }    //添加    public synchronized void put(String string) throws InterruptedException {        if (isFull()){            //队列满了,等待消费者消耗元素            this.wait();        }            array[tail] = string;            tail++;            tail = (tail + 1) % array.length;            useSize++;            this.notify();    }    //删除    public String take() throws InterruptedException {        String ret;        synchronized (this) {            if (useSize <= 0) {                //队列空了,等待生产者添加元素.                this.wait();            }            ret = array[head];            head++;            head = (head + 1) % array.length;            useSize--;            this.notify();        }        return ret;    }    //判断是否满了    public boolean isFull(){        return useSize >= array.length;    }}AI运行代码java 2.3 实现生产者/消费者模式public class Producer_Consumer_Blog {    public static void main(String[] args) {        MyBlockingQueue queue = new MyBlockingQueue(1000);        Thread thread1 = new Thread(()->{            int n = 1;            while (true){                try {                    queue.put(n + "");                    System.out.println("生产元素n = " + n);                    n++;                } catch (InterruptedException e) {                    throw new RuntimeException(e);                }            }        });        Thread thread2 = new Thread(()->{            while (true){                try {                    System.out.println("消费元素n = " + queue.take());                    Thread.sleep(1000);                } catch (InterruptedException e) {                    throw new RuntimeException(e);                }            }        });        thread1.start();        thread2.start();    }}AI运行代码java 3.定时器3.1 概述定时器(Timer):用于在特定时间间隔或指定时间点执行任务的编程模式,广泛应用于定时任务调度、延迟操作、周期性任务等场景。核心思想是将任务的执行逻辑与时间控制解耦,通过统一的定时器管理多个任务 核心作用/特点 1.管理异步任务调度:Timer允许你安排一个任务在未来的某个时间点执行,或者以固定的间隔重复执行2.后台执行:Timer可以使用一个后台线程来执行任务,这意味着调度和执行任务不会阻塞主线程(主线程结束后后台线程跟着结束)3.简单易用:Timer提供了一个相对简单的方式来处理定时任务,适合用于不需要复杂调度的场景标准库Timer构造方法 //1.默认构造方法//创建一个Timer对象,是一个后台线程,并使用线程的默认名字public Timer() {        this("Timer-" + serialNumber());}//2.指定线程名字的构造方法//创建一个Timer对象,是一个后台线程,并使用指定的线程名字public Timer(String name) {        thread.setName(name);        thread.start();}//3.指定是否为后台线程的构造方法//传入true,是后台线程;传入false,是前台线程public Timer(boolean isDaemon) {        this("Timer-" + serialNumber(), isDaemon);}//4.指定线程名字和是否为后台线程的构造方法public Timer(String name, boolean isDaemon) {        thread.setName(name);        thread.setDaemon(isDaemon);        thread.start();}AI运行代码java 标准库Timer的schedule方法 1.schedule(TimerTask task, Date time):安排任务在指定的时间执行一次public static void main(String[] args) {        Timer timer = new Timer();        TimerTask timerTask = new TimerTask() {            @Override            public void run() {                System.out.println("延迟三秒执行");            }        };        //使用Date对象来指定具体的执行时间        //new Date(System.currentTimeMillis()+1000表示当前时间等待1000ms        timer.schedule(timerTask,new Date(System.currentTimeMillis()+1000));}AI运行代码java 2.schedule(TimerTask task, Date firstTime, long period):安排任务在指定的时间首次执行,然后每隔一段时间重复执行public static void main(String[] args) {        Timer timer = new Timer();        TimerTask timerTask = new TimerTask() {            @Override            public void run() {                System.out.println("延迟三秒执行");            }        };        //当前时间等待1000ms后第一次执行任务        //此后每间隔1000ms就执行一次任务        timer.schedule(timerTask,new Date(System.currentTimeMillis()+1000),1000);}AI运行代码java 3.schedule(TimerTask task, long delay):安排任务在指定的延迟时间后执行一次(相对于当前时间)public static void main(String[] args) {        Timer timer = new Timer();        TimerTask timerTask = new TimerTask() {            @Override            public void run() {                System.out.println("延迟三秒执行");            }        };        //当前时间延迟3000ms后执行        timer.schedule(timerTask,3000);}AI运行代码java 4.schedule(TimerTask task, long delay, long period):安排任务在指定的延迟时间后首次执行,然后每隔一段时间重复执行public static void main(String[] args) {        Timer timer = new Timer();        TimerTask timerTask = new TimerTask() {            @Override            public void run() {                System.out.println("延迟三秒执行");            }        };        //当前时间延迟3000ms后执行        //此后每间隔3000ms就执行一次任务        timer.schedule(timerTask,3000,3000);}AI运行代码java 3.2模拟实现定时器class MyTask implements Comparable<MyTask>{    private final Runnable runnable;    private final long time;    public MyTask(Runnable runnable,long delay){        this.runnable = runnable;        this.time = System.currentTimeMillis() + delay;    }    public long getTime(){        return this.time;    }    public void run(){        runnable.run();    }    @Override    public int compareTo(MyTask o) {        return (int)(this.time - o.time);    }}class MyTime{    private final PriorityQueue<MyTask> queue = new PriorityQueue<>();    public void schedule(Runnable runnable,long delay){        synchronized (this) {            MyTask myTask = new MyTask(runnable, delay);            queue.offer(myTask);            this.notify();        }    }    public MyTime(){        Thread thread = new Thread(() -> {            while (true) {                try {                    synchronized (this) {                        while (queue.isEmpty()) {                            this.wait();                        }                        MyTask myTask = queue.peek();                        long curTime = System.currentTimeMillis();                        if (curTime >= myTask.getTime()) {                            myTask.run();                            queue.poll();                        } else {                            this.wait(myTask.getTime() - curTime);                        }                    }                }catch (InterruptedException e){                    throw new RuntimeException(e);                }            }        });        thread.setDaemon(true);        thread.start();    }}AI运行代码java 4.线程池4.1 概述线程池:线程池是一种管理和复用线程的编程模式。它预先创建一定数量的线程,在执行任务需要时,将任务分配给这些线程,从而提高运行效率 核心作用:优化多线程任务的执行效率与管理资源 特点 线程复用:当线程执行完一个任务时,不会立即销毁,而是等待下一个任务的到来(当然这种等待是有时间限制的),这样避免了频繁的创建和销毁线程动态调整:根据实际环境需要动态调整线程数量,以达到最佳性能任务队列:线程池会维护一个任务队列,用于存放待执行的任务,当线程空闲时,从队列中取出任务并执行标准库线程池构造方法 1.int corePoolSize:核心线程数2.int maximumPoolSize:最大线程数3.long keepAliveTime:非核心线程的空闲时的最大存活时间4.TimeUnit unit:时间单位5.BlockingQueue< Runnable > workQueue:任务队列6.ThreadFactory threadFactory:线程工厂,用于创建新线程的工厂7.RejectedExecutionHandler handler:拒绝策略4.3线程池的执行流程假设现在有一个线程池:核心线程数2,最大线程数4,等待队列2 任务数量<=2(A,B)时,由核心线程执行任务2<任务数量<=4(A,B,C,D)时,核心线程无法同时处理所有任务,未被执行的任务(C,D)将会进入等待队列中等待核心线程执行4<任务数量<=6(A,B,C,D,E,F),此时等待队列也满了,线程池就会就会开放非核心线程来执行任务,C和D任务继续在等待队列中等待,新添加的E和F任务由非核心线程来执行任务数量>6,核心线程,等待队列,非核心线程都被任务所占用,仍然无法满足需求,此时就会触发线程池的拒绝策略4.4 拒绝策略  1.AbortPolicy:直接抛异常2.CallerRunsPolicy:由提交该任务的线程来执行3.DiscardPolicy:丢弃新任务4.DiscardOldestPolicy:丢弃最老的任务4.5 模拟实现线程池public class MyThreadPoolExecutor {    private final int capacity = 1000;    //阻塞队列    private final MyBlockingQueue queue = new MyBlockingQueue(capacity);    private final List<Thread> list = new ArrayList<>();    //创建线程    public MyThreadPoolExecutor(int n){        for (int i = 0; i < n; i++) {            Thread thread = new Thread(()->{                while (true) {                    try {                        queue.take().run();                    } catch (InterruptedException e) {                        throw new RuntimeException(e);                    }                }            });            thread.start();            list.add(thread);        }    }    //添加任务    public void submit(Runnable runnable) throws InterruptedException {        queue.put(runnable);    }    public int getCapacity(){        return capacity;    }    //获取线程    public List<Thread> getList() {        return list;    }}AI运行代码java ————————————————原文链接:https://blog.csdn.net/2401_89167985/article/details/150641639
  • [技术干货] 新手向:C语言、Java、Python 的选择与未来指南
    语言即工具,选对方向比埋头苦学更重要你好,编程世界的新朋友!当你第一次踏入代码的宇宙,面对形形色色的编程语言,是否感到眼花缭乱?今天我们就来聊聊最主流的三种编程语言——C语言、Java 和 Python——它们各自是谁,适合做什么,以及未来十年谁能带你走得更远。一、编程世界的三把钥匙:角色定位如果把编程比作建造房屋,那么:C语言是钢筋骨架:诞生于1972年,它直接与计算机硬件“对话”,负责构建最基础的支撑结构。Java是精装套房:1995年问世,以“一次编写,到处运行”闻名,擅长打造稳定、可复用的功能模块。Python是智能管家:1991年出生却在近十年大放异彩,像一位高效助手,用最少的指令完成复杂任务13。二、核心差异对比:从底层到应用1. 语言类型与设计哲学C语言:属于面向过程的编译型语言。代码在执行前需全部翻译成机器指令,运行效率极高,但需要开发者手动管理内存(类似自己打扫房间)15。Java:面向对象的半编译语言。代码先转为字节码,再通过Java虚拟机(JVM)运行。牺牲少许效率换来跨平台能力——Windows、Linux、Mac 都能执行同一份代码39。Python:多范式的解释型语言。代码边翻译边执行,开发便捷但速度较慢。支持面向对象、函数式编程,语法如英语般直白78。翻译2. 语法与学习曲线# Python 打印10次"Hello" for i in range(10):     print("Hello") // Java 实现相同功能public class Main {    public static void main(String[] args) {        for(int i=0; i<10; i++){            System.out.println("Hello");        }    }} /* C语言版本 */#include <stdio.h>int main() {    for(int i=0; i<10; i++){        printf("Hello\n");    }    return 0;}运行本项目Python 接近自然语言,新手1天就能写出实用脚本5Java 需理解类、对象等概念,1-2个月可入门9C语言 需掌握指针、内存分配,门槛最高13. 性能特点语言    执行速度    内存管理    典型场景C语言    ⚡⚡⚡⚡⚡    手动管理    实时系统、高频交易Java    ⚡⚡⚡⚡    自动回收    企业后台服务Python    ⚡⚡    自动回收    数据分析、原型开发C语言直接操作硬件,速度可比Python快50倍以上;Java居中;Python虽慢但可通过C扩展提速210。4. 应用领域C语言:操作系统(Linux内核)、嵌入式设备(空调芯片)、游戏引擎(Unity底层)27Java:    - 安卓APP(微信、支付宝)    - 银行交易系统(高可靠性必须)    - 大型网站后端(淘宝、京东)28Python:    - 人工智能(ChatGPT的基石语言)    - 数据分析(处理百万行Excel只需几行代码)    - 自动化脚本(批量处理文件/网页)185. 生态系统支持Python:拥有28万个第三方库,如NumPy(科学计算)、TensorFlow(AI)2Java:Spring框架统治企业开发,Android SDK构建移动应用2C语言:标准库较小,但Linux/Windows API均以其为核心7三、未来十年:谁主沉浮?1. AI战场:Python 正面临 Java 的挑战Python目前占据90%的AI项目,但2025年可能成为转折点。Java凭借企业级性能正加速渗透:    - Spring AI项目获阿里等巨头支持    - 直接调用GPU提升计算效率(Project Babylon)    - 大厂倾向将AI集成到现有Java系统中46Python 仍靠易用性守住数据科学家阵地,但需解决性能瓶颈10。2. 新兴领域卡位战边缘计算(IoT设备):C语言因极致效率成为传感器、工控设备首选10云原生服务:Java和Go语言(非本文主角)主导容器化微服务8Web3与区块链:Java的强安全性被蚂蚁链等采用23. 就业市场真相Java:国内70%企业系统基于Java,岗位需求最稳定68Python:AI工程师平均薪资比Java高18%,但竞争加剧8C语言:嵌入式开发缺口大,入行门槛高但职业生涯长9四、给新手的终极建议学习路径规划:零基础入门:选 Python → 快速建立成就感,两周做出小工具求职导向:学 Java → 进入金融/电信等行业的核心系统硬件/高薪偏好:攻 C语言 → 深耕芯片、自动驾驶等高端领域关键决策原则:graph LRA[你的目标] --> B{选择语言}B -->|做AI/数据分析| C(Python)B -->|开发企业软件/安卓APP| D(Java)B -->|写操作系统/驱动/引擎| E(C语言)运行本项目专家提醒:2025年之后,掌握“双语言能力”更吃香:Python + C:用Python开发AI原型,C语言加速核心模块Java + Python:Java构建系统,Python集成智能组件五、技术架构深度拆解1. C语言:系统级开发的基石内存操作直接通过malloc()/free()管理内存,程序员可精确控制每一字节:int *arr = (int*)malloc(10 * sizeof(int)); // 申请40字节内存free(arr); // 必须手动释放,否则内存泄漏运行本项目指针的威力与风险指针直接访问物理地址,可实现高效数据传递:void swap(int *a, int *b) { // 通过指针交换变量    int temp = *a;    *a = *b;    *b = temp;}运行本项目典型事故:缓冲区溢出(如strcpy未检查长度导致系统崩溃)应用场景扩展领域    代表项目    关键技术点操作系统    Linux内核    进程调度、文件系统实现嵌入式系统    无人机飞控    实时响应(<1ms延迟)高频交易    证券交易所系统    微秒级订单处理图形渲染    OpenGL底层    GPU指令优化2. Java:企业级生态的王者JVM虚拟机机制Java源码 → 字节码 → JIT编译 → 机器码跨平台原理:同一份.class文件可在Windows/Linux/Mac的JVM上运行垃圾回收(GC)奥秘分代收集策略:graph LRA[新对象] --> B[年轻代-Eden区]B -->|Minor GC| C[Survivor区]C -->|年龄阈值| D[老年代]D -->|Full GC| E[回收]运行本项目调优关键:-Xmx设置堆大小,G1GC减少停顿时间企业级框架矩阵框架    作用    代表应用Spring Boot    快速构建微服务    阿里双11后台Hibernate    对象-数据库映射    银行客户管理系统Apache Kafka    高吞吐量消息队列    美团订单分发系统Netty    高性能网络通信    微信消息推送3. Python:科学计算的终极武器动态类型双刃剑graph TD  A[数据获取] --> B(Pandas处理)  B --> C{建模选择}  C --> D[机器学习-scikit-learn]  C --> E[深度学习-TensorFlow/PyTorch]  D --> F[模型部署-Flask]  E --> F  F --> G[Web服务]运行本项目六、行业应用全景图1. C语言:硬科技核心载体航天控制火星探测器着陆程序:实时计算轨道参数(C代码执行速度比Python快400倍)火箭燃料控制系统:直接操作传感器寄存器汽车电子特斯拉Autopilot底层:毫米波雷达信号处理发动机ECU(电子控制单元):微控制器(MCU)仅支持C工业自动化PLC编程:三菱FX系列用C编写逻辑控制数控机床:实时位置控制精度达0.001mm2. Java:商业系统支柱金融科技支付清算:Visa每秒处理6.5万笔交易(Java+Oracle)风控系统:实时反欺诈检测(Apache Flink流计算)电信领域5G核心网:爱立信Cloud RAN基于Java微服务计费系统:中国移动月账单生成(处理PB级数据)电子商务淘宝商品搜索:Elasticsearch集群(Java开发)京东库存管理:Spring Cloud微服务架构3. Python:数据智能引擎生物医药基因序列分析:Biopython处理FASTA文件药物分子模拟:RDKit库计算3D结构金融分析量化交易:pandas清洗行情数据,TA-Lib技术指标计算风险建模:Monte Carlo模拟预测股价波动AIGC革命Stable Diffusion:PyTorch实现文生图大模型训练:Hugging Face Transformers库七、性能优化实战对比1. 计算圆周率(1亿次迭代)// C语言版:0.8秒#include <stdio.h>int main() {    double pi = 0;    for (int k = 0; k < 100000000; k++) {        pi += (k % 2 ? -1.0 : 1.0) / (2*k + 1);    }    printf("%f", pi * 4);}运行本项目// Java版:1.2秒public class Pi {    public static void main(String[] args) {        double pi = 0;        for (int k = 0; k < 100000000; k++) {            pi += (k % 2 == 0 ? 1.0 : -1.0) / (2*k + 1);        }        System.out.println(pi * 4);    }}运行本项目# Python版:12.7秒 → 用Numpy优化后:1.5秒import numpy as npk = np.arange(100000000)pi = np.sum((-1)**k / (2*k + 1)) * 4print(pi)运行本项目2. 内存消耗对比(处理1GB数据)语言    峰值内存    关键影响因素C    1.1GB    手动分配精确控制Java    2.3GB    JVM堆内存开销Python    5.8GB    对象模型额外开销八、未来十年技术演进预测1. C语言:拥抱现代安全特性新标准演进:C23引入#elifdef简化宏,nullptr替代NULL安全强化:边界检查函数(如strcpy_s())静态分析工具(Clang Analyzer)2. Java:云原生时代进化GraalVM革命:将Java字节码直接编译为本地机器码(启动速度提升50倍)Project Loom:虚拟线程支持百万级并发(颠覆传统线程模型)3. Python:性能突围计划Pyston v3:JIT编译器使速度提升30%Mojo语言:兼容Python语法的超集,速度达C级别(专为AI设计)九、开发者能力矩阵建议能力维度    C语言工程师    Java架构师    Python数据科学家核心技能    指针/内存管理    Spring Cloud生态    Pandas/NumPy汇编接口调用    JVM调优    Scikit-Learn实时系统设计    分布式事务    TensorFlow辅助工具    GDB调试器    Arthas诊断工具    Jupyter NotebookValgrind内存检测    Prometheus监控    MLflow实验管理薪资范围    3-5年经验:30-50万    5-8年经验:50-80万    AI方向:60-100万+结语:三角平衡的编程生态C语言守护数字世界的物理边界——没有它,芯片无法启动,火箭不能升空Java构筑商业文明的数字基石——支撑全球70%的企业交易系统Python点燃智能时代的创新引擎——驱动90%的AI研究论文————————————————原文链接:https://blog.csdn.net/2302_77626561/article/details/151645868
  • [问题求助] isales新增活动v2入参
    【问题来源】【必填】   星网【问题简要】【必填】isales接口【问题类别】【必填】   isales【AICC解决方案版本】【必填】    aicc.22.200.0【期望解决时间】【选填】尽快【问题现象描述】【必填】    新建活动时全局 policyType=0的时候的结果类型resultRetry按文档要求上送json串一直不对 【日志或错误截图】【可选】  
  • [技术干货] 跨境电商的机遇与挑战:云计算赋能全球业务
    引言近年来,跨境电商成为全球贸易的新引擎。随着互联网普及、物流网络完善以及消费者需求多样化,越来越多的企业通过跨境电商平台走向全球。然而,跨境电商的背后也伴随着数据量激增、系统复杂度提升以及合规性挑战。如何借助云计算与智能技术提升运营效率与用户体验,成为跨境电商企业能否持续增长的关键。一、跨境电商的新趋势移动端与社交驱动消费者越来越依赖移动端购物,社交媒体带货成为重要增长点。多语言、多货币支持平台必须快速适配不同国家的支付、物流和客服需求。数据驱动的精细化运营用户画像、商品推荐、智能营销正在成为竞争核心。合规与安全各国对数据安全与跨境支付监管日趋严格,企业必须具备合规能力。二、跨境电商面临的技术挑战高并发访问:促销活动或节假日流量激增,需要平台具备弹性扩展能力。全球化部署:用户遍布多个国家,系统需要具备跨区域低延迟访问能力。海量数据处理:订单、支付、物流、客服产生的数据需要实时处理和分析。支付与合规安全:跨境支付涉及复杂的清结算与安全认证,必须符合国际标准。三、华为云在跨境电商中的价值1. 弹性计算与分布式架构华为云提供的 弹性云服务器(ECS) 和 容器服务 CCE,可以帮助跨境电商平台快速实现弹性扩缩容,确保高峰期依然稳定运行。2. 全球化网络加速通过 华为云 CDN 与云专线,跨境电商平台能够为不同地区用户提供低延迟的访问体验,解决跨境访问慢、卡顿等痛点。3. 大数据与 AI 能力借助 华为云 DataArts 平台,电商企业可以构建统一数据中台,实现全链路数据治理。结合 ModelArts AI 平台,可进行用户画像、智能推荐、需求预测,提升转化率。4. 安全与合规保障华为云在数据安全、隐私保护与合规领域具备丰富经验,提供 数据加密、身份认证、合规认证 等服务,帮助企业满足不同国家和地区的监管要求。四、案例洞察某东南亚跨境电商平台在扩张过程中,面临 促销活动流量激增 与 跨区域访问体验差 的问题。借助华为云:通过 CCE 容器集群 实现业务的自动化部署与弹性伸缩。借助 CDN 全球加速,将访问延迟降低了 40%。使用 AI 推荐算法,实现个性化商品推荐,转化率提升了 25%。最终,该平台不仅支撑了大规模活动流量,还提升了海外用户的购物体验。五、未来展望AI 驱动的智能运营:跨境电商将更多依赖 AI 实现智能客服、动态定价和精准营销。区块链与可信交易:区块链技术将提升跨境支付与供应链的透明度与可信度。云原生架构普及:微服务与 Serverless 将进一步降低系统复杂度,提升迭代效率。https://github.com/quocc6574-creator/e/issues/20https://github.com/quocc6574-creator/e/issues/19https://github.com/quocc6574-creator/e/issues/18https://github.com/quocc6574-creator/e/issues/17https://github.com/quocc6574-creator/e/issues/16https://github.com/quocc6574-creator/e/issues/15https://github.com/quocc6574-creator/e/issues/14https://github.com/quocc6574-creator/e/issues/13https://github.com/quocc6574-creator/e/issues/12https://github.com/quocc6574-creator/e/issues/11https://github.com/quocc6574-creator/e/issues/10总结跨境电商的快速发展既是机遇,也是挑战。面对全球化、多样化和高并发的复杂场景,企业必须依托云计算、大数据和 AI 技术,才能实现安全合规、智能高效的运营。华为云凭借其全球化基础设施与智能化平台能力,正在成为跨境电商企业出海的可靠伙伴。对于开发者与架构师而言,理解并善用云平台能力,不仅能提升业务竞争力,更能在全球数字经济浪潮中抢占先机。
  • [技术干货] Java 在云原生微服务与服务治理中的最佳实践
    引言随着企业业务的快速发展,传统单体架构已经无法满足高并发、快速迭代和弹性扩展的需求。云原生技术的兴起,为应用架构带来了新的机遇。微服务作为云原生的核心思想之一,正在成为企业系统的主流架构模式。而 Java 作为企业级应用开发的“常青树”,在云原生微服务领域扮演着关键角色。本文将结合微服务与服务治理,探讨 Java 在华为云环境下的应用实践与优化思路。一、Java 与微服务的天然契合生态完善:Java 拥有丰富的微服务框架,如 Spring Cloud、Dubbo、Micronaut,这些框架为服务拆分与治理提供了成熟解决方案。平台无关性:基于 JVM 的跨平台特性,使得 Java 应用能够在虚拟机、容器、裸机等多种环境中灵活运行。企业积累深厚:金融、电信、制造等行业的大量系统都基于 Java 构建,微服务化改造时更易平滑迁移。二、服务治理的核心挑战服务发现与注册:随着服务数量增加,如何快速发现与定位服务实例成为难点。负载均衡:保证高并发场景下请求的均匀分配,避免单点过载。容错与限流:在部分服务异常时,如何通过熔断、限流、降级保证整体系统可用性。可观测性:微服务架构下链路复杂,监控与日志追踪是保障稳定性的关键。三、Java 在云原生服务治理中的实践1. Spring Cloud 与服务治理Spring Cloud 通过注册中心、配置中心、负载均衡组件,为 Java 微服务提供了全套治理方案。在华为云容器服务 CCE 中,Spring Cloud 应用可以无缝结合 Kubernetes 的服务发现机制,进一步提升服务注册与扩缩容的效率。2. 服务容错与弹性通过结合 Hystrix 或 Resilience4j,Java 应用能够实现熔断与降级机制。当下游服务不可用时,系统能快速响应预设逻辑,避免雪崩效应。在华为云应用服务平台(AOS)中,这类容错策略可以与云原生弹性伸缩机制结合,实现业务的平滑承载。3. 服务网格与 Java 应用随着 Istio 等服务网格的普及,Java 应用可以通过 Sidecar 模式将服务治理逻辑下沉至基础设施层。开发者无需在业务代码中手动实现熔断、路由,而是通过声明式配置交由服务网格处理。在华为云的微服务引擎 CSE 中,已经提供了与 Java 应用高度集成的服务网格能力。四、可观测性与智能运维在微服务架构下,链路追踪和日志分析是保障系统稳定的关键。Java 应用可以通过 OpenTracing、SkyWalking 等框架收集调用链路,并将数据上报至华为云 APM(应用性能管理)平台,实现全链路监控。同时,结合云上的 AI 运维能力,可以对异常进行智能检测和预测,为系统稳定性保驾护航。五、典型应用案例某大型零售企业在进行数字化转型时,选择将原有的单体电商系统改造为 Java 微服务架构。其核心举措包括:在华为云 CCE 部署基于 Spring Cloud 的微服务集群,实现快速扩缩容。借助华为云 CSE 的服务治理功能,实现跨区域的服务发现与负载均衡。利用 APM 进行链路追踪和性能分析,配合 AI 运维实现故障预测。最终,该企业的系统在促销高峰期依旧保持高可用,用户体验大幅提升。六、未来趋势虚拟线程提升并发能力:随着 Project Loom 的成熟,Java 在高并发微服务中的性能瓶颈将被进一步突破。Serverless 与 Java:借助 GraalVM 原生镜像,Java 应用将在华为云函数计算(FunctionGraph)中具备更快的启动速度。智能化治理:未来服务治理将更多结合 AI,实现自适应的流量调度与异常恢复。https://github.com/anh980436-lgtm/7/issues/9https://github.com/anh980436-lgtm/7/issues/8https://github.com/anh980436-lgtm/7/issues/7https://github.com/anh980436-lgtm/7/issues/6https://github.com/anh980436-lgtm/7/issues/5https://github.com/anh980436-lgtm/7/issues/4https://github.com/anh980436-lgtm/7/issues/3https://github.com/anh980436-lgtm/7/issues/2https://github.com/anh980436-lgtm/7/issues/1总结在云原生时代,Java 凭借其生态、稳定性与社区支持,依旧是构建微服务架构的首选语言。通过与华为云的容器服务、微服务引擎、应用性能管理平台的结合,Java 应用能够在服务发现、负载均衡、容错与可观测性等方面实现最佳实践。对于开发者而言,深入理解 Java 在云原生服务治理中的角色,不仅能提升应用稳定性,还能充分利用云平台的能力,加速数字化转型。 
  • [问题求助] isales 新增外呼号码v2接口报错
    【问题来源】【必填】    星网 【问题简要】【必填】   新增外呼号码v2接口报错【问题类别】【必填】    AICC平台功能【AICC解决方案版本】【必填】    【AICC版本:AICC 24.200.0】【期望解决时间】【选填】    尽快【问题现象描述】【必填】       按照产品文档上的demo上送数据返回报错:CalledNo Type is incorrect
  • [技术干货] 【专题汇总】 八月份技术干货汇总它虽迟但到,快进来瞧瞧吧!
    大家好,8月份的技术汇总贴它虽迟但到。本次带来了关于SpringBoot,C++,Java,python,GO语言等等多方面知识,量大管饱,希望可以帮助到大家。1、Java报错:org.springframework.beans.factory.BeanCreationException的五种解决方法【转载】cid:link_02、C#控制台程序同步调用WebApi实现方式【转载】cid:link_73、java -jar example.jar 产生的日志输出到指定文件的方法【转载】cid:link_84、 SpringBoot项目自定义静态资源映射规则的实现代码【转载】cid:link_15、 SpringBoot中9个内置过滤器用法的完整指南【转载】cid:link_26、C++中的list与forward_list介绍与使用【转载】cid:link_37、Java使用Redis实现消息订阅/发布的几种方式【转载】cid:link_98、Spring Boot中使用@Scheduled和Quartz实现定时任务的详细过程【转载】cid:link_109、 Python中的sort()和sorted()用法示例解析【转载】https://bbs.huaweicloud.com/forum/thread-02102190373187063025-1-1.html10、 python中update()函数的用法和一些例子【转载】cid:link_411、基于Python编写新手向的简易翻译工具 【转载】cid:link_1112、使用Python创建PowerPoint各种图表的详细教程【转载】cid:link_1213、python basicConfig()简介及用法举例【转载】cid:link_514、 Python 存根文件(.pyi)简介与实战案例及类型提示的高级指南【转载】cid:link_615、Go轻松构建WebSocket服务器的实现方案【转载】https://bbs.huaweicloud.com/forum/thread-0294190373041865026-1-1.html
  • [问题求助] isales接口报错
    调用https://ip:port/rest/isales/v1/openapi/campaigns/{vdnId}/{campaignId}这个接口使用get方法报错,掉其他post方法接口没问题 
  • [技术干货] Java JUC 详解:并发.util.concurrent 并发工具包指南
    JUC(Java Util Concurrent)即 Java 并发工具包,是java.util.concurrent包及其子包的简称,自 Java 5 引入,为并发编程提供了高效、安全、可靠的工具类,极大简化了多线程编程的复杂度。JUC 主要包含以下几类组件:线程池框架(Executor Framework)并发集合(Concurrent Collections)同步工具(Synchronizers)原子操作类(Atomic Classes)锁机制(Locks)并发工具类(如 CountDownLatch、CyclicBarrier 等)线程池框架线程池通过重用线程来减少线程创建和销毁的开销,提高系统性能。核心接口与类Executor:最基本的线程池接口,定义了执行任务的方法ExecutorService:扩展了 Executor,提供了更丰富的线程池操作ThreadPoolExecutor:线程池的核心实现类Executors:线程池的工具类,提供了常用线程池的创建方法线程池示例import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit; public class ThreadPoolExample {    public static void main(String[] args) {        // 创建固定大小的线程池        ExecutorService executor = Executors.newFixedThreadPool(3);                // 提交任务        for (int i = 0; i < 10; i++) {            final int taskId = i;            executor.submit(() -> {                try {                    System.out.println("任务 " + taskId + " 由线程 " +                                        Thread.currentThread().getName() + " 执行");                    TimeUnit.SECONDS.sleep(1);                } catch (InterruptedException e) {                    Thread.currentThread().interrupt();                }            });        }                // 关闭线程池        executor.shutdown();        try {            // 等待所有任务完成            if (!executor.awaitTermination(5, TimeUnit.SECONDS)) {                // 超时后强制关闭                executor.shutdownNow();            }        } catch (InterruptedException e) {            executor.shutdownNow();        }    }}AI生成项目ThreadPoolExecutor 核心参数手动创建线程池时,ThreadPoolExecutor的构造函数提供了最灵活的配置:public ThreadPoolExecutor(int corePoolSize,                          int maximumPoolSize,                          long keepAliveTime,                          TimeUnit unit,                          BlockingQueue<Runnable> workQueue,                          ThreadFactory threadFactory,                          RejectedExecutionHandler handler)AI生成项目corePoolSize:核心线程数maximumPoolSize:最大线程数keepAliveTime:非核心线程的空闲超时时间workQueue:任务等待队列threadFactory:线程工厂handler:拒绝策略import java.util.concurrent.ArrayBlockingQueue;import java.util.concurrent.ThreadPoolExecutor;import java.util.concurrent.TimeUnit; public class CustomThreadPool {    public static void main(String[] args) {        // 自定义线程池配置        ThreadPoolExecutor executor = new ThreadPoolExecutor(            2, // 核心线程数            5, // 最大线程数            30, // 空闲时间            TimeUnit.SECONDS,            new ArrayBlockingQueue<>(10), // 有界队列            new ThreadPoolExecutor.CallerRunsPolicy() // 拒绝策略        );                // 提交任务        for (int i = 0; i < 20; i++) {            final int taskId = i;            executor.execute(() -> {                try {                    System.out.println("任务 " + taskId + " 由线程 " +                                       Thread.currentThread().getName() + " 执行");                    TimeUnit.MILLISECONDS.sleep(500);                } catch (InterruptedException e) {                    Thread.currentThread().interrupt();                }            });        }                executor.shutdown();    }}AI生成项目并发集合JUC 提供了一系列线程安全的集合类,相比传统的同步集合,通常具有更好的性能。常用并发集合ConcurrentHashMap:线程安全的 HashMap 替代者CopyOnWriteArrayList:读多写少场景下的线程安全 ListCopyOnWriteArraySet:基于 CopyOnWriteArrayList 实现的 SetConcurrentLinkedQueue:高效的并发队列LinkedBlockingQueue:可阻塞的链表队列ArrayBlockingQueue:有界的数组队列PriorityBlockingQueue:支持优先级的阻塞队列ConcurrentHashMap 示例import java.util.Map;import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit; public class ConcurrentHashMapExample {    public static void main(String[] args) throws InterruptedException {        Map<String, Integer> concurrentMap = new ConcurrentHashMap<>();        ExecutorService executor = Executors.newFixedThreadPool(4);                // 并发写入        for (int i = 0; i < 1000; i++) {            final int num = i;            executor.submit(() -> {                String key = "key" + (num % 10);                // 原子操作:计算并替换                concurrentMap.compute(key, (k, v) -> v == null ? 1 : v + 1);            });        }                executor.shutdown();        executor.awaitTermination(1, TimeUnit.MINUTES);                // 输出结果        concurrentMap.forEach((k, v) -> System.out.println(k + ": " + v));    }}AI生成项目同步工具类JUC 提供了多种同步工具,用于协调多个线程之间的协作。CountDownLatch允许一个或多个线程等待其他线程完成操作。import java.util.concurrent.CountDownLatch;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors; public class CountDownLatchExample {    public static void main(String[] args) throws InterruptedException {        // 计数器为3        CountDownLatch latch = new CountDownLatch(3);        ExecutorService executor = Executors.newFixedThreadPool(3);                for (int i = 0; i < 3; i++) {            final int taskId = i;            executor.submit(() -> {                try {                    System.out.println("任务 " + taskId + " 开始执行");                    Thread.sleep(1000 + taskId * 500);                    System.out.println("任务 " + taskId + " 执行完成");                } catch (InterruptedException e) {                    Thread.currentThread().interrupt();                } finally {                    // 计数器减1                    latch.countDown();                }            });        }                System.out.println("等待所有任务完成...");        // 等待计数器变为0        latch.await();        System.out.println("所有任务已完成,继续执行主线程");                executor.shutdown();    }}AI生成项目CyclicBarrier让一组线程到达一个屏障时被阻塞,直到最后一个线程到达屏障,所有被阻塞的线程才会继续执行。import java.util.concurrent.BrokenBarrierException;import java.util.concurrent.CyclicBarrier;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors; public class CyclicBarrierExample {    public static void main(String[] args) {        // 3个线程到达屏障后,执行Runnable任务        CyclicBarrier barrier = new CyclicBarrier(3, () ->             System.out.println("所有线程已到达屏障,开始下一步操作"));                ExecutorService executor = Executors.newFixedThreadPool(3);                for (int i = 0; i < 3; i++) {            final int threadId = i;            executor.submit(() -> {                try {                    System.out.println("线程 " + threadId + " 正在执行任务");                    Thread.sleep(1000 + threadId * 500);                    System.out.println("线程 " + threadId + " 到达屏障");                    // 等待其他线程到达                    barrier.await();                    System.out.println("线程 " + threadId + " 继续执行");                } catch (InterruptedException | BrokenBarrierException e) {                    Thread.currentThread().interrupt();                }            });        }                executor.shutdown();    }}AI生成项目Semaphore信号量,用于控制同时访问特定资源的线程数量。import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.Semaphore;import java.util.concurrent.TimeUnit; public class SemaphoreExample {    public static void main(String[] args) {        // 允许3个线程同时访问        Semaphore semaphore = new Semaphore(3);        ExecutorService executor = Executors.newFixedThreadPool(5);                for (int i = 0; i < 10; i++) {            final int taskId = i;            executor.submit(() -> {                try {                    // 获取许可                    semaphore.acquire();                    System.out.println("任务 " + taskId + " 获得许可,开始执行");                    TimeUnit.SECONDS.sleep(2);                    System.out.println("任务 " + taskId + " 执行完成,释放许可");                } catch (InterruptedException e) {                    Thread.currentThread().interrupt();                } finally {                    // 释放许可                    semaphore.release();                }            });        }                executor.shutdown();    }}AI生成项目原子操作类JUC 提供了一系列原子操作类,用于在不使用锁的情况下实现线程安全的原子操作。主要原子类包括:基本类型:AtomicInteger、AtomicLong、AtomicBoolean数组类型:AtomicIntegerArray、AtomicLongArray等引用类型:AtomicReference、AtomicStampedReference等字段更新器:AtomicIntegerFieldUpdater等import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit;import java.util.concurrent.atomic.AtomicInteger; public class AtomicExample {    private static AtomicInteger counter = new AtomicInteger(0);        public static void main(String[] args) throws InterruptedException {        ExecutorService executor = Executors.newFixedThreadPool(10);                // 10个线程,每个线程自增1000次        for (int i = 0; i < 10; i++) {            executor.submit(() -> {                for (int j = 0; j < 1000; j++) {                    // 原子自增操作                    counter.incrementAndGet();                }            });        }                executor.shutdown();        executor.awaitTermination(1, TimeUnit.MINUTES);                // 结果应该是10000        System.out.println("最终计数: " + counter.get());    }}AI生成项目锁机制JUC 的java.util.concurrent.locks包提供了比synchronized更灵活的锁机制。Lock 接口Lock接口是所有锁的父接口,主要实现类有:ReentrantLock:可重入锁ReentrantReadWriteLock:可重入读写锁import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock; public class ReentrantLockExample {    private static int count = 0;    // 创建可重入锁    private static Lock lock = new ReentrantLock();        public static void main(String[] args) throws InterruptedException {        ExecutorService executor = Executors.newFixedThreadPool(5);                for (int i = 0; i < 1000; i++) {            executor.submit(() -> {                // 获取锁                lock.lock();                try {                    count++;                } finally {                    // 确保锁被释放                    lock.unlock();                }            });        }                executor.shutdown();        executor.awaitTermination(1, TimeUnit.MINUTES);                System.out.println("最终计数: " + count);    }}AI生成项目读写锁ReentrantReadWriteLock提供了读锁和写锁分离,适合读多写少的场景:import java.util.HashMap;import java.util.Map;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit;import java.util.concurrent.locks.ReadWriteLock;import java.util.concurrent.locks.ReentrantReadWriteLock; public class ReadWriteLockExample {    private Map<String, String> data = new HashMap<>();    private ReadWriteLock lock = new ReentrantReadWriteLock();        // 读操作使用读锁    public String get(String key) {        lock.readLock().lock();        try {            System.out.println("读取 key: " + key + ",线程: " + Thread.currentThread().getName());            return data.get(key);        } finally {            lock.readLock().unlock();        }    }        // 写操作使用写锁    public void put(String key, String value) {        lock.writeLock().lock();        try {            System.out.println("写入 key: " + key + ",线程: " + Thread.currentThread().getName());            data.put(key, value);        } finally {            lock.writeLock().unlock();        }    }        public static void main(String[] args) throws InterruptedException {        ReadWriteLockExample example = new ReadWriteLockExample();        ExecutorService executor = Executors.newFixedThreadPool(5);                // 添加写操作        executor.submit(() -> example.put("name", "Java"));                // 添加多个读操作        for (int i = 0; i < 4; i++) {            executor.submit(() -> {                for (int j = 0; j < 3; j++) {                    example.get("name");                    try {                        TimeUnit.MILLISECONDS.sleep(100);                    } catch (InterruptedException e) {                        Thread.currentThread().interrupt();                    }                }            });        }                executor.shutdown();        executor.awaitTermination(1, TimeUnit.MINUTES);    }}AI生成项目实战案例:生产者消费者模型使用 JUC 的阻塞队列实现经典的生产者消费者模型:import java.util.concurrent.ArrayBlockingQueue;import java.util.concurrent.BlockingQueue;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit; public class ProducerConsumerExample {    // 容量为10的阻塞队列    private static BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);    private static final int MAX_ITEMS = 20;        // 生产者    static class Producer implements Runnable {        private int id;                public Producer(int id) {            this.id = id;        }                @Override        public void run() {            try {                for (int i = 0; i < MAX_ITEMS; i++) {                    int item = id * 100 + i;                    queue.put(item); // 放入队列,如果满了会阻塞                    System.out.println("生产者 " + id + " 生产了: " + item +                                        ",队列大小: " + queue.size());                    TimeUnit.MILLISECONDS.sleep(100); // 模拟生产耗时                }            } catch (InterruptedException e) {                Thread.currentThread().interrupt();            }        }    }        // 消费者    static class Consumer implements Runnable {        private int id;                public Consumer(int id) {            this.id = id;        }                @Override        public void run() {            try {                for (int i = 0; i < MAX_ITEMS; i++) {                    int item = queue.take(); // 从队列取,如果空了会阻塞                    System.out.println("消费者 " + id + " 消费了: " + item +                                        ",队列大小: " + queue.size());                    TimeUnit.MILLISECONDS.sleep(150); // 模拟消费耗时                }            } catch (InterruptedException e) {                Thread.currentThread().interrupt();            }        }    }        public static void main(String[] args) throws InterruptedException {        ExecutorService executor = Executors.newFixedThreadPool(4);                // 创建2个生产者        executor.submit(new Producer(1));        executor.submit(new Producer(2));                // 创建2个消费者        executor.submit(new Consumer(1));        executor.submit(new Consumer(2));                executor.shutdown();        executor.awaitTermination(1, TimeUnit.MINUTES);    }}AI生成项目总结JUC 为 Java 并发编程提供了强大的工具支持,大大简化了多线程程序的开发难度。掌握 JUC 的使用,能够帮助开发者编写高效、安全的并发程序,应对多线程环境下的各种挑战。在实际开发中,应根据具体场景选择合适的并发工具,同时注意线程安全和性能之间的平衡。通过不断实践和深入理解这些工具的原理,您将能够构建出更健壮、更高效的并发应用程序。————————————————原文链接:https://blog.csdn.net/m0_57836225/article/details/149613910
  • [技术干货] 新手向:Java方向讲解
    从诺基亚塞班到阿里双11,从安卓应用到华尔街交易,Java用一行System.out.println()征服了数字世界1998年,诺基亚在塞班系统上首次采用Java ME技术,让手机具备了运行应用程序的能力,开启了移动互联网的序幕。当时的Java开发者们可能不会想到,这个简单的System.out.println()打印语句,会成为改变世界的代码。2009年,阿里首次在双11购物节中使用Java构建的分布式系统,成功应对了每秒数万笔交易的挑战。在2019年双11期间,阿里云更是创下单日处理54.4万笔/秒的世界纪录,这背后是数百万行Java代码的完美配合。在移动端,Android系统基于Java语言构建的应用生态已经覆盖全球超过25亿台设备。从简单的计算器应用到复杂的3D游戏,Java的跨平台特性让同一个应用能在不同设备上稳定运行。在金融领域,华尔街90%以上的高频交易系统使用Java开发。高盛、摩根士丹利等投行依靠Java的稳定性和高性能特性,在纳秒级的时间窗口内完成数以亿计的交易。一个简单的System.out.println()调试语句,可能就关系着数百万美元的交易决策。一、设计哲学:一次编写,到处运行的虚拟王国核心三支柱:graph LR  A[Java语言] --> B[字节码]  B --> C[JVM虚拟机]  C --> D[操作系统] AI生成项目跨平台本质:字节码作为通用货币,JVM担任央行(Windows/Mac/Linux分别实现本地化)内存安全革命:自动垃圾回收(GC)终结手动内存管理时代对象王国宪法:万物皆对象(除基本类型)单继承多接口(规避C++菱形继承问题)强类型检查(编译期拦截90%类型错误)版本进化里程碑:版本    代号    革命性特性    商业影响JDK 1.2    Playground    集合框架/内部类    企业级开发奠基Java 5    Tiger    泛型/注解/枚举    企业注解驱动开发爆发Java 8    Spider    Lambda/Stream API    函数式编程普及Java 17    LTS    密封类/模式匹配    云原生时代标准基石二、JVM虚拟机:万亿级商业系统的动力引擎1. 字节码执行全流程public class Main {      public static void main(String[] args) {          int sum = 0;          for (int i = 1; i <= 100; i++) {              sum += i;          }      }  }  AI生成项目编译后字节码关键指令:0: iconst_0         // 压入常数0  1: istore_1         // 存储到变量1  2: iconst_1         // 压入1  3: istore_2         // 存储到循环变量i  4: iload_2          // 加载i  5: bipush 100       // 压入100  7: if_icmpgt 20     // 比较i>100则跳转  AI生成项目2. JIT即时编译黑科技分层编译策略:层级    编译方式    适用场景Level 0    解释执行    冷门代码Level 3    C1简单编译    短期存活方法Level 4    C2深度优化    热点方法(>万次)逃逸分析优化:// 未优化前:在堆分配100万对象  void process() {      for(int i=0; i<1_000_000; i++){          User user = new User(); // 对象分配      }  }  AI生成项目JIT优化后:拆解User字段为局部变量,彻底消除对象分配翻译3. GC垃圾回收王朝更迭收集器    工作方式    适用场景    暂停时间Serial GC    单线程复制    客户端小程序    数百msParallel GC    多线程标记整理    吞吐优先系统    几十msCMS    并发标记清除    响应敏感系统    10ms以下G1 GC    分区域并发收集    大内存应用    10ms级可控ZGC    染色指针+并发转移    10TB级内存    <1ms阿里双11实战配置:-XX:+UseG1GC -Xmx100g -XX:MaxGCPauseMillis=200  三、技术生态:四大疆域的统治版图1. 企业级开发王国(Java EE / Jakarta EE)Spring帝国架构:graph TD  A[Spring Boot] --> B[自动配置]  A --> C[嵌入式容器]  B --> D[Spring Data]  B --> E[Spring Security]  C --> F[Tomcat/Netty]  AI生成项目微服务黄金组合:注册中心:Nacos/Zookeeper服务调用:OpenFeign熔断降级:Sentinel配置中心:Apollo高并发架构案例(12306系统):@RestController  public class TicketController {      @Autowired      private RedisTemplate<String, Ticket> redisTemplate;       @GetMapping("/grab")      public String grabTicket(@RequestParam String trainId) {          // Redis分布式锁确保原子性          Boolean locked = redisTemplate.opsForValue()                  .setIfAbsent("lock_"+trainId, "1", 10, TimeUnit.SECONDS);          if(locked) {              Ticket ticket = redisTemplate.opsForList().rightPop(trainId);              if(ticket != null) return "抢票成功";          }          return "票已售罄";      }  }  AI生成项目2. 移动端王国(Android)Android架构演进:架构    代表技术    解决痛点MVC    Activity全能控制    逻辑视图耦合MVP    Presenter中介    单元测试困难MVVM    LiveData+DataBinding    数据驱动视图MVI    单向数据流    状态管理混乱Jetpack组件矩阵:graph LR  A[Lifecycle] --> B[ViewModel]  B --> C[LiveData]  C --> D[Room]  A --> E[WorkManager]  D --> F[Paging] AI生成项目3. 大数据王国Hadoop生态链:组件    Java类占比    核心功能HDFS    98%    分布式文件存储MapReduce    100%    批处理计算框架HBase    85%    列式数据库Spark    30%    内存计算(Scala主导)Flink流处理Java示例:DataStream<String> data = env.socketTextStream("localhost", 9999);  data.flatMap((String line, Collector<WordCount> out) -> {          for (String word : line.split(" ")) {              out.collect(new WordCount(word, 1));          }      })      .keyBy(WordCount::getWord)      .sum("count")      .print(); // 实时词频统计  AI生成项目4. 云原生新边疆Quarkus:云原生Java革命@Path("/hello")  public class GreetingResource {      @GET      @Produces(MediaType.TEXT_PLAIN)      public String hello() {          return "启动时间: " + (System.currentTimeMillis() - StartupTimer.start);      }  }  AI生成项目性能对比:指标    传统Tomcat    Quarkus启动时间    4.5秒    0.038秒内存占用    285MB    45MB请求延迟    15ms    3ms四、开发工具链:帝国工程师的武器库1. 构建工具进化史工具    配置文件    依赖管理机制    构建速度Ant    build.xml    手动下载jar    慢Maven    pom.xml    中央仓库自动解析    中等Gradle    build.gradle    增量编译+缓存    快(快30%)Gradle多模块配置:// settings.gradle  include 'user-service', 'order-service', 'gateway'   // build.gradle  subprojects {      apply plugin: 'java'      dependencies {          implementation 'org.springframework.boot:spring-boot-starter-web'      }  }  AI生成项目2. 诊断调优神器JFR飞行记录仪:java -XX:StartFlightRecording=duration=60s,filename=recording.jfr MyApp  Arthas在线诊断:watch com.example.service.UserService queryUser '{params, returnObj}' -x 3  GC日志分析:java -Xlog:gc*=debug:file=gc.log -jar app.jar  五、未来战场:危机与变革1. 云原生时代的挑战者语言    优势领域    Java应对策略Go    高并发微服务    Quarkus/GraalVMRust    系统编程    Panama FFI接口Kotlin    Android开发    Jetpack Compose整合2. 颠覆性技术突破GraalVM原生编译:native-image --no-fallback -jar myapp.jar  将Spring Boot应用转为独立可执行文件(启动<50ms)Loom虚拟线程:try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {      for(int i=0; i<10_000; i++) {          executor.submit(() -> {              Thread.sleep(Duration.ofSeconds(1));              return i;          }); // 万级并发无压力      }  }  AI生成项目Valhalla值类型:__value class Point {      int x;      int y;  } // 栈分配替代对象,性能提升5倍  AI生成项目六、开发者进阶路线图1. 职业赛道选择方向    技术栈    薪资范围(3-5年)企业级开发    Spring Cloud + Alibaba    30-50万Android开发    Jetpack Compose + KMM    25-40万大数据开发    Flink + Hadoop    35-60万云原生架构    Quarkus + Kubernetes    50-80万2. 知识体系图谱graph LR  A[Java基础] --> B[JVM原理]  A --> C[并发编程]  B --> D[性能调优]  C --> E[分布式系统]  D --> F[云原生架构]  E --> G[领域驱动设计]  AI生成项目结语:永不落幕的帝国当Oracle的律师团为版权奔走时,当Rustaceans高呼内存安全时,当Go开发者炫耀协程效率时——Java依然运行在:全球45亿台Android设备华尔街78% 的交易系统阿里云上百万台服务器Java的终极竞争力:用严谨的类型系统构建数字世界的秩序用虚拟机的智慧平衡效率与跨平台用二十年的生态沉淀驾驭技术变革浪潮正如James Gosling在Java诞生时的预言:“我们不是在创造语言,而是在构建数字文明的基石。” 从智能卡到航天器,从物联网到元宇宙,Java帝国仍在拓展它的疆域。————————————————原文链接:https://blog.csdn.net/2302_77626561/article/details/149091813
  • [技术干货] java常见基本算法
    一.查找算法(1)基本查找基本查找就是一个一个遍历数组,直到找到所需元素,效率最低(2)二分/折半查找前提条件:数组中的数据是有序的核心逻辑:每次去除一半的查找范围优点:效率比基本查找要高实现:1.max是数组最大索引2.min是数组最小索引3.mid是二者的整除所取的整数,拿它来跟目标值作比较4.如果mid索引的整数比目标值大,那么min=mid+15.如果比目标值小,那么max=mid-1如果目标值不在数组中,返回索引-1,并且这时候min会大于max(因为当要找的数据大于所有数据的时候,min最后会比max大;如果要找的数据小于所有数据,max最后比min小;如果在数据之中找不到数据,min最后也会比max大;但是一般要查找的的数据都在数组里面)public class BinarySearch {    public static void main(String[] args) {        int[] arr = {1, 22, 33, 44, 55, 6666, 77777, 88888, 99999, 100000};        System.out.println(binarySearch(arr, 22));    }     public static int binarySearch(int[] arr, int target) {        int min=0;        int max=arr.length-1;        while (true){            int mid=(min+max)/2;            if (min>max){                return -1;            }            //mid索引在目标左边            if (arr[mid]<target){                min=mid+1;            }            //mid索引在目标右边            if (arr[mid]>target){                max=mid-1;            }            //mid索引在目标上            if (arr[mid]==target){                return mid;            }        }    }}AI生成项目java运行(3)分块查找用于每个数据之间没有顺序,但是每个区域间有顺序的情况:例如有个数组:{1,3,2,4,5,66,88,77,999,100,101}(会发现每个数据之间确实是没有顺序可言,但是可以把这几个数据分区域,第一个区域的最大值为5,第二个区域最大值为88,第三个区域最大值为101,而且第二个区域的所有数据都大于第一个区域,第三个区域的数据也大于第二个区域的最大数值,那么就可以利用分块查找了。)1.既然要分区,那我们可以先创建一个区域类:Blockclass Block{int maxIndex;int minIndex;int maxNumber;还有构造方法和get,set方法等等}2.创建对象,把每个区域信息填进去,一般创建数据个数的平方根个对象3.创建存放Block对象的数组4.创建方法去把目标值的所在区域找到5.创建方法在区域中找目标值,并返回索引实例:public class BlockSearch {    public static void main(String[] args) {     int[] arr = {1, 22, 34, 33, 55, 66, 78, 68, 9999, 10000};     Block b1= new Block(3, 0, 34);     Block b2= new Block(7, 4, 78);     Block b3= new Block(9, 8, 10000);     Block[] blockArr = {b1, b2, b3};     int target = 33;     int index = finalSearch(blockArr, target, arr);     System.out.println("index = " + index);    }    //先找区域    public static int blockSearch(Block[] arr,int target){        for(int i=0;i<arr.length;i++){            if(arr[i].maxNumber>=target){                return i;            }        }        return -1;    }    //再找位置    public static int finalSearch(Block[] arr1,int target,int[] arr2){        int index = blockSearch(arr1,target);        if (index==-1){            return -1;        }         for(int i=arr1[index].minIndex;i<=arr1[index].maxIndex;i++){            if (arr2[i]==target){                return i;            }        }        return -1;    } }//Blockclass Block{    int maxIndex;    int minIndex;    int maxNumber;     public Block(int maxIndex, int minIndex, int maxNumber) {        this.maxIndex = maxIndex;        this.minIndex = minIndex;        this.maxNumber = maxNumber;    } }AI生成项目java运行结果: 二.排序算法(1)冒泡排序相邻的元素两两比较,先按照要求把最大或者最小的先放到右边:——外循环是看它要执行的次数,也就是数据数量-1次——内循环的-1是为了不让i+1(最后一个数据)超出索引——内循环的-i是为了效率,因为每次执行完,就可以减少最后一个数据,也就是减少一次public class BubbleSort {     public static void main(String[] args) {     int[] arr={2,5,8,9,1,5,6,4,7,8};     for (int i=0;i<arr.length-1;i++){         for (int j=0;j<arr.length-i-1;j++){             if(arr[j]>arr[j+1]){                 int temp=arr[j];                 arr[j]=arr[j+1];                 arr[j+1]=temp;             }         }     }        System.out.println(Arrays.toString(arr));    }}AI生成项目java运行结果:  (2)选择排序 拿第一个元素跟后面的元素比,符合要求的放到一个,继续循环,让第二个元素再依次跟后面比,让符合规则的放到第二个,然后一个一个把最大的挑出来(从大到小排序)。以此类推,跟冒泡不同的是,把确定的元素放到左边——i是用来做比较的下标——j是比i大1,然后逐渐递增的下标的元素下面是排序从大到小:public class SelectionSort {    public static void main(String[] args) {        int[] arr={2,5,8,9,1,5,6,4,7,8};        //i是要拿来做比较的元素下标        for (int i=0;i<arr.length-1;i++){            for(int j=i+1;j<arr.length;j++){                if(arr[j]>arr[i]){                        int temp=arr[i];                        arr[i]=arr[j];                        arr[j]=temp;                }            }        }        System.out.println(Arrays.toString(arr));}}AI生成项目java运行结果:  (3) 插入排序将0索引到n索引的数据看作是有序的,把索引为n+1一直到最后一个索引当作是无序的,遍历无序的数组,将遍历到的数据插入到有序序列中的合适位置,如遇到相同数据,排在后面,这个方法就是插入排序public class InsertSort {    public static void main(String[] args) {         //将下面的数组按照从大到小排列                int[] arr={5,8,3,2,17,19,15,16,90};                //找无序的开始索引                int startIndex=-1;                for(int i=0;i<arr.length;i++){                    if(arr[i+1]>arr[i]){                        startIndex=i+1;                        break;                    }                }                //从无序开始索引开始插入排序,反向遍历,一个一个对比插入                for(int i=startIndex;i<arr.length;i++){                    int j=i;                    while(j>0&&arr[j]>arr[j-1]){                        int temp=arr[j];                        arr[j]=arr[j-1];                        arr[j-1]=temp;                        j--;                    }                }                //看结果                System.out.println(Arrays.toString(arr));    }}AI生成项目java运行结果: 三.递归算法 递归指的是方法中调用方法自己本身的现象。递归的注意点:一定要有出口,否则会内存溢出。所谓出口就是调用到第几次就不再调用自己了。递归的作用:大事化小,小事化了书写递归的两个核心:1.出口2.找规则如何把大问题转换成规模较小的小问题3.再次调用方法的时候,要更靠近出口实例:求1——100的和public class Recursion {    public static void main(String[] args) {        System.out.println(getSum(100));    }    public static int getSum(int number){        if(number == 1){            return 1;        }        return number + getSum(number - 1);    }}AI生成项目java运行//其实就是把1+100转换成:100+1—99的和99+1—98的和98+1—97的和。。。2+1的和1就是出口————————————————原文链接:https://blog.csdn.net/2403_86850076/article/details/146273968
  • [技术干货] java对接第三方接口的三种实现方式详解
    Java 对接第三方接口的三种实现方式详解在 Java 开发中,调用第三方接口是常见的需求。无论是与外部系统进行数据交互,还是集成第三方服务(如支付、地图、短信等),都需要通过 HTTP 请求与目标接口进行通信。本文将详细介绍三种主流的实现方式:HttpURLConnection、Apache HttpClient 和 Spring RestTemplate,并提供代码示例和注意事项,帮助开发者选择最适合的方案。一、使用 HttpURLConnection(Java 原生方式)1.1 特点与适用场景HttpURLConnection 是 Java 自带的 HTTP 客户端工具,无需引入额外依赖,适合简单的 HTTP 请求场景。其优势在于轻量级和无需配置,但功能相对基础,复杂请求(如设置请求头、处理 JSON 数据)需要手动实现。1.2 示例代码以下是一个发送 POST 请求并处理响应的示例:import java.io.*;import java.net.HttpURLConnection;import java.net.URL;public class HttpURLConnectionExample {    public static void main(String[] args) {        try {            // 创建URL对象            URL url = new URL("https://api.example.com/data");            HttpURLConnection conn = (HttpURLConnection) url.openConnection();                        // 设置请求方法为POST            conn.setRequestMethod("POST");            conn.setRequestProperty("Content-Type", "application/json; utf-8");            conn.setRequestProperty("Accept", "application/json");            conn.setDoOutput(true); // 允许输出流(写入请求体)                        // 构建JSON请求体            String jsonInputString = "{\"name\": \"John\", \"age\": 30}";                        // 写入请求体            try (OutputStream os = conn.getOutputStream()) {                byte[] input = jsonInputString.getBytes("utf-8");                os.write(input, 0, input.length);            }                        // 读取响应            try (BufferedReader br = new BufferedReader(                     new InputStreamReader(conn.getInputStream(), "utf-8"))) {                StringBuilder response = new StringBuilder();                String responseLine;                while ((responseLine = br.readLine()) != null) {                    response.append(responseLine.trim());                }                System.out.println("响应结果: " + response.toString());            }        } catch (Exception e) {            e.printStackTrace();        }    }}AI生成项目java运行1.3 优点与缺点优点:无需依赖,简单易用,适合小型项目或快速原型开发。缺点:功能有限,手动处理请求头和响应较繁琐,不支持异步请求。1.4 注意事项需要手动管理连接超时和读取超时:conn.setConnectTimeout(5000);  // 连接超时时间conn.setReadTimeout(5000);     // 读取超时时间AI生成项目java运行对于需要认证的接口,需手动设置请求头:String auth = "Basic " + Base64.getEncoder().encodeToString("username:password".getBytes());conn.setRequestProperty("Authorization", auth);AI生成项目java运行二、使用 Apache HttpClient(功能强大,灵活可控)2.1 特点与适用场景Apache HttpClient 是一个功能强大的 HTTP 客户端库,支持更复杂的请求场景(如文件上传、身份验证、代理配置等)。它比 HttpURLConnection 更灵活,但需要引入额外依赖。2.2 示例代码以下是一个使用 Apache HttpClient 发送 GET 请求的示例:import org.apache.http.HttpEntity;import org.apache.http.client.methods.CloseableHttpResponse;import org.apache.http.client.methods.HttpGet;import org.apache.http.impl.client.CloseableHttpClient;import org.apache.http.impl.client.HttpClients;import org.apache.http.util.EntityUtils;public class HttpClientExample {    public static void main(String[] args) {        try (CloseableHttpClient httpClient = HttpClients.createDefault()) {            // 创建GET请求            HttpGet httpGet = new HttpGet("https://api.example.com/data");                        // 设置请求头            httpGet.setHeader("Content-Type", "application/json");            httpGet.setHeader("Accept", "application/json");                        // 执行请求            CloseableHttpResponse response = httpClient.execute(httpGet);                        // 获取响应实体            HttpEntity entity = response.getEntity();            if (entity != null) {                String result = EntityUtils.toString(entity);                System.out.println("响应结果: " + result);            }        } catch (Exception e) {            e.printStackTrace();        }    }}AI生成项目java运行2.3 优点与缺点优点:功能全面,支持高级特性(如连接池、重试机制、超时配置)。缺点:需要引入依赖(如 httpclient 和 httpcore),代码略显冗长。2.4 注意事项依赖配置(Maven):<dependency>    <groupId>org.apache.httpcomponents</groupId>    <artifactId>httpclient</artifactId>    <version>4.5.13</version></dependency>AI生成项目xml自定义配置(如超时时间):RequestConfig config = RequestConfig.custom()    .setConnectTimeout(5000)    .setSocketTimeout(5000)    .build();CloseableHttpClient httpClient = HttpClients.custom()    .setDefaultRequestConfig(config)    .build();AI生成项目java运行三、使用 Spring RestTemplate(Spring 生态首选)3.1 特点与适用场景RestTemplate 是 Spring 框架提供的 HTTP 客户端工具,专为 RESTful 接口设计。它简化了请求和响应的处理,支持自动序列化/反序列化(如 JSON、XML),是 Spring 项目中的首选方案。3.2 示例代码以下是一个使用 RestTemplate 发送 GET 和 POST 请求的示例:3.2.1 发送 GET 请求import org.springframework.web.client.RestTemplate;public class RestTemplateExample {    public static void main(String[] args) {        RestTemplate restTemplate = new RestTemplate();        String url = "https://api.example.com/data";                // 发送GET请求并获取响应        String response = restTemplate.getForObject(url, String.class);        System.out.println("GET响应结果: " + response);    }}AI生成项目java运行3.2.2 发送 POST 请求import org.springframework.http.HttpEntity;import org.springframework.http.HttpHeaders;import org.springframework.http.MediaType;import org.springframework.web.client.RestTemplate;public class RestTemplatePostExample {    public static void main(String[] args) {        RestTemplate restTemplate = new RestTemplate();        String url = "https://api.example.com/data";                // 构建请求头        HttpHeaders headers = new HttpHeaders();        headers.setContentType(MediaType.APPLICATION_JSON);                // 构建请求体        String requestBody = "{\"name\": \"John\", \"age\": 30}";        HttpEntity<String> requestEntity = new HttpEntity<>(requestBody, headers);                // 发送POST请求并获取响应        String response = restTemplate.postForObject(url, requestEntity, String.class);        System.out.println("POST响应结果: " + response);    }}AI生成项目java运行3.3 优点与缺点优点:与 Spring 框架无缝集成,支持自动序列化/反序列化,代码简洁。缺点:需要依赖 Spring 框架,不适合非 Spring 项目。3.4 注意事项异常处理:RestTemplate 抛出的 RestClientException 需要捕获处理:try {    String response = restTemplate.getForObject(url, String.class);} catch (RestClientException e) {    e.printStackTrace();}AI生成项目java运行配置超时时间:RestTemplate restTemplate = new RestTemplate();restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());((HttpComponentsClientHttpRequestFactory) restTemplate.getRequestFactory())    .setConnectTimeout(5000);AI生成项目java运行四、三种方式的对比与选择建议实现方式    适用场景    优点    缺点HttpURLConnection    简单的小型项目或快速原型开发    无需依赖,轻量级    功能有限,手动处理较繁琐Apache HttpClient    复杂请求(如认证、文件上传等)    功能全面,灵活可控    需要引入依赖,代码冗长Spring RestTemplate    Spring 项目中的 RESTful 接口交互    与 Spring 无缝集成,代码简洁    依赖 Spring 框架,不适合非 Spring 项目选择建议简单需求:优先使用 HttpURLConnection。复杂需求:选择 Apache HttpClient,尤其是需要高级功能(如连接池、重试)时。Spring 项目:推荐使用 RestTemplate,充分利用 Spring 的生态优势。五、最佳实践统一封装工具类:无论选择哪种方式,建议将 HTTP 请求逻辑封装为工具类,便于复用和维护。异常处理:所有 HTTP 请求都应捕获异常(如网络超时、认证失败),并记录日志。性能优化:使用连接池(如 Apache HttpClient 的 PoolingHttpClientConnectionManager)。启用 GZIP 压缩(Accept-Encoding: gzip)。安全性:避免硬编码敏感信息(如 API Key),使用环境变量或配置中心。验证响应数据的合法性(如 JSON 格式校验)。六、总结Java 对接第三方接口的三种主流方式各有特点:HttpURLConnection 适合轻量级需求,但功能有限;Apache HttpClient 提供了更强大的功能,适合复杂场景;Spring RestTemplate 在 Spring 项目中表现优异,代码简洁高效。开发者可根据项目需求和框架选择合适的实现方式,并结合最佳实践优化性能和可维护性。随着 Spring 6 和 Java 11+ 的普及,未来可能会更多采用 HttpClient(Java 11 新特性)或 WebClient(Spring WebFlux),但目前这三种方法仍是主流选择。————————————————原文链接:https://blog.csdn.net/huayula/article/details/148243340
  • [技术干货] Java 排序
    排序稳定的排序:排序之前和排序之后它们俩的相对顺序没有发生变化内部排序:在内存上的排序外部排序:需要借助磁盘等外部空间进行的排序插入排序思想:假设这组数据的第一个元素是有序的,从第二个元素和前面的元素进行比较,找到合适的位置进行插入  // 插入排序    public static void insertSort(int[] array){        for(int i = 1;i < array.length;i++){            int j = i - 1;            int tmp = array[i];            for(;j >= 0;j--){                if(array[j] > tmp){                    array[j+1] = array[j];                }else{                    break;                }            }             array[j + 1] = tmp;        }    }AI生成项目java运行 分析时间复杂度:O(N^2)最坏情况:O(N^2)最好情况:有序的数组,O(N)数据越有序,排序越快适用于待排序数组基本上趋于有序了,时间复杂度趋于O(N)空间复杂度:O(1)稳定性:是一个稳定的排序例子:5 5 7稳定的排序可以改成不稳定的排序,但是不稳定的排序不能改成稳定的排序希尔排序对直接插入排序进行了优化,如果是 5 4 3 2 1 会退化为O(N^2)分组:分完组后,每组都采用直接插入排序中间隔一些元素进行分组的好处:比较大的元素都往后走了,比较小的元素都往前走了缩小增量到最后会把整体看成是一组,5 3 1 组,前面的5 3 都是预排序,真正的排序是最后的一组缩小增量的目的:为了让排序更接近O(N),为了让排序更快   // 希尔排序    public static void shellSort(int[] array){        int gap = array.length;        while(gap > 1){            gap /= 2;            shell(array,gap);        }    }     // 对每组进行插入排序    public static void shell(int[] array,int gap){        for(int i = gap;i < array.length;i++){            int j = i - gap;            int tmp = array[i];            for(;j >= 0;j -= gap){                if(array[j] > tmp){                    array[j+gap] = array[j];                }else{                    break;                }            }             array[j + gap] = tmp;        }    }AI生成项目java运行 分析时间复杂度:O(N^1.3 - N ^ 1.5),时间复杂度不好计算空间复杂度:O(1)稳定性:不稳定的排序检测排序速度: public static void testInsert(int[] array){        long startTime = System.currentTimeMillis();        int[] tmp = Arrays.copyOf(array,array.length);        Sort.insertSort(tmp);         long endTime = System.currentTimeMillis();        System.out.println(" " + (endTime - startTime));    }     public static void testShell(int[] array){        long startTime = System.currentTimeMillis();        int[] tmp = Arrays.copyOf(array,array.length);        Sort.shellSort(tmp);         long endTime = System.currentTimeMillis();        System.out.println(" " + (endTime - startTime));    }     // 逆序初始化    public static void initOrder(int[] array){        for(int i = 0;i < array.length;i++){            array[i] = array.length - i;        }    }    public static void main(String[] args) {        int[] arr = new int[10000];        initOrder(arr);        testInsert(arr);        testShell(arr);    }AI生成项目java运行 选择排序在当前i下标对应的值的后面,找到后面最小的值和i下标对应的值交换 // 交换    public static void swap(int i, int j, int[] array){        int tmp = array[i];        array[i] = array[j];        array[j] = tmp;    }     // 选择排序    public static void selectSort(int[] array){        // 在i下标的后面找到比i下标对应的值的最小值,然后交换        int n = array.length;        for(int i = 0;i < n;i++){            int minIndex = i;            for(int j = i + 1;j < n;j++){                if(array[j] < array[i]){                   if(array[j] < array[minIndex]){                       minIndex = j;                   }                }            }            swap(i,minIndex,array);        }    }AI生成项目java运行 双向选择排序时间复杂度还是O(N^2)左边找最大的,右边找最小的,和第一个数和最后一个数交换 存在缺陷,maxIndex下标可能是在0下标是最大的,0下标会和最小值小标的值交换,那么0下标就不是最大值下标,应该更新为maxIndex = minIndex  public static void selectSort2(int[] array){        // 在i下标的后面找到比i下标对应的值的最小值,然后交换        int left = 0;        int right = array.length - 1;        while(left < right){            int minIndex = left;            int maxIndex = left;            for(int i = left + 1;i <= right;i++){                if(array[i] < array[minIndex]){                    minIndex = i;                }                if(array[i] > array[maxIndex]){                    maxIndex = i;                }            }            swap(left,minIndex,array);            // 第一个数是最大的数,防止最小的下标和第一个数换了,最大值就在minIndex的位置了            if(maxIndex == left){                maxIndex = minIndex;            }            swap(right,maxIndex,array);            left++;            right--;        }    }AI生成项目java运行 分析时间复杂度:O(N^2)空间复杂度:O(1)稳定性:不稳定的排序堆排序// 堆排序    private static void shifDown(int[] array,int parent,int len){        int child = 2 * parent + 1;        while(child < len){            if(child + 1 < len && array[child] < array[child + 1]){                child++;            }             if(array[child] > array[parent]){                swap(child,parent,array);                parent = child;                child = 2 * parent + 1;            }else{                break;            }        }    }     private static void createHeap(int[] array){        // 建立大根堆        for(int parent = (array.length - 1 - 1) / 2;parent >= 0;parent--) {            shifDown(array, parent, array.length);        }    }     public static void heapSort(int[] array){        createHeap(array);        int end = array.length - 1;        while(end > 0){            swap(end,0,array);            shifDown(array,0,end);            end--;        }    }AI生成项目java运行 分析时间复杂度:O(N * logN)空间复杂度:O(1)稳定性:不稳定的排序冒泡排序// 冒泡排序    public static void bubbleSort(int[] array){        // i是趟数        for(int i = 0;i < array.length;i++){            // j是比较的大小的            boolean flag = true;            for(int j = 0;j < array.length - i - 1;j++){                if(array[j] > array[j + 1]){                    swap(j,j + 1,array);                    flag = false;                }            }            if(flag) {                break;            }        }    }AI生成项目java运行 分析时间复杂度:O(N ^ 2)空间复杂度:O(1)稳定性:稳定的排序快速排序霍尔法根据二叉树进行递归划分  // 快速排序    public static void quickSort(int[] array){        quick(array,0,array.length - 1);    }      private static void quick(int[] array,int start,int end){        if(start >= end){            return;        }         int prvot = partitionHoare(array,start,end);        quick(array,start,prvot - 1);        quick(array,prvot + 1,end);    }     private static int partitionHoare(int[] array,int left,int right){        // 基准元素        int tmp = array[left];        // 记录第一个基准下标        int i = left;        while(left < right) {            // 必须先找先右再左            // 找小            while (left < right && array[right] >= tmp) {                right--;            }            // 找大            while (left < right && array[left] <= tmp) {                left++;            }            swap(left, right, array);        }        swap(i,left,array);         return left;    }AI生成项目java运行 为什么有等于号?没有等于号,会死循环,比如两端都是6  为什么先从右边开始,不先从左边开始?先走左边的话,先遇到大的停下来,如果相遇的话,那么相遇位置的值就是大于基准元素的,这时候交换的话,6的左边有一个数比6大 分析时间复杂度:最好情况下:O(N * logN)每层都有N个节点,高度为logN,需要每个节点都遍历到,N * logN次遍历最坏情况下:O(N^2),有序/逆序,单分支的树空间复杂度:最好情况下:O(logN)最坏情况下:O(N),有序/逆序,单分支的树递归左边再递归右边,递归右边左边没有释放稳定性:不稳定的排序挖坑法找基准先走右边再走左边,以第一个元素为基准,并且拿出基准元素,基准元素的位置就是坑,如果右边找到比基准小的,把它放入坑中,左边找到比基准元素大的放到坑中,最后两者相遇,把基准元素放入其中// 挖坑法    private static int partitionHole(int[] array,int left,int right){        // 基准元素        int tmp = array[left];        while(left < right) {            // 必须先找先右再左            // 找小            while (left < right && array[right] >= tmp) {                right--;            }            array[left] = array[right];            // 找大            while (left < right && array[left] <= tmp) {                left++;            }            array[right] = array[left];        }        array[left] = tmp;         return left;    }AI生成项目java运行 前后指针法如果cur比基准元素小并且cur下标的值和prev下标的值不相等,  // 前后指针法    public static int partition(int[] array,int left,int right){        int prev = left;        int cur = left + 1;        while(cur <= right){            while(array[cur] < array[left] && array[++prev] != array[cur]){                swap(cur,prev,array);            }            cur++;        }        swap(prev,left,array);         return prev;    }AI生成项目java运行 题目优先试挖坑法,其次是Hoare,最后是前后指针法A   快排的优化均匀的分割数组让递归的次数变少三数取中法三数取中法:left,right,mid三个下标中的中间值和第一个数交换位置,然后右边找比基准元素小的值,左边找比基准元素大的值规定array[mid] <= array[left] <= array[right] // 三数取中法,求中位数的下标    private static int middleNum(int[] array,int left,int right){        int mid = (left + right) / 2;        if(array[left] < array[right]){            // 1. x < 3 < 9            // 2. 3 < 9 < x            // 3. 3 < x < 9            if(array[mid] < array[left]){                return left;            }            else if(array[mid] > array[right]){                return right;            }            else{                return mid;            }        }else{            // 9 > 3 == left > right            // 1. x > left > right            if(array[mid] > array[left]){                return left;            }else if(array[right] > array[mid]){                // 2. left > right > x                return right;            }else{                // 3. left > x > right                return mid;            }        }    }     private static void quick(int[] array,int start,int end){        if(start >= end){            return;        }         // 1 2 3 4 5 6 7        // 中间值的下标和第一个数交换,作为新的基准元素        int index = middleNum(array,start,end);        swap(index,start,array);        // 4 2 3 1 5 6 7        // 为了让左右分布更均匀,降低树的高度,减少递归的次数         int prvot = partition(array,start,end);        quick(array,start,prvot - 1);        quick(array,prvot + 1,end);    }AI生成项目java运行 只剩最后几层时,使用插入排序进行优化,降低递归次数,可以使用插入排序是因为前面递归成有序的序列了 public static void insertSort(int[] array,int left,int right){        for(int i = left + 1;i <= right;i++){            int j = i - 1;            int tmp = array[i];            for(;j >= left;j--){                if(array[j] > tmp){                    array[j+1] = array[j];                }else{                    break;                }            }             array[j + 1] = tmp;        }    }     private static void quick(int[] array,int start,int end){        if(start >= end){            return;        }         if(end - start + 1 <= 15){            // 减少递归的次数            // 因为最后几层节点数最多,递归次数也多            insertSort(array,start,end);            return;        }         // 1 2 3 4 5 6 7        // 中间值的下标和第一个数交换,作为新的基准元素        int index = middleNum(array,start,end);        swap(index,start,array);        // 4 2 3 1 5 6 7        // 为了让左右分布更均匀,降低树的高度,减少递归的次数         int prvot = partition(array,start,end);        quick(array,start,prvot - 1);        quick(array,prvot + 1,end);    }AI生成项目java运行 非递归实现快排找基准里面会进行交换元素,进行排序,外面就进行找到左右下标位置   // 非递归实现快速排序    public static void quickSortNor(int[] array){        int start = 0;        int end = array.length - 1;        Stack<Integer> stack = new Stack<>();         int pivot = partitionHoare(array,start,end);        if(pivot - 1 > start){            // 左边有两个元素            stack.push(start);            stack.push(pivot - 1);        }        else if(pivot + 1 < end){            // 右边至少有两个元素            stack.push(pivot + 1);            stack.push(end);        }        // 找基准里面会互换元素进行排序        while(!stack.empty()){            end = stack.pop();            start = stack.pop();             pivot = partitionHoare(array,start,end);            if(pivot - 1 > start){                // 左边有两个元素                stack.push(start);                stack.push(pivot - 1);            }            else if(pivot + 1 < end){                // 右边至少有两个元素                stack.push(pivot + 1);                stack.push(end);            }        }AI生成项目java运行 归并排序分解:根据mid进行分解 合并:第一个有序段和第二个有序段,比较大小放入一个新的数组中  // 归并排序    public static void mergeSort(int[] array){        merge(array,0,array.length - 1);    }     private static void merge(int[] array,int start,int end){        if(start >= end){            return;        }         int mid = (start + end) / 2;        // 分解        merge(array,start,mid);        merge(array,mid + 1,end);        // 合并        mergeHeB(array,start,mid,end);    }     private static void mergeHeB(int[] array, int left, int mid, int right) {        int s1 = left;        int e1 = mid;        int s2 = mid + 1;        int e2 = right;         // 新数组的下标        int k = 0;        int[] tmpArray = new int[right - left + 1];         while(s1 <= e1 && s2 <= e2){            if(array[s1] < array[s2]){                tmpArray[k++] = array[s1++];            }else{                tmpArray[k++] = array[s2++];            }        }         while(s1 <= e1){            tmpArray[k++] = array[s1++];        }         while(s2 <= e2){            tmpArray[k++] = array[s2++];        }         // left是因为有左边还有右边的数组        // tmpArray是临时数组,会销毁的,需要拷贝回原来的数组        for(int i = 0;i < tmpArray.length;i++){            array[i + left] = tmpArray[i];        }    }AI生成项目java运行 分析时间复杂度:O(N * logN)空间复杂度:O(N),因为每次合并数组的时候要开O(N)大小的额外空间稳定性:稳定的排序非递归实现归并排序先一个一个有序,两个两个有序,四个四个有序,八个八个有序…gap = 1left = imid = left + gap - 1right = mid + gapgap *= 2每组合并完,最终就有序了  // 非递归实现归并排序    public static void mergeSortNor(int[] array){        // gap表示每组的数据个数        int gap = 1;        while(gap < array.length){             for(int i = 0;i < array.length;i = i + 2 * gap){                int left = i;                 // mid和right可能会越界                // 比如只有5个元素                // 分解右边一半的时候                // l = i mid = 5 r = 7                int mid = left + gap - 1;                int right = mid + gap;                 if(mid >= array.length){                    mid = array.length - 1;                }                if(right >= array.length){                    right = array.length - 1;                }                  mergeHeB(array,left,mid,right);            }             gap *= 2;        }    }AI生成项目java运行 海量数据的排序使用归并排序进行外部排序,如果内存中不够空间的话  非比较的排序计数排序通过统计每次数字出现的次数,最后按照顺序从小到大输出这些数字适用的场景:指定范围内的数据  // 计数排序,指定范围内的数据进行排序// O(Max(N,范围))    public static void countSort(int[] array){        int minVal = array[0];        int maxVal = array[0];                // O(N)        for(int i = 0;i < array.length;i++){            if(minVal > array[i]){                minVal = array[i];            }            if(maxVal < array[i]){                maxVal = array[i];            }        }         int len = maxVal - minVal + 1;        int[] count = new int[len];        // O(N)        for(int i = 0;i < array.length;i++){            count[array[i] - minVal]++;        }                               // 写回array数组中        // O(范围)        // 因为count数组集中于一个数字,那么也是O(范围)        // 如果count数组不集中于一个数子,也是N倍的范围        // 也是O(范围)        int k = 0;        for(int i = 0;i < count.length;i++){            while(count[i] > 0){                array[k++] = i + minVal;                count[i]--;            }        }    }AI生成项目java运行 分析时间复杂度:O(Max(N,范围))空间复杂度:O(范围)稳定性:稳定的排序基数排序开10个大小的空间,分别依次比较个位大小,十位大小和百位大小,最终达到有序,每个空间都是一个队列  桶排序先把数字放入一个范围的区间内进行排序,排好序依次拿出来,最终就有序了———————————————— 原文链接:https://blog.csdn.net/2301_79722622/article/details/149584998
  • [技术干货] Java 基础——Scanner 类
    一、Scanner 类概述Scanner 类是 Java 中用于获取用户输入的一个实用类,它位于 java.util 包下。通过 Scanner 类,可以方便地从多种输入源(比如标准输入流,也就是键盘输入,或者文件等)读取不同类型的数据,例如整数、小数、字符串等,大大简化了输入操作相关的编程工作。二、Scanner 类的创建在使用 Scanner 类之前,需要先创建它的对象。如果要从标准输入(键盘)读取数据,创建示例代码如下:import java.util.Scanner; public class ScannerExample {    public static void main(String[] args) {        Scanner scanner = new Scanner(System.in);        // 后续可使用该scanner对象进行输入读取操作    }}AI生成项目这里通过 new Scanner(System.in) 创建了一个 Scanner 对象,System.in 表示标准输入流,意味着后续操作将从键盘获取输入内容。三、常用方法及读取不同类型数据1.读取整数使用 nextInt() 方法可以读取用户输入的整数,示例代码如下:import java.util.Scanner; public class ReadInt {    public static void main(String[] args) {        Scanner scanner = new Scanner(System.in);        System.out.println("请输入一个整数:");        int num = scanner.nextInt();//程序执行到这里就会停下来,等待键盘的输入。                                    //键盘如果没有输入,这里就会一直卡着            //直到用户输入了内容之后,敲回车,这行代码就执行结束了             //这样就完成了数据从控制台到内存         System.out.println("你输入的整数是: " + num);        scanner.close();    }}AI生成项目这里提示用户输入整数后,调用 nextInt() 方法获取输入并赋值给 int 类型的变量 num,最后输出展示读取到的整数内容。需要注意的是,在读取完成后,如果不再需要使用该 Scanner 对象,最好调用 scanner.close() 方法关闭它,以释放相关资源。注意:针对nextInt()方法来说,只能接收整数数字。输入其他的字符串会报错。2.读取浮点数(小数)若要读取浮点数,可以使用 nextFloat() 方法(读取单精度浮点数) 或者 nextDouble() 方法(读取双精度浮点数),示例代码如下:import java.util.Scanner; public class ReadFloat {    public static void main(String[] args) {        Scanner scanner = new Scanner(System.in);        System.out.println("请输入一个单精度浮点数:");        float fNum = scanner.nextFloat();        System.out.println("你输入的单精度浮点数是: " + fNum);         System.out.println("请输入一个双精度浮点数:");        double dNum = scanner.nextDouble();        System.out.println("你输入的双精度浮点数是: " + dNum);         scanner.close();    }}AI生成项目上述代码分别演示了读取单精度和双精度浮点数的过程,按照提示输入相应类型的小数,就能通过对应方法获取并输出展示。3.读取字符串读取字符串有两种常用方式,一种是 next() 方法,一种是 nextLine() 方法。(1).next() 方法: 它读取输入的下一个单词(以空格、制表符等空白字符作为分隔符)细节:从键盘上接收一个字符串,但是接收的是第一个空格之前的内容示例代码1:import java.util.Scanner; public class ReadStringNext {    public static void main(String[] args) {        Scanner scanner = new Scanner(System.in);        System.out.println("请输入一些单词(以空格分隔):");        String word = scanner.next();        System.out.println("你输入的单词是: " + word);        scanner.close();    }}AI生成项目输入多个单词时,它只会获取第一个单词并返回。示例代码2:import java.util.Scanner;public class scannerTest {    public static void main(String[] args) {        Scanner s=new Scanner(System.in);        String username=s.next();        System.out.println(username);    }}AI生成项目(2).nextLine() 方法:该方法读取输入的一整行内容,示例代码:import java.util.Scanner; public class ReadStringNextLine {    public static void main(String[] args) {        Scanner scanner = new Scanner(System.in);        System.out.println("请输入一行文字:");        String line = scanner.nextLine();        System.out.println("你输入的文字内容是: " + line);        scanner.close();    }}AI生成项目它会获取从当前位置到行尾的所有字符,更适合读取完整的语句等情况。注意:从键盘上接收一个字符串,但是接收的是第一个换行符\n之前的内容可能遇到的问题及注意事项1.输入不匹配异常如果用户输入的数据类型和期望读取的数据类型不一致,例如:期望读取整数,但用户输入了字母等非数字内容,会抛出 InputMismatchException 异常。所以在实际应用中,可能需要添加异常处理代码来让程序更健壮,示例如下:import java.util.InputMismatchException;import java.util.Scanner; public class ExceptionHandle {    public static void main(String[] args) {        Scanner scanner = new Scanner(System.in);        try {            System.out.println("请输入一个整数:");            int num = scanner.nextInt();            System.out.println("你输入的整数是: " + num);        } catch (InputMismatchException e) {            System.out.println("输入的数据类型不正确,请重新输入整数!");        } finally {            scanner.close();        }    }}AI生成项目这里使用 try-catch 语句块捕获可能出现的输入类型不匹配异常,并在 catch 块中给出相应提示,无论是否出现异常,最终都会在 finally 块中关闭 Scanner 对象。2.nextLine() 方法使用的坑由于nextInt()只读取整数,不读取后续的换行符,这会导致nextLine()在下一次调用时直接读取空字符串。解决方法是使用nextLine()获取整数后的换行符,避免空字符导致的跳过输入现象。import java.util.Scanner;public class scannerTest {    public static void main(String[] args) {        Scanner s=new Scanner(System.in);        String username=s.next(); //无论是next(),还是nextInt(),nextDouble()这几个方法接收的是第一个空格之前的内容                         //而对于 son依旧留在缓存中,其在缓存的格式为 son\r(回车符)        System.out.println(username);         String position=s.nextLine();//执行到这一行时,nextLine回去缓存读内容,而读到\r时就结束了                                     //即读取了 son                                     //所以这一行的运行,用户无法输入东西        System.out.println(position);         String name =s.nextLine();        System.out.println(name);    }}AI生成项目运行结果: 当在调用 nextInt() 或者其他读取基本类型的方法(如 nextFloat() 等)后紧接着调用 nextLine() 方法时,可能会出现问题。因为 nextInt() 等方法读取数据后,留下的换行符(回车键对应的字符)会被 nextLine() 当作输入内容读取,导致 nextLine() 似乎 “跳过” 了用户的输入。解决办法通常是在调用 nextLine() 之前,先额外调用一次 nextLine() 来消耗掉前面留下的换行符,示例如下:import java.util.Scanner; public class NextLineIssue {    public static void main(String[] args) {        Scanner scanner = new Scanner(System.in);        System.out.println("请输入一个整数:");        int num = scanner.nextInt();        scanner.nextLine(); // 消耗掉换行符         System.out.println("请输入一行文字:");        String line = scanner.nextLine();        System.out.println("你输入的文字内容是: " + line);         scanner.close();    }}AI生成项目总之,Scanner 类在 Java 中是很常用的用于处理输入的类,掌握好它的使用方法以及注意相关问题,能更好地实现具有交互性的 Java 程序。————————————————原文链接:https://blog.csdn.net/m0_73941339/article/details/144803973
  • [技术干货] javaSE泛型、反射与注解
    泛型、反射与注解是 JavaSE 中支撑 “灵活编程” 与 “框架设计” 的核心技术。泛型解决 “类型安全” 问题,反射实现 “运行时动态操作类”,注解提供 “代码标记与元数据” 能力 —— 三者结合构成了 Java 框架(如 Spring、MyBatis)的底层基础。本章节将系统讲解这三项技术的核心原理与实际应用。一、泛型(Generic):编译时的类型安全保障在泛型出现之前,集合(如List)默认存储Object类型,取出元素时需强制转换,容易出现ClassCastException(类型转换异常)。泛型通过 “编译时类型指定”,让集合只能存储特定类型元素,从源头避免类型错误。1.1 泛型的核心作用编译时类型检查:限制集合(或泛型类)只能存储指定类型元素,编译阶段就报错,而非运行时崩溃。避免强制转换:取出元素时无需手动转换(编译器自动确认类型)。代码复用:一套逻辑支持多种类型(如List<String>、List<Integer>共用List的实现)。1.2 泛型的基本用法1.2.1 泛型类与泛型接口泛型类 / 接口在定义时声明 “类型参数”(如<T>),使用时指定具体类型(如String)。泛型类示例:// 定义泛型类:声明类型参数T(Type的缩写,可自定义名称)class GenericBox<T> {    // 使用T作为类型(类似变量,代表一种类型)    private T value;     // T作为方法参数和返回值    public void setValue(T value) {        this.value = value;    }     public T getValue() {        return value;    }} public class GenericClassDemo {    public static void main(String[] args) {        // 使用时指定类型为String(只能存String)        GenericBox<String> stringBox = new GenericBox<>();        stringBox.setValue("Hello"); // 正确:存入String        // stringBox.setValue(123); // 编译错误:不能存Integer         // 取出时无需转换(自动为String类型)        String str = stringBox.getValue();        System.out.println(str); // 输出:Hello         // 指定类型为Integer        GenericBox<Integer> intBox = new GenericBox<>();        intBox.setValue(100);        Integer num = intBox.getValue(); // 无需转换        System.out.println(num); // 输出:100    }}AI生成项目泛型接口示例:// 定义泛型接口(支持多种类型的“生产者”)interface Producer<T> {    T produce();} // 实现泛型接口时指定具体类型(如String)class StringProducer implements Producer<String> {    @Override    public String produce() {        return "生产的字符串";    }} // 实现时保留泛型(让子类也成为泛型类)class NumberProducer<T extends Number> implements Producer<T> {    private T value;     public NumberProducer(T value) {        this.value = value;    }     @Override    public T produce() {        return value;    }} public class GenericInterfaceDemo {    public static void main(String[] args) {        Producer<String> strProducer = new StringProducer();        String str = strProducer.produce();        System.out.println(str); // 输出:生产的字符串         Producer<Integer> intProducer = new NumberProducer<>(100);        Integer num = intProducer.produce();        System.out.println(num); // 输出:100    }}AI生成项目1.2.2 泛型方法泛型方法在方法声明时独立声明类型参数(与类是否泛型无关),适用于 “单个方法需要支持多种类型” 的场景。class GenericMethodDemo {    // 定义泛型方法:<E>是方法的类型参数,声明在返回值前    public <E> void printArray(E[] array) {        for (E element : array) {            System.out.print(element + " ");        }        System.out.println();    }     // 泛型方法带返回值    public <E> E getFirstElement(E[] array) {        if (array != null && array.length > 0) {            return array[0];        }        return null;    }} public class TestGenericMethod {    public static void main(String[] args) {        GenericMethodDemo demo = new GenericMethodDemo();         // 调用时自动推断类型(无需显式指定)        String[] strArray = {"A", "B", "C"};        demo.printArray(strArray); // 输出:A B C          Integer[] intArray = {1, 2, 3};        demo.printArray(intArray); // 输出:1 2 3          // 获取第一个元素(自动返回对应类型)        String firstStr = demo.getFirstElement(strArray);        Integer firstInt = demo.getFirstElement(intArray);        System.out.println("字符串数组第一个元素:" + firstStr); // 输出:A        System.out.println("整数数组第一个元素:" + firstInt);   // 输出:1    }}AI生成项目泛型方法特点:类型参数声明在方法返回值前(如<E>),与类的泛型参数无关。调用时编译器自动推断类型(无需手动指定,如传入String[]则E自动为String)。1.2.3 类型通配符(Wildcard)当需要处理 “未知类型的泛型” 时(如方法参数需要接收任意泛型List),使用通配符?及限定符(extends、super)控制类型范围。通配符形式    含义    适用场景<?>    任意类型(无限制)    仅读取元素,不修改(如打印任意 List)<? extends T>    上限:只能是 T 或 T 的子类    读取(可获取 T 类型),不能添加(除 null)<? super T>    下限:只能是 T 或 T 的父类    添加(可添加 T 或子类),读取只能到 Object通配符示例:import java.util.ArrayList;import java.util.List; public class WildcardDemo {    // 1. 无限制通配符<?>:接收任意List,只能读,不能写(除null)    public static void printList(List<?> list) {        for (Object obj : list) { // 只能用Object接收            System.out.print(obj + " ");        }        System.out.println();        // list.add("A"); // 编译错误:无法确定类型,不能添加非null元素    }     // 2. 上限通配符<? extends Number>:只能接收Number或其子类(如Integer、Double)    public static double sum(List<? extends Number> list) {        double total = 0;        for (Number num : list) { // 可安全转为Number            total += num.doubleValue(); // 调用Number的方法        }        return total;    }     // 3. 下限通配符<? super Integer>:只能接收Integer或其父类(如Number、Object)    public static void addIntegers(List<? super Integer> list) {        list.add(10); // 可添加Integer(或其子类,如Integer本身)        list.add(20);        // Integer num = list.get(0); // 编译错误:只能用Object接收    }     public static void main(String[] args) {        // 测试<?>        List<String> strList = List.of("A", "B");        List<Integer> intList = List.of(1, 2);        printList(strList); // 输出:A B         printList(intList); // 输出:1 2          // 测试<? extends Number>        List<Integer> integerList = List.of(1, 2, 3);        List<Double> doubleList = List.of(1.5, 2.5);        System.out.println("整数和:" + sum(integerList)); // 输出:6.0        System.out.println("小数和:" + sum(doubleList));  // 输出:4.0         // 测试<? super Integer>        List<Number> numberList = new ArrayList<>();        addIntegers(numberList); // 向NumberList添加Integer        System.out.println("添加后:" + numberList); // 输出:[10, 20]    }}AI生成项目1.3 泛型的局限不能用基本类型:泛型参数只能是引用类型(如List<int>错误,需用List<Integer>)。运行时擦除:泛型信息在编译后被擦除(如List<String>和List<Integer>运行时都是List),无法通过instanceof判断泛型类型。静态方法不能用类的泛型参数:静态方法属于类,而泛型参数随对象变化,若需泛型需定义为泛型方法。二、反射(Reflection):运行时的类信息操作反射允许程序在运行时获取类的信息(如类名、属性、方法、构造器),并动态操作这些成分(如调用私有方法、修改私有属性)。这打破了 “编译时确定代码逻辑” 的限制,让程序更灵活(也是框架实现 “自动装配”“依赖注入” 的核心)。2.1 反射的核心作用运行时获取类信息:无需提前知道类名,就能获取类的属性、方法等元数据。动态创建对象:通过类信息动态实例化对象(如Class.newInstance())。动态调用方法:包括私有方法(通过反射可绕过访问权限)。动态操作属性:包括私有属性(可修改值)。2.2 反射的核心类反射的所有操作都基于java.lang.Class类(类对象),它是反射的 “入口”。核心类 / 接口    作用Class    类的元数据对象,代表一个类的信息Constructor    类的构造器对象,用于创建实例Method    类的方法对象,用于调用方法Field    类的属性对象,用于访问 / 修改属性值2.3 反射的基本操作2.3.1 获取 Class 对象(反射入口)获取Class对象有 3 种方式,根据场景选择:class Student {    private String name;    private int age;     public Student() {}     public Student(String name, int age) {        this.name = name;        this.age = age;    }     public void study() {        System.out.println(name + "正在学习");    }     private String getInfo() {        return "姓名:" + name + ",年龄:" + age;    }} public class GetClassDemo {    public static void main(String[] args) throws ClassNotFoundException {        // 方式1:通过对象.getClass()(已知对象)        Student student = new Student();        Class<?> clazz1 = student.getClass();        System.out.println("方式1:" + clazz1.getName()); // 输出:Student         // 方式2:通过类名.class(已知类名,编译时确定)        Class<?> clazz2 = Student.class;        System.out.println("方式2:" + clazz2.getName()); // 输出:Student         // 方式3:通过Class.forName("全类名")(仅知类名,运行时动态获取,最常用)        Class<?> clazz3 = Class.forName("Student"); // 全类名:包名+类名(此处默认无包)        System.out.println("方式3:" + clazz3.getName()); // 输出:Student         // 验证:同一个类的Class对象唯一        System.out.println(clazz1 == clazz2); // 输出:true        System.out.println(clazz1 == clazz3); // 输出:true    }}AI生成项目说明:一个类的Class对象在 JVM 中唯一,是类加载的产物(类加载时 JVM 自动创建Class对象)。2.3.2 反射创建对象(通过构造器)通过Class对象获取Constructor,再调用newInstance()创建实例(支持无参和有参构造)。import java.lang.reflect.Constructor;import java.lang.reflect.InvocationTargetException; public class ReflectNewInstance {    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {        // 1. 获取Class对象        Class<?> clazz = Class.forName("Student");         // 2. 方式1:调用无参构造(若类无无参构造,会抛异常)        Student student1 = (Student) clazz.newInstance(); // 已过时,推荐用Constructor        System.out.println("无参构造创建:" + student1);         // 3. 方式2:调用有参构造(更灵活,推荐)        // 获取有参构造器(参数为String和int)        Constructor<?> constructor = clazz.getConstructor(String.class, int.class);        // 传入参数创建实例        Student student2 = (Student) constructor.newInstance("张三", 18);        System.out.println("有参构造创建:" + student2);    }}AI生成项目2.3.3 反射调用方法(包括私有方法)通过Method对象调用方法,支持公有和私有方法(私有方法需先设置setAccessible(true)取消访问检查)。import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method; public class ReflectInvokeMethod {    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {        Class<?> clazz = Class.forName("Student");        Student student = (Student) clazz.getConstructor(String.class, int.class).newInstance("张三", 18);         // 1. 调用公有方法(study())        // 获取方法:参数1为方法名,参数2为参数类型(无参则不写)        Method studyMethod = clazz.getMethod("study");        // 调用方法:参数1为实例对象,参数2为方法参数(无参则不写)        studyMethod.invoke(student); // 输出:张三正在学习         // 2. 调用私有方法(getInfo())        // 获取私有方法需用getDeclaredMethod(getMethod只能获取公有)        Method getInfoMethod = clazz.getDeclaredMethod("getInfo");        // 取消访问检查(关键:私有方法必须设置,否则抛异常)        getInfoMethod.setAccessible(true);        // 调用私有方法        String info = (String) getInfoMethod.invoke(student);        System.out.println("私有方法返回:" + info); // 输出:姓名:张三,年龄:18    }}AI生成项目2.3.4 反射操作属性(包括私有属性)通过Field对象访问或修改属性,私有属性同样需要setAccessible(true)。import java.lang.reflect.Field; public class ReflectOperateField {    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {        Class<?> clazz = Class.forName("Student");        Student student = (Student) clazz.getConstructor().newInstance(); // 无参构造创建         // 1. 获取并修改私有属性name        Field nameField = clazz.getDeclaredField("name"); // 获取私有属性        nameField.setAccessible(true); // 取消访问检查        nameField.set(student, "李四"); // 设置属性值(参数1为实例,参数2为值)         // 2. 获取并修改私有属性age        Field ageField = clazz.getDeclaredField("age");        ageField.setAccessible(true);        ageField.set(student, 20);         // 验证修改结果(调用之前的私有方法getInfo())        Method getInfoMethod = clazz.getDeclaredMethod("getInfo");        getInfoMethod.setAccessible(true);        String info = (String) getInfoMethod.invoke(student);        System.out.println("修改后信息:" + info); // 输出:姓名:李四,年龄:20    }}AI生成项目2.4 反射的应用场景框架底层:Spring 的 IOC 容器通过反射创建对象并注入依赖;MyBatis 通过反射将数据库结果集映射为 Java 对象。注解解析:自定义注解需配合反射获取注解标记的类 / 方法,执行对应逻辑(如权限校验)。动态代理:AOP 的动态代理(如 JDK 代理)基于反射实现方法增强。工具类:如 JSON 序列化工具(Jackson、FastJSON)通过反射获取对象属性并转为 JSON。2.5 反射的优缺点优点:灵活性高,支持运行时动态操作,是框架的核心技术。缺点:性能损耗:反射操作绕开编译优化,性能比直接调用低(但框架中影响可接受)。破坏封装:可直接访问私有成员,可能导致代码逻辑混乱。可读性差:反射代码较繁琐,不如直接调用直观。三、注解(Annotation):代码的标记与元数据注解(Annotation)是 Java 5 引入的特性,本质是 “代码的标记”,可在类、方法、属性等元素上添加,用于携带 “元数据”(描述数据的数据)。注解本身不直接影响代码逻辑,但可通过反射解析注解,执行对应操作。3.1 注解的核心作用标记代码:如@Override标记方法重写,编译器会校验是否符合重写规则。携带元数据:如@Test标记测试方法,测试框架会自动执行标记的方法。简化配置:替代 XML 配置(如 Spring 的@Controller标记控制器类)。3.2 常用内置注解Java 内置了 3 个基本注解(定义在java.lang包),编译器会识别并处理:注解名称    作用    使用位置@Override    标记方法为重写父类的方法,编译器校验    方法@Deprecated    标记元素(类、方法等)已过时,编译器警告    类、方法、属性等@SuppressWarnings    抑制编译器警告(如未使用变量警告)    类、方法等内置注解示例:public class BuiltInAnnotationDemo {    // @Deprecated:标记方法已过时    @Deprecated    public void oldMethod() {        System.out.println("这是过时的方法");    }     // @Override:标记方法重写(若父类无此方法,编译报错)    @Override    public String toString() {        return "BuiltInAnnotationDemo对象";    }     // @SuppressWarnings:抑制“未使用变量”警告    @SuppressWarnings("unused")    public void test() {        int unusedVar = 10; // 若没有@SuppressWarnings,编译器会警告“变量未使用”        // 调用过时方法(编译器会警告,但可执行)        oldMethod();    }     public static void main(String[] args) {        new BuiltInAnnotationDemo().test();    }}AI生成项目3.3 元注解:定义注解的注解自定义注解时,需要用 “元注解”(注解的注解)指定注解的 “作用范围”“保留策略” 等。Java 提供 4 个元注解(定义在java.lang.annotation包):元注解名称    作用    常用值@Target    指定注解可使用的位置(如方法、类)    ElementType.METHOD(方法)、ElementType.TYPE(类)等@Retention    指定注解的保留策略(生命周期)    RetentionPolicy.RUNTIME(运行时保留,可反射获取)@Documented    标记注解会被 javadoc 文档记录    无参数@Inherited    标记注解可被子类继承    无参数核心元注解:@Target和@Retention是自定义注解必须的 ——@Target限制使用位置,@Retention(RetentionPolicy.RUNTIME)确保注解在运行时存在(才能被反射解析)。3.4 自定义注解及解析自定义注解需配合反射使用:先定义注解,再在代码中标记,最后通过反射解析注解并执行逻辑。示例:自定义权限校验注解import java.lang.annotation.*;import java.lang.reflect.Method; // 1. 定义自定义注解@Target(ElementType.METHOD) // 注解只能用在方法上@Retention(RetentionPolicy.RUNTIME) // 运行时保留,可反射获取@interface RequirePermission {    // 注解属性(类似方法,可指定默认值)    String value(); // 权限名称(如"admin")} // 2. 使用注解标记方法class UserService {    // 标记需要"admin"权限才能执行    @RequirePermission("admin")    public void deleteUser() {        System.out.println("执行删除用户操作");    }     // 标记需要"user"权限才能执行    @RequirePermission("user")    public void queryUser() {        System.out.println("执行查询用户操作");    }} // 3. 通过反射解析注解,实现权限校验class PermissionChecker {    // 模拟当前用户拥有的权限    private String currentPermission = "admin";     // 执行方法前校验权限    public void executeWithCheck(Object obj, String methodName) throws Exception {        // 获取方法对象        Method method = obj.getClass().getMethod(methodName);        // 判断方法是否有@RequirePermission注解        if (method.isAnnotationPresent(RequirePermission.class)) {            // 获取注解对象            RequirePermission annotation = method.getAnnotation(RequirePermission.class);            // 获取注解的权限值            String requiredPerm = annotation.value();            // 校验权限            if (currentPermission.equals(requiredPerm)) {                method.invoke(obj); // 权限通过,执行方法            } else {                throw new RuntimeException("权限不足,需要:" + requiredPerm);            }        } else {            // 无注解,直接执行            method.invoke(obj);        }    }} // 测试public class CustomAnnotationDemo {    public static void main(String[] args) throws Exception {        UserService userService = new UserService();        PermissionChecker checker = new PermissionChecker();         checker.executeWithCheck(userService, "deleteUser"); // 输出:执行删除用户操作(权限足够)        checker.executeWithCheck(userService, "queryUser");  // 输出:执行查询用户操作(权限足够)    }}AI生成项目解析流程:定义注解:用@Target和@Retention指定使用位置和生命周期。使用注解:在目标方法上添加注解,设置属性值。反射解析:通过method.isAnnotationPresent()判断是否有注解,method.getAnnotation()获取注解对象,进而获取属性值并执行逻辑。四、三者关系与总结泛型:编译时保障类型安全,避免强制转换,是编写健壮代码的基础。反射:运行时动态操作类信息,突破编译时限制,是框架灵活性的核心。注解:通过标记携带元数据,配合反射实现 “标记 - 解析 - 执行” 的逻辑,是简化配置的关键。三者结合构成了 Java 高级编程的基础 —— 泛型保证类型安全,反射提供动态能力,注解简化元数据携带,共同支撑了 Spring、MyBatis 等主流框架的设计。————————————————原文链接:https://blog.csdn.net/m0_64198455/article/details/149465961
总条数:685 到第
上滑加载中