http://blog.csdn.net/dream_broken/article/details/8830489
反射中,最基础的是对Class类的了解和使用。在JAVA中Object是一切类的父类,而getClass()方法是Object中定义的,如下
public final native Class<?> getClass();
那么可以这么说,所有类的对象实际上都是Class类的实例。如果你对类加载及JVM方法区有所了解,这个应该很容易理解。
本文主要是写点代码认识Class类的一些常用方法。
1.获取Class对象
在Class类中,只定义了个私有的构造方法,这意味着,无法通过new Class()方式创建一个Class对象。
虽然无法直接使用new Class()方式创建对象,但是Class类中提供了forName()方法,通过它仍然可以获得Class对象。
public static Class<?> forName(String className) throws ClassNotFoundException { return forName0(className, true , ClassLoader.getCallerClassLoader()); } public static Class<?> forName(String name, boolean initialize, ClassLoader loader) throws ClassNotFoundException
除了使用forName()方法获得Class对象外,上面说过了Object是所有类的父类,而Object中有getClass()方法,所以通过"类名.getClass()"也可以获得Class对象,也可以通过“类名.class"
package test; public class A1 { } <span style="font-size:18px;" > public class A2 { public static void main(String[] args){ Class<?> c1=null ; Class<?> c2=null ; Class<?> c3=null ; try { c1=Class.forName("test.A1" ); c2=A1.class ; A1 a1=new A1(); c3=a1.getClass(); } catch (ClassNotFoundException e) { e.printStackTrace(); } System.out.println("类路径:" +c1.getName()); System.out.println("类路径:" +c2.getName()); System.out.println("类路径:" +c3.getName()); } }</span>
运行结果
类路径:test.A1 类路径:test.A1 类路径:test.A1
通过运行结果可知,3种实例化Class对象的方式是一样的,但是使用forName()是较为常用的一种(当然,如果使用Hibernate或spring等框架时,经常使用"类.class“方式传送一个JavaBean实体)。
下面先看过设计上比较丑陋的例子。
<span style= "font-size:18px;" > package test; public interface Fruit { public void say(); } package test; public class Apple implements Fruit { @Override public void say() { System.out.println("hello,I'm apple!" ); } } public class Banana implements Fruit { @Override public void say() { System.out.println("hello,I'm banana!" ); } } package test; public class FruitUtil { public static Fruit createFruit(String fruitName){ if ( "apple" .equalsIgnoreCase(fruitName)) return (Fruit) new Apple(); if ( "banana" .equalsIgnoreCase(fruitName)) return (Fruit) new Banana(); return null ; } } package test; public class Test { public static void main(String[] args){ Fruit f=FruitUtil.createFruit("apple" ); if (f!= null ) { f.say(); }else { System.out.println("没有水果!" ); } } </span>}
运行结果
hello,I'm apple!
代码没错,运行结果也没错,我之所以说它丑陋,是从代码扩展性方面考虑。比如,如果我要再添加一种水果呢?那么就必须修改FruitUtil.createFruit()方法中的代码了,增加if判断。那如果我要新曾几十种水果呢?那是不是要写几十个if判断。。。。。作为一个接触JAVA两年的菜鸟的我,都觉得代码设计不友好了,更别说修改原有代码对系统的危害了。那有没有一种方法,当新增水果时,不需要对原有代码做任何修改呢?有,这时,Class.forName()一声大哄,粉墨登场了。
<span style= "font-size:18px;" > package test; public interface Fruit { public void say(); } package test; public class Apple implements Fruit { @Override public void say() { System.out.println("hello,I'm apple!" ); } } package test; public class Banana implements Fruit { @Override public void say() { System.out.println("hello,I'm banana!" ); } } package test; public class FruitUtil { public static Fruit createFruit(String classPath) throws Exception{ Fruit fruit=null ; try { fruit=(Fruit)Class.forName(classPath).newInstance(); } catch (Exception e) { e.printStackTrace(); throw new Exception( "创建水果失败!" ); } return fruit; } } package test; import java.io.File; import java.io.FileInputStream; import java.util.Properties; public class Test { private final static String FRUIT_CONF_PATH=System.getProperty( "user.dir" ); public static void main(String[] args){ Properties p=new Properties(); try { FileInputStream in=new FileInputStream( new File(FRUIT_CONF_PATH+File.separator+ "bin" +File.separator+ "fruit.properties" )); p.load(in); String fruitClassPath=p.getProperty("apple" ); p.clear(); in.close(); Fruit f=FruitUtil.createFruit(fruitClassPath); f.say(); } catch (Exception e) { e.printStackTrace(); System.out.println("获取水果实例失败!" ); } } }</span>
fruit.properties配置文件
apple=test.Apple banana=test.Banana
运行结果
hello,I'm apple!
这样改写后,以后有新增水果时,只要编写新增水果类,并再配置文件中配置新水果的类路径就OK了,原有的代码不需要修改。
这样的设计就具有很好的扩展性。
2.获取类中的成员变量
getFields():获得类(包括父类)的public成员变量
getDeclaredFields():获得类(不包括父类)的全部成员变量
package test; public class A { public int n_A; private String s_A; protected double d_A; } package test; public class A1 extends A { public int n_A1; private String s_A1; protected double d_A1; } package test; import java.lang.reflect.Field; public class A2 { public static void main(String[] args){ Class<?> c1=null ; try { c1=Class.forName("test.A1" ); Field[] f1=c1.getFields(); for (Field f:f1) System.out.println("A1(包括父类)类中public 成员变量:" +f.getName()); System.out.println("获取A1(不包括父类)类中的所有成员变量::::::::" ); Field[] f2=c1.getDeclaredFields(); for (Field f:f2) System.out.println("A1(不包括父类)类中的成员变量:" +f.getName()); } catch (Exception e) { e.printStackTrace(); } } }
运行结果
A1(包括父类)类中public 成员变量:n_A1 A1(包括父类)类中public 成员变量:n_A 获取A1(不包括父类)类中的所有成员变量:::::::: A1(不包括父类)类中的成员变量:n_A1 A1(不包括父类)类中的成员变量:s_A1 A1(不包括父类)类中的成员变量:d_A1
3.获取类中的方法
getMethods():获取类(包括父类)中的public方法(不包括构造方法)
getDeclaredMethods():获取本类(不包括父类)中的所有方法(不包括构造方法)
getConstructors():获取本类(不包括父类)中的所有public构造方法
考虑到篇幅问题,就不贴代码了。
4.实例化对象
<span style= "font-size:18px;" > package test; public class A1 { private int n; public A1(){ this .n= 0 ; } public A1( int n){ this .n=n; } public int getN() { return n; } public void setN( int n) { this .n = n; }; } package test; import java.lang.reflect.Constructor; public class A2 { public static void main(String[] args){ Class<?> c1=null ; try { c1=Class.forName("test.A1" ); A1 a1=(A1)c1.newInstance(); System.out.println("使用Class类中的newInstance()方法实例化,a1.n=" +a1.getN()); Constructor<?>[] con=c1.getConstructors(); A1 a2=(A1)con[0 ].newInstance(); System.out.println("使用Constructor类中的public T newInstance(Object ... initargs)方法实例化,a2.n=" +a2.getN()); A1 a3=(A1)con[1 ].newInstance( 10 ); System.out.println("使用Constructor类中的public T newInstance(Object ... initargs)方法实例化,a3.n=" +a3.getN()); } catch (Exception e) { e.printStackTrace(); } } }</span>
运行结果
使用Class类中的newInstance()方法实例化,a1.n=0 使用Constructor类中的public T newInstance(Object ... initargs)方法实例化,a2.n=0 使用Constructor类中的public T newInstance(Object ... initargs)方法实例化,a3.n=10
5.通过反射调用类中的方法
<span style= "font-size:18px;color:#000000;" > package test; public class A { public void sayHello(){ System.out.println("hello,world" ); } public void sayHello(String name){ System.out.println("hello," +name); } } package test; import java.lang.reflect.Method; public class Test01 { public static void main(String[] args){ Class<?> c=null ; try { c=Class.forName("test.A" ); A a=(A)c.newInstance(); Method m1=c.getMethod("sayHello" ); m1.invoke(a); Method m2=c.getMethod("sayHello" , String. class ); m2.invoke(a, "everyOne" ); } catch (Exception e) { e.printStackTrace(); } } }</span>
运行结果
hello,world hello,everyOne
6.通过反射破坏类的封装性(给私有变量赋值并访问)
<span style= "font-size:18px;" > package test; public class User { private String name; private int age; public String getName() { return name; } public int getAge() { return age; } } package test; import java.lang.reflect.Field; public class Test01 { public static void main(String[] args){ Class<?> c=null ; try { c=Class.forName("test.User" ); User user=(User)c.newInstance(); Field name=c.getDeclaredField("name" ); Field age=c.getDeclaredField("age" ); name.setAccessible(true ); age.setAccessible(true ); name.set(user, "张三" ); age.set(user, 20 ); System.out.println("姓名:" +name.get(user)+ " " +user.getName()); System.out.println("年龄:" +age.get(user)+ " " +user.getAge()); } catch (Exception e) { e.printStackTrace(); } } }</span>
运行结果
姓名:张三 张三 年龄:20 20