您的位置:首页 > 职场人生

黑马程序员java之反射

2015-09-05 13:55 363 查看

 ------- <a href="http://www.itheima.com" target="blank">android培训</a>、<a href="http://www.itheima.com" target="blank">java培训</a>、期待与您交流! ----------

反射技术:动态加载一个指定的类,并获取该类中的所有的内容。而且将字节码文件封装成对象,并将字节码文件中的内容都封装成对象,这样便于操作这些成员。就是通过class文件对象,去使用该文件中的成员变量,构造方法,成员方法。
反射的好处:大大的增强了程序的扩展性。

反射的基本步骤:
1、获得Class对象,就是获取到指定的名称的字节码文件对象。
2、实例化对象,获得类的属性、方法或构造函数。
3、访问属性、调用方法、调用构造函数创建对象。

获取这个Class对象,有三种方式:
1:通过每个对象都具备的方法getClass来获取。弊端:必须要创建该类对象,才可以调用getClass方法。
2:每一个数据类型(基本数据类型和引用数据类型)都有一个静态的属性class。弊端:必须要先明确该类。
3:使用的Class类中的方法,静态的forName方法

  指定什么类名,就获取什么类字节码文件对象,这种方式的扩展性最强,只要将类名的字符串传入即可。

package cn.itcast_01;

/*
* 反射:就是通过class文件对象,去使用该文件中的成员变量,构造方法,成员方法。
*
* Person p = new Person();
* p.使用
*
* 要想这样使用,首先你必须得到class文件对象,其实也就是得到Class类的对象。
* Class类:
* 成员变量 Field
* 构造方法 Constructor
* 成员方法 Method

* 一般我们到底使用谁呢?
* A:自己玩 任选一种,第二种比较方便
* B:开发 第三种
* 为什么呢?因为第三种是一个字符串,而不是一个具体的类名。这样我们就可以把这样的字符串配置到配置文件中。
*/
public class ReflectDemo {
public static void main(String[] args) throws ClassNotFoundException {
// 方式1
Person p = new Person();
Class c = p.getClass();

Person p2 = new Person();
Class c2 = p2.getClass();

System.out.println(p == p2);// false
System.out.println(c == c2);// true
//可以证明,p和p2不是同一个文件对象,却有相同的字节码文件也就是。class文件

// 方式2
Class c3 = Person.class;;
System.out.println(c == c3);//true

// 方式3
Class c4 = Class.forName("cn.itcast_01.Person");
System.out.println(c == c4);//true
//通过实验可以证明,有三种方式可以获得文件的字节码文件。
}
}


反射都需要获取字节码文件,获取了字节码文件对象后,最终都需要创建指定类的对象:
获取所有构造器。
    Constructor[] constructors =clazz.getConstructors();//只包含公共的
    constructors =clazz.getDeclaredConstructors();//本类公有,包含私有的
    for(Constructorcon : constructors) {
      
System.out.println(con);
    }
我们一般只需要获取一个带参数的构造器。
      Constructorconstructor = clazz.getConstructor(String.class,int.class);
想要对对象进行初始化,使用构造器的方法newInstance();
      Objectobj = constructor.newInstance("zhagnsan",30);
package cn.itcast_02;

import java.lang.reflect.Constructor;

/*
* 需求:通过反射去获取该构造方法并使用:
* public Person(String name, int age, String address)
*
* Person p = new Person("林青霞",27,"北京");
* System.out.println(p);
*/
public class ReflectDemo2 {
public static void main(String[] args) throws Exception {
// 获取字节码文件对象
Class c = Class.forName("cn.itcast_01.Person");

// 获取带参构造方法对象可以叫构造器
Constructor con = c.getConstructor(String.class, int.class,
String.class);

// 通过带参构造方法对象创建对象
Object obj = con.newInstance("林青霞", 27, "北京");

System.out.println(obj);
}
}

package cn.itcast_02;

import java.lang.reflect.Constructor;

/*
* 需求:通过反射获取私有构造方法并使用
* private Person(String name){}
*
* Person p = new Person("风清扬");
* System.out.println(p);
*/
public class ReflectDemo3 {
public static void main(String[] args) throws Exception {
// 获取字节码文件对象
Class c = Class.forName("cn.itcast_01.Person");

// 获取私有构造方法对象
// NoSuchMethodException:出现了这个方法异常
// 原因是一开始我们使用的方法只能获取公共的构造函数,private修饰的需要特殊构造器
//getDeclaredConstructor可以访问所有构造函数包括私有构造函数
Constructor con = c.getDeclaredConstructor(String.class);

// 用该私有构造方法创建对象
// IllegalAccessException:会出现非法的访问异常。
// 因为对象私有,我们需要强制访问,这种方式称为暴力访问
con.setAccessible(true);// 值为true则指示反射的对象在使用时应该取消Java语言访问检查。
Object obj = con.newInstance("风清扬");

System.out.println(obj);
}
package cn.itcast_03;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

/*
* 通过发生获取成员变量并使用
*/
public class ReflectDemo {
public static void main(String[] args) throws Exception {
// 获取字节码文件对象
Class c = Class.forName("cn.itcast_01.Person");

// 获取所有的成员变量
// Field[] fields = c.getFields();
// Field[] fiel
d577
ds = c.getDeclaredFields();
// for (Field field : fields) {
// System.out.println(field);
// }

/*
* Person p = new Person(); p.address = "北京"; System.out.println(p);
*/

// 通过无参构造方法创建对象
Constructor con = c.getConstructor();
Object obj = con.newInstance();

// 获取单个的成员变量
// 获取address并对其赋值
Field addressField = c.getField("address");
// 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
addressField.set(obj, "北京"); // 给obj对象的addressField字段设置值为"北京"

// 获取name并对其赋值访问私有成员变量
// NoSuchFieldException
Field nameField = c.getDeclaredField("name");
// IllegalAccessException
nameField.setAccessible(true);//暴力访问
nameField.set(obj, "林青霞");
System.out.println(obj);

}
}


获取类中所有的方法
      //获取字节码文件对象
    Class c = Class.forName("cn.itcast_01.Person")
    //获取所有的方法
    // Method[]
methods =c.getMethods(); //获取自己的包括父亲的公共方法
    // Method[]
methods =c.getDeclaredMethods(); //获取自己的所有的方法
    // for
(Method method :methods) {
    //System.out.println(method);
    // }

package cn.itcast_04;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class ReflectDemo {
public static void main(String[] args) throws Exception {
// 获取字节码文件对象
Class c = Class.forName("cn.itcast_01.Person");

Constructor con = c.getConstructor();
Object obj = con.newInstance();

// 获取单个方法并使用
Method m1 = c.getMethod("show");

m1.invoke(obj); // 调用obj对象的m1方法
// 第一个参数表示的方法名,如果有传入参数,表示的是方法的参数的class类型
Method m2 = c.getMethod("method", String.class);
m2.invoke(obj, "hello");;

//获取private成员函数,想要获取私有方法。必须用getDeclearMethod();
Method m4 = c.getDeclaredMethod("function");
m4.setAccessible(true);//暴力访问
m4.invoke(obj);
}
}

ArrayList<Integer>的一个对象,我想在这个集合中添加一个字符串数据,如何实现呢?

package cn.itcast.test;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;

public class ArrayListDemo {
/*
* ArrayList<Integer>的一个对象,我想在这个集合中添加一个字符串数据,如何实现呢?
*/
public static void main(String[] args) throws NoSuchMethodException,
SecurityException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
// 创建集合对象
ArrayList<Integer> array = new ArrayList<Integer>();

// array.add("hello");
// array.add(10);

Class c = array.getClass(); // 集合ArrayList的class文件对象
Method m = c.getMethod("add", Object.class);

m.invoke(array, "hello"); // 调用array的add方法,传入的值是hello
m.invoke(array, "world");
m.invoke(array, "java");

System.out.println(array);
}
}


数组的反射。

具有相同维数和元素类型的数组属于同一类型。即具有相同的Class实例对象。

例如:int[] a=new
int[]{1,2,3};

         int[] a1=new int[5];

         int[][] a2=new int[4][3];

         String[] s=new String[2];

a和a1是相同的维数和元素类型,所以他们具有相同的字节码。

而其他的都不相同,或因维数不同,或因类型不同。

 

代表数据的Class实例对象的getSuperclass()方法返回的是父类的Object类对应的
Class.

所以基本数据类型的一维数组可以被当做Object类型使用,不能当做Object[]数组类型使用。

 非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[]数组类型使用。

从上面例子中,引用到这里可以写成:

Object o1=a;     

Object o2=a1;   

Object o3[]=a2;

Object o4[]=s;

而Object o5[]=a
是编译不通过的。


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: