------- android培训、java培训、期待与您交流! ----------
1.什么是反射?
反射就是把java类中的成员映射成不同的java类。
2.Class
我们编写的java程序是由java类构成,那么这个java类是如何得到的,java虚拟机会对我们的代码进行编译,会在硬盘上生成一个.class的文件,这个文件是类的字节码文件,我们在程序中使用的类都的先把这个文件加载到内存中去才可以去生成对象等操作,通过Class这个类同样可以产生对象。
示例:根据类名得到一个类的字节码文件
Class claszz = Class.forName("java.lang.String");
这时我们可以得到一个String类的字节码文件,同样使用这个文件我们可以得到对象等得到类的所有,因为反射操作的就是一个类的所有成员。
示例程序:
public static void main(String[] args) throws ClassNotFoundException {
Class cls1 = Person.class;//Class生成要得到这个类的字节码。
Class cls2 = Class.forName("java.lang.String");//若虚拟机中加载了该类并有了该类的字节码,直接得到,若没有加载,就重新加载得到。
//得到字节码的三种方式
String str = "abc";
Class c1 = str.getClass();//通过对象得到字节码
Class c2 = String.class;//通过类的到字节码
Class c3 = Class.forName("java.lang.String");//通过完整类名得到字节码
System.out.println(c1==c2);
System.out.println(c2==c3);
System.out.println(c1.isPrimitive());
//只要是在源程序中出现的类型,都有对应的class实例对象
}
class Person
{
}
}
反射就是把java类中的各种成分映射成相应的java类。Construct类代表某个类中的构造方法。得到某个类的所有构造方法getConstructs();得到一个单独的构造getConstruct();
示例程序:
public class Demo3 {
public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchFieldException {
Constructor c1 = String.class.getConstructor(StringBuffer.class);
//想要new String(new StringBuffer())
String str = (String)c1.newInstance(new StringBuffer("abc"));
System.out.println(str);
//Class中也有newinstance方法,简练使用,
/*成员变量的反射
* Field类
* */
Person1 p1 = new Person1("小叶",20);
Field f1 = p1.getClass().getDeclaredField("name");
//f1的值是多少?不是5,f1不是对象身上的变量,而是类上,要用他得到对象的值
f1.setAccessible(true);//抢。暴力反射。
System.out.println(f1.get(p1));
}
}
class Person1
{
public Person1(String name, int age) {
super();
this.name = name;
this.age = age;
}
private String name;
private int 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 + "]";
}
}
注意:这里使用了构造方法来产生一个对象,在字节码对象Class中也有一个得到对象的方法,其实它是为了操作简单,底层还是使用的无参数的构造函数。
练习:把一个对象的所有字符串成员的值得包含b的改为a
public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {
ReflectPoint rp = new ReflectPoint(3,5);
Field[] fs = rp.getClass().getDeclaredFields();
for(Field f:fs)
{
if(f.getType() == String.class)//对字节码用等号比,因为是同一份字节码
{
String strValue = (String)f.get(rp);
String newValue = strValue.replaceAll("b", "a");
f.set(rp, newValue);
}
}
System.out.println(rp.str1+":"+rp.str2+":"+rp.str3);
}
}
class ReflectPoint
{
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
private int x;
private int y;
public String str1 = "ball";
public String str2 = "basketball";
public String str3 = "itcast";
}
Method类
Method类Method类代表某个类中的一个成员方法得到一个类的某一个方法 Method charAt = Class.forName("java.lang.String").getMethod("charAt",int.calss) 调用方法通常方法:str.charAt(1);反射方式:charAt.invoke(str,1);
public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
String str = new String("abc");
Method charAt = str.getClass().getMethod("charAt", int.class);
System.out.println(charAt.invoke(str, 1));
//如果invoke的第一个参数为null则这个方法是一个静态方法
}
练习:写一个程序,这个程序能够根据用户提供的类名,去执行该类中的main方法
public class Demo6 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Class c1 = Class.forName("com.ccsu.reflection.TestArg");
Method m1 = c1.getMethod("main",String[].class);
//System.out.println(m1.invoke(null,new String[] {"fsdf","3","78"}));//异常:参数的类型不对
//上面java认为受到了三个参数。jdk 此时认为数组是几个Object
//方法1
System.out.println(m1.invoke(null, new Object[] {new String[] {"fsdf","3","78"}}));
//方法2
System.out.println(m1.invoke(null,(Object)new String[] {"fsdf","3","78"}));
}
}
class TestArg
{
public static void main(String[] args) {
for(String s:args)
{
System.out.println(s);
}
}
}
数组的反射
具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象
代表数组的Class实例对象的getSuperClass方法返回的父类为Object类对应的Class
基本类型的一维数组可以被当做Object类型使用,不能当做Object[]类型使用,非基本类型的一维数组,
既可以当做Object类型使用,又可以当做Object[] 类型使用
Arrays.asList方法处理int[] 和String[] 时的差异
public static void main(String[] args) {
int[] a1 = {2,3,4};
int[] a2 = new int[4];
int[][] a3 = new int[2][3];
String[] str = new String[4];
System.out.println(a1.getClass() == a2.getClass());
//数组的维数相同,得到的字节码是同一份。
System.out.println(a1.getClass().getName());
//System.out.println(a1.getClass() == a3.getClass());
System.out.println(a1.getClass().getSuperclass().getName());
//一维数组的父类都是Object
//所以
Object o1 = a1;
//对数组进行反射,没有办法得到整个数组元素的类型,可以得到某一个元素的类型来得到整体的类型
//使用类Array来操作,一个打印方法
printArray(a1);
printArray(str);
}
public static void printArray(Object obj)
{
Class clazz = obj.getClass();
if(clazz.isArray())
{
int len = Array.getLength(obj);
for (int i = 0; i < len; i++) {
System.out.println(Array.get(obj, i));
}
}else
{
System.out.println(obj);
}
}
}
编写一个小框架程序,从配置文件中读取类的信息,通过反射来执行
public static void main(String[] args) throws IOException, InstantiationException, IllegalAccessException, ClassNotFoundException {
//hashCode方法的作用,对对象进行计算,当修改对象后hashcode会改变,再去操作会内存泄露
//小框架书写
FileInputStream fis = new FileInputStream("test.properties");
Properties p = new Properties();
p.load(fis);
fis.close();
String className = p.getProperty("className");
System.out.println(className);
Collection c = (Collection)Class.forName(className).newInstance();
PersonDemo p1 = new PersonDemo("小叶",20);
PersonDemo p2 = new PersonDemo("小李",25);
PersonDemo p3 = new PersonDemo("小王",24);
PersonDemo p4 = new PersonDemo("小叶",20);
PersonDemo p5 = new PersonDemo("小叶",20);
c.add(p4);
c.add(p3);
c.add(p2);
c.add(p1);
c.add(p5);
System.out.println(c.size());
}
}
class PersonDemo
{
public PersonDemo(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj)
{
if(!(obj instanceof Person))
return false;
PersonDemo p = (PersonDemo)obj;
if(this.name == p.name && this.age == p.age)
{
return true;
}
else
return false;
}
public int hashCode() {
return name.hashCode();
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
private String name;
private int 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;
}
}