【黑马程序员】Java基础加强15:反射Reflect

---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------


一、什么是反射

反射是程序在运行时期,对一个类的class文件进行解析,获取其构造方法、成员变量、成员方法,还能运行这些方法;

简单一句话:反射就是把Java类中的各种成分映射成相应的Java类,出现的目的是增强程序的扩展性。

 

反射的基石:Class

Java程序中的各个Java类属于同一类事物,描述这类事物的Java类名就是Class

Class类代表Java类,它的各个实例对象对应各个类在内存中的字节码,比如String是一种类,它加载到内存中会反射为String.class的类。

 

得到Class对象(字节码)的三种方法:

1、对象.getClass(),例如,new Person().getClass()

2、已知类名.class,例如,System.classPerson.class

3Class.forName("完整类名"),例如,Class.forName("java.util.Date")Class.forName("java.lang.String");在反射之中,常用第三种方法,类名可以在需要时换成字符串变量,最后传入。

/*
通过代码示例三种得到Class对象的方法
Person p = new Person(); 

第一种方法,通过对象获取  
Class c1 = p.getClass();  
System.out.println(c1);

第二种方法,通过类的静态属性获取  
Class c2 = Person.class;  
System.out.println(c2);  
System.out.println(c2 == c1);//true  
System.out.println(c2.equals(c1));//true  

第三种方法,通过Class.forName(完整类名)
Person如果定义了包,应该为:包名.类名  
Class c3 = Class.forName("Person");  
System.out.println(c3);  
*/

九种预定义Class实例对象

1在Class类中共创建了九个预定义对象,八个基本类型boolean,byte,char,short,int,long,float,double和void(void也有对应的class);

2预定义对象有如下示例:int.class==Integer.TYPEvoid.class==Void.TYPE

3这些对象仅能通过声明为publicstaticfinal的变量访问。

	//对class类型的判断
	System.out.println(int.class.isPrimitive());//true
	System.out.println(int.class == Integer.class);//false
	System.out.println(int.class == Integer.TYPE);//true
	System.out.println(int[].class.isPrimitive());//false,不是基本类型
	System.out.println(int[].class.isArray());//true,是数组类型

二、Java反射的三个重要类

1Constructor类:代表某个类中的构造方法

获取方法:

getConstructor(Class<?>... parameterTypes) 返回公共构造方法

getConstructors() 返回公共构造方法数组

getDeclaredConstructor(Class<?>... parameterTypes) 返回构造方法,包括私有

getDeclaredConstructors()返回构造方法数组,包括私有

代码示例:获得String类中所有的构造方法

package blog.itheima;

import java.lang.reflect.Constructor;

public class ReflectConstructor {

	public static void main(String[] args) throws Exception {
		
		//获得String类中的公有构造方法数组,也可以自定义类的构造方法,通过反射获取
		Constructor[] construtor = Class.forName("java.lang.String").getConstructors();
		//获得某一个构造方法:默认得到的是无参的构造方法
		Constructor constructor2 = Class.forName("java.lang.Thread").getConstructor();
		System.out.println(constructor2);//打印:public java.lang.Thread()
		
		//得到String类中的String(StringBuffer buffer)的构造方法
		//也可以通过可变参数,多传几个class类型,得到多个构造方法
		Constructor constructor = String.class.getConstructor(StringBuffer.class);
		System.out.println(constructor);
		/*打印:public java.lang.String(java.lang.StringBuffer)
		说明constructor是对应String类的StringBuffer构造方法的字节码对象
		
		再通过newInstance来创建实例化对象,里面需要传入同类型的对象StringBuffer,可以调用多次*/
		String string1 = (String) constructor.newInstance(new StringBuffer("abc"));
		System.out.println(string1.charAt(1));
		
		//Class.newInstance()方法等价于使用constructor,newInstance()无参构造器
		String string2 = (String) Class.forName("java.lang.String").newInstance();
		//该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象
	}
}

2Field类:代表某个类中的成员变量

获取方法:

getField(String name) 返回公共成员字段

getFields() 返回公共成员字段数组

getDeclaredField(String nam) 返回成员字段,包括私有

getDeclaredFields()返回成员字段数组,包括私有

//获得某个类上的字节码对象,并取得对应的值
package blog.itheima;
import java.lang.reflect.Field;
import java.util.Date;

public class ReflectFieldGet {
	public static void main(String[] args) throws Exception {
	
		ReflectTest rt = new ReflectTest(3,5);
		//要得到一个类身上的字段,需要先得到类的字节码
		Field fieldY = rt.getClass().getField("y");
		System.out.println(fieldY);
		/*打印结果:public int blog.itheima.ReflectTest.y
		fieldY只是代表类字节码身上的变量,没有对应到对象身上的值
		要取得某个对象上对应的值,需要指定相应的对象*/
		System.out.println(fieldY.get(rt));
		
		//想要取x字段,用与y相同的方法
		//Field fieldX = rt.getClass().getField("x");
		//但是运行结果会报错,因为x是私有字段,要用如下方法获取
		Field fieldX = rt.getClass().getDeclaredField("x");
		//因为是私有 字段,要更改属性为可以访问,称为暴力反射
		//注意,Constructor, Field, Method 三个常用类都有暴力反射方法
		fieldX.setAccessible(true);
		System.out.println(fieldX.get(rt));
	}
}

class ReflectTest {

	private int x;
	public int y;
	
	public ReflectTest(int x, int y) {
		super();
		this.setX(x);
		this.y = y;
	}
	
	public int getX() {
		return x;
	}
	public void setX(int x) {
		this.x = x;
	}
}

//字段的更改
//需求:将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的"n"改成"a"。
package blog.itheima;
import java.lang.reflect.Field;
public class ReflectFieldReplace {
	public static void main(String[] args) throws Exception {
		ReflectTest2 rt = new ReflectTest2();
		changeStringValue(rt);
		System.out.println(rt);
	}
	
	private static void changeStringValue(Object obj) throws Exception {
		Field[] fields = obj.getClass().getFields();//得到所有字段的数组
		for(Field field : fields){
			//if(field.getType().equals(String.class)){
			//字节码只有一分,用等号比更加专业
			if(field.getType() == String.class){
				//得到字节码对应对象的值,强转成String
				String oldValue = (String)field.get(obj);
				String newValue = oldValue.replace('n', 'a');
				/*void set(Object obj, Object value) 
				将指定对象变量上此 Field 对象表示的字段设置为指定的新值*/
				field.set(obj, newValue);
			}
		}
	}	//字段反射的作用:可以更改对象里的字段信息,或者更改配置文件的信息
}

class ReflectTest2 {

	public String str1 = "baidu";
	public String str2 = "Tencent";
	public String str3 = "sina";
	
	@Override
	public String toString() {
		return "ReflectTest2 [str1=" + str1 + ", str2=" + str2 + ", str3="
				+ str3 + "]";
	}
}

3Method类:代表某个类中的成员方法

获取方法:

getMethod(String name, Class<?>...parameterTypes)公共成员方法

getMethods() 公共成员方法数组

getDeclaredMethod(String name, Class<?>...parameterTypes)所有成员方法

getDeclaredMethods() 所有成员方法数组,包括私有

//获取String中的charAt方法

package blog.itheima;
import java.lang.reflect.Method;
public class ReflectMethod {

	public static void main(String[] args) throws Exception {
		
		String s = "abcde";
		/*getMethod(String name,Class<?>... parameterTypes)
		name - 方法名      parameterTypes - 参数列表,charAt返回的是int型*/
		Method methodCharAt = String.class.getMethod("charAt", int.class);
		/*Object invoke(Object obj, Object... args) 
		  对带有指定参数的对象调用由此 Method 对象表示的底层方法,即调用charAt方法*/
		System.out.println(methodCharAt.invoke(s, 1));//string.charAt(1)
		/*注意:如果传递给Method对象的invoke方法的第一个参数为null,说明该Method
		对象对应的是一个静态方法*/
		
		//1.4语法调用,把2当作Integer对象,传入一个元素到Object数组中
		System.out.println(methodCharAt.invoke(s, new Object[]{2}));
	}
}

//用反射方式执行某个类中的main方法
package blog.itheima;
import java.lang.reflect.Method;
public class ReflectMethodMain {

	public static void main(String[] args) throws Exception {
		//用静态代码方法直接调用,传统的调用方法
		//TestArguments.main(new String[]{"111","222","333"});
		
		/*用反射方式去调用main方法的原因?因为有可能开始并不知道类名,
		最后才传入类名参数,为了不更改源代码,可以用反射*/
		String startingClassName = args[0];
		//main方法参数形式是String的数组,只有一个参数
		Method mainMethod = 
			Class.forName(startingClassName).getMethod("main", String[].class);
		//main是静态方法,第一个参数为null,
		//把new String[]打包成一个Object数组,让系统拆包成一个,只让拆一次
		//mainMethod.invoke(null, new Object[]{new String[]{"111","222","333"}});
		
		//也可以把new String[]数组直接强制转成Object,变成一个对象,不让拆包
		mainMethod.invoke(null, (Object)new String[]{"111","222","333"});
	}
}

class TestArguments{
	public static void main(String[] args){
		for(String arg : args){
			System.out.println(arg);
		}
	}
}
---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值