反射
透彻分析反射的基础_Class类
Java类用于描述一类事物的共性、描述该类应该具有的属性,而属性具体的值则由这个类的实例对象来确定
Class类是描述Java程序中的各个Java类的类型,通过class可以得到类方方面面的信息
Method[] ——getMethods();
String——getName();
Package——getPackage();
Class——getInterfaces();
字节码:类的代码编译成的二进制代码
Class cls = 字节码;
得到字节码的三种方式
public class ReflectTest {
public static void main(String[] args) throws Exception{
String str = "123";
Class class1 = str.getClass();//字节码
Class class2 = String.class;//字节码
Class class3 = Class.forName("java.lang.String");//字节码
}
}
九个预定义Class实例对象
八个基本类型和void
public class ReflectTest {
public static void main(String[] args){
Class class = String.class;//字节码
sop(class.isPrimitive());//class对象的类型是否是几种预定义类型
sop(int.class.isPrimitive);
sop(int.class == Integer.class);//False
sop(int.class == Integer.TYPE);//True,Integer.TYPE表示包装类中被包装类型的字节码,九种预制类型中有这个属性
}
public static void sop(Object obj){
System.out.println(obj);
}
}
数字类型Class实例对象
class TestReflectTest{
public static void main(String[] args){
System.out.println(int[].class.isPrimitive);//False,这个是数组类型
System.out.println(int[].class.isArray);
}
}
总结:只要是在源程序中出现的类型,都有各自的Class类型实例对象
理解反射的概念
反射就是把Java类型中的每一个成分(包、方法、字段等)映射(解析成)相应的类型
通过写程序可以得到Java类型中的各个成分所对应的类的对象
构造方法的反射应用
得到一个类中的构造方法
public class ConstructorReflect {
public static void main(String[] args) throws Exception{
//得到类中的所有构造方法
Constructor[] cons =
Class.forName("java.lang.String").getConstructors();
//根据参数得到类中一个构造方法
Constructor con =
Class.forName("java.lang.String").getConstructor(String.class);
}
}
通过反射实现创建对象
public class ConstructorReflect {
public static void main(String[] args) throws Exception{
//String str = new String(new StringBuffer("abc"));
Class cls = String.class
Constructor con = cls.getConstructor(StringBuffer.class);
String str = (String)con.newInstance(new StringBuffer("abc"));
System.out.println(str.charAt());
}
}
Class.newInstance()方法
在创建class对象的时候,调用对象的newInstance方法,会将无参的函数缓存起来,方便再次调用无参构造方法
public class ConstructorReflect {
public static void main(String[] args) throws Exception{
Class clsStud = Student.class;
//当class类对象调用newInstance方法的时候,会直接调用无参构造方法,并且缓存方便调用
Student s1 = (Student)clsStud.newInstance();
//要调用有参数的构造函数,则需要通过反射的原理
Constructor con = clsStud.getConstructor(String.class, int.class);
Student s2 = (Student)con.newInstance(new String("zhangsan"), );
System.out.println(con.toString());
}
}
class Student{
private String name;
private int age;
public Student(){
System.out.println("I`M A STUDENT");
}
public Student(String name, int age){
this.name = name;
this.age = age;
System.out.println(name + "::" + age);
}
}
总结:反射会导致程序性能下降
成员变量的反射
public class ReflectTest {
public static void main(String[] args) throws Exception{
ReflectPoint pt = new ReflectPoint(,);
//fieldY不是对象里的变量,而是将字节码里面的某个变量赋给它
Field fieldY = ReflectPoint.class.getField("y");
//Field fieldY = pt1.getClass().getField("y"));这句话和上面语句是一个意思
sop(fieldY.get(pt));
//x成员变量是私有的,对getField()方法不可见
//Field FieldX = pt.getClass().getField("x");此方法对私有变量无效
//用getDeclaredField()方法可以读取到私有成员变量,但是不能使用
Field fieldX = ReflectPoint.class.getDeclaredField("x");
//需要通过setAccessible()方法进行设置,暴力反射
fieldX.setAccessible(true);
sop(fieldX.get(pt));
}
public class ReflectPoint {
private int x;
public int y;
public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}
}
public static void sop(Object obj){
System.out.println(obj);
}
}
反射的综合案例
字段的反射:将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的“b”改成“a”
public class ReflectTransB {
public static void main(String[] args) throws Exception{
ReflectPoint pt = new ReflectPoint();
changeStringValue(pt);
System.out.println(pt.toString());
}
public static void changeStringValue(Object obj) throws Exception{
Field[] fields = obj.getClass().getFields();
for(Field temp: fields){
//字节码只有一份,用“==”比较更好
if(temp.getType()==String.class){
String oldValue = (String)temp.get(obj);
//replave(oleChar, newChar);
String newValue = oldValue.replace('b', 'a');
temp.set(obj, newValue);
}
}
}
class ReflectPoint {
public String str1 = "ball";
public String str2 = "basketball";
public String str3 = "nothave";
public String toString() {
return "ReflectPoint [str1=" + str1 + ", str2=" + str2 + ", str3="
+ str3 + "]";
}
}
}
成员方法的反射
public class ReflectTest(){
public static void main(String[] args){
String str = "abc";
//通常方式
System.out.println(str.charAt());
//反射方式
Method methodCharAt = String.class.getMethod("charAt", int.class);
System.out.println(methodCharAt.invoke(str, ));//invoke()调用
//在调用静态方法的时候,是不需要穿参数的,用null代替
//System.out.println(methodCharAt.invoke(null, 1));
//兼容1.4之前的版本问题
System.out.println(methodCharAt.invoke(str, new Object[]{}));
}
}
对接受数组参数的成员方法进行反射
写一个程序能够根据用户提供的类名,去执行该类中的main方法
public class ReflectTest {
public static void main(String[] args) throws Exception{
//通常调用方法
TestArguments.main(new String[]{"111", "222", "333"});
System.out.println("**************************************");
//为什么要用反射的方式调用
//String startClassName = args[0];启动的时候,传入的args[]数据中要含有要运行类的名称
String startClassName = "TestReflect.TestArguments";
Method mainMethod = Class.forName(startClassName).getMethod("main", String[].class);
//为了兼容JDK1.4版本,传入的参数new String[]{"111", "222", "333"}会被拆成三个参数
//所以在外面在包一个Object数组
//mainMethod.invoke(null, new Object[]{new String[]{"111", "222", "333"}});
mainMethod.invoke(null, (Object)new String[]{"111", "222", "333"});
}
}
class TestArguments{
public static void main(String[] args){
for(String arg: args){
ReflectTest.sop(arg);
}
}
}
数据与Object关系及其反射类型
具有相同类型的和相同维度的数据的Class字节码文件相同
public class ReflectArray {
public static void main(String[] args){
int[] a1 = new int[];
int[] a2 = new int[];
int[][] a3 = new int[][];
String[] a4 = new String[];
sop(a1.getClass() == a2.getClass());
sop(a1.getClass().getName());
sop(a1.getClass().equals(a3.getClass()));
sop(a1.getClass().equals(a4.getClass()));
//以下三条显示为:“java.lang.Object”
sop(a1.getClass().getSuperclass().getName());
sop(a3.getClass().getSuperclass().getName());
sop(a4.getClass().getSuperclass().getName());
Object aObj1 = a1;
Object aObj2 = a4;
//int[]中装的是基本类型int,基本类型的父类不是Object
//Object[] aObj3 = a1;
//二维数据int[][]可以看做是装着int数组的数组,int数组的父类是Object,所以二维数据可以放入Object[]中
Object[] aObj4 = a3;
Object[] aObj5 = a4;
sop("###########################################");
int[] arri = new int[]{,,};
String[] arrs = new String[]{"abc", "efd", "hij"};
sop(arri);
sop(arrs);
sop(Arrays.asList(arri));
sop(Arrays.asList(arrs));
/*
[[email protected]
[Ljava.lang.String;@2afbb5f5
[[[email protected]]
[abc, efd, hij]
这个就是解释了int[]中装的是基本类型int,基本类型int的父类不是Object,
所以转换的时候将int[]作为一个元素存入list中
*/
}
public static void sop(Object obj){
System.out.println(obj);
}
}
数组的反射应用
public class ReflectArray {
public static void main(String[] args){
String[] arrs = new String[]("123", "asd", "zxc");
printObject(arrs);
printObject("asd");
}
public static void printObject(Object obj){
Class classObj = obj.getClass();
if(classObj.isArray()){
int len = Array.getLength(obj);
for(int i = ; i < len; i++){
System.out.println(Array.get(obj, i));
}
}else{
System.out.println(obj);
}
}
}
ArrayList_HashSet的比较及Hashcode分析
public class ReflectTest {
public static void main(String[] args){
Collection collections = new HashSet();
ReflectPoint pt1 = new ReflectPoint(,);
ReflectPoint pt2 = new ReflectPoint(,);
ReflectPoint pt3 = new ReflectPoint(,);
collections.add(pt1);
collections.add(pt2);
collections.add(pt3);
collections.add(pt1);
//ArrayList的容量为4
//HashSet的容量为3
//重写ReflectPoint类的equals方法后,HashSet的容量为2
System.out.println(collections.size());
pt1.y = ;
collections.remove(pt1);
//修改y值后,hashCode值改变,删除操作会在原来的hashCode值区域查找,删除无效HashSet的容量为2
//持续修改对象删除该对象,就会造成内存泄露
//如果不修改,删除后,HashSet的容量为1
System.out.println(collections.size());
}
}
框架的概念及用反射技术开发框架的原理
public class ReflectTest {
public static void main(String[] args) throws Exception{
FileInputStream fis = new FileInputStream("config.properties");
Properties props = new Properties();
props.load(fis);
fis.close();
String className = props.getProperty("className");
Collection collection = (Collection)Class.forName(className).newInstance();
ReflectPoint rp1 = new ReflectPoint(,);
ReflectPoint rp2 = new ReflectPoint(,);
ReflectPoint rp3 = new ReflectPoint(,);
collection.add(pt1);
collection.add(pt2);
collection.add(pt3);
collection.add(pt1);
System.out.println(collection.size());
}
}
配置文件config.properties
className = java.util.HashSet