前言:
现在兄弟们对“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 "publicprivate 方法获取 可以使用 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