JAVA--反射机制

元数据:描述数据的描述数据
反射:得到类的元数据的过程
在运行时期,动态的去获取某一个类中的成员信息(构造器,方法,字段,内部类,接口,父类等)
并把类中的每一种成员都描述成一个新的类
Class:表示一个类
Constructor:表示所有的构造器
Method:表示所有的方法
Fleid:表示所有的字段


一、通过反射来获取某一个类的构造器

1.获取所有构造器

(1)获取构造器所在类的字节码对象:Class clz = T.class;
(2)获取clz对象中所有的构造器

  • public Constructor<?>[] getConstructors():该方法只能获取public修饰的构造器
  • public Constructor<?>[] getDeclaredConstructors():该方法能获取所有构造器,与访问权限无关
2.获取指定构造器

(1)获取构造器所在类的字节码对象:Class clz = T.class;
(2)获取clz对象中指定的构造器:

  • Constructor con = clz.getConstructor();该方法只能获取public修饰的构造器
  • Constructor con = clz.getDeclaredConstructor(String.class,int.class);该方法获取构造器与访问权限无关
相关实例:
    class Person {
    	public Person() {
    
    	}
    
    	public Person(String name) {
    
    	}
    
    	private Person(String name, int age) {
    
    	}
    }
    
    public class GetConstructorDemo {
    
    	public static void main(String[] args) throws Exception {
    		getAll();
    		System.out.println("------------------------------------------------");
    		getOne();
    
    	}
    	//获取指定的一个构造器
    	private static void getOne() throws Exception {
    		//获取构造器所在类的字节码对象
    		Class<Person> clz = Person.class;
    		//1.获取public Person()
    		Constructor<Person> con = clz.getConstructor();
    		System.out.println(con);
    		//2.获取public Person(String name)
    		con = clz.getConstructor(String.class);
    		System.out.println(con);
    		//3.获取private Person(String name, int age)
    		con = clz.getDeclaredConstructor(String.class,int.class);
    		System.out.println(con);
    	}
    	//获取所有构造器
    	private static void getAll(){
    		//1.获取构造器所在类的字节码对象
    		Class<Person> clz = Person.class;
    		//2.获取clz对象中所有的构造器
    		//public Constructor<?>[] getConstructors():该方法只能获取public修饰的构造器
    		Constructor<?>[] cs = clz.getConstructors();//只能获取public修饰的构造器,private修饰的构造器不能访问
    		System.out.println(cs.length);
    		for (Constructor<?> constructor : cs) {
    			System.out.println(constructor);
    		}
    		System.out.println("------------------------------------------------");
    		//public Constructor<?>[] getDeclaredConstructors():该方法能获取所有构造器,与访问权限无关
    		cs = clz.getDeclaredConstructors();
    		System.out.println(cs.length);
    		for (Constructor<?> constructor : cs) {
    			System.out.println(constructor);
    		}
    	}
    }

在这里插入图片描述


二、使用反射调用构造器

1.创建对象:Class clz = T.class;
2.调用对象:Constructor con = clz.getConstructor(Class<?> parameterType);
3.调用构造器的newInstance方法来创建对象,并传入实参:con.newInstance(Object…args);
4.当对象是私有成员时,用
Constructor con = clz.getDeclaredConstructor(Class<?> parameterType),
再设置当前构造器可以访问con.setAccessible(true),
最后调用newInstance方法来创建对象,并传入实参

相关实例:
class User {
	public User() {
		System.out.println("无参数构造器");
	}

	public User(String name) {
		System.out.println("构造器" + name);	
	}

	private User(String name, int age) {
		System.out.println("私有构造器" + name + age);
	}
}

public class CreateObjectDemo {

	public static void main(String[] args) throws Exception {
		// 传统方式创建对象
		new User();
		new User("hello");
		//new User("hello",12);//private修饰的构造器不能访问
		System.out.println("----------------------------------");
		//反射机制调用
		Class<User> clz = User.class;
		//调用public User()
		Constructor<User> con = clz.getConstructor();
		//调用构造器的newInstance方法来创建对象,并传入实参
		con.newInstance();
		//public User(String name)
		con = clz.getConstructor(String.class);
		con.newInstance("hello");
		//private User(String name, int age),使用反射可以调用私有的成员
		con = clz.getDeclaredConstructor(String.class,int.class);
		//设置当前构造器可以访问
		con.setAccessible(true);
		con.newInstance("hello",17);
	}
}

在这里插入图片描述


三、使用反射获取方法

1.获取方法所在类的字节码对象
2.获取方法
3.调用方法

Class类中常用的方法

  • public Method[] getMethoss():获取包括自身和继承过来的所有的piblic方法

  • public Method[] getDeclaredMethods():获取自身所有的方法(不包括继承的,和访问权限无关)

  • public Method getMethod(String methodName,Class<?> parameterType):表示调用指定的一个公共的方法(包括继承的)
    参数:
    methodName:表示被调用的方法的名字
    parameterType:表示被调用方法的参数的Class类型,如String.class

  • public Method getDeclaredMethod(String methodName,Class<?> parameterType):表示调用指定的一个公共的方法(不包括继承的)
    参数:
    methodName:表示被调用的方法的名字
    parameterType:表示被调用方法的参数的Class类型,如String.class

相关实例
class User {
	public void doWork() {

	}

	public static void doWork(String name) {

	}

	private String sayHello(String name, int age) {
		return name + "," + age;

	}
}

public class MethodDemo {
	public static void main(String[] args) throws Exception {
		getAll();
		System.out.println("-------------------------------------------------------");
		getOne();
	}
	//获取单个指定的方法
	private static void getOne() throws Exception{
		Class clz = User.class;
		//获取dowork()
		Method m = clz.getMethod("doWork");
		System.out.println(m);
		//获取doWork(String name)
		m = clz.getMethod("doWork", String.class);
		System.out.println(m);
		//获取private String sayHello(String name, int age)
		m = clz.getDeclaredMethod("sayHello", String.class,int.class);
		System.out.println(m);
	}
	//获取所有方法
	private static void getAll() {
		Class clz = User.class;
		//public Method[] getMethoss():获取包括自身和继承过来的所有的piblic方法
		Method[] ms = clz.getMethods();
		System.out.println(ms.length);//11
		for (Method method : ms) {
			System.out.println(method);
		}
		System.out.println("-------------------------------------------------------");
		//public Method[] getDeclaredMethods():获取自身所有的方法(不包括继承的,和访问权限无关)
		ms = clz.getDeclaredMethods();
		System.out.println(ms.length);//3
		for (Method method : ms) {
			System.out.println(method);
		}
	}
}

在这里插入图片描述


四、使用反射调用方法

1.获取方法所在类的字节码对象
2.获取方法
3.调用方法

  • 在Method类中有方法
    public Object invoke(Object obj,Object…args):表示调用当前Method所表示的方法
    参数
    obj:表示被调用的方法底层所属对象
    args:表示调用方法时传递的实际参数
    返回
    底层方法的返回结果

  • 调用私有方法:
    在调用私有方法之前:应该设置该方法为可访问的
    又因为Method是AccessibleObject的子类,所以Method中具有该方法:setAccessible(true);

  • 调用静态方法
    静态方法不属于任何对象,静态方法属于类的本身
    此时把invoke方法的第一个参数设置为null即可

相关实例
class Person {
	public void doWork() {
		System.out.println("Person.doWork()");
	}

	public static void doWork(String name) {
		System.out.println("Person.doWork()"+name);
	}

	private String sayHello(String name, int age) {
		System.out.println("Person.sayHello()"+name+","+age);
		return name + "," + age;
	}
	
	public static void sayNo(String name){
		System.out.println("Person.sayNo()" + name);
	}
}

public class MethodInvokeDemo {

	public static void main(String[] args) throws Exception, Exception {
		//不使用反射
		new Person().doWork();
		//使用反射
		Class clz = Person.class;
		//调用public void doWork()
		Method m = clz.getMethod("doWork");
		//public Object invoke(Object obj,Object...args):表示调用当前Method所表示的方法
		Object ret =m.invoke(clz.newInstance());
		System.out.println(ret);
		//调用public static void doWork(String name)
		m = clz.getMethod("doWork", String.class);
		ret = m.invoke(clz.newInstance(), "hello");
		System.out.println(ret);
		//调用private String sayHello(String name, int age)
		m = clz.getDeclaredMethod("sayHello", String.class,int.class);
		//设置可访问私有的成员
		m.setAccessible(true);
		//调用方法
		ret = m.invoke(clz.newInstance(), "hello",17);
		System.out.println(ret);
		//使用反射调用Date的toLocalString()
		Object obj = new java.util.Date();
		Method method = obj.getClass().getMethod("toLocaleString");
		Object d = method.invoke(obj);
		System.out.println(d);
		//使用反射调用静态方法
		//静态方法不属于任何对象,静态方法属于类的本身
		//此时把invoke方法的第一个参数设置为null即可
		m = clz.getMethod("sayNo", String.class);
		ret = m.invoke(null, "nono");
		System.out.println(ret);
	}   
}

在这里插入图片描述


五、使用反射调用数组参数

调用方法的时候把实际参数统统作为Object数组的元素即可
Method对象.invoke.(方法底层所属对象,new Object[]{所有实参})

相关实例
class Employe {
	public static void doWork1(int...arr){
		System.out.println("Employe.doWork1()" + Arrays.toString(arr));
	}
	public static void doWork2(String...arr){
		System.out.println("Employe.doWork2()" + Arrays.toString(arr));
	}
	public static <T> List<T> asList(T... a){
		return null;
	}
}


public class MethodInvokeDemo2 {

	public static void main(String[] args) throws Exception, Exception {
		Class clz = Employe.class;
		//1.数组的元素类型是基本数据类型
		Method method = clz.getMethod("doWork1", int[].class);
		method.invoke(null, new int[]{1,2,3,4,5});
		method.invoke(null, new Object[]{new int[]{1,2,3,4,5}});
		//2.数组的元素类型是引用类型
		method = clz.getMethod("doWork2", String[].class);
		System.out.println(method);
		method.invoke(null, new Object[]{new String[]{"A","B","C"}});
		//3.泛型要提升到最高类型
		method = clz.getMethod("asList", Object[].class);
		System.out.println(method);
	}

}

在这里插入图片描述


六、操作反射相关的API

1.获取类的修饰符
2.获取类的名称:全限定名称 getName();简易名称 getSimpleName();
3.获取包名:getPackage().getName()
4.获取父类:.getSuperclass()
等等(API文档中)

相关实例
public class OtherAPI {

	public static void main(String[] args) {
		// 获取类的修饰符
		Class clz = OtherAPI.class;
		int mod = clz.getModifiers();
		String m = Modifier.toString(mod);
		System.out.println(m);
		// 获取类的名称
		String name = OtherAPI.class.getName();
		System.out.println(name);//other.OtherAPI
		String simpleName = OtherAPI.class.getSimpleName();
		System.out.println(simpleName);//OtherAPI
		//获取包名
		String packageName = OtherAPI.class.getPackage().getName();
		System.out.println(packageName);
		//获取父类
		System.out.println(OtherAPI.class.getSuperclass());
	}

}

在这里插入图片描述

七、反射中的Array

相关实例
public class ArrayDemo {
	public static void main(String[] args) {
		Object arr = new int[] {1,3,5,7,9};
		//获取arr数组中索引为2的元素
		Object val = Array.getInt(arr, 2);
		System.out.println(val);
		//设置arr数组中索引为2的新元素为100
		Array.set(arr, 2, 100);
		System.out.println(Array.getInt(arr, 2));
		//数组复制
		int[] src = new int[] {1,2,3,4,5,6,7,8,9,10};
		int[] dest = new int[10];
		System.out.println(Arrays.toString(src));
		arraycopy(src,3,dest,2,5);
		System.out.println(Arrays.toString(dest));
	}

	public static void arraycopy(Object src, int srcPos, Object dest, 
			int destPos, int length) {
		if (src == null || dest == null) {
			throw new NullPointerException("源数组和目标数组都不能为空");
		}
		if (!src.getClass().isArray() || !dest.getClass().isArray()) {
			throw new ArrayStoreException("源和目标必须都是数组");
		}
		if (src.getClass().getComponentType() != dest.getClass().getComponentType()) {
			throw new ArrayStoreException("源和目标元素类型必须相同");
		}
		if (srcPos < 0 || destPos < 0 || length < 0 
				|| srcPos + length > Array.getLength(src)
				|| destPos + length > Array.getLength(dest)) {
			throw new IndexOutOfBoundsException("索引越界");
		}
		for (int index = srcPos;index <srcPos + length;index ++) {
			//获取需要拷贝的元素
			Object val = Array.get(src, index);
			//给目标数组设置元素
			Array.set(dest, destPos, val);
			destPos++;
		}
	}
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你这个橘子不要皮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值