Java反射原理以及一些常见的应用

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 创建对象有四大方法,new、反射、克隆、反序列化创建,今天我们将由阿里技术专家 关键,围绕反射来展开分享。主要内容有类装载、反射原理、反射使用场景、AOP。

本文由内容志愿者整理阿里云社群直播而来。

讲师:关键

目录
image.png

一、类装载

我们都知道,java在编译类后并不是产生固有机器的机器码,而是一段字节码,这段字节码可以存放于任何地方,如.class文件,jar包中,可以通过网络传输。JVM虚拟机在拿取到这段二进制数据流字节码后,就会处理这些数据,并最终转换成一个java.lang.Class的实例(注意,这里并不是类本身的实例)。

java.lang.Class实例是访问类型元数据的接口,也是实现反射的关键数据。通过Class类提供的接口,可以访问一个类型的方法,字段等信息。

二进制数据流字节码被加载到虚拟机之后,会进行一系列的验证检查,主要步骤如下:

1.格式检查:包括魔数检查(识别文件类型开头的几个十六进制数,每一种文件类型都不同),版本检查,长度检查

2.语义检查:是否继承final,是否有父类,抽象方法是否有实现

3.字节码验证:跳转指令是否指向正确位置,操作数类型是否合理

4.符号引用验证:符号引用的直接引用是否存在

当一个类验证通过时,虚拟机就会进入准备阶段。分配内存空间,分配初始值。如果类存在常量字段,如果被final修饰,就会被直接放入常量池中。如果没有final修饰,就会在初始化中赋值,而不是直接放入常量池。

准备阶段完成后,就是解析类,解析类就是把字节码中的类,接口,字段,方法放入JVM虚拟机实际内存的地址中,方便程序可以真正执行,比如说类的方法会有一个方法表,当需要调用一个类的方法时,就要知道这个方法在方法表中的偏移量,直接调用该方法。

类的初始化是类装载的最后一个阶段。初始化的重要工作就是执行类的初始化方法。方法是由编译器自动生成的,它是由类静态成员的赋值语句以及static语句合并产生的。类似代码如下

public class SimpleStatic {
    public static int id = 1;
    public static int number;
    static {
        number = 4;
    }
}

反射代码示例如下:

public class ClassTest {
    public static void main(String[] args) throws ClassNotFoundException {
        Class clzStr = Class.forName("java.lang.String");
        //获取该类的所有方法
        Method[] ms = clzStr.getDeclaredMethods();
        for (Method m:ms) {
            //获取该方法的修饰符
            String mod = Modifier.toString(m.getModifiers());
            //打印方法的修饰符,方法名跟起始括号
            System.out.print(mod + " " + m.getName() + " (");
            //获取方法的所有参数类型
            Class<?>[] ps = m.getParameterTypes();
            //如果没有参数,直接打印结束括号
            if (ps.length == 0) {
                System.out.print(')');
            } else {
                //取出所有的参数类型名称,以逗号分隔
                for (int i = 0; i < ps.length; i++) {
                    char end = i == ps.length - 1 ? ')' : ',';
                    System.out.print(ps[i].getSimpleName() + end);
                }
            }
            System.out.println();
        }
    }
}

运行结果:

public equals (Object)
public toString ()
public hashCode ()
public compareTo (String)
public volatile compareTo (Object)
public indexOf (String,int)
public indexOf (String)
public indexOf (int,int)
public indexOf (int)
static indexOf (char[],int,int,char[],int,int,int)
static indexOf (char[],int,int,String,int)
public static valueOf (int)
public static valueOf (long)
public static valueOf (float)
public static valueOf (boolean)
public static valueOf (char[])
public static valueOf (char[],int,int)
public static valueOf (Object)
public static valueOf (char)
public static valueOf (double)
public charAt (int)
private static checkBounds (byte[],int,int)
public codePointAt (int)
public codePointBefore (int)
public codePointCount (int,int)
public compareToIgnoreCase (String)
public concat (String)
public contains (CharSequence)
public contentEquals (CharSequence)
public contentEquals (StringBuffer)
public static copyValueOf (char[])
public static copyValueOf (char[],int,int)
public endsWith (String)
public equalsIgnoreCase (String)
public static transient format (Locale,String,Object[])
public static transient format (String,Object[])
public getBytes (int,int,byte[],int)
public getBytes (Charset)
public getBytes (String)
public getBytes ()
public getChars (int,int,char[],int)
 getChars (char[],int)
private indexOfSupplementary (int,int)
public native intern ()
public isEmpty ()
public static transient join (CharSequence,CharSequence[])
public static join (CharSequence,Iterable)
public lastIndexOf (int)
public lastIndexOf (String)
static lastIndexOf (char[],int,int,String,int)
public lastIndexOf (String,int)
public lastIndexOf (int,int)
static lastIndexOf (char[],int,int,char[],int,int,int)
private lastIndexOfSupplementary (int,int)
public length ()
public matches (String)
private nonSyncContentEquals (AbstractStringBuilder)
public offsetByCodePoints (int,int)
public regionMatches (int,String,int,int)
public regionMatches (boolean,int,String,int,int)
public replace (char,char)
public replace (CharSequence,CharSequence)
public replaceAll (String,String)
public replaceFirst (String,String)
public split (String)
public split (String,int)
public startsWith (String,int)
public startsWith (String)
public subSequence (int,int)
public substring (int)
public substring (int,int)
public toCharArray ()
public toLowerCase (Locale)
public toLowerCase ()
public toUpperCase ()
public toUpperCase (Locale)
public trim ()

Class.forName可以得到代表String类的Class实例,它是反射中最重要的方法。

二、反射原理

反射离不开Class.forName(),我们先从Class.forName说起。
反射可以跟new一个对象有相同的效果。例如:

public class Company {
    private String a;
    private String b;

    @Override
    public String toString() {
        return "Company{" +
                "a='" + a + '\'' +
                ", b='" + b + '\'' +
                '}';
    }

    public Company() {
        this.a = "A";
        this.b = "B";
    }
}


public class CompanyInstance {
    private static Company company = new Company();

    public static void main(String[] args) {
        System.out.println(company);
    }
}

运行结果:

Company{a='A', b='B'}

又可以写成如下

public class CompanyInstance {

    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        System.out.println(Class.forName("com.guanjian.Company").newInstance());
    }
}

运行结果:

Company{a='A', b='B'}
new VS newInstance

虽然效果一样,但他们的过程并不一样。 首先,newInstance( )是一个方法,而new是一个关键字;其次,Class下的newInstance()的使用有局限,因为它生成对象只能调用无参的构造函数,而使用 new关键字生成对象没有这个限制。

newInstance()的时候是使用的上篇说的类装载机制的,它会走完全部过程。具体可以看 浅析类装载 ,而new一个实例的时候,走的流程不太一样,它会先在JVM内部先去寻找该类的Class实例,然后依照该Class实例的定义,依葫芦画瓢,把该类的实例给生成出来。

但如果找不到该类的Class实例,则会走上篇说的装载流程。 其中JDK的Class实例一般是在jvm启动时用启动类加载器完成加载,用户的Class实例则是在用到的时候再加载。

Class.forName()

Class.forName()被重载为有一个参数和三个参数的,我们来看一下其源码。

@CallerSensitive
public static Class<?> forName(String className)
            throws ClassNotFoundException {
    Class<?> caller = Reflection.getCallerClass();
    return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}

无论是三参还是单参的都调用了此方法:

private static native Class<?> forName0(String name, boolean initialize,
                                        ClassLoader loader,
                                        Class<?> caller)
    throws ClassNotFoundException;

它的第二个参数boolean initialize表示是否要初始化该类,单参Class.forName()默认true是要初始化的,三参的Class.forName()由你自己选择。一旦初始化,就会触发目标对象的 static块代码执行,static参数也也会被再次初始化。当然如果你使用了三个参数的Class.forName(),并调用了newInstance()以后,是肯定会初始化的。

ClassLoader,这个才是真正装载类的核心组件。所有的Class都是由ClassLoader进行加载的,ClassLoader负责通过各种方式将Class信息的二进制字节码数据流读入系统,然后交给JVM虚拟机进行连接、初始化等操作。

ClassLoader的分类

在标准的Java程序中,Java虚拟机会创建3类ClassLoader为整个应用程序服务。它们分别是:BootStrap ClassLoader(启动类加载器),Extension ClassLoader(扩展类加载器),App ClassLoader(应用类加载器,也称为系统类加载器)。

此外,每一个应用程序还可以拥有自定义的ClassLoader,扩展Java虚拟机获取Class数据的能力。其中,应用类加载器的双亲为扩展类加载器,扩展类加载器的双亲为启动类加载器。

当系统需要使用一个类时,在判断类是否已经被加载时,会先从当前底层类加载器进行判断。当系统需要加载一个类时,会从顶层类开始加载,依次向下尝试,直到成功。

三、反射使用场景

1、编码阶段不知道需要实例化的类名是哪个,需要在runtime从配置文件中加载:

Class clazz = class.forName("xxx.xxx.xxx")
clazz.newInstance();

2、在runtime阶段,需要临时访问类的某个私有属性

ClassA objA = new ClassA();
Field xxx = objA.getClass().getDeclaredField("xxx")
xxx.setAccessible(true);

3、当使用标签的时候,我们要获取标签

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotionTest {
    String value() default "哈士奇";
}
@AnnotionTest
public class Dog {
    private String type;
    private String name;
    public Dog() {
        type = "金毛";
        name = "大黄";
    }
public Dog(String type,String name){
        this.type = type;
        this.name = name;
}

// toString()省略
}
public class CheckDog {
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("com.guanjian.Dog");
        if (clazz.isAnnotationPresent(AnnotionTest.class)) {
            Field field = clazz.getDeclaredField("type");
            field.setAccessible(true);
            System.out.println(field.get(clazz.newInstance()));
            AnnotionTest test = (AnnotionTest)clazz.getAnnotation(AnnotionTest.class);
            System.out.println(test.value());
        }
    }
}

4、获取具体的构造器来构造类本身的实例

Class<?>[] constructorParams = {String.class,String.class};
        Constructor<?> cons = clazz.getConstructor(constructorParams);
        System.out.println(cons.newInstance("哈士奇","神哈"));

5、其他(可以用到的地方还有很多,比如获取父类的方法,判断是不是一个接口等等)

四、AOP

AOP主要是通过动态代理实现的,动态代理分两种,一种是JDK的,一种是CGlib。JDK的动态代理必须有一个接口。

public interface Greeting {
    void sayHello(String name);
}

还有一个实现类,是实现了它的主要功能。

public class GreetingImpl implements Greeting {
    public void sayHello(String name) {
        System.out.println("Hello! " + name);
    }
}
public class DynamicProxy<T> implements InvocationHandler {
    private Object target;

    public DynamicProxy(Object target) {
        this.target = target;
    }
    //获取目标对象的代理类实例
    public T getProxy() {
        return (T) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),  //目标对象类的加载器
                target.getClass().getInterfaces(),  //目标对象类的接口数组(因为一个类可能有几个接口)
                this
        );
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        before();
        Object result = method.invoke(target,args);
        after();
        return result;
    }
    private void before() {
        System.out.println("Before");
    }
    private void after() {
        System.out.println("After");
    }
}

main方法

public class Client {
    public static void main(String[] args) {
        Greeting greetingProxy = new DynamicProxy<Greeting>(new GreetingImpl()).getProxy();
        greetingProxy.sayHello("Jack");
    }
}

运行结果:

Before
Hello! Jack
After

动态代理是通过反射来实现的,这里有一个Proxy.newProxyInstance,我们来看一下它的源代码。

//代理类的构造器的参数类型数组
private static final Class<?>[] constructorParams =
    { InvocationHandler.class };
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
                                      Class<?>[] interfaces,
                                      InvocationHandler h)
    throws IllegalArgumentException
{
    //要求动态代理类本身不为空,如果为空会抛出异常
    Objects.requireNonNull(h);
    //将接口数组克隆出来
    final Class<?>[] intfs = interfaces.clone();
    //启动Java安全管理器
    final SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        //检查调用类是否有启动接口的Class实例的加载器的权限
        checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
    }

    /*
     * Look up or generate the designated proxy class.
     * 创建代理类的Class实例
     */
    Class<?> cl = getProxyClass0(loader, intfs);

    /*
     * Invoke its constructor with the designated invocation handler.
     */
    try {
        if (sm != null) {
            //检查调用类是否有该代理类的权限
            checkNewProxyPermission(Reflection.getCallerClass(), cl);
        }
        //通过构造参数类型来获取代理类的具体某一个构造器
        final Constructor<?> cons = cl.getConstructor(constructorParams);
        //代理类本身实例
        final InvocationHandler ih = h;
        //获取代理类Class实例的所有修饰符,并判断是否为public,如果不为public则通过cons.setAccessible(true)设置为可以访问
        if (!Modifier.isPublic(cl.getModifiers())) {
            AccessController.doPrivileged(new PrivilegedAction<Void>() {
                public Void run() {
                    cons.setAccessible(true);
                    return null;
                }
            });
        }
        //通过该具体的构造器来构造代理类本身的实例,之前我们有说过Class的newInstance只能通过无参构造器来构造,但此处是选择了具体的有参构造器构造
        return cons.newInstance(new Object[]{h});
    } catch (IllegalAccessException|InstantiationException e) {
        throw new InternalError(e.toString(), e);
    } catch (InvocationTargetException e) {
        Throwable t = e.getCause();
        if (t instanceof RuntimeException) {
            throw (RuntimeException) t;
        } else {
            throw new InternalError(t.toString(), t);
        }
    } catch (NoSuchMethodException e) {
        throw new InternalError(e.toString(), e);
    }
}

由以上代码可知,该动态代理必须要有接口才能代理,而不能代理没有接口的类。

没有接口的类,我们可以使用CGLib来动态代理,要使用CGLib,先要在pom中加入它的引用

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.2.2</version>
</dependency>
public class CGLibDynamicProxy<T> implements MethodInterceptor {
    private static CGLibDynamicProxy instance = new CGLibDynamicProxy();

    private CGLibDynamicProxy() {
    }

    /**
     * 通过单例模式获取代理类的实例
     * @return
     */
    public static CGLibDynamicProxy getInstance() {
        return instance;
    }

    /**
     * 通过实现类的Class实例跟代理类对象关联
     * @param cls
     * @return
     */
    public T getProxy(Class<T> cls) {
        return (T)Enhancer.create(cls,this);
    }
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        before();
        Object result = methodProxy.invokeSuper(o,objects);
        after();
        return result;
    }
    private void before() {
        System.out.println("Before");
    }
    private void after() {
        System.out.println("After");
    }
}

main方法

public class Client {
    public static void main(String[] args) {
        Greeting greetingProxy = (Greeting) CGLibDynamicProxy.getInstance().getProxy(GreetingImpl.class);
        greetingProxy.sayHello("Jack");
    }
}

我们来简单看一下Enhancer.create的源码

public static Object create(Class type, Callback callback) {
    Enhancer e = new Enhancer();  //创建一个增强代理类对象,它可以拦截被代理的除final,static以外的所有类
    e.setSuperclass(type);  //设置该代理类的父类为实现类
    e.setCallback(callback);  //设置实现了MethodInterceptor接口的回调类,这里即为我们动态代理类本身的实例,因为MethodInterceptor是继承于Callback的接口,它是一个
                              //对象方法拦截器
    return e.create();       //返回实现类的增强类(所谓增强即可以对这个类进行拦截和各种处理操作)
}

了解了动态代理之后,我们来了解一下Spring+AspectJ的AOP。我们主要结合拦截指定注解(@annotation)的方式来大概说明一下用法。

比如说我们要拦截一个自定义的标签,对标有该标签的方法,记录日志,通过MQ(具体不限定哪种MQ)发送到日志中心,进行存储。

首先我们有一个日志的实体类。

@Builder
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Log implements Serializable {

   private static final long serialVersionUID = -5398795297842978376L;

   private Long id;
   private String username;
   /** 模块 */
   private String module;
   /** 参数值 */
   private String params;
   private String remark;
   private Boolean flag;
   private Date createTime;
   private String ip;
   private String area;
}

有一个自定义的标签,这是一个方法级标签。

/**
 * 日志注解
 *
 */
@Target({ ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
public @interface LogAnnotation {

   String module();

   /**
    * 记录参数<br>
    * 尽量记录普通参数类型的方法,和能序列化的对象
    * 
    * @return
    */
   boolean recordParam() default true;
}

增加日志所属的模块(用户操作)。

/**
 * 日志模块定义
 *
 */
public abstract class LogModule {

    public static final Map<String, String> MODULES = new HashMap<>();

    public static final String LOGIN = "LOGIN";
    public static final String LOGOUT = "LOGOUT";

    public static final String ADD_PERMISSION = "ADD_PERMISSION";
    public static final String UPDATE_PERMISSION = "UPDATE_PERMISSION";
    public static final String DELETE_PERMISSION = "DELETE_PERMISSION";

    public static final String ADD_ROLE = "ADD_ROLE";
    public static final String UPDATE_ROLE = "UPDATE_ROLE";
    public static final String DELETE_ROLE = "DELETE_ROLE";
    public static final String SET_PERMISSION = "SET_PERMISSION";

    public static final String SET_ROLE = "SET_ROLE";
    public static final String UPDATE_USER = "UPDATE_USER";
    public static final String UPDATE_ME = "UPDATE_ME";

    public static final String UPDATE_PASSWORD = "UPDATE_PASSWORD";
    public static final String RESET_PASSWORD = "RESET_PASSWORD";

    public static final String ADD_MENU = "ADD_MENU";
    public static final String UPDATE_MENU = "UPDATE_MENU";
    public static final String DELETE_MENU = "DELETE_MENU";
    public static final String SET_MENU_ROLE = "SET_MENU_ROLE";

    public static final String ADD_BLACK_IP = "ADD_BLACK_IP";
    public static final String DELETE_BLACK_IP = "DELETE_BLACK_IP";

    public static final String FILE_UPLOAD = "FILE_UPLOAD";
    public static final String FILE_DELETE = "FILE_DELETE";

    public static final String ADD_MAIL = "ADD_MAIL";
    public static final String UPDATE_MAIL = "UPDATE_MAIL";
    public static final String DELETE_USER = "DELETE_USER";

    static {
        MODULES.put(LOGIN, "登陆");
        MODULES.put(LOGOUT, "退出");

        MODULES.put(ADD_PERMISSION, "添加权限");
        MODULES.put(UPDATE_PERMISSION, "修改权限");
        MODULES.put(DELETE_PERMISSION, "删除权限");

        MODULES.put(ADD_ROLE, "添加角色");
        MODULES.put(UPDATE_ROLE, "修改角色");
        MODULES.put(DELETE_ROLE, "删除角色");
        MODULES.put(SET_PERMISSION, "分配权限");
        MODULES.put(SET_ROLE, "分配角色");

        MODULES.put(UPDATE_USER, "修改用户");
        MODULES.put(UPDATE_ME, "修改个人信息");
        MODULES.put(UPDATE_PASSWORD, "修改密码");
        MODULES.put(RESET_PASSWORD, "重置密码");

        MODULES.put(ADD_MENU, "添加菜单");
        MODULES.put(UPDATE_MENU, "修改菜单");
        MODULES.put(DELETE_MENU, "删除菜单");
        MODULES.put(SET_MENU_ROLE, "分配菜单");

        MODULES.put(ADD_BLACK_IP, "添加黑名单");
        MODULES.put(DELETE_BLACK_IP, "删除黑名单");

        MODULES.put(FILE_UPLOAD, "文件上传");
        MODULES.put(FILE_DELETE, "文件删除");

        MODULES.put(ADD_MAIL, "保存邮件");
        MODULES.put(UPDATE_MAIL, "修改邮件");
        MODULES.put(DELETE_USER, "删除用户");

    }

}

然后我们定义一个AOP的实现类。

@Aspect
public class LogAop {

    private static final Logger logger = LoggerFactory.getLogger(LogAop.class);
    //对@LogAnnotation标签进行环绕增强
    @Around(value = "@annotation(com.cloud.model.log.LogAnnotation)")
    public Object logSave(ProceedingJoinPoint joinPoint) throws Throwable { //ProceedingJoinPoint joinPoint连接点,可以通过该对象获取方法的任务信息,例如,方
        Log log = new Log();                                                //法名,参数等。
        log.setCreateTime(new Date());
        LoginAppUser loginAppUser = AppUserUtil.getLoginAppUser();
        if (loginAppUser != null) {
            log.setUsername(loginAppUser.getUsername());
        }
        //通过连接点获取方法签名
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        //通过方法的签名获取方法的标签
        LogAnnotation logAnnotation = methodSignature.getMethod().getDeclaredAnnotation(LogAnnotation.class);
        log.setModule(logAnnotation.module());
        //我们是否要收集方法的参数,默认为true
        if (logAnnotation.recordParam()) {
            String[] paramNames = methodSignature.getParameterNames();// 获取方法参数名
            if (paramNames != null && paramNames.length > 0) {
                Object[] args = joinPoint.getArgs();// 通过连接点获取传入参数值
                //定义一个HashMap,并将对应的参数名和参数值全部放入该HashMap
                Map<String, Object> params = new HashMap<>();
                for (int i = 0; i < paramNames.length; i++) {
                    params.put(paramNames[i], args[i]);
                }

                try {
                    log.setParams(JSONObject.toJSONString(params)); //Json序列化对应参数信息放入log对象中
                } catch (Exception e) {
                    logger.error("记录参数失败:{}", e.getMessage());
                }
            }
        }

        try {
            Object object = joinPoint.proceed();// 执行原方法
            //执行成功处理
            log.setFlag(Boolean.TRUE);

            return object;
        } catch (Exception e) {
            //执行失败处理
            log.setFlag(Boolean.FALSE);
            log.setRemark(e.getMessage());
            throw e;
        } finally {
            // 异步将Log对象发送到队列
            CompletableFuture.runAsync(() -> {
                try {
                    /////////此处可以将日志对象log发送到消息队列,由于在一些系统中,一些用户的操作大量且频繁,推荐使用Kafka来作为推送日志的消息队列,比如
                    /////////商品购买,退货等等,在LogModule中添加对应的操作标志。
                    logger.info("发送日志到队列:{}", log);
                } catch (Exception e2) {
                    e2.printStackTrace();
                }
            });

        }

    }
}

因为@Aspect标签是未被Spring托管的,所以要对LogAop实行自动配置,在资源文件夹下的spring.factories中

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.cloud.log.autoconfigure.LogAop

有多条以, 分隔成多行。在一些自己开发的jar包导入新的Spring boot工程中,此种方法是最为有效的依赖注入方式。

比如在用户模块要修改个人信息的时候

/**
 * 修改自己的个人信息
 *
 * @param appUser
 * @return
 */
@LogAnnotation(module = LogModule.UPDATE_ME)
@PutMapping("/users/me")
public Map<String, Object> updateMe(@RequestBody AppUser appUser) {
    AppUser user = AppUserUtil.getLoginAppUser();
    appUser.setId(user.getId());

    appUserService.updateAppUser(appUser);

    return ResponseUtils.getDataResult(user);
}

这个updateMe方法就会被AOP环绕增强,将操作的信息,传递参数放入log对象,并通过MQ发送到日志中心进行接收。其实这里面接入点的具体实现也是通过反射来处理的。而AOP的整个实现也是通过动态代理来实现的。当然不要忘了在本模块内的配置文件中增加。

spring:
  aop:  
    proxy-target-class: true

它的默认值是false,默认只能代理接口(使用JDK动态代理),当为true时,才能代理目标类(使用CGLib动态代理)。

相关实践学习
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
【涂鸦即艺术】基于云应用开发平台CAP部署AI实时生图绘板
相关文章
|
1月前
|
人工智能 算法 Java
Java与AI驱动区块链:构建智能合约与去中心化AI应用
区块链技术和人工智能的融合正在开创去中心化智能应用的新纪元。本文深入探讨如何使用Java构建AI驱动的区块链应用,涵盖智能合约开发、去中心化AI模型训练与推理、数据隐私保护以及通证经济激励等核心主题。我们将完整展示从区块链基础集成、智能合约编写、AI模型上链到去中心化应用(DApp)开发的全流程,为构建下一代可信、透明的智能去中心化系统提供完整技术方案。
226 3
|
3月前
|
存储 数据采集 搜索推荐
Java 大视界 -- Java 大数据在智慧文旅旅游景区游客情感分析与服务改进中的应用实践(226)
本篇文章探讨了 Java 大数据在智慧文旅景区中的创新应用,重点分析了如何通过数据采集、情感分析与可视化等技术,挖掘游客情感需求,进而优化景区服务。文章结合实际案例,展示了 Java 在数据处理与智能推荐等方面的强大能力,为文旅行业的智慧化升级提供了可行路径。
Java 大视界 -- Java 大数据在智慧文旅旅游景区游客情感分析与服务改进中的应用实践(226)
|
3月前
|
存储 监控 数据可视化
Java 大视界 -- 基于 Java 的大数据可视化在企业生产运营监控与决策支持中的应用(228)
本文探讨了基于 Java 的大数据可视化技术在企业生产运营监控与决策支持中的关键应用。面对数据爆炸、信息孤岛和实时性不足等挑战,Java 通过高效数据采集、清洗与可视化引擎,助力企业构建实时监控与智能决策系统,显著提升运营效率与竞争力。
|
1月前
|
消息中间件 缓存 Java
Spring框架优化:提高Java应用的性能与适应性
以上方法均旨在综合考虑Java Spring 应该程序设计原则, 数据库交互, 编码实践和系统架构布局等多角度因素, 旨在达到高效稳定运转目标同时也易于未来扩展.
121 8
|
2月前
|
人工智能 Java API
Java与大模型集成实战:构建智能Java应用的新范式
随着大型语言模型(LLM)的API化,将其强大的自然语言处理能力集成到现有Java应用中已成为提升应用智能水平的关键路径。本文旨在为Java开发者提供一份实用的集成指南。我们将深入探讨如何使用Spring Boot 3框架,通过HTTP客户端与OpenAI GPT(或兼容API)进行高效、安全的交互。内容涵盖项目依赖配置、异步非阻塞的API调用、请求与响应的结构化处理、异常管理以及一些面向生产环境的最佳实践,并附带完整的代码示例,助您快速将AI能力融入Java生态。
460 12
|
2月前
|
安全 Java API
Java SE 与 Java EE 区别解析及应用场景对比
在Java编程世界中,Java SE(Java Standard Edition)和Java EE(Java Enterprise Edition)是两个重要的平台版本,它们各自有着独特的定位和应用场景。理解它们之间的差异,对于开发者选择合适的技术栈进行项目开发至关重要。
392 1
|
3月前
|
设计模式 XML 安全
Java枚举(Enum)与设计模式应用
Java枚举不仅是类型安全的常量,还具备面向对象能力,可添加属性与方法,实现接口。通过枚举能优雅实现单例、策略、状态等设计模式,具备线程安全、序列化安全等特性,是编写高效、安全代码的利器。
|
3月前
|
机器学习/深度学习 人工智能 自然语言处理
Java 大视界 -- Java 大数据机器学习模型在自然语言生成中的可控性研究与应用(229)
本文深入探讨Java大数据与机器学习在自然语言生成(NLG)中的可控性研究,分析当前生成模型面临的“失控”挑战,如数据噪声、标注偏差及黑盒模型信任问题,提出Java技术在数据清洗、异构框架融合与生态工具链中的关键作用。通过条件注入、强化学习与模型融合等策略,实现文本生成的精准控制,并结合网易新闻与蚂蚁集团的实战案例,展示Java在提升生成效率与合规性方面的卓越能力,为金融、法律等强监管领域提供技术参考。
|
3月前
|
存储 人工智能 算法
Java 大视界 -- Java 大数据在智能医疗影像数据压缩与传输优化中的技术应用(227)
本文探讨 Java 大数据在智能医疗影像压缩与传输中的关键技术应用,分析其如何解决医疗影像数据存储、传输与压缩三大难题,并结合实际案例展示技术落地效果。
|
3月前
|
机器学习/深度学习 安全 Java
Java 大视界 -- Java 大数据在智能金融反洗钱监测与交易异常分析中的应用(224)
本文探讨 Java 大数据在智能金融反洗钱监测与交易异常分析中的应用,介绍其在数据处理、机器学习建模、实战案例及安全隐私等方面的技术方案与挑战,展现 Java 在金融风控中的强大能力。
下一篇
oss云网关配置