黑马程序员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);
}
获取类中所有的方法
//获取字节码文件对象
Class c = Class.forName("cn.itcast_01.Person")
//获取所有的方法
// Method[]
methods =c.getMethods(); //获取自己的包括父亲的公共方法
// Method[]
methods =c.getDeclaredMethods(); //获取自己的所有的方法
// for
(Method method :methods) {
//System.out.println(method);
// }
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
是编译不通过的。
------- <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
是编译不通过的。
相关文章推荐
- 《剑指Offer》面试题:合并两个排序的链表
- 黑马程序员——46,enum枚举类的简单应用
- 黑马程序员java之多线程
- 黑马程序员—Java之面向对象
- 面试题 9 Fibonacci数列
- 我的程序员未婚夫
- 高欢的职业生涯
- 黑马程序员java基础学习日记——做题遇到GBK查资料发现了个有趣的文章——ASCII、Unicode、GBK和UTF-8字符编码的区别联系
- 剑指offer——面试题42:(二)字符串的坐旋转操作
- 中国移动手机阅读基地社会招聘笔试面试全过程
- 面试题 8
- 那些不能遗忘的知识点回顾——操作系统系列(笔试面试高频题)
- 剑指offer——面试题42:(一)翻转单词顺序
- 黑马程序员——CSS
- JAVA多线程和并发基础面试问答
- 程序员文史综合
- 黑马程序员----c基础笔记----指针
- 黑马程序员--OC继承
- 黑马程序员----c基础笔记----数组部分
- 【全民讨论】TGT后牧师双子与各职业橙卡[单卡讨论]