反射机制

来源:互联网 发布:平面构成 知乎 编辑:程序博客网 时间:2024/05/20 21:45

获取类字节码的三种方式

1.类名.class

2.对象.getClass()

3.Class.forName(className)


类获取某个类的构造方法:Constructor

得到某个类所有的构造方法

Constructor[] constructors = Class.forName(“java.lang.String”).getConstructors();

得到某一个构造方法

Constructor constructor = Class.forName(“java.lang.String”).getConstructor(StringBuffer.class);


创建实例对象

通常方式:String str = new String(new StringBuffer(“abc”));

反射方式创建实例对象

String str = (String)constructor.newInstance(new StringBuffer(“abc”));



Field类,获取某个类的字段



package cn.itcast.reflect;

import java.lang.reflect.*;

class Student


{

public String name;

private int age;

Student(){}

Student(String name,int age)


{


this.name =name;

this.age = age;


}


}




public class ReflectTest

{


public static void main(String[] args)throws Exception


{


Student stu = new Student(“何竹冬”,25);

//访问公有属性name

Field fieldName = stu.getClass().getField(“name”);

//暴力反射,访问私有属性

Field fieldAge = stu.getClass().getDeclaredField(“age”);

fieldAge.setAccessible(true);//将age属性设置为可访问

System.out.println(fieldName.get(stu)+”...”+fieldAge.get(stu));


}


}






Method类,获取某个类的方法

Method类代表某一个类中的一个成员方法。



得到类中的某一个方法

例如 Method charAt = Class.forName(“java.lang.String”).getMethod(“charAt”,int.class);

通过反射调用方法

String str = “abc”;


charAt.invoke(str,1);

用反射执行某个类中的main方法

问题:


启动java程序main方法参数是一个字符串数组,即public static void main(String[] args),通过反射方式调用main方法时,

如何为invoke方法传递参数呢?按jdk1.5的语法整个数组是一个参数,而按jdk1.4的语法,数组中每一个元素对于一个参数,当

把一个字符串数组作为参数传递给invoke方法时,javac到底会按照那种语法进行处理呢?jdk1.5肯定要兼容jdk1.4的语法,会按

照jdk1.4的语法进行处理,即把数组打散成若干个单独的参数。所以,在给main方法传参数时,不能使用代码

mainMethod.invoke(null,new String[]{“xxxx”});java只把它作为jdk1.4语法进行理解,而不把它作为jdk1.5语法解释,因此

会出现参数类型不对的问题。


解决办法:


mainMethod.invoke(null,new Object[]{new String[]{“xxxx”}})

mainMethod.invoke(null,(Object)new String[]{“xxxx”});


代码体现:

import java.lang.reflect.*;

public class Test


{

public static void main(String[] args) throws Exception

{


String startingClassName = args[0];

Method mainMethod=  Class.forName(startingClassName).getMethod(“main”,String[].class);

//将字符串数组作为Object数组的一个元素

mainMethod.invoke(null,new Object[]{new String[]{“111”,”222”,”333”}});


}


}




class TestArguments

{

public static void main(String[] args)

{


for(String arg : args)

System.out.println(arg);


}


}


数组的反射

特点:

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

2.代表数组的Class实例对象的getSupperClass()方法返回的父类为Object类对应的Class。

3.基本类型的一维数组可以当做Object类型来使用,不能当做Object[]来使用;

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


int[] a1 = new int[3];

int[] a2 = new int[4];

int[][] a3 =new int[2][3];

String[] a4 = new String[3];

System.out.println(a1.getClass()==a2.getClass());//元素数据类型和数组维度相同是同一份字节码

System.out.println(a1.getClass()==a3.getClass());//元素数据类型相同,数组维度不同不是同一份字节码

System.out.println(a1.getClass()==a4.getClass());//元素数据类型不同,数组维度也不同不是同一份字节码


反射的综合案例

ArrayList和HashSet以及hashCode分析

1. ArrayList可以存储相同元素

2. HashSet不可以存储相同元素,和其他哈希结构的集合判断元素唯一的依据是hashCode和equals方法。

3. hashCode的由来

我们要判断集合中是否存在某一个元素要遍历这个集合进行查找,这样效率很低,有人发明了一种方法,将集合分成几个区域,

每个对象可以算出一个哈希码,将这些哈希码分组,不同的哈希码对于不同的存储区域,要判断集合中是否有某个元素,根据它

的哈希码去指定的区域查找即可,这样大大提高了效率。

4. 当一个对象被存储进HashSet集合中以后,就不要在修改这个对象中那些参与计算哈希值的字段,否则,对象修改后的哈希值

与最初存储进HashSet集合时的哈希值就不同了。在这种情况下,即使在contains方法是用该对象的当前引用作为的参数去

HashSet集合中检索对象,也将返回找不到对象的结果,这也会导致无法从HashSet中单独删除当前对象,从而造成内存泄露。

代码示例:演示反射获取ArrayList和HashSet的元素个数,以及复写hashCode和equals方法

要往集合中添加的对象所属的类ReflectPoint


package cn.itheima.reflect;


/**

* 要往集合中添加的对象所属的类ReflectPoint

* @author hezhudong

*


*/


public class ReflectPoint {

private int x;

@Override

public int hashCode() {


final int prime = 31;

int result = 1;

result = prime * result + x;

result = prime * result + y;

return result;


}




@Override

public boolean equals(Object obj) {

if (this == obj)

return true;

if (obj == null)

return false;

if (getClass() != obj.getClass())

return false;


ReflectPoint other = (ReflectPoint) obj;


if (x != other.x)

return false;

if (y != other.y)

return false;

return true;


}


public int y;


ReflectPoint(int x,int y) {

this.x = x;

this.y = y;


}






}










演示:ArrayList和HashSet集合元素的存储,以及通过反射获取集合



package cn.itheima.reflect;

import java.util.ArrayList;

import java.util.Collection;

import java.util.HashSet;




/**

* 演示:ArrayList和HashSet集合元素的存储,以及通过反射获取集合


*/


public class ReflectTest {



public static void main(String[] args) {


testArrayList();

testHashSet();


}


public static void testArrayList() {

Collection coll = new ArrayList();

//ArrayList可以存放相同元素,所以打印size应该是3

coll.add(new ReflectPoint(3,3));

coll.add(new ReflectPoint(5,5));

coll.add(new ReflectPoint(3,3));

System.out.println("the size of ArrayList is "+coll.size());


}



public static void testHashSet() {

Collection coll = new HashSet();

//HashSet不可以存放相同元素,判断元素是否相同的依据是hashCode和equals方法,

//所以打印size应该是2

coll.add(new ReflectPoint(3,3));

coll.add(new ReflectPoint(5,5));

coll.add(new ReflectPoint(3,3));

System.out.println("the size of HashSet is "+coll.size());


}


原创粉丝点击