Java让咱们在识别对象和类的信息,主要有两种方式:一种是传统的RTTI,它假定咱们在编译时已经知道了全部的类型信息;另外一种是反射机制,它容许咱们在运行时发现和使用类的信息。java
使用反射赋予了Java动态编译的能力,不然类的元数据信息只能经过静态编译的方式实现。缓存
静态编译:在编译时肯定类型,绑定对象即经过ide
动态编译:运行时肯定类型,绑定对象。动态编译最大限度地发挥了Java的灵活性,体现了多态的应用,能够下降类之间的耦合性。this
反射就是在运行时才知道要操做的类是什么,而且能够在运行时获取类的完整构造,并调用对应的方法。对象
反射是被视为动态语言的关键,反射机制容许程序在执行期间借助Reflection API取得任何类的内部信息,并能直接操做任意对象的内部属性和方法。内存
在运行时判断任意一个对象所属的类get
在运行的时候构造任意一个类的对象it
在运行时判断任意一个类所具备的成员变量和方法io
在运行时调用任意一个对象的成员变量和方法编译
public class Person {
public String name;
private int age;
public int id;
public Person() {
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
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 "Person [name=" + name + ", age=" + age + "]";
}
public void show(){
System.out.println("我是人类");
}
public void display(String nation){
System.out.println("个人家乡:"+nation);
}
public static void info(){
System.out.println("元宵节快乐!");
}
}
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import org.junit.Test;
public class TestField {
// 获取对应运行时类的属性
@Test
public void test1(){
Class clazz = Person.class;
// 1.getFields():只能获取运行时类中及其父类声明为public的属性
Field[] fields = clazz.getFields();
for (int i = 0; i < fields.length; i++) {
System.out.println(fields[i].getName());
}
//2.getDeclaredFields():获取运行时类自己声明的全部属性
Field[] fields2 = clazz.getDeclaredFields();
for (Field f : fields2) {
System.out.println(f.getName());
}
}
// 获取权限修饰符 变量类型 属性名
@Test
public void test2(){
Class clazz = Person.class;
Field[] fields = clazz.getDeclaredFields();
for (Field f : fields) {
// 1.获取每一个属性的访问修饰符
int i = f.getModifiers();
System.out.println(Modifier.toString(i)+" ");
// 2.获取属性的类型
Class type = f.getType();
System.out.println(type.getName()+" ");
// 3.获取属性名
System.out.println(f.getName()+" ");
System.out.println();
}
}
// 调用运行时类中指定的属性
@Test
public void test3() throws Exception{
Class clazz = Person.class;
// 1.获取指定的属性
// getField(String fieldName):获取运行时类中声明为public的属性名
Field name = clazz.getField("name");
// 2.建立运行时类的对象
Person p = (Person) clazz.newInstance();
System.out.println(p);
// 3.将运行时类的属性赋值
name.set(p, "jack");
System.out.println(p);
// 4.getDeclaredField(String fieldName):获取运行时类中指定的名为fieldName的属性
Field age = clazz.getDeclaredField("age");
// 因为属性权限修饰符的限制,为了保证能够为属性赋值,须要在操做前使得此属性能够被操做。
age.setAccessible(true);
age.set(p, 20);
System.out.println(p);
}
}
import java.lang.reflect.Constructor;
import org.junit.Test;
public class TestConstructor {
@Test
public void test1() throws Exception{
// 建立对应运行时类的对象使用newInstance()其实是调用了运行时类的空参构造器
// 要求:1.对应的运行时类要有空参的构造器 2.构造器的权限修饰符权限要足够
String className = "com.hpe.reflect.Person";
Class clazz = Class.forName(className);
Person p = (Person) clazz.newInstance();
System.out.println(p);
}
// 获取Person类中全部的构造器
@Test
public void test2() throws Exception{
Class clazz = Class.forName("com.hpe.reflect.Person");
Constructor[] cons = clazz.getDeclaredConstructors();
for (Constructor c : cons) {
System.out.println(c);
}
}
// 调用指定的构造器
@Test
public void test3() throws Exception{
Class clazz = Class.forName("com.hpe.reflect.Person");
Constructor cons = clazz.getDeclaredConstructor(String.class,int.class);
cons.setAccessible(true);
Person p = (Person) cons.newInstance("张三",20);
System.out.println(p);
}
}
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import org.junit.Test;
public class TestMethod {
// 调用运行时类中指定的方法
@Test
public void test1() throws Exception{
Class clazz = Person.class;
// getMethod(String methodName,class... params):获取运行时类中声明为public的方法
Method m1 = clazz.getMethod("show");
Person p = (Person) clazz.newInstance();
// 调用指定的方法Object invoke(Object obj,Object... obj)
Object returnVal = m1.invoke(p);
System.out.println(returnVal);
// 带有返回值类型的方法
Method m2 = clazz.getMethod("toString");
// 设置属性值
Field name = clazz.getField("name");
name.set(p, "lim");
Object returnVal2 = m2.invoke(p);
System.out.println(returnVal2);
// 调用静态方法
Method m3 = clazz.getMethod("info");
m3.invoke(Person.class);
// getDeclaredMethod(String methodName,class...param):获取运行时类声明的指定方法
Method m4 = clazz.getDeclaredMethod("display", String.class);
m4.setAccessible(true);
m4.invoke(p, "CHN");
}
}
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import org.junit.Test;
public class TestReflection { // 经过传统方式调用对象 调用其方法 @Test public void test1(){ Person p = new Person(); p.setAge(15); p.setName("jack"); System.out.println(p); p.show(); p.display("山东"); } // 有了反射,能够经过反射建立一个类的对象,并调用其中的结构 @Test public void test2() throws Exception{ Class clazz = Person.class; // 1.建立clazz对应运行时类Person类的对象 Person p = (Person)clazz.newInstance(); System.out.println(p); // 二、经过反射调用运行时类指定的属性 Field f1 = clazz.getField("name"); // 设置某个对象的属性值 f1.set(p, "jack"); System.out.println(p); Field f2 = clazz.getDeclaredField("age"); // 设置容许访问 f2.setAccessible(true); f2.set(p, 20); System.out.println(p); // 3.经过反射调用运行时类指定的方法 Method m1 = clazz.getMethod("show"); // 调用方法 m1.invoke(p); Method m2 = clazz.getMethod("display", String.class); m2.invoke(p, "China"); } /* * java.lang.Class:反射的源 * 建立一个类,经过编译(javac.exe)生成对应的class文件,以后咱们经过java.exe(JVM类加载器)加载此class文件 * 到内存,就是一个运行时类,存放在缓存区。Class clazz = Person.class * 1.每一个运行时类只加载一次 * 2.有了Class实例后,能够执行: * ①.建立对应运行时类的对象(重点) * ②.获取对应运行时类的完整结构(属性、方法、构造器、内部类、父类、包、异常、注解) * ③.调用对应的运行时类的指定结构(属性、方法、构造器)(重点) */ @Test public void test3(){ Person p = new Person(); // 调用其getClass()方法返回运行时类 Class clazz = p.getClass();// Person.class System.out.println(clazz); } @Test public void test4() throws ClassNotFoundException{ // 1.调用类自己的.class属性 Class clazz1 = Person.class; System.out.println(clazz1.getName()); Class clazz2 = String.class; System.out.println(clazz2.getName()); // 2.经过类的对象获取 Person p = new Person(); Class clazz3 = p.getClass(); System.out.println(clazz3.getName()); // 3.经过Class类的静态方法获取 String className = "com.hpe.reflect.Person"; Class clazz4 = Class.forName(className); System.out.println(clazz4.getName()); // 4.经过类的加载器(了解) ClassLoader classLoader = this.getClass().getClassLoader(); Class clazz5 = classLoader.loadClass(className); System.out.println(clazz5.getName()); }}