龙空技术网

关于java中的反射,我只能努力到这一步了

索码理 700

前言:

现在兄弟们对“java中的forname”大约比较注重,兄弟们都想要知道一些“java中的forname”的相关知识。那么小编同时在网络上搜集了一些关于“java中的forname””的相关资讯,希望姐妹们能喜欢,兄弟们一起来了解一下吧!

反射是java高级特性之一,常用的框架,例如:spring、mybatis等在实现的过程中都使用到了反射,所以还是非常有必要了解反射的。

反射是什么

Java反射提供了检查和修改应用程序运行时行为的能力。反射允许我们在「运行时」检查和操作类、接口、构造函数、方法和字段,即使类在编译时不可访问。我们还可以使用反射来实例化一个对象,调用它的方法,更改字段值。这种「动态获取的信息以及动态调⽤对象的⽅法的功能」称为java语⾔的反射机制。

反射的用途

可能有些人认为反射在工作中用的并不多,但其实并不是这样的,工作中处处都能见到反射的影子,比如工作中经常会通过对象 「.」 的时候编译器会列出该对象可以调用的方法,其实这个原理使用的也是反射。还有像Spring、Mybatis、Tomcat等通用框架或者容器底层都会大量的使用到反射。所以如果你想实现一个通用的功能,反射或许是最好的选择之一。

反射的缺点

反射的好处是允许我们在运行时对类、接口等进行一系列操作。但是它也有缺点:

性能不佳: 由于 java 反射动态解析类型,它涉及扫描类路径以查找要加载的类等处理,导致性能下降。安全限制:反射需要运行时权限,这对于在安全管理器下运行的系统可能不可用。由于安全管理器,这可能会导致应用程序在运行时失败。安全问题: 使用反射我们可以访问我们不应该访问的部分代码,例如我们可以访问一个类的私有字段并更改它的值。这可能是一个严重的安全威胁,并导致应用程序行为异常。高维护: 反射代码难以理解和调试,并且在编译时无法发现代码的任何问题,因为类可能不可用,使其灵活性降低且难以维护。反射的基本运用

以下类用于测试

BaseInterface.java

package com.example.reflection;public interface BaseInterface {    public int interfaceInt=0;    void method1();    int method2(String str);}

BaseClass.java

package com.example.reflection;public class BaseClass {    public int baseInt;    private static void method3(){        System.out.println("Method3");    }    public int method4(){        System.out.println("Method4");        return 0;    }    public static int method5(){        System.out.println("Method5");        return 0;    }    void method6(){        System.out.println("Method6");    }    // inner public class    public class BaseClassInnerClass{}    //member public enum    public enum BaseClassMemberEnum{}}

ConcreteClass.java

package com.example.reflection;public class ConcreteClass extends BaseClass implements BaseInterface{    public int publicInt;    private String privateString="private string"; public static String staticStr = "public static string";    protected boolean protectedBoolean;    Object defaultObject;    public ConcreteClass(int i){        this.publicInt=i;    } public ConcreteClass(){    }    private ConcreteClass(String privateString){        this.privateString = privateString;    }    @Override    public void method1() {        System.out.println("Method1 impl.");    }    @Override    public int method2(String str) {        System.out.println("Method2 impl.");        return 0;    }    @Override    public int method4(){        System.out.println("Method4 overriden.");        return 0;    }    public int method5(int i){        System.out.println("Method4 overriden.");        return 0;    }    // inner classes    public class ConcreteClassPublicClass{}    private class ConcreteClassPrivateClass{}    protected class ConcreteClassProtectedClass{}    class ConcreteClassDefaultClass{}    //member enum    enum ConcreteClassDefaultEnum{}    public enum ConcreteClassPublicEnum{}    //member interface    public interface ConcreteClassPublicInterface{}}
获取Class 类对象

java.lang.Class是所有反射操作的入口点。Class 类只有java虚拟机才能new出来,任何⼀个类都是Class 类的实例对象。要使用反射首先要获取到Class对象,Class 对象有三种方式可以获取到:

通过.class

Class<Integer> integerClass = Integer.class;
使用对象的getClass方法
Date date = new Date();Class<? extends Date> dateClass = date.getClass();
通过java.lang.Class.forName(String fullyClassifiedClassName)方法
Class<Integer> forName = Class.forName("java.lang.Integer");

对于基本类型和数组,Class对象的获取可以通过.class的方式获取。

Class<?> booleanClass = boolean.class;System.out.println(booleanClass.getCanonicalName()); // prints booleanClass<?> cDouble = Double.TYPE;System.out.println(cDouble.getCanonicalName()); // prints doubleClass<?> cDoubleArray = Class.forName("[D");System.out.println(cDoubleArray.getCanonicalName()); //prints double[]Class<?> twoDStringArray = String[][].class;System.out.println(twoDStringArray.getCanonicalName()); // prints java.lang.String[][]

对于包装类,也可以通过静态变量TYPE获取Class对象

Class<?> doubleClass = Double.TYPE;
类相关的反射获取包名

getPackage()方法返回这个类所在的包。该类的类加载器用于查找包。

final Package aPackage = ConcreteClass.class.getPackage();System.out.println(aPackage); System.out.println(aPackage.getName());

结果:

package com.example.reflectioncom.example.reflection
获取supperClass

getSuperclass() 如果是类对象调用的话会返回类的父类,如果此类为Object类、接口、基本类型或void,则返回null。如果此对象为数组类,则返回表示Object类的类对象。

final Class<? super Integer> superclass = Integer.class.getSuperclass();System.out.println(superclass); // 结果:class java.lang.NumberSystem.out.println(Object.class.getSuperclass()); // 结果:nullSystem.out.println(String[][].class.getSuperclass()); // 结果:class java.lang.Object
获取Public成员类

getClasses()返回一个Class类型数组, 通过getClasses()可以获取到Class对象的所有Public类、接口和枚举类。这包括从父类继承的公共类和接口以及由类声明的公共类和接口。如果Class对象没有Public成员类、接口,又或者Class对象是个数组、基本类型、void, getClasses() 会返回一个空数组。

final Class<?>[] publicClasses = ConcreteClass.class.getClasses();Arrays.stream(publicClasses).forEach(System.out::println);

结果:

获取声明的类

getDeclaredClasses()方法返回一个 Class 对象数组,返回声明为该 Class 对象表示的类成员的所有类和接口。返回的数组不包括在继承的类和接口中声明的类。

final Class<?>[] declaredClasses = ConcreteClass.class.getDeclaredClasses();Arrays.stream(declaredClasses).forEach(System.out::println);

结果:

获取所有Public构造方法

getConstructors()方法返回Class对象的Public构造方法列表。

final Constructor<?>[] constructors = ConcreteClass.class.getConstructors();Arrays.stream(constructors).forEach(System.out::println);

结果:

public com.example.reflection.ConcreteClass()public com.example.reflection.ConcreteClass(int)
获取泛型参数

如果有与该类关联的任何泛型参数,getTypeParameters() 则返回 TypeVariable 数组。泛型参数的返回顺序与声明的顺序相同。

TypeVariable<?>[] typeParameters = Class.forName("java.util.HashMap").getTypeParameters();for(TypeVariable<?> t : typeParameters){    System.out.print(t.getName()+",");}

结果:

K,V,
获取实现的接口

getGenericInterfaces() 方法返回由具有泛型类型信息的类实现的接口数组。

getInterfaces()方法返回类实现的所有接口

final Class<?> hashMapClass = Class.forName("java.util.HashMap");System.out.println(Arrays.toString(hashMapClass.getGenericInterfaces()));System.out.println(Arrays.toString(hashMapClass.getInterfaces()));

结果:

[java.util.Map<K, V>, interface java.lang.Cloneable, interface java.io.Serializable][interface java.util.Map, interface java.lang.Cloneable, interface java.io.Serializable]
获取所有Public方法

getMethods()方法返回该类的公共方法数组,包括它的父类和实现的接口的公共方法。

final Method[] allMethods = ConcreteClass.class.getMethods();Arrays.stream(allMethods).forEach(System.out::println);

结果:

获取所有Public字段

getFields() 方法返回该类的公共字段数组,包括它的父类和实现的接口的公共字段。

public int com.example.reflection.ConcreteClass.publicIntpublic static final int com.example.reflection.BaseInterface.interfaceIntpublic int com.example.reflection.BaseClass.baseInt
获取所有注释

getAnnotations() 方法返回元素的所有注释。

final Annotation[] annotations = ConcreteClass.class.getAnnotations();System.out.println(Arrays.toString(annotations));

结果:

[@java.lang.Deprecated()]
获取权限修饰符

getModifiers()方法返回类修饰符的int表示,可以使用java.lang.reflect.Modifier.toString()方法以源代码中使用的字符串格式来显示出来。

final int modifiers = ConcreteClass.class.getModifiers();final String modifier = Modifier.toString(modifiers);System.out.println("modifiers="+modifiers +",modifier="+modifier);

结果:

modifiers=1,modifier=public

java.lang.reflect.Modifier 权限修饰符表示的常量

public static final int PUBLIC           = 0x00000001;/** * The {@code int} value representing the {@code private} * modifier. */public static final int PRIVATE          = 0x00000002;/** * The {@code int} value representing the {@code protected} * modifier. */public static final int PROTECTED        = 0x00000004;
字段相关反射获取字段

getField()getDeclaredField() 方法可以获取到类的字段。不同的是,getField()获取的必须是声明了public的字段,包括父类或者实现的接口中的public字段; getDeclaredField() 只能获取的本类中定义的字段。

final Class<ConcreteClass> concreteClassClass = ConcreteClass.class;//获取public字段final Field interfaceInt = concreteClassClass.getField("interfaceInt");System.out.println(interfaceInt.getName());//获取private字段final Field privateString = concreteClassClass.getDeclaredField("privateString");// 这一步很重要privateString.setAccessible(true);System.out.println(privateString.getName());

对于private类型字段一定要用setAccessible(true) 关闭访问检查,表示让字段可以被访问到,如果不关闭会报错。

字段赋值

//public 字段设值final Field publicInt = concreteClassClass.getField("publicInt");ConcreteClass obj = new ConcreteClass(5);System.out.println(publicInt.get(obj)); //prints 5publicInt.setInt(obj, 10); //setting field value to 10 in objectSystem.out.println(publicInt.get(obj)); //prints 10//private字段设值Field privateField = concreteClassClass.getDeclaredField("privateString");privateField.setAccessible(true);ConcreteClass objTest = new ConcreteClass(1);System.out.println(privateField.get(objTest)); // prints "private string"privateField.set(objTest, "private string updated");System.out.println(privateField.get(objTest)); //prints "private string updated"//static字段final Field staticStr = concreteClassClass.getField("staticStr");staticStr.set(null , "public static string updated");System.out.println(staticStr.get(null));

如果字段是静态的,可以在 get() 方法中将 第一个Object参数传NULL值来调用。

获取字段类型

getType() 方法返回声明的字段类型的 Class 对象,如果字段是原始类型,则返回包装类对象。

final Class<ConcreteClass> concreteClassClass = ConcreteClass.class;final Field publicInt = concreteClassClass.getField("publicInt");final Class<?> type = publicInt.getType();System.out.println(type.getCanonicalName()); //prints int
获取字段声明类

可以使用getDeclaringClass()字段对象来获取声明字段的类。

final Field interfaceInt = concreteClassClass.getField("interfaceInt");final Class<?> declaringClass = interfaceInt.getDeclaringClass();System.out.println(declaringClass);
方法相关的反射获取方法public方法的获取:以HashMap 的 put() 方法为例。

可以使用getMethod()来获取类的公共方法,我们需要传递该方法的方法名和参数类型。如果在类中找不到该方法,反射 API 会在超类中查找该方法。

Method method = Class.forName("java.util.HashMap").getMethod("put", Object.class, Object.class);//get method parameter types, prints "[class java.lang.Object, class java.lang.Object]"System.out.println(Arrays.toString(method.getParameterTypes()));//get method return type, return "class java.lang.Object", class reference for voidSystem.out.println(method.getReturnType());//get method modifiersSystem.out.println(Modifier.toString(method.getModifiers())); //prints "public
private 方法获取 可以使用 getDeclaredMethod() 来获取私有方法,要使用setAccessible(true)关闭访问检查
final Class<BaseClass> baseClassClass = BaseClass.class;Method method = baseClassClass.getDeclaredMethod("method3", null);method.setAccessible(true);
调用方法public方法调用 可以使用 Method 对象的 invoke() 方法来调用方法,以HashMap 的put()方法为例
Method method = Class.forName("java.util.HashMap").getMethod("put", Object.class, Object.class);Map<String, String> hm = new HashMap<>();method.invoke(hm, "key", "value");System.out.println(hm); // prints {key=value}
private方法调用 以调用静态且没有参数的 BaseClass 的 method3()为例。
final Class<BaseClass> baseClassClass = BaseClass.class;Method method = baseClassClass.getDeclaredMethod("method3", null);method.setAccessible(true);method.invoke(null, null); //prints "Method3"
和静态字段一样,invoke() 方法的第一个参数object传NULL值则是调用静态方法。
构造方法的反射获取构造方法

可以在对象的类表示上使用 getConstructor() 方法来获取特定的public构造函数。 可以在对象的类表示上使用 getDeclaredConstructor() 方法来获取特定的public构造函数。

//获取有参构造方法Constructor<?> constructor = concreteClassClass.getConstructor(int.class);//获取构造方法参数System.out.println(Arrays.toString(constructor.getParameterTypes())); // prints "[int]"//获取无参构造方法final Constructor<ConcreteClass> classClassConstructor = concreteClassClass.getConstructor();System.out.println(classClassConstructor); // 结果:public com.example.reflection.ConcreteClass()//获取私有构造方法final Constructor<ConcreteClass> declaredConstructor =concreteClassClass.getDeclaredConstructor(String.class);declaredConstructor.setAccessible(true);System.out.println(declaredConstructor); //结果:private com.example.reflection.ConcreteClass(java.lang.String)
使用构造函数实例化对象

可以在构造函数对象上使用 newInstance() 方法来实例化该类的新实例。

//获取有参构造方法Constructor<?> constructor = concreteClassClass.getConstructor(int.class);final Object newInstance = constructor.newInstance(111);//获取method1 方法final Method method1 = newInstance.getClass().getMethod("method1", null);//调用method1方法method1.invoke(newInstance , null);
总结

从上面所有的测试中我们可以发现,在Class对象中的方法中只要是带有「Declared」字段的都是获取本类中声明的方法、字段或者构造方法等,反之则是调用public的方法;在调用私有方法时要注意一点要将访问检查关闭

参考资料:

标签: #java中的forname