一、一个使用反射的例子
Person类:
import java.io.Serializable;
public class Person implements Serializable {
private String name;
public int age;
public static final long serialVersionUID=82349802L;
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;
}
public Person(String name, int age)
{
this.name=name;
this.age=age;
}
private Person(String name)
{
this.name=name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public void show()
{
System.out.println("hello");
}
private String showNation(String nation)
{
System.out.println("我的国籍是"+nation);
return nation;
}
}
使用反射创建Person类对象、调用Person类方法等:
import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ReflectionTest {
@Test
//反射之前,对于Person的操作
public void test1()
{
//1. 创建person对象
Person p1=new Person("Tom",12);
//2. 通过对象,调用其内部的属性、方法
p1.age=10;
System.out.println(p1.toString());
p1.show();
//Person类外部,不能调用其内部私有结构
}
@Test
public void test2() throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException, NoSuchFieldException {
//通过反射,创建Person类对象
Class cl=Person.class;
Constructor cons=cl.getConstructor(String.class,int.class);
Object obj=cons.newInstance("Tom",12);
Person p=(Person)obj;
//通过反射,调用对象的指定属性和方法
Field age = cl.getDeclaredField("age");
age.set(p,10);
System.out.println(p.toString());
//调用方法
Method show = cl.getMethod("show");
show.invoke(p);//invoke 调用
//通过反射,可以调用Person类的私有结构,比如私有的构造器,私有的方法、属性
Constructor cons2 = cl.getDeclaredConstructor(String.class);
cons2.setAccessible(true);
Object o = cons2.newInstance("zhangsan");
Person p2=(Person)o;
Field name = cl.getDeclaredField("name");
name.setAccessible(true);
name.set(p2,"lisi");
Method showNation = cl.getDeclaredMethod("showNation", String.class);
showNation.setAccessible(true);
showNation.invoke(p2,"chn");
System.out.println(p2.toString());
}
}
二、关于java.lang.Class类的理解
-
类的加载过程
程序经过javac.exe命令之后,会生成一个或多个字节码文件(.class)
接着我们使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中。此过程被称为类的加载。加载到内存中的类,称为运行时类,此运行时类,就作为Class的一个实例 -
Class的实例就是一个运行时类
三、Class类
获得Class类的对象的四种方法
//反射机制学习
// 之前已经写了一个Employee对象 ee
//1. 跟踪一个对象的类名
Class cl=ee.getClass(); //获得一个Class类型的实例
System.out.println(ee.getClass().getName()+" "+ ee.getName());
//如果类在包里,包的名字也作为类名的一部分
Random generator=new Random();
cl=generator.getClass();
String Name=cl.getName(); //name is java.util.Random
//2. 还可以使用静态方法forName获得类名对应的Class对象
String className="java.util.Random";
// Class cl2=Class.forName(className);
//3. 获得class对象的第三种方法(直接获得!):
//T是任意的Java类型,T.class代表匹配的类的对象
Class cl1=Random.class;
Class c12=int.class;
Class cl3=Employee.class;
Class cl4=double[].class;
//与e instanceof Employee不同,如果e是某个子类的实例,以下测试将失败
if(ee.getClass()==Employee.class)
{
System.out.println("pass");
}
else System.out.println("fail");
//方式四:ClassLoader
ClassLoader classLoader=ReflectionTest.class.getClassLoader();
Class cl4=classLoader.loadClass("Person");
方式二,只有运行时候才知道!(体现程序运行时的动态性)
类加载器的作用
- 类加载的作用:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时的数据结构,然后再在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口
- 类缓存:标准的JavaSE类加载器可以按要求查找类,但一旦某个类被加载到类加载器中,它将维持加载一段时间。不过JVM的垃圾回收机制可以回收这些Class对象。
四、ClassLoader读取配置文件
/*
Properties:用来读取配置文件
* */
@Test
public void test3() throws IOException {
Properties pros=new Properties();
//此时的文件默认在当前的module下
//方式1:
// FileInputStream fis=new FileInputStream("src\\jdbc.properties");
// pros.load(fis);
//方式二:配置文件的默认识别为:当前module的src下;工程中一般放在src下
ClassLoader classLoader=ReflectionTest.class.getClassLoader();
InputStream is = classLoader.getResourceAsStream("jdbc.properties");
pros.load(is);
String user = pros.getProperty("user");
String password = pros.getProperty("password");
System.out.println("user="+user+",password="+password);
}
五、其他补充
反射可以—获取类的内部结构,调用类的内部结构。
具体参考part1中的例子就已经足够~