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
|