Java学习笔记 14、反射与JDK动态代理(二)

简介: Java学习笔记 14、反射与JDK动态代理(二)

五、获取运行时类的完整结构


通过反射技术调用Class的方法能够获取到类的完整结构:实现的全部接口、继承的父类、构造器、方法、属性、注解、权限修饰符、返回类型、参数列表参数、异常、包


接口:


public Class[] getInterfaces() :确定此对象所表示的类或接口实现的接口

父类:


public Class getSuperclass():表示此 Class 所表示的实体(类、接口、基本类型)的父类的 Class。

构造器:


public Constructor[] getConstructors():返回此 Class 对象所表示的类的所有public构造方法(该对象必须显示声明才能获取到,无法获取父类的构造器)。

public Constructor[] getDeclaredConstructors():返回此 Class 对象表示的类声明的所有构造方法(默认的无参构造也能够获取到)。

Constructor类:包含的方法

public int getModifiers():取得修饰符。

public String getName();:取得方法名称。

public Class[] getParameterTypes();:取得参数的类型。

方法:


public Method[] getMethods() :返回此Class对象所表示的类或接口的public的方法(包括所有父类public方法)。

public Method[] getDeclaredMethods():返回此Class对象所表示的类或接口的全部方法(不包括父类的方法)。

Method类:包含的方法

public Class getReturnType():取得全部的返回值。

public Class[] getParameterTypes():取得全部的参数。

public int getModifiers():取得修饰符。

public Class[] getExceptionTypes():取得异常信息。

属性(Field):


public Field[] getFields() :返回此Class对象所表示的类或接口的public的Field(包括所有父类public方法)。。

public Field[] getDeclaredFields() :返回此Class对象所表示的类或接口的全部Field。

Field类:包含的方法

public int getModifiers():以整数形式返回此Field的修饰符。

public Class getType():得到Field的属性类型。

public String getName():返回Field的名称。

注解(Annotation):


Annotation[] getAnnotations():获取该类上的注解。

泛型:


Type getGenericSuperclass():获取父类泛型类型。

getActualTypeArguments():获取运行时的带泛型的父类的泛型。

包:


Package getPackage():获取当前类的包。

说明:这里只是举了一小部分方法,还有其他许多方法都类似,一定要熟悉反射包的作用,其反射机制。



六、调用运行时类的指定方法


1、调用指定方法(invoke方法)

前面介绍了获取方法类Method的方式,这里来学习通过反射调用类中的方法(Method类中的invoke方法):


①首先我们需要从指定的Class中获取到指定的方法Method实例:


调用方法Method getMethod(String name, Class<?>... parameterTypes)

name(参数):表示指定方法的名称

parameterTypes(参数):填写方法参数的类型,如String.class

②接着使用指定Method实例来调用invoke方法


调用方法:Object invoke(Object obj, Object... args)

obj(参数):该方法被调用的对象,若该方法是静态方法可填null。

args(参数):该方法填入的参数,若参数为空可填null或不填。

Object(返回值):对应原方法的返回值,若原方法无返回值,则返回null。

注意点:若是该方法是私有private,使用getDeclaredMethod方法获取实例,并在调用invoke方法之前使用method.setAccessible(true);才可调用私有方法。


测试一下:


class Student{
    private void say(){
        System.out.println("新年快乐!");
    }
}
public class Main {
    public static void main(String[] args) throws Exception {
        Class<Student> clazz = Student.class;
        Method method = clazz.getDeclaredMethod("say");
        method.setAccessible(true);//不设置为true会报错java.lang.IllegalAccessException
        method.invoke(clazz.newInstance());//若是该方法是静态方法可以填null
    }
}




2、调用指定属性

在反射机制中,可以直接通过Field类操作类中的属性,通过Field类提供的set()和 get()方法就可以完成设置和取得属性内容的操作。


①首先取得Filed类(指定属性),使用Class类的getField(String name)或public Field getDeclaredField(String name)


name(参数):对应参数名称。

②通过调用Filed的方法取得与设置该属性的值。


public Object get(Object obj):取得指定对象obj上此Field的属性内容。

public void set(Object obj,Object value):设置指定对象obj上此Field的属性内容

参数obj对于静态属性时可以填null直接获取与上面调用方法一致。

注意点:获取Class中指定私有属性需要使用getDeclaredField(String name)方法,并且在调用get()或set()前使用Field类的setAccessible(true);方法才能获取到。


测试一下:


class Student{
    private String name;
}
public class Main {
    public static void main(String[] args) throws Exception {
        //获取属性name
        Class<Student> clazz = Student.class;
        Field field = clazz.getDeclaredField("name");
        field.setAccessible(true);
        System.out.println(field.get(clazz.newInstance()));
        //设置属性name为changlu
        Student student = clazz.newInstance();
        field.set(student,"changlu");//设置属性
        System.out.println(field.get(student));
    }
}




setAccessible方法说明

Method和Field、Constructor类都有void setAccessible(boolean flag)方法。


flag可填true或false。

true:指示反射的对象在使用时应该取消Java语言访问检查。能够提升反射的效率,并使得原本无法访问的private属性或方法能够访问。

false:默认为此参数,指示反射的对象应该实施Java语言访问检查。

注意:无论public、private的属性、方法、构造器都可以使用该方法并设置true来取消java访问检查,能够提升反射效率(频繁反射操作建议关闭)。需要最最注意一点就是若是想要通过反射访问private的属性,一定要将访问检查取消,也就是要调用setAccessible(true),并且前面在获取Filed、Method类…需要使用如getDeclaredField()否则会报异常。



七、反射应用(动态代理)


1、介绍动态代理

代理设计模式原理:通过使用一个代理将对象包装起来,然后使用该代理对象取代原始对象。任何原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。


代理分类:静态代理与动态代理。

静态代理:代理类与目标对象的类都是在编译期间确定下来,不利于程序的扩展。同时每一个代理类只能为一个接口服务,这样一来程序开发中必然产生过多的代理。(最好就通过一个代理类完成全部的代理功能)

动态代理:指客户通过代理类来调用其他对象的方法,并且是在程序运行时根据需要动态创建目标类的代理对象。使用场景如调试、远程方法调用。

动态代理相对于静态代理优点:抽象角色中(接口)声明的所有方法都转移到调用处理器一个集中的方法中处理,这样我们能够更加灵活和统一的处理众多的方法。



2、基于接口的动态代理

介绍Proxy、InvocationHandler

Java中动态代理的实现,关键两个类为Proxy、InvocationHandler:


Proxy :专门完成代理的操作类,是所有动态代理类的父类。通过此类为一个或多个接口动态地生成实现类。提供用于创建动态代理类和动态代理对象的静态方法:

static Class<?> getProxyClass(ClassLoader loader,Class<?>... interfaces):创建一个动态代理类所对应的Class对象。

static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h):直接创建一个动态代理类对象。

loader:传入类加载器。

interfaces:传入需要代理类实现的全部接口,数组形式。

h:实现InvocationHandler 接口的实现类实例。

InvocationHandler接口:需要实现该接口并实现其中的invoke()方法。

Object invoke(Object proxy, Method method, Object[] args):完成代理的具体操作。

proxy:代理类的对象。

method:此时调用的方法。

args:调用方法时的参数。

注意:在运行中创建的动态代理对象的父类就是Proxy类。



JDK实现动态代理(两个例子)

第一个动态代理程序


首先定义了一个接口Person,接着使用JDK提供的Proxy类的newProxyInstance方法来创建实现Person的接口代理类对象,这种没有实现接口类但是在运行期间创建了一个接口对象的方式,称为动态代码。这里JDK提供的动态创建接口对象的参数,叫做动态代理。


mport java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * @ClassName ProxyTest
 * @Author ChangLu
 * @Date 2021/2/20 15:28
 * @Description TODO
 */
//被代理类接口
interface Person{
    void say(String name);
    String walk();
}
//实现InvocationHandler接口,并重写方法
class OwnInvocationHandler implements InvocationHandler {
    //注意这里的proxy是真实对象的代理类(这里指的是Person接口的代理类,父类是Proxy类)
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //通过method实例的getName()来判断当前调用的是哪个方法
        if("say".equals(method.getName())){
            System.out.println("我是"+args[0]);
        }else if("walk".equals(method.getName())){
            System.out.println("在走路中.....");
        }
        return null;
    }
}
public class AnnotationTest {
    public static void main(String[] args) {
        //动态创建Person的代理类
        Person person = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class[]{Person.class}, new OwnInvocationHandler());
        person.say("changlu");//我是changlu
        person.walk();//在走路中.....
    }
}



第39行:这里的person实例实际上是Person接口的代理类,是在运行期间创建的一个接口对象。

对于实现哪个接口的代理类根据Proxy.newProxyInstance传入的第二个参数相关,传入指定接口的Class类用数组形式传递。

第35、36行:使用多态方式调用其接口方法时会执行OwnInvocationHandler(也就是实现InvocationHandler接口的实现类)的invoke方法。



针对于实现类进行动态代理


若我们想要一个实现接口类进行方法增强,可以使用通过动态代理的方式实现,在实现接口类指定方法的前后添加代码功能:


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * @ClassName ProxyTest
 * @Author ChangLu
 * @Date 2021/2/20 15:28
 * @Description TODO
 */
//被代理类接口
interface Person{
    void say(String name);
    String walk();
}
//创建Person的实现类
class Student implements Person{
    @Override
    public void say(String name) {
        System.out.println("student名字叫"+name);
    }
    @Override
    public String walk() {
        System.out.println("student跑步....");
        return "1000公里";
    }
}
class OwnInvocationHandler implements InvocationHandler{
    private Object obj;
    public OwnInvocationHandler(Object obj) {
        this.obj = obj;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(method.getName()+"方法执行前...");
        //执行代理类调用的方法
        Object invokeReturn = method.invoke(obj, args);
        System.out.println(method.getName()+"方法执行后...");
        return invokeReturn;//将调用方法的返回值返回
    }
}
public class ProxyTest {
    public static void main(String[] args) {
        //传入指定的实体类
        Student student = new Student();
        InvocationHandler handler = new OwnInvocationHandler(student);
        //动态创建Person的代理类
        Person person = (Person) Proxy.newProxyInstance(Student.class.getClassLoader(), student.getClass().getInterfaces(),handler);
        //代理类开始执行方法了
        person.say("changlu");
        System.out.println("-----------------");
        person.walk();
    }
}



重要重要:


第38行:要想使用指定接口实现类的方法,在这里很关键的是在实现InvocationHandler中多增加了一个有参构造,用于将对应接口实现类实例传入进来,便于之后在invoke()(InvocationHandler接口实现类中的)中使用method.invoke(obj,参数)来反射调用接口实现类的指定方法。

第46行:该行实际上就是通过反射来调用obj实例的方法,在此前后我们可以添加其他的相关操作。

第59行:newProxyInstance()方法中的传参说明,第一个参数就是传入一个类加载器(并不限制于如上的获取类加载器方法),第二个参数比较重要,也就是你想要在运行期间实现的接口。(这里student.getClass().getInterfaces()也可以使用new Class[]{Person.class},获取到对应接口class类并且以数组形式传入)

说明:这个例子也可以说是Spring中AOP的简单实现了,可用于日志记录等其他使用场景。



关于InvocationHandler接口中第一个参数proxy
InvocationHandler接口如下:
public interface InvocationHandler {
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}


这里的proxy指的是在运行期间动态创建的接口对象,即真实对象的真实代理对象,代理对象为com.sun.proxy.$Proxy0。


使用用途:通常情况下invoke方法都会返回真实对象的返回结果(如前面例2中调用实际类的方法返回值),该方法返回值为Object,我们也可以将proxy对象返回,可以通过这个返回对象做相关操作。


例子:返回proxy的用途如下


import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * @ClassName ProxyTest
 * @Author ChangLu
 * @Date 2021/2/20 15:28
 * @Description TODO
 */
interface Account {
    Account deposit(double value);
    double getBalance();
}
class OwnInvocationHandler implements InvocationHandler {
    private double balance;
    @Override
    public Object invoke (Object proxy, Method method, Object[] args) throws Throwable {
        if ("deposit".equals(method.getName())) {
            Double value = (Double) args[0];
            System.out.println("deposit: " + value);
            balance += value;
            return proxy; 
        }
        if ("getBalance".equals(method.getName())) {
            return balance;
        }
        return null;
    }
}
public class ProxyTest {
    public static void main(String[] args) {
        Account account = (Account) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Account.class}, new OwnInvocationHandler());
        account.deposit(100).deposit(200).deposit(300);
        System.out.println(account.getBalance());
        account.deposit(100).deposit(200);
        System.out.println(account.getBalance());
    }
}


第23行:在invoke()方法中通过反射调用无返回值的方法,返回proxy实例即真实代理类。我们可以看到41行可以对该代理对象进行连续调用。

这里又会有一个问题就是为什么不返回this,而是返回proxy?


答:若是在invoke()方法中返回this,就是返回的是OwnInvocationHandler实例了,而不是真实的代理对象。


3、JDK动态代理原理分析


我们通过上面InvocationHandler第一个参数proxy案例来进行过程原理分析:


首先看该方法:Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Account.class}, new OwnInvocationHandler());


使用的是Proxy类中的newProxyInstance方法。


//Proxy类
public class Proxy implements java.io.Serializable {
    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);
        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }
        //通过传入方法的类加载器以及接口class类来创建出代理类
        Class<?> cl = getProxyClass0(loader, intfs);
   ...
    }
}


第18行:getProxyClass0方法返回的代理类是在运行期间中创建的类名为$Proxy0,暂存在JVM中,我们在JDK核心类库中是找不到该代理类的。(该代理类的名称后面的0是编号,有多个代理类会一次递增)

由于该代理类是动态生成的类文件,暂时缓存在jvm中,我们通过下面方法获取到class文件:


interface Account {
    Account deposit(double value);
    double getBalance();
}
public class ProxyTest {
    public static void main(String[] args) throws IOException {
        //第一个为类名Proxy0,第二个为要实现的接口(数组形式传递)
        byte[]classFile = ProxyGenerator.generateProxyClass("Proxy0",new Class[]{Account.class});
        File file =new File("Proxy0.class");
        FileOutputStream fos =new FileOutputStream(file);
        fos.write(classFile);
        fos.flush();
        fos.close();
    }
}


我们会在目录文件下获得Proxy0.class,在idea中打开即可进行反编译。

动态生成的Proxy0类如下:


//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import xyz.changlu.reflection.Account;
public final class Proxy0 extends Proxy implements Account {
    private static Method m1;
    private static Method m3;
    private static Method m2;
    private static Method m4;
    private static Method m0;
    public Proxy0(InvocationHandler var1) throws  {
        //这里就会触发调用Proxy的有参构造
        super(var1);
    }
    public final boolean equals(Object var1) throws  {
        try {
            return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
        } catch (RuntimeException | Error var3) {
            throw var3;
        } catch (Throwable var4) {
            throw new UndeclaredThrowableException(var4);
        }
    }
    public final double getBalance() throws  {
        try {
            //调用通过构造器传入的InvocationHandler实例调用方法,这里m3指的就是getBalance
            return (Double)super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
    public final String toString() throws  {
        try {
            return (String)super.h.invoke(this, m2, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
    public final Account deposit(double var1) throws  {
        try {
            //调用通过构造器传入的InvocationHandler实例调用方法,这里m4指的就是deposit
            return (Account)super.h.invoke(this, m4, new Object[]{var1});
        } catch (RuntimeException | Error var4) {
            throw var4;
        } catch (Throwable var5) {
            throw new UndeclaredThrowableException(var5);
        }
    }
    public final int hashCode() throws  {
        try {
            return (Integer)super.h.invoke(this, m0, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
    static {
        try {
            //分别为equals方法、hashcode()方法、toString()方法
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m3 = Class.forName("xyz.changlu.reflection.Account").getMethod("getBalance");
            m2 = Class.forName("java.lang.Object").getMethod("toString");
            m4 = Class.forName("xyz.changlu.reflection.Account").getMethod("deposit", Double.TYPE);
            m0 = Class.forName("java.lang.Object").getMethod("hashCode");
        } catch (NoSuchMethodException var2) {
            throw new NoSuchMethodError(var2.getMessage());
        } catch (ClassNotFoundException var3) {
            throw new NoClassDefFoundError(var3.getMessage());
        }
    }
}


梳理一下其中做的事情:

①声明3个主要方法(equals()方法、hashcode()方法、toString()方法)以及实现接口的总共五个Mehtod,并在static代码块中对类进行初始化通过反射获取Mehtod实例。

②有一个有参构造器,传入的参数为InvocationHandler类,并且其中会触发调用Proxy的有参构造器,并传递InvocationHandler实例。

③各个方法中都通过反射来调用各自Method的invoke()方法,实现了动态代理。

我们接着上面的newProxyInstance()部分看下去:


public class Proxy implements java.io.Serializable {  
    private static final Class<?>[] constructorParams =
        { InvocationHandler.class };
    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
     ....
     /*
     * Invoke its constructor with the designated invocation handler.
     */
    try {
        if (sm != null) {
            checkNewProxyPermission(Reflection.getCallerClass(), cl);
        }
        //cl是运行中生成的代理类Class即上面的说明的Proxy0的Class类
        //通过反射获取Proxy0的有参构造器,参数为constructorParams = { InvocationHandler.class };
        final Constructor<?> cons = cl.getConstructor(constructorParams);
        //将方法参数中的InvocationHandler实例h传入ih
        final InvocationHandler ih = h;
        if (!Modifier.isPublic(cl.getModifiers())) {
            AccessController.doPrivileged(new PrivilegedAction<Void>() {
                public Void run() {
                    cons.setAccessible(true);
                    return null;
                }
            });
        }
        //这里就是通过反射调用Proxy0的有参构造创建实例,并传入InvocationHandler实例h
        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);
    }
}



这里通过反射获取Proxy0的有参构造器,并在最后调用有参构造并将方法参数中InvocationHandler实例传入。

在调用Proxy0有参构造器时也会创建Proxy的有参构造。


public class Proxy implements java.io.Serializable {
    protected InvocationHandler h;
    protected Proxy(InvocationHandler h) {
        Objects.requireNonNull(h);
      //这里是给Proxy的InvocationHandler实例h赋值,实际上就是在调用newProxyInstance()传入的InvocationHandler实例
        this.h = h;
    }
}


之后我们通过Proxy0实例调用接口方法时,也就会执行其中的invoke()方法,我们看一下Proxy0中的getBalance()方法:


public final double getBalance() throws  {
    try {
        //super指的是其父类Proxy,h即为Proxy中的InvocationHandler实例h(之前调用有参构造时进行赋值了),调用我们重写的实现InvocationHandler接口的invoke()方法,m3则是我们自定义接口实现类通过反射获得的getBalance()的Method实例
        return (Double)super.h.invoke(this, m3, (Object[])null);
    } catch (RuntimeException | Error var2) {
        throw var2;
    } catch (Throwable var3) {
        throw new UndeclaredThrowableException(var3);
    }
}


动态代理就是这么来的,经过这一下子分析对于反射有了更加深的理解,我们通过Proxy调用newProxyInstance方法能够获取到一个在运行期间的实现指定接口的代理类。通过实现InvocationHandler接口中的invoke()方法我们能够对指定类的方法进行动态代理调用。


有了动态代理的技术,那么就可以在不修改方法源码的情况下,增强被代理对象的方法的功能,在方法执行前后做任何你想做的事情,例如Spring框架中的IOC与AOP都使用到了动态代理。


通过上面的分析梳理,大致对JDK提供的这种动态代理的方式有了一些理解,之后会更加深入源码进行学习,若是有错误之处请指出。

相关文章
|
2月前
|
Java Linux
java基础(3)安装好JDK后使用javac.exe编译java文件、java.exe运行编译好的类
本文介绍了如何在安装JDK后使用`javac.exe`编译Java文件,以及使用`java.exe`运行编译好的类文件。涵盖了JDK的安装、环境变量配置、编写Java程序、使用命令行编译和运行程序的步骤,并提供了解决中文乱码的方法。
51 2
|
3天前
|
安全 Java 编译器
JDK 10中的局部变量类型推断:Java编程的简化与革新
JDK 10引入的局部变量类型推断通过`var`关键字简化了代码编写,提高了可读性。编译器根据初始化表达式自动推断变量类型,减少了冗长的类型声明。虽然带来了诸多优点,但也有一些限制,如只能用于局部变量声明,并需立即初始化。这一特性使Java更接近动态类型语言,增强了灵活性和易用性。
82 53
|
16天前
|
设计模式 Java API
[Java]静态代理与动态代理(基于JDK1.8)
本文介绍了代理模式及其分类,包括静态代理和动态代理。静态代理分为面向接口和面向继承两种形式,分别通过手动创建代理类实现;动态代理则利用反射技术,在运行时动态创建代理对象,分为JDK动态代理和Cglib动态代理。文中通过具体代码示例详细讲解了各种代理模式的实现方式和应用场景。
15 0
[Java]静态代理与动态代理(基于JDK1.8)
|
17天前
|
存储 Java
[Java]反射
本文详细介绍了Java反射机制的基本概念、使用方法及其注意事项。首先解释了反射的定义和类加载过程,接着通过具体示例展示了如何使用反射获取和操作类的构造方法、方法和变量。文章还讨论了反射在类加载、内部类、父类成员访问等方面的特殊行为,并提供了通过反射跳过泛型检查的示例。最后,简要介绍了字面量和符号引用的概念。全文旨在帮助读者深入理解反射机制及其应用场景。
12 0
[Java]反射
|
28天前
|
安全 Java 测试技术
🌟Java零基础-反射:从入门到精通
【10月更文挑战第4天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
23 2
|
28天前
|
Java
【编程进阶知识】静态代理、JDK动态代理及Cglib动态代理各自存在的缺点及代码示例
本文介绍了三种Java代理模式:静态代理、JDK动态代理和Cglib动态代理。静态代理针对特定接口或对象,需手动编码实现;JDK动态代理通过反射机制实现,适用于所有接口;Cglib动态代理则基于字节码技术,无需接口支持,但需引入外部库。每种方法各有优缺点,选择时应根据具体需求考虑。
18 1
|
28天前
|
Java
让星星⭐月亮告诉你,jdk1.8 Java函数式编程示例:Lambda函数/方法引用/4种内建函数式接口(功能性-/消费型/供给型/断言型)
本示例展示了Java中函数式接口的使用,包括自定义和内置的函数式接口。通过方法引用,实现对字符串操作如转换大写、数值转换等,并演示了Function、Consumer、Supplier及Predicate四种主要内置函数式接口的应用。
21 1
|
26天前
|
IDE Java 编译器
java的反射与注解
java的反射与注解
16 0
|
2月前
|
Oracle Java 关系型数据库
Linux下JDK环境的配置及 bash: /usr/local/java/bin/java: cannot execute binary file: exec format error问题的解决
如果遇到"exec format error"问题,文章建议先检查Linux操作系统是32位还是64位,并确保安装了与系统匹配的JDK版本。如果系统是64位的,但出现了错误,可能是因为下载了错误的JDK版本。文章提供了一个链接,指向Oracle官网上的JDK 17 Linux版本下载页面,并附有截图说明。
Linux下JDK环境的配置及 bash: /usr/local/java/bin/java: cannot execute binary file: exec format error问题的解决
|
1月前
|
Java 数据安全/隐私保护
java学习笔记(基础习题)
java学习笔记(基础习题)
31 0
下一篇
无影云桌面