Java反射

反射概述

概念:Java程序中的各个Java类属于同一类事物,描述这类事物的Java类名就是Class(其实反射就是把Java类中的各种成分映射成相应的java类)
所有的人,都可以定义一个Person类,那么所有的类也是同样的道理,用一个Class类来描述。
Class类型实例对象的三种方式
类名.class
对象.getClass()
static Class forName("类名") :此方法,有返回Class对象有两种方式,一种是字节码已经被加载进虚拟机,直接返回对象;第二种是虚拟机里面没有字节码,则用类加载器去加载,把加载进来的字节码缓存在虚拟机。
九个预定义的Class实例对象:八个基本数据类型+void类型(除这9个外,还有数组型)
class Demo1Reflect {

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

		String str = "反射";
		
		Class cls1 = String.class;
		Class cls2 = str.getClass();
		Class cls3 = Class.forName("java.lang.String");
		
		System.out.println(cls1 == cls3);   //三种方式创建出来的字节码都相同
		System.out.println(cls1.isPrimitive());  //isPrimitive()判断是否是基本数据类型
                System.out.println(int.class.isPrimitive());
                System.out.println(int.class == Integer.class);   //这个返回false,因为int是预定义的实例对象,Integer是一个类
		System.out.println(int[].class.isArray());  //isArray()判断是否是数组类型
		
	}

}
一个Java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个Java的Java类来表示,就像汽车是一个类,汽车中的发动机 ,变速箱等等也是一个个的类。表示Java类的Class类显然要提供一系列的方法,来获得其中的变量,方法,构造方法,修饰符,包等信息 ,这些信息就是用相应类的 实例对象来表示,它们是Contuctor,Method,Field,Array等等。

Constructor类

Constructor类代表某一个类中的一个构造函数
得到某个类所有的构造方法:
              Constructor[] constructors = Class.forName("java.lang.String") .getConstructor()
得到某一个构造方法:
              Constructor constructor = Class.forName("java.lang.String") .getConstructor(StringBuffer.class)
创建实例对象:
              String str = (String)constructor. newInstatce(new StringBuffer("abc"))
import java.lang.reflect.Constructor;

class Demo2Construtor {

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

		Constructor<String> constructor = String.class.getConstructor(StringBuffer.class);  //得到String类中的一个构造方法,并且该构造方法只能传递//StringBuffer型参数
		
		String str = (String)constructor.newInstance(new StringBuffer("反射"));  //创建实例对象,newInstance返回的Object类型,所以要向下转型
		
		System.out.println(str);
		
	}

}

Class.newInstance():该方法内部先得到默认的空参数构造方法,然后用该构造方法创建实例对象
String obj = (String)Class.forName("java.lang.String").newInstance();

Field类

Field类代表某个 类中的一个成员
import java.lang.reflect.Field;

class Demo3Field {

	public static void main(String[] args) throws Exception {
		
		FieldDemo fd = new FieldDemo(4,6);
		
		Field fieldY = fd.getClass().getField("y"); //获取一个Field类实例
		System.out.println(fieldY.get(fd)); //得到变量 y的值
		
		Field fieldX = fd.getClass().getDeclaredField("x"); //因为变量x被私有,所以通过getDeclaredField()方法来获取
		fieldX.setAccessible(true);  //通过setAccessible()方法是否允许得到变量x的值
		System.out.println(fieldX.get(fd));
		
		
	}
	
}
class FieldDemo {
	
	private int x;
	public int y;
	
	FieldDemo(int x,int y) {
		
		this.x = x;
		this.y = y;
		
	}
	
}

将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的“b”改成“a”
思路:
    1、遍历对象中的所有字段,取出String类型的字段。
    2、对字段进行内容的替换,把b替换成a
import java.lang.reflect.Field;

class Demo3Field {

	public static void main(String[] args) throws Exception {
		
                FieldDemo fd = new FieldDemo();                 
 
		replaceStr(fd)
	}
	
	public static void replaceStr(Object fd) throws Exception{
		
		Field[] fields = fd.getClass().getFields(); //getFields得到对象中的所有字段
		
		//遍历Field[]数组
		for(Field field : fields) {
			
			//判断字段类型是否是String类型,(因为都是一个字节码,所以用==比较)是的话就开始替换
			if(field.getType() == String.class) {
				
				String oldValue = (String)field.get(fd);   //得到原来的字符串
				String newValue = oldValue.replace('b', 'a');   //把字符串里面的b替换成a
				
				field.set(fd, newValue);    //再用set方法对字段进行修改
				
			}
			
		}
		
	}

}


class FieldDemo {
	
	public String str1 = "ball";
	public String str2 = "basketball";
	public String str3 = "sport";
	
	public String toString() {  //重写toString方法,一遍打印此雕像是能够直接显示字符串
		
		return str1 + "," + str2 + "," + str3;
		
	}
	
}

Method类

Method类代表某个类中的一个成员方法
得到类中的某一个方法:
Metho charAt = Class forName("java.lang.String") .getMethod("charAt",int.calss);
调用方法:
  通常方法:System.out.println(str.charAt(1));
  反射方式:System.out.println(charAt.invoke(str,1));
  注意:如果传递给Method对象的invoke()方法的第一个参数为null,说明该Method对象对应的是一个静态方法
import java.lang.reflect.*;

class Demo4Method {

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

		String str = "反射Method";
		
		Method charAt = str.getClass().getMethod("charAt", int.class);  //通过调用String字节码,获取Method类的实例对象
		
		System.out.println(charAt.invoke(str, 3));//invoke()调用String类中charAt()方法
	}
}

用反射方式执行某个类中的main方法
import java.lang.reflect.*;

class Demo4Method {

	public static void main(String[] args) throws Exception {
		
		String className = args[0];  //主函数传参,假设数组args第一个元素为calssName
		Method mainMethod = Class.forName(className).getMethod("main", String[].class);  //得到TestAgruments类里面的main方法
		mainMethod.invoke(null, new Object[]{new String[]{"反射","字段","方法"}});
		
		/*
		  启动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[]{"反射","字段","方法"});
		 */
		
		
		
	}

}

class TestArguments {
	
	public static void main(String[] args) {
		
		for(String str : args) {
			
			System.out.println(str);
			
		}
		
	}
	
}

Jdk1.4和Jdk1.5的invoke方法的区别:
   Jdk1.5:
public Object invoke(Object obj,Object...args)
   Jdk1.4:public Object invoke(Object obj,Object[] args),即按Jdk1.4的语法需要将一个数组作为参数
                   传递给invoke方法时,数组中的每个元素分别对应被调用方法中的一个参数,所以,调用charAt方法
                   的代码也可以用Jdk1.4改写为charAt.inboke("str",new Object[]{1})形式

数组的反射

特点:
1、具有相同的维度和元素类型的数组属于同一个类型,即具有相同的Class实例对象
2、代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class(字节码)Object.class
3、基本类型的一维数组可以被当做Object使用,不能当做Object[]类型使用。非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[]类型使用
import java.util.*;
import java.lang.reflect.*;

class Demo5Array {

	public static void main(String[] args) {

		int[] arr1 = new int[3];
		String[] arr2 = new String[]{"a","b","c"};
		
		System.out.println(arr1.getClass().getSuperclass().getName());
		
		Object obj1 = arr1;
		Object obj2 = arr2;
	//	Object[] obj3 = arr1; 如果把arr1赋值给Object[]型则编译失败
		Object[] obj4 = arr2;
		
		/*   
		arr1的打印结果为一个对象的哈希值,这时因为1.4版本接收的是Object[]类型,基本类型不能当做Object[]类型使用,
		只能当做Object使用,而1.5版本的jdk接收的是Object类型。
		*/
		System.out.println(Arrays.asList(arr1));
		
		
		System.out.println(Arrays.asList(arr2));
		
		printObject(arr2);
		
	}
	
      //用反射的方式遍历数组
	public static void printObject(Object obj) {
		
		Class cls = obj.getClass();  //获取字节码
		if(cls.isArray()) {  //判断该字节码是不是数组类型
			
			int len = Array.getLength(obj);  //使用静态方法getLength()获取数组长度
			for(int x = 0 ; x < len ; x++) {
				
				System.out.println(Array.get(obj, x));  //得到值
				
			} 
		}else {
			System.out.println(obj);
			
		}
		
	}

}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值