获取类字节码的三种方式
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());
}