Detailed explanation of Java reflection
This article still uses small examples to illustrate, because I always feel that case-driven is the best, otherwise if you only read the theory, you won’t understand it after reading it. However, it is recommended that you look back at the theory after reading the article and have a better understanding.
The main text begins below.
[Case 1] Obtain the complete package and class name through an object
package Reflect; /** * Get the complete package name and class name through an object* */class Demo{ //other codes...} class hello{ public static void main(String[] args) { Demo demo=new Demo(); System.out.println(demo.getClass().getName()); }}【Running result】: Reflect.Demo
Add a sentence: All objects of classes are actually instances of Class.
【Case 2】Instantiate Class object
package Reflect;class Demo{ //other codes...} class hello{ public static void main(String[] args) { Class<?> demo1=null; Class<?> demo2=null; Class<?> demo3=null; try{ //Generally try to use this form demo1=Class.forName("Reflect.Demo"); } catch(Exception e){ e.printStackTrace(); } demo2=new Demo().getClass(); demo3=Demo.class; System.out.println("Class Name"+demo1.getName()); System.out.println("Class Name"+demo2.getName()); System.out.println("Class Name"+demo3.getName()); }}【Operation results】:
Class nameReflect.Demo
Class nameReflect.Demo
Class nameReflect.Demo
[Case 3] Instantiate objects of other classes through Class
Instantiated objects by constructing non-parameters
package Reflect; class Person{ public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString(){ return "["+this.name+" "+this.age+"]"; } private String name; private int age; } class hello{ public static void main(String[] args) { Class<?> demo=null; try{ demo=Class.forName("Reflect.Person"); } catch (Exception e) { e.printStackTrace(); } Person per=null; try { per=(Person)demo.newInstance(); } catch (InstantiationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } per.setName("Rollen"); per.setAge(20); System.out.println(per); }}【Operation results】:
[Rollen 20]
But note that when we cancel the default parameterless constructor in Person, for example, after we define only one constructor with parameters, an error will occur:
For example, I defined a constructor:
public Person(String name, int age) { this.age=age; this.name=name; }Then continue running the above program, and it will appear:
java.lang.InstantiationException: Reflect.Person
at java.lang.Class.newInstance0(Class.java:340)
at java.lang.Class.newInstance(Class.java:308)
at Reflect.hello.main(hello.java:39)
Exception in thread "main" java.lang.NullPointerException
at Reflect.hello.main(hello.java:47)
So when you write objects that use Class to instantiate other classes, you must define your own constructor without parameters.
[Case] Call constructors in other classes through Class (you can also create objects of other classes through Class in this way)
package Reflect; import java.lang.reflect.Constructor; class Person{ public Person() { } public Person(String name){ this.name=name; } public Person(int age){ this.age=age; } public Person(String name, int age) { this.age=age; this.name=name; } public String getName() { return name; } public int getAge() { return age; } @Override public String toString(){ return "["+this.name+" "+this.age+"]"; } private String name; private int age;} class hello{ public static void main(String[] args) { Class<?> demo=null; try{ demo=Class.forName("Reflect.Person"); } catch (Exception e) { e.printStackTrace(); } Person per1=null; Person per2=null; Person per3=null; Person per4=null; //Get all constructors Constructor<?> cons[]=demo.getConstructors(); try{ per1=(Person)cons[0].newInstance(); per2=(Person)cons[1].newInstance("Rollen"); per3=(Person)cons[2].newInstance(20); per4=(Person)cons[3].newInstance("Rollen",20); }catch(Exception e){ e.printStackTrace(); } System.out.println(per1); System.out.println(per2); System.out.println(per3); System.out.println(per4); }}【Operation results】:
[null 0]
[Rollen 0]
[null 20]
[Rollen 20]
【Case】
Returns the interface implemented by a class:
package Reflect; interface China{ public static final String name="Rollen"; public static int age=20; public void saysChina(); public void saysHello(String name, int age);} class Person implements China{ public Person() { } public Person(String sex){ this.sex=sex; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } @Override public void sayChina(){ System.out.println("hello ,china"); } @Override public void saysHello(String name, int age){ System.out.println(name+" "+age); } private String sex;} class hello{ public static void main(String[] args) { Class<?> demo=null; try{ demo=Class.forName("Reflect.Person"); } catch (Exception e) { e.printStackTrace(); } //Save all interfaces Class<?> intes[]=demo.getInterfaces(); for (int i = 0; i < intes.length; i++) { System.out.println("Implemented Interface"+intes[i].getName()); } }}【Operation results】:
Implemented interface Reflect.China
(Note that the following examples will use the Person class of this example, so in order to save space, we will no longer paste the Person code part here, only the code of the main class hello)
【Case】: Get the parent class in other classes
class hello{ public static void main(String[] args) { Class<?> demo=null; try{ demo=Class.forName("Reflect.Person"); }catch (Exception e) { e.printStackTrace(); } //Get the parent class Class<?> temp=demo.getSuperclass(); System.out.println("The inherited parent class is: "+temp.getName()); }}【Running results】
The inherited parent class is: java.lang.Object
【Case】: Obtain all constructors in other classes
This example requires adding import java.lang.reflect.* at the beginning of the program;
Then write the main class as:
class hello{ public static void main(String[] args) { Class<?> demo=null; try{ demo=Class.forName("Reflect.Person"); } catch (Exception e) { e.printStackTrace(); } Constructor<?>cons[]=demo.getConstructors(); for (int i = 0; i < cons.length; i++) { System.out.println("Constructor: "+cons[i]); } }}【Operation results】:
Constructing method: public Reflect.Person()
Constructor: public Reflect.Person(java.lang.String)
But careful readers will find that the above constructor does not have modifiers such as public or private
Let's get the modifier in the following example
class hello{ public static void main(String[] args) { Class<?> demo=null; try{ demo=Class.forName("Reflect.Person"); } catch (Exception e) { e.printStackTrace(); } Constructor<?>cons[]=demo.getConstructors(); for (int i = 0; i < cons.length; i++) { Class<?> p[]=cons[i].getParameterTypes(); System.out.print("Constructor: "); int mo=cons[i].getModifiers(); System.out.print(Modifier.toString(mo)+" "); System.out.print(cons[i].getName()); System.out.print("("); for(int j=0;j<p.length;++j){ System.out.print(p[j].getName()+" arg"+i); if(j<p.length-1){ System.out.print(","); } } System.out.println("){}"); } }【Operation results】:
Constructor: public Reflect.Person(){}
Constructor: public Reflect.Person(java.lang.String arg1){}
Sometimes there may be exceptions in a method, haha. Let's take a look:
class hello{ public static void main(String[] args) { Class<?> demo=null; try{ demo=Class.forName("Reflect.Person"); }catch (Exception e) { e.printStackTrace(); } Method method[]=demo.getMethods(); for(int i=0;i<method.length;++i){ Class<?> returnType=method[i].getReturnType(); Class<?> para[]=method[i].getParameterTypes(); int temp=method[i].getModifiers(); System.out.print(Modifier.toString(temp)+" "); System.out.print(returnType.getName()+" "); System.out.print(method[i].getName()+" "); System.out.print("("); for(int j=0;j<para.length;++j){ System.out.print(para[j].getName()+" "+"arg"+j); if(j<para.length-1){ System.out.print(","); } } Class<?> exceed[]=method[i].getExceptionTypes(); if(exce.length>0){ System.out.print(") throws "); for(int k=0;k<exce.length;++k){ System.out.print(exce[k].getName()+" "); if(k<exce.length-1){ System.out.print(","); } } }else{ System.out.print(")"); } System.out.println(); } }}【Operation results】:
public java.lang.String getSex ()
public void setSex (java.lang.String arg0)
public void saysChina ()
public void saysHello (java.lang.String arg0,int arg1)
public final native void wait (long arg0) throws java.lang.InterruptedException
public final void wait () throws java.lang.InterruptedException
public final void wait (long arg0,int arg1) throws java.lang.InterruptedException
public boolean equals (java.lang.Object arg0)
public java.lang.String toString ()
public native int hashCode ()
public final native java.lang.Class getClass ()
public final native void notify ()
public final native void notifyAll ()
[Case] Next, let's get all the properties of other classes. Finally, I will sort them out together, that is, to get the entire framework of a class through class
class hello { public static void main(String[] args) { Class<?> demo = null; try { demo = Class.forName("Reflect.Person"); } catch (Exception e) { e.printStackTrace(); } System.out.println("========================================================================================================================================================================================================================================================================================================================================================================================================================================= Permission modifier int mo = field[i].getModifiers(); String priv = Modifier.toString(mo); // Property type Class<?> type = field[i].getType(); System.out.println(priv + " " + type.getName() + " " + field[i].getName() + ";"); } System.out.println("====================================================================================================================================================================================================================================================================================================================================================================================================================== filed1 = demo.getFields(); for (int j = 0; j < filed1.length; j++) { // Permission modifier int mo = filed1[j].getModifiers(); String priv = Modifier.toString(mo); // Property type Class<?> type = filed1[j].getType(); System.out.println(priv + " " + type.getName() + " " + filed1[j].getName() + ";"); } }}【Operation results】:
==================================================
private java.lang.String sex;
=========================================================
public static final java.lang.String name;
public static final int age;
[Case] In fact, methods in other classes can also be called through reflection:
class hello { public static void main(String[] args) { Class<?> demo = null; try { demo = Class.forName("Reflect.Person"); } catch (Exception e) { e.printStackTrace(); } try{ //Calling the sayChina method in the Person class Method method=demo.getMethod("sayChina"); method.invoke(demo.newInstance()); //Calling the Person's sayHello method=demo.getMethod("sayHello", String.class,int.class); method.invoke(demo.newInstance(),"Rollen",20); }catch (Exception e) { e.printStackTrace(); } }}【Operation results】:
hello ,china
Rollen 20
【Case】Call set and get methods of other classes
class hello { public static void main(String[] args) { Class<?> demo = null; Object obj=null; try { demo = Class.forName("Reflect.Person"); } catch (Exception e) { e.printStackTrace(); } try{ obj=demo.newInstance(); } catch (Exception e) { e.printStackTrace(); } setter(obj,"Sex","Male",String.class); getter(obj,"Sex"); } /** * @param obj * Object of operation* @param att * Attributes of the operation* */ public static void getter(Object obj, String att) { try { Method method = obj.getClass().getMethod("get" + att); System.out.println(method.invoke(obj)); } catch (Exception e) { e.printStackTrace(); } } /** * @param obj * Object of the operation* @param att * Attributes of the operation* @param value * Set value* @param type * Attributes of the parameter* */ public static void setter(Object obj, String att, Object value, Class<?> type) { try { Method method = obj.getClass().getMethod("set" + att, type); method.invoke(obj, value); } catch (Exception e) { e.printStackTrace(); } }}// end class【Operation results】:
male
【Case】Operation by reflection
class hello { public static void main(String[] args) throws Exception { Class<?> demo = null; Object obj = null; demo = Class.forName("Reflect.Person"); obj = demo.newInstance(); Field field = demo.getDeclaredField("sex"); field.setAccessible(true); field.set(obj, "male"); System.out.println(field.get(obj)); }}// end class[Case] Obtain and modify the information of the array through reflection:
import java.lang.reflect.*;class hello{ public static void main(String[] args) { int[] temp={1,2,3,4,5}; Class<?>demo=temp.getClass().getComponentType(); System.out.println("Array type: "+demo.getName()); System.out.println("Array length"+Array.getLength(temp)); System.out.println("First element of the array: "+Array.get(temp, 0)); Array.set(temp, 0, 100); System.out.println("After modifying the first element of the array is: "+Array.get(temp, 0)); }}【Operation results】:
Array type: int
Array length 5
The first element of the array: 1
After modification, the first element of the array is: 100
【Case】Modify the array size through reflection
class hello{ public static void main(String[] args) { int[] temp={1,2,3,4,5,6,7,8,9}; int[] newTemp=(int[])arrayInc(temp,15); print(newTemp); System.out.println("====================================================================================================================================================================================== String[])arrayInc(atr,8); print(str1); } /** * Modify array size* */ public static Object arrayInc(Object obj,int len){ Class<?>arr=obj.getClass().getComponentType(); Object newArr=Array.newInstance(arr, len); int co=Array.getLength(obj); System.arraycopy(obj, 0, newArr, 0, co); return newArr; } /** * Print* */ public static void print(Object obj){ Class<?>c=obj.getClass(); if(!c.isArray()){ return; } System.out.println("Array length is: "+Array.getLength(obj)); for (int i = 0; i < Array.getLength(obj); i++) { System.out.print(Array.get(obj, i)+" "); } }}【Operation results】:
The array length is: 15
1 2 3 4 5 6 7 8 9 0 0 0 0 0 0 ========================================
The array length is: 8
abc null null null null null
Dynamic Agent
[Case] First, let’s take a look at how to get the class loader:
class test{ }class hello{ public static void main(String[] args) { test t=new test(); System.out.println("ClassLoader"+t.getClass().getClassLoader().getClass().getName()); }}【Program output】:
Class loader sun.misc.Launcher$AppClassLoader
In fact, there are three kinds of class loaders in Java.
1) Bootstrap ClassLoader This loader is written in C++ and is rarely seen in general development.
2) Extension ClassLoader is used to load extended classes, generally corresponding to classes in jre/lib/ext directory
3) AppClassLoader loads the class specified by classpath and is the most commonly used loader. It is also the default loader in Java.
If you want to complete a dynamic proxy, you first need to define a subclass of the InvocationHandler interface, and the specific operation of the proxy has been completed.
package Reflect;import java.lang.reflect.*; //Define project interface interface Subject { public String says(String name, int age);} //Define real project class RealSubject implements Subject { @Override public String says(String name, int age) { return name + " " + age; }} class MyInvocationHandler implements InvocationHandler { private Object obj = null; public Object bind(Object obj) { this.obj = obj; return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj .getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object temp = method.invoke(this.obj, args); return temp; }} class hello { public static void main(String[] args) { MyInvocationHandler demo = new MyInvocationHandler(); Subject sub = (Subject) demo.bind(new RealSubject()); String info = sub.say("Rollen", 20); System.out.println(info); }}【Operation results】:
Rollen 20
The life cycle of a class
After a class is compiled, the next step is to start using the class. If you want to use a class, it is definitely inseparable from JVM. During program execution, the JVM is completed through these three steps: loading, linking, and initializing.
Class loading is done through a class loader. The loader loads the binary file of the .class file into the JVM method area and creates a java.lang.Class object describing this class in the heap area. Used to encapsulate data. But the same class will only be loaded by the class loader before
Links are to assemble binary data into a state that can be run.
The link is divided into three stages: verification, preparation and parsing
Verification is generally used to confirm whether this binary file is suitable for the current JVM (version).
Preparation is to allocate memory space for static members. and set default values
Parsing refers to the process of converting the code in the constant pool as a direct reference until all symbolic references can be used by the running program (establish a complete correspondence)
After completion, the type is initialized. After initialization, the object of the class can be used normally. After an object is no longer used, it will be garbage collected. Free up space.
When no reference points to the Class object, it will be uninstalled, ending the class life cycle
Use reflection for factory mode
Let’s take a look at the factory mode if you don’t need reflection:
http://www.cnblogs.com/rollenholt/archive/2011/08/18/2144851.html
/** * @author Rollen-Holt Factory mode of design pattern*/ interface fruit{ public abstract void eat();} class Apple implements fruit{ public void eat(){ System.out.println("Apple"); }} class Orange implements fruit{ public void eat(){ System.out.println("Orange"); }} // Construct the factory class// In other words, if we only need to modify the factory class when adding other instances in the future class Factory{ public static fruit getInstance(String fruitName){ fruit f=null; if("Apple".equals(fruitName)){ f=new Apple(); } if("Orange".equals(fruitName)){ f=new Orange(); } return f; }}class hello{ public static void main(String[] a){ fruit f=Factory.getInstance("Orange"); f.eat(); } }In this way, when we add a subclass, we need to modify the factory class. If we add too many subclasses, we will change a lot.
Now let's take a look at the utilizing reflection mechanism:
package Reflect; interface fruit{ public abstract void eat();} class Apple implements fruit{ public void eat(){ System.out.println("Apple"); }} class Orange implements fruit{ public void eat(){ System.out.println("Orange"); }} class Factory{ public static fruit getInstance(String ClassName){ fruit f=null; try{ f=(fruit)Class.forName(ClassName).newInstance(); }catch (Exception e) { e.printStackTrace(); } return f; }}class hello{ public static void main(String[] a){ fruit f=Factory.getInstance("Reflect.Apple"); if(f!=null){ f.eat(); } }}Now even if we add as many subclasses, the factory class does not need to be modified.
Although the above love can obtain an instance of the interface through reflection, it needs to pass in the complete package and class name. Moreover, users cannot know how many subclasses can be used in an interface, so we configure the required subclasses in the form of attribute files.
Let's take a look at: Factory mode combining attribute files
First create a fruit.properties resource file.
Contents are:
apple=Reflect.Apple
orange=Reflect.Orange
Then write the main class code:
package Reflect; import java.io.*;import java.util.*; interface fruit{ public abstract void eat();} class Apple implements fruit{ public void eat(){ System.out.println("Apple"); }} class Orange implements fruit{ public void eat(){ System.out.println("Orange"); }} //Operation property file class init{ public static Properties getPro() throws FileNotFoundException, IOException{ Properties pro=new Properties(); File f=new File("fruit.properties"); if(f.exists()){ pro.load(new FileInputStream(f)); }else{ pro.setProperty("apple", "Reflect.Apple"); pro.setProperty("orange", "Reflect.Orange"); pro.store(new FileOutputStream(f), "FRUIT CLASS"); } return pro; }} class Factory{ public static fruit getInstance(String ClassName){ fruit f=null; try{ f=(fruit)Class.forName(ClassName).newInstance(); }catch (Exception e) { e.printStackTrace(); } return f; }}class hello{ public static void main(String[] a) throws FileNotFoundException, IOException{ Properties pro=init.getPro(); fruit f=Factory.getInstance(pro.getProperty("apple")); if(f!=null){ f.eat(); } }}【Run result】: Apple
The above is a detailed explanation of the Java reflection mechanism. We will continue to add relevant information in the future. Thank you for your support for this site!