黑马程序员——反射
------- android培训、java培训、期待与您交流! ----------
反射的概念:一个类是由多个部分组成,例如:成员变量,方法,构造函数等,反射就是加载类<把硬盘中的class文件加载到内存中>,并解剖类的各个组成部分,包括私有的。
应用场景:主要是用于制作框架的时候使用,通过配置文件进行反射。
那么该如何加载类,如何反射呢?
Java是面向对象语言,万物皆对象,所以sun公司把所有类用一个Class类来描述。
通过字节码对象获取构造方法,创建对象,使用了Constructor类描述一个类的构造方法。创建对象用newInstance
通过一个字节码对象获取到成员函数,sun使用了一个Method类描述函数。执行指定方法用invoke
通过字节码对象获取成员变量 , sun使用了Field描述了一个类的成员变量。
首先我们先描述一个Person类,以Person类为列进行反射:
package cn.chen.reflect;
import java.io.InputStream;
import java.util.List;
public class Person {
//成员变量
public String name="aaa";
private int age = 22;
//构造函数
public Person(){
System.out.println("person");
}
public Person(String name){
System.out.println(name);
}
public Person(String name,int pass){
System.out.println(name+":"+pass);
}
//集合作为形参传递
private Person(List list){
System.out.println("list");
}
public void aa1(){
System.out.println("aa1...");
}
public void aa1(String name,int pass){
System.out.println(name+":"+pass);
}
//返回类型是数组
public Class[] aa1(String name,int[] pass){
return new Class[]{String.class};
}
private void aa1(InputStream io){
System.out.println(io);
}
//静态方法
public static void aa1(String name){
System.out.println(name);
}
public static void main(String[] args) {
System.out.println("main...");
}
}
步骤如下:
1:首先把硬盘中的class文件加载进内存中;
加载类进内存有三种方法:
a:通过Class类中forName方法:forName(String className)
b:通过上帝Object类中getClass方法:对象.getClass()
c:通过类名.class
代码实现如下:
</pre><pre name="code" class="java">package cn.chen.reflect;
public class Demo1 {
public static void main(String[] args) throws ClassNotFoundException {
//第一种方法
Class clazz1 = Class.forName("cn.chen.reflect.Person");
//第二种方法
Class clazz2 = new Person().getClass();
//第三种方法
Class clazz3 = Person.class;
}
}
2:通过上个步骤获得该类字节码;通过该类的字节码获得该类的所以构造函数描述的类,该类有一个方法,根据构造函数指定的参数创建对象。
反射构造函数代码如下:
package cn.chen.reflect;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
public class Demo2 {
@Test
public void test1() throws Exception{
Class clazz = Class.forName("cn.chen.reflect.Person");
Constructor c = clazz.getConstructor(null);
Person p = (Person) c.newInstance(null);
System.out.println(p.name);
}
@Test
public void test2() throws Exception{
Class clazz = Class.forName("cn.chen.reflect.Person");
Constructor c = clazz.getConstructor(String.class);
Person p = (Person) c.newInstance("chenlong");
System.out.println(p.name);
}
@Test
public void test3() throws Exception{
Class clazz = Class.forName("cn.chen.reflect.Person");
Constructor c = clazz.getConstructor(String.class,int.class);
Person p = (Person) c.newInstance("xieli",20);
System.out.println(p.name);
}
@Test
public void test4() throws Exception{
//获得字节码文件对象
Class clazz = Class.forName("cn.chen.reflect.Person");
//反射私有成员时用的方法
Constructor c = clazz.getDeclaredConstructor(List.class);
//暴力反射
c.setAccessible(true);
//返回类型是Object,所以需要强制转换
Person p = (Person) c.newInstance(new ArrayList());
System.out.println(p.name);
}
@Test
public void test5() throws Exception{
Class clazz = Class.forName("cn.chen.reflect.Person");
Person p = (Person) clazz.newInstance();
System.out.println(p.name);
}
}
package cn.chen.reflect;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Method;
import org.junit.Test;
public class Demo3 {
@Test
public void test1() throws Exception{
Person p = new Person();
Class clazz = Class.forName("cn.chen.reflect.Person");
Method method = clazz.getMethod("aa1", null);
method.invoke(p,null);
}
@Test
public void test2() throws Exception{
Person p = new Person();
//获得字节码文件对象
Class clazz = Class.forName("cn.chen.reflect.Person");
//获得该类方法对象
Method method = clazz.getMethod("aa1", String.class,int.class);
//根据指定的参数,执行指定的方法。第一个参数是指定那个类的对象,后面参数是该类方法的形参
method.invoke(p, "chen",25);
}
@Test
public void test3() throws Exception{
Person p = new Person();
Class clazz = Class.forName("cn.chen.reflect.Person");
Method method = clazz.getMethod("aa1", String.class , int[].class);
Class cs[] = (Class[]) method.invoke(p, "xieli",new int[]{12,2});
System.out.println(cs[0]);
}
@Test
public void test4() throws Exception{
Person p = new Person();
Class clazz = Class.forName("cn.chen.reflect.Person");
Method method = clazz.getDeclaredMethod("aa1", InputStream.class);
method.setAccessible(true);
method.invoke(p,new FileInputStream("H:\\1.jpg"));
}
@Test
public void test5() throws Exception{
Class clazz = Class.forName("cn.chen.reflect.Person");
Method method = clazz.getMethod("aa1", String.class);
//反射静态方法,不需要对象、
method.invoke(null,"chen");
}
@Test
public void test6() throws Exception{
Person p = new Person();
Class clazz = Class.forName("cn.chen.reflect.Person");
Method method = clazz.getMethod("main", String[].class);
//第一种解决方案,由于传入数组jvm会拆开,所以进行包装
// method.invoke(null,(Object)new String[]{"s"});
//第二种解决方案。
method.invoke(null,new Object[]{new String[]{"bb","aa"}});
}
}
反射字段即成员变量
package cn.chen.reflect;
import java.lang.reflect.Field;
import org.junit.Test;
public class Demo4 {
@Test
public void test1() throws Exception{
Person p = new Person();
Class clazz = Class.forName("cn.chen.reflect.Person");
//根据参数获取对应的字段
Field f = clazz.getField("name");
System.out.println(f.get(p));
}
@Test
public void test2() throws Exception{
Person p = new Person();
Class clazz = Class.forName("cn.chen.reflect.Person");
Field f = clazz.getDeclaredField("age");
f.setAccessible(true);
System.out.println(f.get(p));
}
}
注意部分:反射时如果是私有成员,必须使用带有Declared字母的方法,如果需要使用时,需要调用setAccessible(true) 方法告诉Jvm需要暴力访问。