在这篇文章中,我们将为您详细介绍如何通过JavaReflection动态创建Java类?的内容,并且讨论关于java动态创建类以及方法的相关问题。此外,我们还会涉及一些关于JavaReflection
在这篇文章中,我们将为您详细介绍如何通过Java Reflection动态创建Java类?的内容,并且讨论关于java动态创建类以及方法的相关问题。此外,我们还会涉及一些关于Java Reflection、Java Reflection Tutorial、java reflection 疑问、Java Reflection-获取软件包列表的知识,以帮助您更全面地了解这个主题。
本文目录一览:- 如何通过Java Reflection动态创建Java类?(java动态创建类以及方法)
- Java Reflection
- Java Reflection Tutorial
- java reflection 疑问
- Java Reflection-获取软件包列表
如何通过Java Reflection动态创建Java类?(java动态创建类以及方法)
反射用于加载Java类类并即时对其进行操作。但是我遇到了一个怪异的问题,问我如何通过Reflection快速创建Java类,这意味着这些类在我们要创建之前就没有编译或没有源代码。真的有可能吗?有什么例子吗?
答案1
小编典典您可以尝试ASM ASM
或字节码工程库
字节码工程库
用于在运行时创建类
在.NET中,我们具有Reflection.Emit(C#)可以执行该
Reflection.Emit
Java Reflection
Java Reflection
Reflection Class
Class对象
检查一个类的信息之前,首先需要获取类的Class对象。Java中得所有类型包括基本类型(int,long,float…),即使是数组都有与之关联的Class类的对象。
如果在编译期知道一个类的名字的话,使用如下方式获取一个类的Class对象:
Class objClass = MyObject.Class;
如果在编译期不知道类的名字,但是可以在运行期获得类名的字符串:
String className = “objClass”;
Class objClass = Class.forName(className);
使用Class.forName()时,必须提供一个类的全名,即包含包名,可能会抛出ClassNotFoundException
类名
从Class对象中获取两个版本的类名
String className = objClass.getName();//包含包名
String simpleClassName = objClass.getSimpleName();//不包含包名
修饰符
可以通过Class对象来访问一个类的修饰符
int modifiers = objClass.getModifiers();
修饰符都被包装成一个int类型的数字,这样每个修饰符都是一个位标识(flag bit),这个位标识可以设置和清除修饰符的类型。使用Modifier类中的方法检查修饰符的类型:
Modifier.isAbstract(int modifiers);
Modifier.isFinal(int modifiers);
Modifier.isNative(int modifiers);
Modifier.isPrivate(int modifiers);
Modifier.isProtected(int modifiers);
Modifier.isPublic(int modifiers);
Modifier.isStatic(int modifiers);
Modifier.isStrict(int modifiers);
Modifier.isSynchronized(int modifiers);
Modifier.isVolatile(int modifiers);
包信息
Package package = objClass.getPackage();
通过Package对象可以获取包的相关信息(包名),也可以通过Manifest文件访问
父类
Class superClass = objClass.getSuperClass();
实现的接口
Class[] interfaces = objClass.getInterfaces();
此方法仅仅返回当前类实现的借口,父类的不包括。
构造器
Constructor[] constructors = objClass.getConstructors();
方法
Method[] methods = objClass.getMethods();
变量
Field[] fields = objClass.getFields();
注解
Annotation[] annotations = objClass.getAnnotations();
构造器
利用java的反射机制可以检查一个类的构造方法,并且可以在运行期间创建一个对象。
Constructor对象
通过Class对象来获取Constructor类的实例
Constructor[] constructors = objClass.getConstructors();
返回的Constructor数组包含每一个声明为public的构造方法。如果知道构造方法的参数类型:
Constructor constructor = objClass.getConstructor(new Class[]{String.class});
如果没有指定的构造方法能满足匹配的方法参数会抛出:NoSuchMethodException
构造方法参数
Class[] paraneterType = constructor.getParameterTypes();
利用Constructor对象实例化一个类
Object obj = constructor.newInstance(“constructor-arg1”);
newInstance()参数是一个可变参数列表,调用构造方法的时候必须提供精确的参数,形成一一对应。此例子中传入的是一个String类型的参数
变量
使用java反射机制可以在运行期检查一个类的变量信息(成员变量)或者获取或者设置变量的值。
获取Field对象
Field[] fields = objClass.getFields();
返回的Field对象数组包含了指定类中声明为public的所有变量集合。如果知道要访问的变量名称:
Field field = objClass.getField(“someField”);
可能会抛出NoSuchFieldException
变量名称
String fieldname = field.getName();
变量类型
Object fieldType = field.getType();
获取或设置(get/set)变量值
Class objClass = MyObject.Class;
Field field = objClass.getField(“someField”);
MyObject objectInstance = new MyObject();
Object value = field.get(objectInstance);
field.set(objectInstance, value);
set()传入的参数objectInstance应该拥有指定变量的类的实例。上述例子中传入的参数是MyObject类的实例,是因为someField是Myobject类的实例
如果变量是静态变量的话,传入null作为参数而不用传递改变量的类的实例。
方法
使用java反射可以在运行期检查一个方法的信息以及在运行期调用这个方法
获取Method对象
Method[] methods = objClass.getMethods();
返回的Method对象数组包含了指定类中声明为public的所有方法集合。
如果知道要调用方法的具体参数类型:
Method method = objClass.getMethod(“doSomething”, new Class[]{String,class});
可能会抛出NoSuchMethodException
如果获得方法没有参数,第二个参数传入null。
方法参数以及返回类型
Class[] parameterTypes = method.getParemeterTypes();
Class returnType = method.getReturnType();
通过Method对象调用方法
Method method = Myobject.class.getMethod(“donSomething”, String.class);
Object returnValue = method.invoke(null, “parameter-value”);
传入的null参数是你要调用方法的对象,如果是一个静态方法调用的话可以用null代替指定对象作为invoke()的参数,如果doSomething不是静态方法的话,需要传入有效的MyObject实例。第二个参数是一个可变参数列表,但是必须传入与调用方法的形参一一对应的实参。
getters、setters
使用反射可以在运行期检查一个方法的信息以及在运行期调用这个方法,使用这个功能同样可以获取指定类的getters和setters。
Getter
以get开头,没有方法参数,返回一个值。
Setter
以set开头,有一个方法参数,一般没有返回值。
Eg.
public static void printGettersSetters(Class aClass){
Method[] methods = aClass.getMethods();
for(Method method : methods){
if(isGetter(method)) System.out.println("getter: " + method);
if(isSetter(method)) System.out.println("setter: " + method);
}
}
public static boolean isGetter(Method method){
if(!method.getName().startsWith("get")) return false;
if(method.getParameterTypes().length != 0) return false;
if(void.class.equals(method.getReturnType()) return false;
return true;
}
public static boolean isSetter(Method method){
if(method.getParameterTypes().length != 1) return false;
return true;
}
私有变量、私有方法
通常情况下从对象的外部访问私有变量以及方法是不允许的,使用反射机制可以做到这一点。SecurityManager会现在这样使用。
访问私有变量
PrivateObject privateObject = new PrivateObject("The Private Value");
Field privateStringField = PrivateObject.class.
getDeclaredField("privateString");
privateStringField.setAccessible(true);
String fieldValue = (String) privateStringField.get(privateObject);
System.out.println("fieldValue = " + fieldValue);
这个例子会输出”fieldValue = The Private Value”,privateString是PrivateObject实例的私有变量,调用getDeclaredField(“privateString”)方法会返回一个私有变量,调用setAccessible()方法会关闭指定类Field实例的反射访问检查,执行后不论私有还是其他的访问作用域都可以访问。
访问私有方法
PrivateObject privateObject = new PrivateObject("The Private Value");
Method privateStringMethod = PrivateObject.class.
getDeclaredMethod("getPrivateString", null);
privateStringMethod.setAccessible(true);
String returnValue = (String)
privateStringMethod.invoke(privateObject, null);
System.out.println("returnValue = " + returnValue);
注解
利用反射机制在运行期获取java类的注解信息。
简介
注解是插入代码中得一种注释或者说是一种元数据(meta data)。这些注解信息可以在编译期使用预编译工具进行处理(pre-compiler tools)。也可以在运行期使用java反射机制进行处理。
元注解:
@Target 表示该注解可以用于什么地方,可能的ElementType有:
CONSTRUCTOR:构造器的声明
FIFLD:域声明(包括enum实例)
LOCAL_VARIABLE:局部变量声明
METHOD:方法声明
PACKAGE:包声明
PARAMETER:参数声明
TYPE:类,接口(包括注解类型)或enum声明
@Retention 表示需要在什么级别保存改注解信息。可选的RetentionPolicy参数
SOURCE:注解将被编译器丢弃
CLASS:注解在class文件中可用,但会被VM丢弃
RUNTIME:VM将在运行期间保留注解,因此可以通过反射机制读取注解的信息
@Documented 将注解包含在Javadoc中
@Inherited 允许子类继承父类中得注解
注解定义:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
public String name();
public String value();
}
使用:
@MyAnnotation(name="someName", value = "Hello World")
public class TheClass {
}
在interface前面的@符号表明这是一个注解。
@Target(ElementType.Type),说明这个注解改怎么使用
@Retention(RetentionPolicy.RUNTIME)表示这个注解可以运行通过反射访问。
类注解
可以在运行期访问类,方法或者变量的注解信息
Class aClass = TheClass.class;
Annotation[] annotations = aClass.getAnnotations();
for(Annotation annotation : annotations){
if(annotation instanceof MyAnnotation){
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println("name: " + myAnnotation.name());
System.out.println("value: " + myAnnotation.value());
}
}
指定一个类的注解
Class aClass = TheClass.class;
Annotation annotation = aClass.getAnnotation(MyAnnotation.class);
if(annotation instanceof MyAnnotation){
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println("name: " + myAnnotation.name());
System.out.println("value: " + myAnnotation.value());
}
方法注解
下面是一个方法注解的例子:
public class TheClass {
@MyAnnotation(name="someName", value = "Hello World")
public void doSomething(){}
}
可以像这样访问方法注解:
Method method = ... //获取方法对象
Annotation[] annotations = method.getDeclaredAnnotations();
for(Annotation annotation : annotations){
if(annotation instanceof MyAnnotation){
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println("name: " + myAnnotation.name());
System.out.println("value: " + myAnnotation.value());
}
}
可以像这样访问指定的方法注解:
Method method = ... // 获取方法对象
Annotation annotation = method.getAnnotation(MyAnnotation.class);
if(annotation instanceof MyAnnotation){
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println("name: " + myAnnotation.name());
System.out.println("value: " + myAnnotation.value());
}
参数注解
方法参数也可以添加注解,就像下面这样:
public class TheClass {
public static void doSomethingElse(
@MyAnnotation(name="aName", value="aValue") String parameter){
}
}
你可以通过Method对象来访问方法参数注解:
Method method = ... //获取方法对象
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
Class[] parameterTypes = method.getParameterTypes();
int i=0;
for(Annotation[] annotations : parameterAnnotations){
Class parameterType = parameterTypes[i++];
for(Annotation annotation : annotations){
if(annotation instanceof MyAnnotation){
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println("param: " + parameterType.getName());
System.out.println("name : " + myAnnotation.name());
System.out.println("value: " + myAnnotation.value());
}
}
}
需要注意的是Method.getParameterAnnotations()方法返回一个注解类型的二维数组,每一个方法的参数包含一个注解数组。
变量注解
下面是一个变量注解的例子:
public class TheClass {
@MyAnnotation(name="someName", value = "Hello World")
public String myField = null;
}
可以像这样来访问变量的注解:
Field field = ... //获取方法对象</pre>
<pre>Annotation[] annotations = field.getDeclaredAnnotations();
for(Annotation annotation : annotations){
if(annotation instanceof MyAnnotation){
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println("name: " + myAnnotation.name());
System.out.println("value: " + myAnnotation.value());
}
}
可以像这样访问指定的变量注解:
Field field = ...//获取方法对象</pre>
<pre>
Annotation annotation = field.getAnnotation(MyAnnotation.class);
if(annotation instanceof MyAnnotation){
MyAnnotation myAnnotation = (MyAnnotation) annotation;
System.out.println("name: " + myAnnotation.name());
System.out.println("value: " + myAnnotation.value());
}
泛型
运用泛型反射的经验法则
经典使用泛型的场景
声明一个需要被参数化(parameterizable)的类/接口
声明一个参数化类
List接口就是典型的例子
泛型方法返回类型
获得了java.lang.reflect.Method对象,那么你就可以获取到这个方法的泛型返回类型信息。如果方法是在一个被参数化类型之中那么你无法获取他的具体类型,但是如果方法返回一个泛型类(那么你就可以获得这个泛型类的具体参数化类型。你可以在“Java Reflection: Methods”中阅读到有关如何获取Method对象的相关内容。下面这个例子定义了一个类这个类中的方法返回类型是一个泛型类型:
public class MyClass {
protected List<String> stringList = ...;
public List<String> getStringList(){
return this.stringList;
}
}
可以获取getStringList()方法的泛型返回类型,换句话说,我们可以检测到getStringList()方法返回的是List而不仅仅只是一个List。如下例:
Method method = MyClass.class.getMethod("getStringList", null);
Type returnType = method.getGenericReturnType();
if(returnType instanceof ParameterizedType){
ParameterizedType type = (ParameterizedType) returnType;
Type[] typeArguments = type.getActualTypeArguments();
for(Type typeArgument : typeArguments){
Class typeArgClass = (Class) typeArgument;
System.out.println("typeArgOSC_h3_41">
可以通过反射来获取方法参数的泛型类型,下面这个例子定义了一个类,这个类中的方法的参数是一个被参数化的List: public class MyClass { protected List<String> stringList = ...; public void setStringList(List<String> list){ this.stringList = list; } } 可以像这样来获取方法的泛型参数: method = Myclass.class.getMethod("setStringList", List.class); Type[] genericParameterTypes = method.getGenericParameterTypes(); for(Type genericParameterType : genericParameterTypes){ if(genericParameterType instanceof ParameterizedType){ ParameterizedType aType = (ParameterizedType) genericParameterType; Type[] parameterArgTypes = aType.getActualTypeArguments(); for(Type parameterArgType : parameterArgTypes){ Class parameterArgClass = (Class) parameterArgType; System.out.println("parameterArgOSC_h3_42">
同样可以通过反射来访问公有(Public)变量的泛型类型,无论这个变量是一个类的静态成员变量或是实例成员变量。你可以在“Java Reflection: Fields”中阅读到有关如何获取Field对象的相关内容。这是之前的一个例子,一个定义了一个名为stringList的成员变量的类。 public class MyClass { public List<String> stringList = ...; } Field field = MyClass.class.getField("stringList"); Type genericFieldType = field.getGenericType(); if(genericFieldType instanceof ParameterizedType){ ParameterizedType aType = (ParameterizedType) genericFieldType; Type[] fieldArgTypes = aType.getActualTypeArguments(); for(Type fieldArgType : fieldArgTypes){ Class fieldArgClass = (Class) fieldArgType; System.out.println("fieldArgOSC_h2_43">
反射机制中是的数组,不要和java.util.Array混淆。 int[] intArray = (int[]) Array.newInstance(int.class, 3); 第一个参数表示要创建数组类型,第二个参数表示数据空间。 Array.set(intArray, 0, 123); Array.set(intArray, 1, 456); Array.set(intArray, 2, 789); System.out.println("intArray[0] = " + Array.get(intArray, 0)); System.out.println("intArray[1] = " + Array.get(intArray, 1)); System.out.println("intArray[2] = " + Array.get(intArray, 2)); 通常会用下面这个方法来获取普通对象以及原生对象的Class对象: public Class getClass(String className){ if("int" .equals(className)) return int .class; if("long".equals(className)) return long.class; ... return Class.forName(className); } 一旦你获取了类型的Class对象,你就有办法轻松的获取到它的数组的Class对象,你可以通过指定的类型创建一个空的数组,然后通过这个空的数组来获取数组的Class对象。这样做有点讨巧,不过很有效。如下例: Class theClass = getClass(theClassName); Class stringArrayClass = Array.newInstance(theClass, 0).getClass(); 这是一个特别的方式来获取指定类型的指定数组的Class对象。无需使用类名或其他方式来获取这个Class对象。 为了确保Class对象是不是代表一个数组,你可以使用Class.isArray()方法来进行校验: Class stringArrayClass = Array.newInstance(String.class, 0).getClass(); System.out.println("is array: " + stringArrayClass.isArray()); 获取了一个数组的Class对象,你就可以通过Class.getComponentType()方法获取这个数组的成员类型。成员类型就是数组存储的数据类型。例如,数组int[]的成员类型就是一个Class对象int.class。String[]的成员类型就是java.lang.String类的Class对象。 下面是一个访问数组成员类型的例子: String[] strings = new String[3]; Class stringArrayClass = strings.getClass(); Class stringArrayComponentType = stringArrayClass.getComponentType(); System.out.println(stringArrayComponentType); 下面这个例子会打印“java.lang.String”代表这个数组的成员类型是字符串。 利用反射机制在运行期动态的创建接口的实现。 可以通过使用Proxy.newProxyInstance()方法创建动态代理。newProxyInstance()方法有三个参数: 1、类加载器(ClassLoader)用来加载动态代理类。 2、一个要实现的接口的数组。 3、一个InvocationHandler把所有方法的调用都转到代理上。 如下例: InvocationHandler handler = new MyInvocationHandler(); MyInterface proxy = (MyInterface) Proxy.newProxyInstance( MyInterface.class.getClassLoader(), new Class[] { MyInterface.class }, handler); 在执行完这段代码之后,变量proxy包含一个MyInterface接口的的动态实现。所有对proxy的调用都被转向到实现了InvocationHandler接口的handler上。 调用Proxy.newProxyInstance()方法时,必须要传入一个InvocationHandler接口的实现。所有对动态代理对象的方法调用都会被转向到InvocationHandler接口的实现上,下面是InvocationHandler接口的定义: public interface InvocationHandler{ Object invoke(Object proxy, Method method, Object[] args) throws Throwable; } 下面是它的实现类的定义: public class MyInvocationHandler implements InvocationHandler{ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //do something "dynamic" } } 传入invoke()方法中的proxy参数是实现要代理接口的动态代理对象。通常你是不需要他的。 invoke()方法中的Method对象参数代表了被动态代理的接口中要调用的方法,从这个method对象中你可以获取到这个方法名字,方法的参数,参数类型等等信息。关于这部分内容可以查阅之前有关Method的文章。 Object数组参数包含了被动态代理的方法需要的方法参数。注意:原生数据类型(如int,long等等)方法参数传入等价的包装对象(如Integer, Long等等)。 动态代理常被应用到以下几种情况中 1.数据库连接以及事物管理 2.单元测试中的动态Mock对象 3.自定义工厂与依赖注入(DI)容器之间的适配器 4.类似AOP的方法拦截器 所有Java应用中的类都是被java.lang.ClassLoader类的一系列子类加载的。因此要想动态加载类的话也必须使用java.lang.ClassLoader的子类。 一个类一旦被加载时,这个类引用的所有类也同时会被加载。类加载过程是一个递归的模式,所有相关的类都会被加载。但并不一定是一个应用里面所有类都会被加载,与这个被加载类的引用链无关的类是不会被加载的,直到有引用关系的时候它们才会被加载。 在Java中类加载是一个有序的体系。当你新创建一个标准的Java类加载器时你必须提供它的父加载器。当一个类加载器被调用来加载一个类的时候,首先会调用这个加载器的父加载器来加载。如果父加载器无法找到这个类,这时候这个加载器才会尝试去加载这个类。 类加载器加载类的顺序如下: 1、检查这个类是否已经被加载。 2、如果没有被加载,则首先调用父加载器加载。 3、如果父加载器不能加载这个类,则尝试加载这个类。 当你实现一个有重载类功能的类加载器,它的顺序与上述会有些不同。类重载不会请求的他的父加载器来进行加载。在后面的段落会进行讲解。 动态加载一个类十分简单。你要做的就是获取一个类加载器然后调用它的loadClass()方法。下面是个例子: public class MainClass { public static void main(String[] args){ ClassLoader classLoader = MainClass.class.getClassLoader(); try { Class aClass = classLoader.loadClass("com.jenkov.MyClass"); System.out.println("aClass.getName() = " + aClass.getName()); } catch (ClassNotFoundException e) { e.printStackTrace(); } } 动态类重载有一点复杂。Java内置的类加载器在加载一个类之前会检查它是否已经被加载。因此重载一个类是无法使用Java内置的类加载器的,如果想要重载一个类你需要手动继承ClassLoader。 在你定制ClassLoader的子类之后,你还有一些事需要做。所有被加载的类都需要被链接。这个过程是通过ClassLoader.resolve()方法来完成的。由于这是一个final方法,因此这个方法在ClassLoader的子类中是无法被重写的。resolve()方法是不会允许给定的ClassLoader实例链接一个类两次。所以每当你想要重载一个类的时候你都需要使用一个新的ClassLoader的子类。你在设计类重载功能的时候这是必要的条件。 在前面已经说过你不能使用已经加载过类的类加载器来重载一个类。因此你需要其他的ClassLoader实例来重载这个类。但是这又带来了一些新的挑战。 所有被加载到Java应用中的类都以类的全名(包名 + 类名)作为一个唯一标识来让ClassLoader实例来加载。这意味着,类MyObject被类加载器A加载,如果类加载器B又加载了MyObject类,那么两个加载器加载出来的类是不同的。看看下面的代码: MyObject object = (MyObject) myClassReloadingFactory.newInstance("com.jenkov.MyObject"); MyObject类在上面那段代码中被引用,它的变量名是object。这就导致了MyObject这个类会被这段代码所在类的类加载器所加载。 如果myClassReloadingFactory工厂对象使用不同的类加载器重载MyObject类,你不能把重载的MyObject类的实例转换(cast)到类型为MyObject的对象变量。一旦MyObject类分别被两个类加载器加载,那么它就会被认为是两个不同的类,尽管它们的类的全名是完全一样的。你如果尝试把这两个类的实例进行转换就会报ClassCastException。 你可以解决这个限制,不过你需要从以下两个方面修改你的代码: 1、标记这个变量类型为一个接口,然后只重载这个接口的实现类。 2、标记这个变量类型为一个超类,然后只重载这个超类的子类。 请看下面这两个例子: MyObjectInterface object = (MyObjectInterface) myClassReloadingFactory.newInstance("com.jenkov.MyObject"); MyObjectSuperclass object = (MyObjectSuperclass) myClassReloadingFactory.newInstance("com.jenkov.MyObject"); 只要保证变量的类型是超类或者接口,这两个方法就可以正常运行,当它们的子类或是实现类被重载的时候超类跟接口是不会被重载的。 为了保证这种方式可以运行你需要手动实现类加载器然后使得这些接口或超类可以被它的父加载器加载。当你的类加载器加载MyObject类时,超类MyObjectSuperclass或者接口MyObjectSuperclass也会被加载,因为它们是MyObject的依赖。你的类加载器必须要代理这些类的加载到同一个类加载器,这个类加载器加载这个包括接口或者超类的类。 下面这个例子是一个类加载器的子类。注意在这个类不想被重载的情况下它是如何把对一个类的加载代理到它的父加载器上的。如果一个类被它的父加载器加载,这个类以后将不能被重载。记住,一个类只能被同一个ClassLoader实例加载一次。 就像我之前说的那样,这仅仅是一个简单的例子,通过这个例子会向你展示类加载器的基本行为。这并不是一个可以让你直接用于设计你项目中类加载器的模板。你自己设计的类加载器应该不仅仅只有一个,如果你想用来重载类的话你可能会设计很多加载器。并且你也不会像下面这样将需要加载的类的路径硬编码(hardcore)到你的代码中。 public class MyClassLoader extends ClassLoader{ public MyClassLoader(ClassLoader parent) { super(parent); } public Class loadClass(String name) throws ClassNotFoundException { if(!"reflection.MyObject".equals(name)) return super.loadClass(name); try { String url = "file:C:/data/projects/tutorials/web/WEB-INF/" + "classes/reflection/MyObject.class"; URL myUrl = new URL(url); URLConnection connection = myUrl.openConnection(); InputStream input = connection.getInputStream(); ByteArrayOutputStream buffer = new ByteArrayOutputStream(); int data = input.read(); while(data != -1){ buffer.write(data); data = input.read(); } input.close(); byte[] classData = buffer.toByteArray(); return defineClass("reflection.MyObject", classData, 0, classData.length); } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return null; } } 下面是使用MyClassLoader的例子: public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException { ClassLoader parentClassLoader = MyClassLoader.class.getClassLoader(); MyClassLoader classLoader = new MyClassLoader(parentClassLoader); Class myObjectClass = classLoader.loadClass("reflection.MyObject"); AnInterface2 object1 = (AnInterface2) myObjectClass.newInstance(); MyObjectSuperClass object2 = (MyObjectSuperClass) myObjectClass.newInstance(); //create new class loader so classes can be reloaded. classLoader = new MyClassLoader(parentClassLoader); myObjectClass = classLoader.loadClass("reflection.MyObject"); object1 = (AnInterface2) myObjectClass.newInstance(); object2 = (MyObjectSuperClass) myObjectClass.newInstance(); } 下面这个就是被加载的reflection.MyObject类。注意它既继承了一个超类并且也实现了一个接口。这样做仅仅是为了通过例子演示这个特性。在你自定义的情况下你可能仅会实现一个类或者继承一两个接口。 public class MyObject extends MyObjectSuperClass implements AnInterface2{ //... body of class ... override superclass methods // or implement interface methods } What is reflection, why is it useful, and how to use it? ##1. What is reflection? "Reflection is commonly used by programs which require the ability to examine or modify the runtime behavior of applications running in the Java virtual machine." This concept is often mixed with introspection. The following are their definitions from Wiki: Introspection is the ability of a program to examine the type or properties of an object at runtime. Reflection is the ability of a program to examine and modify the structure and behavior of an object at runtime. From their definitions, introspection is a subset of reflection. Some languages support introspection, but do not support reflection, e.g., C++. Introspection Example: The instanceof operator determines whether an object belongs to a particular class. Reflection Example: The Class.forName() method returns the Class object associated with the class/interface with the given name(a string and full qualified name). The forName method causes the class with the name to be initialized. In Java, reflection is more about introspection, because you can not change structure of an object. There are some APIs to change accessibilities of methods and fields, but not structures. ##2. Why do we need reflection? Reflection enables us to: Reflection is the common approach of famework. For example, JUnit use reflection to look through methods tagged with the @Test annotation, and then call those methods when running the unit test. (Here is a set of examples of how to use JUnit.) For web frameworks, product developers define their own implementation of interfaces and classes and put is in the configuration files. Using reflection, it can quickly dynamically initialize the classes required. For example, Spring uses bean configuration such as: When the Spring context processes this < bean > element, it will use Class.forName(String) with the argument "com.programcreek.Foo" to instantiate that Class. It will then again use reflection to get the appropriate setter for the < property > element and set its value to the specified value. The same mechanism is also used for Servlet web applications: ##3. How to use reflection? How to use reflection API can be shown by using a small set of typical code examples. Example 1: Get class name from object Output: Example 2: Invoke method on unknown object For the code example below, image the types of an object is unknown. By using reflection, the code can use the object and find out if the object has a method called "print" and then call it. Example 3: Create object from Class instance Example 4: Get constructor and create instance Output: In addition, you can use Class instance to get implemented interfaces, super class, declared field, etc. Example 5: Change array size though reflection Output: ##Summary The above code examples shows a very small set of functions provided by Java reflection. Reading those examples may only give you a taste of Java reflection, you may want to Read more information on Oracle website. References: 记得在学java Reflection时,提到如果使用反射修改对象的值,需要调用setAccessable()取消权限检查,可是今天编程发现,即使没有取消权限检查,也可以访问,这是怎么回事??是规则改了??还是我理解错了?? 我正在构建一个具有许多不同程序包的Java应用程序。我希望能够以编程方式告诉应用程序中存在哪些以特定前缀开头的软件包。无论如何,Java反射API可以做到这一点吗?我没有看到任何与反射API相关的信息。 例: 我想通过知道前缀“ com.app.controls”来枚举所有这些信息,并了解将来可能会集成一个新程序包。 谢谢! 您可以使用Package.getPackages()来执行此操作,该方法返回当前类加载器已知的所有软件包的数组。您必须手动遍历数组,并使用getName()查找具有适当前缀的数组。 这是一个简单的例子: 请注意,此技术将仅返回在当前类加载器中定义的包。如果您需要来自其他类加载器的软件包,则有一些选择: 进行安排,以便您的程序可以从该类加载器内部运行以上代码。这要求您的代码库有一定的组织,这可能可行,也可能不可行。 使用反射在适当的类加载器上调用(通常受保护的)方法getPackages()。如果程序在安全管理器下运行,则此方法将无效。 我们今天的关于如何通过Java Reflection动态创建Java类?和java动态创建类以及方法的分享就到这里,谢谢您的阅读,如果想了解更多关于Java Reflection、Java Reflection Tutorial、java reflection 疑问、Java Reflection-获取软件包列表的相关信息,可以在本站进行搜索。 本文标签:泛型方法参数类型
泛型变量类型
数组
java.lang.reflect.Array
创建一个数组
访问一个数组
获取数组的Class对象
获取数组的成员类型
动态代理
创建代理
InvocationHandler接口
常见用例
动态类加载、重载
类加载器
类加载体系
类加载
动态类加载
动态类重载
自定义类重载
类加载/重载实例
Java Reflection Tutorial
if(obj instanceof Dog){
Dog d = (Dog)obj;
d.bark();
}
// with reflection
Class<?> c = Class.forName("classpath.and.classname");
Object dog = c.newInstance();
Method m = c.getDeclaredMethod("bark", new Class<?>[0]);
m.invoke(dog);
<bean id="someID" class="com.programcreek.Foo">
<property name="someField" value="someValue" />
</bean>
<servlet>
<servlet-name>someServlet</servlet-name>
<servlet-class>com.programcreek.WhyReflectionServlet</servlet-class>
<servlet>
package myreflection;
import java.lang.reflect.Method;
public class ReflectionHelloWorld {
public static void main(String[] args){
Foo f = new Foo();
System.out.println(f.getClass().getName());
}
}
class Foo {
public void print() {
System.out.println("abc");
}
}
myreflection.Foo
package myreflection;
import java.lang.reflect.Method;
public class ReflectionHelloWorld {
public static void main(String[] args){
Foo f = new Foo();
Method method;
try {
method = f.getClass().getMethod("print", new Class<?>[0]);
method.invoke(f);
} catch (Exception e) {
e.printStackTrace();
}
}
}
class Foo {
public void print() {
System.out.println("abc");
}
}
abc
package myreflection;
public class ReflectionHelloWorld {
public static void main(String[] args){
//create instance of "Class"
Class<?> c = null;
try{
c=Class.forName("myreflection.Foo");
}catch(Exception e){
e.printStackTrace();
}
//create instance of "Foo"
Foo f = null;
try {
f = (Foo) c.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
f.print();
}
}
class Foo {
public void print() {
System.out.println("abc");
}
}
package myreflection;
import java.lang.reflect.Constructor;
public class ReflectionHelloWorld {
public static void main(String[] args){
//create instance of "Class"
Class<?> c = null;
try{
c=Class.forName("myreflection.Foo");
}catch(Exception e){
e.printStackTrace();
}
//create instance of "Foo"
Foo f1 = null;
Foo f2 = null;
//get all constructors
Constructor<?> cons[] = c.getConstructors();
try {
f1 = (Foo) cons[0].newInstance();
f2 = (Foo) cons[1].newInstance("abc");
} catch (Exception e) {
e.printStackTrace();
}
f1.print();
f2.print();
}
}
class Foo {
String s;
public Foo(){}
public Foo(String s){
this.s=s;
}
public void print() {
System.out.println(s);
}
}
null
abc
package myreflection;
import java.lang.reflect.Array;
public class ReflectionHelloWorld {
public static void main(String[] args) {
int[] intArray = { 1, 2, 3, 4, 5 };
int[] newIntArray = (int[]) changeArraySize(intArray, 10);
print(newIntArray);
String[] atr = { "a", "b", "c", "d", "e" };
String[] str1 = (String[]) changeArraySize(atr, 10);
print(str1);
}
// change array size
public static Object changeArraySize(Object obj, int len) {
Class<?> arr = obj.getClass().getComponentType();
Object newArray = Array.newInstance(arr, len);
//do array copy
int co = Array.getLength(obj);
System.arraycopy(obj, 0, newArray, 0, co);
return newArray;
}
// print
public static void print(Object obj) {
Class<?> c = obj.getClass();
if (!c.isArray()) {
return;
}
System.out.println("\nArray length: " + Array.getLength(obj));
for (int i = 0; i < Array.getLength(obj); i++) {
System.out.print(Array.get(obj, i) + " ");
}
}
}
Array length: 10
1 2 3 4 5 0 0 0 0 0
Array length: 10
a b c d e null null null null null
java reflection 疑问
public class FieldTroubleException {
private boolean b = true;
public static void main(String[] args) throws Exception {
FieldTroubleException ft = new FieldTroubleException();
Class<?> c = ft.getClass();
Field f = c.getDeclaredField("b");
// f.setAccessible(true); //缺少这一行代码也可以运行
f.setBoolean(ft, Boolean.FALSE);
System.out.println(ft.b);
}
}
Java Reflection-获取软件包列表
com.app.controls.textcom.app.controls.pickercom.app.controls.dateetc
答案1
小编典典 public List<String> findPackageNamesStartingWith(String prefix) { return Package.getPackages().stream() .map(Package::getName) .filter(n -> n.startsWith(prefix)) .collect(toList());}