zoukankan      html  css  js  c++  java
  • Spring的学习

    IoC是什么?

    ioc通过文件配置来实现对象的创建,以及对象的赋值和注入。

       

    IoC的依赖

    ioc所依赖的包

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    <?xml version="1.0" encoding="UTF-8"?>

    <project xmlns="http://maven.apache.org/POM/4.0.0"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

    <modelVersion>4.0.0</modelVersion>

       

    <groupId>com.wiggin</groupId>

    <artifactId>aispring</artifactId>

    <version>1.0-SNAPSHOT</version>

    <packaging>jar</packaging>

    <repositories>

    <repository>

    <id>huaweicloud</id>

    <name>huaweicloud</name>

    <url>>https://mirrors.huaweicloud.com/repository/maven/</url>

    </repository>

    </repositories>

    <dependencies>

    <dependency>

    <groupId>org.springframework</groupId>

    <artifactId>spring-context</artifactId>

    <version>5.0.7.RELEASE</version>

    </dependency>

    <!-- 简化实体类代码开发-->

    <dependency>

    <groupId>org.projectlombok</groupId>

    <artifactId>lombok</artifactId>

    <version>1.18.0</version>

    <scope>provided</scope>

    </dependency>

       

    <dependency>

    <groupId>dom4j</groupId>

    <artifactId>dom4j</artifactId>

    <version>1.1</version>

    </dependency>

    </dependencies>

       

       

       

       

    </project>

    @Data:控制数据输出成String类型,以及gettersetter函数

    @AllArgsConstructor:快速条件构造函数

    @NoArgsConstructor:添加无参构造

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    package Com.wiggin.entity;

    @Data

    @AllArgsConstructor

    @NoArgsConstructor

    public class Student {

    private Long id;

    private String name;

    private int age;

    private Address address;

       

    }

       

    配置文件

    1.通过配置Bean标签来完成对象的管理

    2.id:对象名

    3.class:对象的模板类。(交给ioc管理的类必须要有无参构造方法,spring底层通过反射机制来创建对象,调用的是无参构造)

    4.对象的成员变量通过property标签完成赋值

    5.name:成员变量名,value成员变量值(基本数据类型,String可以直接赋值,引用类型通过ref注入)

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    <?xml version="1.0" encoding="UTF-8"?>

    <beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="student" class="com.wiggin.entity.Student">

    <property name="id" value="1"></property>

    <property name="name" value="wiggin"></property>

    <property name="age" value="22"></property>

    <property name="address" ref="address"></property>

    </bean>

    <bean id="address" class="com.wiggin.entity.Address">

    <property name="id" value="2"></property>

    <property name="name" value="vivian"></property>

    </bean>

    </beans>

       

       

    IOC的底层原理

    1.读取配置文件,解析XML

    2.通过反射机制,实例化配置文件中所配置文件中所有的Bean

       

    通过运行时类获取bean

    1

    2

    3

    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");

    Student student = (Student) applicationContext.getBean("student");

    System.out.println(student);

    这种方式存在一个问题,配置文件中一个数据类型的对象只能有一个实例。否则会抛出异常,因为没有唯一的bean

       

       

    通过有参构造来创建bean

    1

    2

    3

    4

    5

    6

    <bean id="student3" class="com.wiggin.entity.Student">

    <constructor-arg name="id" value="3"></constructor-arg>

    <constructor-arg name="name" value="bob"></constructor-arg>

    <constructor-arg name="age" value="18"></constructor-arg>

    <constructor-arg name="address" ref="address"></constructor-arg>

    </bean>

    其中name可以实省略,但是可以通过下标来确定位置,但顺序必须与成员变量顺序一致

    1

    2

    3

    4

    5

    6

    <bean id="student3" class="com.wiggin.entity.Student">

    <constructor-arg index="0" value="3"></constructor-arg>

    <constructor-arg index="1" value="bob"></constructor-arg>

    <constructor-arg index="2" value="18"></constructor-arg>

    <constructor-arg index="3" ref="address"></constructor-arg>

    </bean>

       

    给bean注入集合

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    <bean id="student" class="com.wiggin.entity.Student">

    <property name="id" value="1"></property>

    <property name="name" value="wiggin"></property>

    <property name="age" value="22"></property>

    <property name="addresses">

    <list>

    <ref bean="address"></ref>

    <ref bean="address2"></ref>

    </list>

    </property>

    </bean>

    <bean id="address" class="com.wiggin.entity.Address">

    <property name="id" value="1"></property>

    <property name="name" value="科技路"></property>

    </bean>

    <bean id="address2" class="com.wiggin.entity.Address">

    <property name="id" value="2"></property>

    <property name="name" value="高新区"></property>

    </bean>

       

    Scope作用域

    Spring管理bean是根据scope来生成的,表示bean的作用域,共有4种,默认是单例模式

    1)singleton:单例,表示通过Spring容器获取的bean是唯一的,

    2)prototype:原型,表示通过Spring容器获取的bean是不同的

    3)request:请求,表示一次Http请求内有效

    4)session:回话,表示在一个用户会话内有效

    requestsession是适用于web项目,大多数使用单例和原型。

    prototype模式当业务代码获取Ioc容器中的bean时(getbean),Spring才去调用无参构造来创建对应的bean。创建一个bean开辟一个空间,避免bean的利用率低的问题,但是也浪费了地址空间。

    1

    2

    3

    <bean id="student2" class="com.wiggin.entity.Student" scope="prototype">

    <property name="name" value="vivian"></property>

    </bean>

    singleton模式当ioc容器创建时(new ClassPathXmlApplicationContext("applicationContext.xml"))时,bean已经被创造。多个bean指向同一个地址更加节省空间,但是bean在被创建后的利用率低。

       

    Spring的继承

    与java的继承不同,java是类层面的继承,子类可以继承父类的父类的内部结构信息,Spring是对象层面的继承,子对象可以继承父对象的属性值。

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    <bean id="student2" class="com.wiggin.entity.Student">

    <property name="name" value="vivian"></property>

    <property name="id" value="2"></property>

    <property name="age" value="22"></property>

    <property name="addresses">

    <list>

    <ref bean="address"></ref>

    <ref bean="address2"></ref>

    </list>

    </property>

    </bean>

    <bean id="stu" class="com.wiggin.entity.Student" parent="student2">

    <property name="name" value="wzxsb"></property>

    </bean>

       

    Spring的继承的关注点在于具体的对象,而不在于类,即不同的两个类的实例化对象可以完成继承,前提是子对象的属于一定是包括父对象的属性。

    1

    <bean id="user" class="com.wiggin.entity.User" parent="student2"></bean>

       

       

    Spring的依赖

    与继承类似,依赖也是描述bean和bean之间的一种关系,配置依赖之后,被依赖的bean一定要先被创建。

    1

    2

    3

    <bean id="student" class="com.wiggin.entity.Student" ></bean>

       

    <bean id="user" class="com.wiggin.entity.User" depends-on="student"></bean>

       

    Spring的p命名空间

    p命名空间实对ioc/DI的简化操作,使用p命名空间可以更加方便的完成bean的配置以及bean之间的依赖注入

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    <?xml version="1.0" encoding="UTF-8"?>

    <beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:p="http://www.springframework.org/schema/p"

    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

       

       

    <bean id="student" class="com.wiggin.entity.Student" p:id="1" p:name="张三" p:age="22" p:address-ref="address"></bean>

    <bean id="address" class="com.wiggin.entity.Address" p:id="2" p:name="科技路"></bean>

    </beans>

       

    Spring的工厂方法

    ioC通过工厂模式创建bean的方式有两种:

    1)静态工厂方法

    2)实例工厂方法

    静态工厂方法:工厂不需要实例化,直接使用工厂方法

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    package com.wiggin.entity;

       

    import lombok.AllArgsConstructor;

    import lombok.Data;

    import lombok.NoArgsConstructor;

       

    @Data

    @AllArgsConstructor

    @NoArgsConstructor

    public class Car {

    private long id;

    private String name;

    }

    ------

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    package com.wiggin.factory;

       

    import com.wiggin.entity.Car;

       

    import java.util.HashMap;

    import java.util.Map;

       

    public class StaticFactory {

    private static Map<Long, Car> carMap; // Long id,Car是返回容器

    static{

    carMap = new HashMap<Long, Car>();

    carMap.put(1L,new Car(1L,"sf"));

    carMap.put(2L,new Car(2L,"sb"));

    }

       

    public static Car getCar(long id){

    // 根据id提取car信息

    return carMap.get(id);

    }

    }

    ------

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    package com.wiggin.test;

       

    import com.wiggin.entity.Car;

    import com.wiggin.factory.StaticFactory;

    import org.springframework.context.ApplicationContext;

    import org.springframework.context.support.ClassPathXmlApplicationContext;

       

    public class Test3 {

    public static void main(String[] args) {

    // 传统方法

    /*Car car = StaticFactory.getCar(1L);

    System.out.println(car);*/

    // ioc工厂模式

    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-factory.xml");

    Car car = (Car)applicationContext.getBean("car");

    System.out.println(car);

    }

    }

    ------

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    <?xml version="1.0" encoding="UTF-8"?>

    <beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:p="http://www.springframework.org/schema/p"

    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

       

    <!--用到几个对象配置几个bean-->

    <bean id="car" class="com.wiggin.factory.StaticFactory" factory-method="getCar">

    <constructor-arg value="2"></constructor-arg>

    </bean>

    </beans>

    实例工厂方法:工厂需要实例化,且工厂方法要依赖工厂

    1

    2

    3

    4

    5

    6

    <!-- 配置实例工厂 bean -->

    <bean id="carFactory" class="com.wiggin.factory.InstanceCarFactory"></bean>

    <!-- 配置实例工厂创建 car -->

    <bean id="car2" factory-bean="carFactory" factory-method="getCar">

    <constructor-arg value="2"></constructor-arg>

    </bean>

       

    IoC自动装载(Autowire)

    ioC负责创建对象,DI负责完成对象的依赖注入,通过配置Property标签的ref属性来完成,同时Spring提供了另一种更加间接的依赖注入方法,即自动装载,不用手动配置property,IoC容器会自动选择bean完成注入。

       

    自动装载有两种方式:

    1)byname:通过属性名自动装载

    2)bytype:通过属性类型装载

    byName:通过属性名自动装载

    1

    2

    3

    4

    5

    6

    7

    8

    9

    <bean id="car" class="com.wiggin.entity.Car">

    <property name="id" value="1"></property>

    <property name="name" value="宝马"></property>

    </bean>

    <bean id="person" class="com.wiggin.entity.Person" autowire="byName">

    <property name="id" value="1"></property>

    <property name="name" value="wiggin"></property>

       

    </bean>

    byType:通过属性类型装载

    1

    2

    3

    4

    5

    <bean id="person2" class="com.wiggin.entity.Person" autowire="byType">

    <property name="id" value="1"></property>

    <property name="name" value="wiggin"></property>

       

    </bean>

       

    Spring的AOP

    AOP:Aspect Oriented Programming 面向切面编程

    AOP 优点:

    1. 降低模块之间的耦合度
    2. 使得系统更容易扩展
    3. 更好的代码服用
    4. 非业务代码更加集中,不分散,使于统一管理
    5. 业务代码更加简介纯粹,不掺杂其他代码的影响

    总结:AOP是对面向对象编程的补充,在运行时,动态地将代码切入到类的指定方法、指定位置上的编程思想就是面向切面编程,将不同方法的同一个位置抽象成为一个企鹅面对象,对该企鹅面对象进行编程,这就是AOP。

       

    如何使用?

    1)创建一个maven工程,pom.xml添加

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    <dependencies>

       

    <dependency>

    <groupId>org.springframework</groupId>

    <artifactId>spring-aop</artifactId>

    <version>5.0.7.RELEASE</version>

    </dependency>

    <dependency>

    <groupId>org.springframework</groupId>

    <artifactId>spring-aspects</artifactId>

    <version>5.0.7.RELEASE</version>

    </dependency>

    </dependencies>

    2)创建一个计算器接口Cal,定义四则运算。

    1

    2

    3

    4

    5

    6

    package com.wiggin.utils;

    public interface Cal {

    public int add(int num1,int num2);

    public int sub(int num1,int num2);

    public int mul(int num1,int num2);

    public int div(int num1,int num2);

    }

    3)创建接口的实现类impl

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    package com.wiggin.utils.impl;

    public class CalImpl implements Cal {

       

    public int add(int num1, int num2) {

    System.out.println("add方法参数是["+num1+","+num2+"]");

    int result = num1 + num2;

    System.out.println("add方法的结果是:"+result);

    return num1 + num2;

    }

       

    public int sub(int num1, int num2) {

    int result = num1 - num2;

    System.out.println("sub方法参数是["+num1+","+num2+"]");

    System.out.println("sub方法结果是:"+result);

    return result;

    }

       

    public int mul(int num1, int num2) {

    int result = num1 * num2;

    System.out.println("mul方法参数是["+num1+","+num2+"]");

    System.out.println("mul方法结果是:"+result);

    return result;

    }

       

    public int div(int num1, int num2) {

    int result = num1 / num2;

    System.out.println("div方法参数是["+num1+","+num2+"]");

    System.out.println("div方法结果是:"+result);

    return result;

    }

    }

    上述代码种,日志信息和业务逻辑的耦合性很高,不利于系统的维护,使用AOP可以进行优化,如何来实现AOP?实现动态代理方式来实现。

       

    给予业务代码找一个代理,打印日志信息的工作交给代理来做,这样的话业务代码就只需要关注自身的业务即可。

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    package com.wiggin.utils;

    public class MyInvocationHandler implements InvocationHandler {

       

    // 接收委托对象

    private Object object = null;

       

    // 返回代理对象(委托对象传入代理对象),用这个类创建动态代理类

    public Object bind(Object object){

    this.object = object;

    /*Proxy.newProxyInstance:返回代理实类,

    object.getClass()获得委托对象的运行实类,

    .getClassLoader()获取类加载器,生成动态实类

    object.getClass().getInterfaces()委托对象的功能代理类必须全部拥有,根据它创建功能一样的代理类

    this:通过当前类创建对象*/

    //

    return Proxy.newProxyInstance(object.getClass().getClassLoader(),object.getClass().getInterfaces(),this);

    }

       

    @Override

    // 打印日志结果

    /*

    method为代理类实现的方法

    method.invoke(this.object,objects)通过反射机制调用,this.object是委托对象,objects为传入参数

       

    */

    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {

    System.out.println(method.getName()+"方法参数是"+ Arrays.toString(objects));

    // 委托对象调用自己的方法

    Object result = method.invoke(this.object,objects);

    System.out.println(method.getName()+"方法的结果是:"+result);

    return result;

       

    }

       

       

    }

    以上是通过动态代理来实现AOP的过程,过程复杂,不好理解,Spring框架对AOP进行了封装,使用Spring框架可以用面向对象的思想来实现AOP。

    Spring框架种不需要创建InvocationHandler,只需要创建一个切面对象,将所有的非业务代码在切面对象种完成即可,Spring框架底层会自动根据切面类以及目标类生成代理对象。

       

    LoggerAspect类

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    package com.wiggin.aop;

    @Aspect // 成为切面对象,给予功能

    @Component // LoggerAspect对象在ioc里面配置

    public class LoggerAspect {

    // 传入实体类,切割实体类种的所有方法,在执行业务之前,*为方法的通配符,(..)为参数的通配符

    // @Before表示执行的具体时机

    @Before("execution(public int com.wiggin.utils.impl.CalImpl.*(..))")

    // JoinPoint joinPoint获得目标方法的相关信息

    public void before(JoinPoint joinPoint){

    // 获取方法joinPoint.getSignature(),方法名getName()

    String name = joinPoint.getSignature().getName();

       

    //获取参数joinPoint.getArgs()

    String args = Arrays.toString(joinPoint.getArgs());

    System.out.println(name + "方法的参数是:" + args);

       

       

       

    }

    }

    注意CaLimpl也需要@Component注解,交给IoC容器进行管理

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    package com.wiggin.utils.impl;

    @Component

    public class CalImpl implements Cal {

       

    public int add(int num1, int num2) {

       

    int result = num1 + num2;

       

    return result;

    }

       

    public int sub(int num1, int num2) {

    int result = num1 - num2;

       

    return result;

    }

       

    public int mul(int num1, int num2) {

    int result = num1 * num2;

       

    return result;

    }

       

    public int div(int num1, int num2) {

    int result = num1 / num2;

       

    return result;

    }

    }

    在Spring-aop.xml种配置AOP

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    <?xml version="1.0" encoding="UTF-8"?>

    <beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:aop="http://www.springframework.org/schema/aop"

    xmlns:context="http://www.springframework.org/schema/context"

    xmlns:tx="http://www.springframework.org/schema/tx"

    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd

    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd

    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd

    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">

    <!-- 自动扫描 寻找component注解-->

    <context:component-scan base-package="com.wiggin"></context:component-scan>

       

    <!-- aspect注解生效,为目标类自动生成代理对象-->

    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

    </beans>

    loggerAspect实现更多业务功能

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    package com.wiggin.aop;

    @Aspect // 成为切面对象,给予功能

    @Component // LoggerAspect对象在ioc里面配置

    public class LoggerAspect {

    // 传入实体类,切割实体类种的所有方法,在执行业务之前,*为方法的通配符,(..)为参数的通配符

    // @Before表示执行的具体时机

    @Before("execution(public int com.wiggin.utils.impl.CalImpl.*(..))")

    // JoinPoint joinPoint获得目标方法的相关信息

    public void before(JoinPoint joinPoint){

    // 获取方法joinPoint.getSignature(),方法名getName()

    String name = joinPoint.getSignature().getName();

       

    //获取参数joinPoint.getArgs()

    String args = Arrays.toString(joinPoint.getArgs());

    System.out.println(name + "方法的参数是:" + args);

       

       

       

       

    }

    @After("execution(public int com.wiggin.utils.impl.CalImpl.*(..))")

    public void after(JoinPoint joinPoint){

    // 获取方法joinPoint.getSignature(),方法名getName()

    String name = joinPoint.getSignature().getName();

    System.out.println(name + "方法执行了");

       

    }

    @AfterReturning(value = "execution(public int com.wiggin.utils.impl.CalImpl.*(..))",returning = "result")

    // result交给了 @AfterReturning,然后给了public void afterReturning

    public void afterReturning(JoinPoint joinPoint,Object result){

    // 获取方法名

    String name = joinPoint.getSignature().getName();

    System.out.println(name + "方法执行结果是:"+result);

    }

       

    @AfterThrowing(value = "execution(public int com.wiggin.utils.impl.CalImpl.*(..))",throwing = "expection")

    // result交给了 @AfterReturning,然后给了public void afterReturning

    public void afterThrowing(JoinPoint joinPoint,Exception expection){

    // 获取方法名

    String name = joinPoint.getSignature().getName();

    System.out.println(name + "方法执行异常:"+expection);

    }

    }

    IoC调用

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    package com.wiggin.test;

       

    import com.wiggin.utils.Cal;

    import com.wiggin.utils.MyInvocationHandler;

    import com.wiggin.utils.impl.CalImpl;

    import org.springframework.context.ApplicationContext;

    import org.springframework.context.support.ClassPathXmlApplicationContext;

       

    public class Test2 {

    public static void main(String[] args) {

    // 加载配置文件

    ApplicationContext applicationContext =new ClassPathXmlApplicationContext("Spring.xml");

       

    // 获取代理对象

    Cal proxy = (Cal) applicationContext.getBean("test");

    proxy.add(1,1);

    proxy.div(6,0);

       

    }

    切面:横切关注点被模块化的抽象对象(对象中相同的非业务代码)

    通知:切面对象完成的工作(非业务代码)

    目标:被通知的对象,即被切面的对象(非业务代码存在的类)

    代理:切面、通知、目标混合之后的对象(一个代理实现非业务代码功能的类)

    连接点:通知要插入业务代码的具体位置(代理和目标之间的联系)

    切点:AOP通过切点定位到连接点

  • 相关阅读:
    Java实现 LeetCode 27 移除元素
    Java实现 LeetCode 26 删除排序数组中的重复项
    Java实现 LeetCode 26 删除排序数组中的重复项
    Java实现 LeetCode 26 删除排序数组中的重复项
    Java实现 LeetCode 25 K个一组翻转链表
    Java实现 LeetCode 25 K个一组翻转链表
    Java实现 LeetCode 25 K个一组翻转链表
    Java实现 LeetCode 24 两两交换链表中的节点
    Java实现 LeetCode 24 两两交换链表中的节点
    Java实现 LeetCode 24 两两交换链表中的节点
  • 原文地址:https://www.cnblogs.com/wigginess/p/13416795.html
Copyright © 2011-2022 走看看