1. オブジェクトを通じて完全なパッケージ名とクラス名を取得します
Java コード
package Reflect; /** * 通过一个对象获得完整的包名和类名 * */ class Demo{ //other codes... } class hello{ public static void main(String[] args) { Demo demo=new Demo(); System.out.println(demo.getClass().getName()); } }
[実行結果]: Reflect.Demo
文を追加します: すべてのクラス オブジェクトは実際には Class のインスタンスです。
2. Class オブジェクトをインスタンス化します
Java コード
package Reflect; class Demo{ //other codes... } class hello{ public static void main(String[] args) { Class<?> demo1=null; Class<?> demo2=null; Class<?> demo3=null; try{ //一般尽量采用这种形式 demo1=Class.forName("Reflect.Demo"); }catch(Exception e){ e.printStackTrace(); } demo2=new Demo().getClass(); demo3=Demo.class; System.out.println("类名称 "+demo1.getName()); System.out.println("类名称 "+demo2.getName()); System.out.println("类名称 "+demo3.getName()); } }
[実行結果]:
クラス名 Reflect.Demo
クラス名 Reflect.Demo
3. Class Object を通じて他のオブジェクトをインスタンス化します。 of class
引数なしの構築によるオブジェクトのインスタンス化
Java コード
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); } }
[実行結果]:
[Rollen 20]
ただし、たとえば、次の後に、 Person でデフォルトの引数なしのコンストラクタをキャンセルするときは注意してください。パラメーター付きのコンストラクターのみを定義すると、エラーが表示されます:
たとえば、コンストラクターを定義すると:
Java コード
public Person(String name, int age) { this.age=age; this.name=name; }
その後、上記のプログラムを実行し続けると、エラーが表示されます:
Java コード
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)
そのため、今後 Class を使用して他のクラスをインスタンス化するオブジェクトを作成する場合は、独自のパラメーターなしのコンストラクターを定義する必要があります
4. Class を通じて他のクラスのコンストラクターを呼び出します (この方法で Class を通じてコンストラクターを作成することもできます)。クラス)
Java コード
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; //取得全部的构造函数 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); } }
[実行結果]:
[null 0]
[Rollen 0]
[null 20]
[Rollen 20]
5. クラス実装インターフェース
Java を返します。コード
package Reflect; interface China{ public static final String name="Rollen"; public static int age=20; public void sayChina(); public void sayHello(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 sayHello(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(); } //保存所有的接口 Class<?> intes[]=demo.getInterfaces(); for (int i = 0; i < intes.length; i++) { System.out.println("实现的接口 "+intes[i].getName()); } } }
[実行結果]:
実装インターフェース Reflect.China
6. 他のクラスの親クラスを取得
Java コード
class hello{ public static void main(String[] args) { Class<?> demo=null; try{ demo=Class.forName("Reflect.Person"); }catch (Exception e) { e.printStackTrace(); } //取得父类 Class<?> temp=demo.getSuperclass(); System.out.println("继承的父类为: "+temp.getName()); } }
[実行結果]
継承 親クラスは: java .lang.Object
7. 他のクラスのすべてのコンストラクターを取得します
Java コード
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("构造方法: "+cons[i]); } } }
[実行結果]:
構築メソッド: public Reflect.Person()
構築メソッド: public Reflect.Person(java. lang.String)
しかし、注意深い読者は、上記のコンストラクターには public や private などの修飾子がないことがわかるでしょう
次の例では、修飾子を取得します
Java コード
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("构造方法: "); 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("){}"); } } }
[実行結果] :
構築メソッド: public Reflect.person(){}
構築メソッド: public Reflect.Person(java.lang.String arg1){}
場合によっては、メソッドに異常がある場合もあります (笑)。以下を見てください:
Java コード
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<?> exce[]=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(); } } }
[実行結果]:
public java.lang.String getSex ()
public void setSex (java.lang.String arg0)
public voidsayChina ()
public voidsayHello (java.lang.String arg0,int arg1)
publicfinalnative voidwait(longarg0)throws java.lang.InterruptedException
publicfinal voidwait()throws java.lang.InterruptedException
publicfinal void wait (long arg0,int arg1) は java.lang.InterruptedException をスローします
public boolean = (java.lang.Object arg0)
public java.lang.String toString ()
publicative int hashCode ()
public Final Native java.lang.Class getClass ()
publicfinalnativevoidnotify()
publicfinalnativevoidnotifyAll()
8. 最後に、これらを入れていきます。つまり、クラス
Java コード
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("===============本类属性========================"); // 取得本类的全部属性 Field[] field = demo.getDeclaredFields(); for (int i = 0; i < field.length; i++) { // 权限修饰符 int mo = field[i].getModifiers(); String priv = Modifier.toString(mo); // 属性类型 Class<?> type = field[i].getType(); System.out.println(priv + " " + type.getName() + " " + field[i].getName() + ";"); } System.out.println("===============实现的接口或者父类的属性========================"); // 取得实现的接口或者父类的属性 Field[] filed1 = demo.getFields(); for (int j = 0; j < filed1.length; j++) { // 权限修饰符 int mo = filed1[j].getModifiers(); String priv = Modifier.toString(mo); // 属性类型 Class<?> type = filed1[j].getType(); System.out.println(priv + " " + type.getName() + " " + filed1[j].getName() + ";"); } } }
を通じてクラスのフレームワーク全体を取得します [実行結果]:
================ この属性クラス ===== ===================
プライベート java.lang.String セックス
============= ===親クラスの実装されたインターフェイスまたは属性 =======================
public static Final java.lang.String name; public static Final int age;
[ケース] 実際、リフレクションを通じて他のクラスのメソッドを呼び出すこともできます:
Java コード
class hello { public static void main(String[] args) { Class<?> demo = null; try { demo = Class.forName("Reflect.Person"); } catch (Exception e) { e.printStackTrace(); } try{ //调用Person类中的sayChina方法 Method method=demo.getMethod("sayChina"); method.invoke(demo.newInstance()); //调用Person的sayHello方法 method=demo.getMethod("sayHello", String.class,int.class); method.invoke(demo.newInstance(),"Rollen",20); }catch (Exception e) { e.printStackTrace(); } } }
hello, china
Rollen 20
9. 他のクラスの set メソッドと get メソッドを呼び出す
Java コード
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","男",String.class); getter(obj,"Sex"); } /** * @param obj * 操作的对象 * @param att * 操作的属性 * */ 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 * 操作的对象 * @param att * 操作的属性 * @param value * 设置的值 * @param type * 参数的属性 * */ 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
[実行結果]:
男性
10. リフレクションによる属性の操作
Java コード
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, "男"); System.out.println(field.get(obj)); } }// end class
11.リフレクションによる配列情報の変更:
Javaコード
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("数组类型: "+demo.getName()); System.out.println("数组长度 "+Array.getLength(temp)); System.out.println("数组的第一个元素: "+Array.get(temp, 0)); Array.set(temp, 0, 100); System.out.println("修改之后数组第一个元素为: "+Array.get(temp, 0)); } }
【実行結果】:
配列型: int
配列長5
配列の最初の要素: 1
変更後の配列の最初の要素は: 100
12. リフレクションによる配列サイズの変更
Java コード
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[] atr={"a","b","c"}; String[] str1=(String[])arrayInc(atr,8); print(str1); } /** * 修改数组大小 * */ 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; } /** * 打印 * */ public static void print(Object obj){ Class<?>c=obj.getClass(); if(!c.isArray()){ return; } System.out.println("数组长度为: "+Array.getLength(obj)); for (int i = 0; i < Array.getLength(obj); i++) { System.out.print(Array.get(obj, i)+" "); } } }
【运行结果】:
数组长度为: 15
1 2 3 4 5 6 7 8 9 0 0 0 0 0 0 =====================
数组长度为: 8
a b c null null null null null
13、动态代理
如何获得类加载器:
Java代码
class test{ } class hello{ public static void main(String[] args) { test t=new test(); System.out.println("类加载器 "+t.getClass().getClassLoader().getClass().getName()); } }
【程序输出】:
类加载器 sun.misc.Launcher$AppClassLoader
其实在java中有三种类类加载器。
1)Bootstrap ClassLoader 此加载器采用c++编写,一般开发中很少见。
2)Extension ClassLoader 用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类
3)AppClassLoader 加载classpath指定的类,是最常用的加载器。同时也是java中默认的加载器。
如果想要完成动态代理,首先需要定义一个InvocationHandler接口的子类,已完成代理的具体操作。
Java代码
package Reflect; import java.lang.reflect.*; //定义项目接口 interface Subject { public String say(String name, int age); } // 定义真实项目 class RealSubject implements Subject { @Override public String say(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); } }
【运行结果】:
Rollen 20
类的生命周期
在一个类编译完成之后,下一步就需要开始使用类,如果要使用一个类,肯定离不开JVM。在程序执行中JVM通过装载,链接,初始化这3个步骤完成。
类的装载是通过类加载器完成的,加载器将.class文件的二进制文件装入JVM的方法区,并且在堆区创建描述这个类的java.lang.Class对象。用来封装数据。 但是同一个类只会被类装载器装载以前
链接就是把二进制数据组装为可以运行的状态。
链接分为校验,准备,解析这3个阶段
校验一般用来确认此二进制文件是否适合当前的JVM(版本),
准备就是为静态成员分配内存空间,。并设置默认值
解析指的是转换常量池中的代码作为直接引用的过程,直到所有的符号引用都可以被运行程序使用(建立完整的对应关系)
完成之后,类型也就完成了初始化,初始化之后类的对象就可以正常使用了,直到一个对象不再使用之后,将被垃圾回收。释放空间。
当没有任何引用指向Class对象时就会被卸载,结束类的生命周期
14、将反射用于工厂模式
如果不用反射的时候,的工厂模式吧:
Java代码
/** * @author Rollen-Holt 设计模式之 工厂模式 */ 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 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(); } }
这样,当我们在添加一个子类的时候,就需要修改工厂类了。如果我们添加太多的子类的时候,改的就会很多。
现在我们看看利用反射机制:
Java代码
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(); } } }
现在就算我们添加任意多个子类的时候,工厂类就不需要修改。
上面的爱吗虽然可以通过反射取得接口的实例,但是需要传入完整的包和类名。而且用户也无法知道一个接口有多少个可以使用的子类,所以我们通过属性文件的形式配置所需要的子类。
下面我们来看看: 结合属性文件的工厂模式
首先创建一个fruit.properties的资源文件,
内容为:
Java代码
apple=Reflect.Apple orange=Reflect.Orange
然后编写主类代码:
Java代码
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"); } } //操作属性文件类 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(); } } }
【运行结果】:Apple
===========================================
实际项目中的应用:
利用java的反射机制,给两个不同的对象的属性赋值,主要是两个有相同属性的对象,类似于entity bean 和 VO 这样的POJO
Java代码
import java.lang.reflect.Field; import java.lang.reflect.Method; import javax.persistence.Id; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * <转换对象工具> * <功能详细描述> * @author zengyouyuan * @version [版本号, 2013-5-27] * @see [相关类/方法] * @since [产品/模块版本] */ public class ConvertObjectUtil { // log private static Log log = LogFactory.getLog(ConvertObjectUtil.class); /** * <两个属性相同的对象,把源对象的属性值动态赋给目标对象> * <功能详细描述> * @param srcClass 源类型 * @param srcObject 源对象 * @param destObject 目标对象 * @return 转换后的目标对象 * @see [类、类#方法、类#成员] */ public static Object convert(Class<?> srcClass, Object srcObject, Object destObject) { Field[] srcFields = srcClass.getDeclaredFields(); int fieldCount = srcFields.length; log.info("src class has :" + fieldCount + " fields"); for (int i = 0; i < fieldCount; i++) { // serialVersionUID和自增长的ID除外 if (srcFields[i].getName().equals("serialVersionUID")) { continue; } if (srcFields[i].getAnnotation(Id.class) != null) { continue; } try { // 利用源对象的get方法和目标对象的set方法,来给目标对象赋值 Method srcMethod = srcObject.getClass().getMethod("get" + uppercaseFirst(srcFields[i].getName())); Object srcValue = srcMethod.invoke(srcObject); Method destMethod = destObject.getClass().getMethod("set" + uppercaseFirst(srcFields[i].getName()), srcFields[i].getType()); destMethod.invoke(destObject, srcValue); } catch (Exception e) { // TODO Auto-generated catch block log.error(e); } } return destObject; } /** * <首字母大写> * <功能详细描述> * @param name * @return * @see [类、类#方法、类#成员] */ private static String uppercaseFirst(String name) { return name.substring(0, 1).toUpperCase() + name.substring(1); } }