Java反射机制

什么是反射?

Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于ReflectionAPI取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。

主要实现

通过反射机制我们可以实现以下功能:
①在运行时判断任意一个对象所属的类
②在运行时构造任意一个类的对象
③在运行时判断任意一个类所具有的成员变量和方法
④在运行时调用任意一个对象的成员变量和方法
⑤生成动态代理

Class类

在Object类中定义了一个方法,此方法可以被所有子类继承:
public final Class getClass()
此方法返回值类型是一个Class类,Class类是Java反射的源头。每一个对象实例都能记得自己是被哪个Class实例所生成的,所以我们可以通过Class类获得一个类的完整结构。
我们需要明确几点:
①Class类也是一个类,虽然它和关键字 class长得很像。
②Class类的对象只能由系统创建。
③一个类在JVM 中只会有一个Class实例。
④一个Class对象对应的是一个加载到JVM中的一个.class文件。


/**
	 * 我们创建了一个类 通过编译(javac.exe),生成对应的.class文件,然后使用java.exe加载(JVM的类加载器).class文件
	 * 此.class文件加载到内存以后就是一个运行时类,存在缓存区中。那么这个运行时类本身就是一个Class的实例。一个运行时类只被加载一次
	 */
	@Test
	public void test() {
		Person p = new Person();
		Class clazz = p.getClass();
		System.out.println(clazz);
	}
实例化Class类对象的四种方式

1)前提:若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高

       实例:Class clazz = String.class;

2)前提:已知某个类的实例,调用该实例的getClass()方法获取Class对象

       实例:String str = new String("123");

                 Class clazz =str.getClass();

3)前提:已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException

       实例:Class clazz= Class.forName(“java.lang.String”);

4)其他方式

                  ClassLoader cl =this.getClass().getClassLoader();

                  Class clazz4 = cl.loadClass(“类的全类名”);

通过反射创建类对象

①通过调用类的无参构造器创建类对象

前提:Person类存在无参的构造器,且必须有足够的权限(public)

@Test
	public void test2() throws Exception {
		Class clazz = Class.forName("com.wya.j2se.reflection.Person");
		System.out.println(clazz);
		Object obj = clazz.newInstance();
		Person p = (Person)obj;
		System.out.println(p);
	}
②通过调用无参构造创建类的对象

/**
	 * 通过有参构造创建类的对象
	 * @throws Exception
	 */
	@Test
	public void test3() throws Exception {
		Class clazz = Class.forName("com.wya.j2se.reflection.Person");
		//获取类的有参构造器
		Constructor con = clazz.getConstructor(String.class,Integer.class);
		//传入参数,通过有参构造器创建类对象
		Object obj = con.newInstance("jack",21);
		//获取对象实例
		Person p = (Person)obj;
		System.out.println(p);
	}
通过反射获取运行时类的属性
@Test
	public void test4() throws Exception {
		Class clazz = Person.class;
		//getFields()方法只能获取运行时类及其父类中的public的属性
		Field[] fields = clazz.getFields();
		for(Field f : fields){
			System.out.println(f);
		}
		//getFields()方法只能获取运行时类中的所有的属性
		fields = clazz.getDeclaredFields();
		for(Field f : fields){
			System.out.println(f);
		}
		
	}

public java.lang.String com.wya.j2se.reflection.Person.name
public java.lang.String com.wya.j2se.reflection.Person.name
private java.lang.Integer com.wya.j2se.reflection.Person.age
/**
	 * 获取类的属性的修饰符、类型、名称
	 * @throws Exception
	 */
	@Test
	public void test5() throws Exception {
		Class clazz = Person.class;
		//getFields()方法只能获取运行时类中的所有的属性
		Field[] fields = clazz.getDeclaredFields();
		for(Field f : fields){
			int m = f.getModifiers();
			System.out.print("修饰符:"+Modifier.toString(m));
			Class t = f.getType();
			System.out.print("变量类型:"+t.getName());
			System.out.print("变量名:"+f.getName());
			System.out.println();
		}
		
	}

修饰符:public变量类型:java.lang.String变量名:name
修饰符:private变量类型:java.lang.Integer变量名:age
通过反射获取类的方法
/**
	 * 获取类的方法
	 * @throws Exception
	 */
	@Test
	public void test6() throws Exception {
		Class clazz = Person.class;
		//getMethods()方法只能获取运行时类及其父类中的public的方法
		Method[] methods = clazz.getMethods();
		for(Method m : methods){
			System.out.println(m);
		}
		//getDeclaredMethods()方法只能获取运行时类中的所有的方法
		methods = clazz.getDeclaredMethods();
		for(Method m : methods){
			System.out.println(m);
		}
	}
/**
	 * 获取类的方法的注解 权限修饰符 返回值类型 方法名 形参列表 异常
	 * @throws Exception
	 */
	@Test
	public void test7() throws Exception {
		Class clazz = Person.class;
		Method[] methods = clazz.getDeclaredMethods();
		for(Method m : methods){
			Annotation[] anns =  m.getAnnotations();
			for(Annotation ann : anns){
				System.out.print("注解:"+ann);
			}
			int i = m.getModifiers();
			System.out.print("权限修饰符:"+Modifier.toString(i));
			Class type = m.getReturnType();
			System.out.print("返回值类型:"+type.getName());
			System.out.print("方法名:"+m.getName());
			System.out.print("参数列表(");
			Class[] params =  m.getParameterTypes();
			for(int j =0 ;j<params.length;j++ ){
				System.out.print(params[j].getName()+"args-"+j+" ");
			}
			System.out.print(")");
			System.out.print("异常:");
			Class[] exs = m.getExceptionTypes();
			for(Class ex : exs){
				System.out.print(ex.getName());
			}
			System.out.println();
		}
	}

权限修饰符:public返回值类型:java.lang.String方法名:toString参数列表()异常:
权限修饰符:public返回值类型:java.lang.String方法名:getName参数列表()异常:
权限修饰符:public返回值类型:void方法名:setName参数列表(java.lang.Stringargs-0 )异常:
权限修饰符:public返回值类型:void方法名:setAge参数列表(java.lang.Integerargs-0 )异常:
权限修饰符:public返回值类型:java.lang.Integer方法名:getAge参数列表()异常:
权限修饰符:public返回值类型:void方法名:display参数列表()异常:java.lang.Exception

获取运行时类的构造器

@Test
	public void test8() throws Exception {
		Class clazz = Person.class;
		Constructor[] cons = clazz.getDeclaredConstructors();
		for(Constructor con : cons){
			System.out.println(con);
		}
	}
public com.wya.j2se.reflection.Person()
public com.wya.j2se.reflection.Person(java.lang.String,java.lang.Integer)


获取运行时类的直接父类
/**
	 * 获取父类
	 * @throws Exception
	 */
	@Test
	public void test9() throws Exception {
		Class clazz = Person.class;
		Class superClazz = clazz.getSuperclass();
		System.out.println(superClazz);
	}
	
	/**
	 * 获取带泛型的父类
	 * @throws Exception
	 */
	@Test
	public void test10() throws Exception {
		Class clazz = Person.class;
		Type type = clazz.getGenericSuperclass();
		System.out.println(type);
	}

	/**
	 * 获取父类的泛型
	 * @throws Exception
	 */
	@Test
	public void test11() throws Exception {
		Class clazz = Person.class;
		Type type = clazz.getGenericSuperclass();
		ParameterizedType pt = (ParameterizedType)type;
		Type[] types = pt.getActualTypeArguments();
		System.out.println((Class)types[0]);
	}
获取运行时类实现的接口

/**
	 * 获取实现的接口
	 * @throws Exception
	 */
	@Test
	public void test12() throws Exception {
		Class clazz = Person.class;
		Class[] clazzs = clazz.getInterfaces();
		for(Class c : clazzs){
			System.out.println(c);
		}
	}
获取其他
/**
	 * 获取所在的包
	 * @throws Exception
	 */
	@Test
	public void test13() throws Exception {
		Class clazz = Person.class;
		Package p = clazz.getPackage();
		System.out.println(p);
	}
	
	/**
	 * 获取注解,只能获取runtime的注解
	 * @throws Exception
	 */
	@Test
	public void test14() throws Exception {
		Class clazz = Person.class;
		Annotation[] anns = clazz.getAnnotations();
		for(Annotation ann : anns){
			System.out.println(ann);
		}
	}
调用指定的属性

/**
	 * 调用指定的属性
	 * @throws Exception
	 */
	@Test
	public void test15() throws Exception {
		Class clazz = Person.class;
		Field name = clazz.getField("name");
		Person p = (Person)clazz.newInstance();
		name.set(p, "tom");
		Field age = clazz.getDeclaredField("age");
		//私有的属性需要设置权限
		age.setAccessible(true);
		age.set(p, 22);
		System.out.println(p);//Person [name=tom, age=22]
	}

调用指定的方法

/**
	 * 调用指定方法
	 * @throws Exception
	 */
	@Test
	public void test16() throws Exception {
		Class clazz = Person.class;
		Person p = (Person)clazz.newInstance();
		//getMethod(String name, Class<?>... parameterTypes)
		Method m = clazz.getMethod("display", String.class);
		// invoke(Object obj, Object... args) 参数必须与getMethod的方法数量相同否则抛出异常//私有方法需要设置操作权限m.setAccessible(true);
		m.invoke(p, "jeff");
		//调用静态方法 
		Method m2 = clazz.getMethod("info");
		m2.invoke(Person.class);
	}
i am person my name is jeff
hello world


反射与动态代理

前面接口部分介绍了接口的一个应用:静态代理。

特征是代理类和目标对象的类都是在编译期间确定下来,不利于程序的扩展。同时,每一个代理类只能为一个接口服务,这样一来程序开发中必然产生过多的代理。最好可以通过一个代理类完成全部的代理功能。

动态代理

动态代理是指客户通过代理类来调用其它对象的方法,并且是在程序运行时根据需要动态创建目标类的代理对象。
代理设计模式的原理 :

使用一个代理将对象包装起来, 然后用该代理对象取代原始对象. 任何对原始对象的调用都要通过代理. 代理对象决定是否以及何时将方法调用转到原始对象上。

实现动态代理需要一个类:Proxy, 专门完成代理的操作类,是所有动态代理类的父类。通过此类为一个或多个接口动态地生成实现类。

它提供了用于创建动态代理类和动态代理对象的静态方法:
static  Class <?>   getProxyClass( ClassLoader  loader,Class<?>... interfaces 创建一个动态代理类所对应的Class对象
static  Object   newProxyInstance( ClassLoader  loader,Class<?>[] interfaces, InvocationHandler h 直接创建一个动态代理对象
实现方式

package com.wya.j2se.reflection;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

//接口
interface Subject{
	public void action();
}
//被代理类
class MySubject implements Subject{
	@Override
	public void action() {
		System.out.println("我被代理了");
	}
}

//接口
interface Human{
	public void fly();
}
//被代理类
class Superman implements Human{
	@Override
	public void fly() {
		System.out.println("我会飞了");
	}
}
//创建一个实现接口InvocationHandler的类,它必须实现invoke方法,以完成代理的具体操作。
class MyInvocationHandler implements InvocationHandler{

	//被代理类的声明
	private Object obj;
	
	//给被代理类实例化并返回该代理类的对象
	public Object blind(Object obj){
		this.obj = obj;
		return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
	}
	//执行代理类重写的方法
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object returnValue = method.invoke(obj, args);
		return returnValue;
	}
	
}

public class TestProxy {

	public static void main(String[] args) {
		//创建实现了InvocationHandler的类对象
		MyInvocationHandler handler = new MyInvocationHandler();
		
		//创建被代理类的对象
		MySubject mySubject = new MySubject();
		//动态绑定并返回一个同样实现了MySubject实现的接口的实现类
		Object obj = handler.blind(mySubject);
		//此时subject就是被代理类的对象
		Subject subject = (Subject)obj;
		subject.action();
		
		//创建被代理类的对象
		Superman superman = new Superman();
		obj = handler.blind(superman);
		Human human = (Human)obj;
		human.fly();
	}
}

我被代理了
我会飞了

动态代理与AOP
AOP代理里的方法可以在执行目标方法之前、之后插入一些通用处理。这样我们就可以把一些方法中的重复代码抽取出来,如日志管理,用户权限验证等。



定义一个通用方法的类
package com.wya.j2se.reflection;

public class MyUtil {
	
	public static void method1(){
		System.out.println("通用方法1");
	}

	public static void method2(){
		System.out.println("通用方法2");
	}
}
重写invoke方法
@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		MyUtil.method1();
		Object returnValue = method.invoke(obj, args);
		MyUtil.method2();
		return returnValue;
	}
	

通用方法1
我被代理了
通用方法2
通用方法1
我会飞了
通用方法2

类加载机制
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目标检测(Object Detection)是计算机视觉领域的一个核心问题,其主要任务是找出图像中所有感兴趣的目标(物体),并确定它们的类别和位置。以下是对目标检测的详细阐述: 一、基本概念 目标检测的任务是解决“在哪里?是什么?”的问题,即定位出图像中目标的位置并识别出目标的类别。由于各类物体具有不同的外观、形状和姿态,加上成像时光照、遮挡等因素的干扰,目标检测一直是计算机视觉领域最具挑战性的任务之一。 二、核心问题 目标检测涉及以下几个核心问题: 分类问题:判断图像中的目标属于哪个类别。 定位问题:确定目标在图像中的具体位置。 大小问题:目标可能具有不同的大小。 形状问题:目标可能具有不同的形状。 三、算法分类 基于深度学习的目标检测算法主要分为两大类: Two-stage算法:先进行区域生成(Region Proposal),生成有可能包含待检物体的预选框(Region Proposal),再通过卷积神经网络进行样本分类。常见的Two-stage算法包括R-CNN、Fast R-CNN、Faster R-CNN等。 One-stage算法:不用生成区域提议,直接在网络中提取特征来预测物体分类和位置。常见的One-stage算法包括YOLO系列(YOLOv1、YOLOv2、YOLOv3、YOLOv4、YOLOv5等)、SSD和RetinaNet等。 四、算法原理 以YOLO系列为例,YOLO将目标检测视为回归问题,将输入图像一次性划分为多个区域,直接在输出层预测边界框和类别概率。YOLO采用卷积网络来提取特征,使用全连接层来得到预测值。其网络结构通常包含多个卷积层和全连接层,通过卷积层提取图像特征,通过全连接层输出预测结果。 五、应用领域 目标检测技术已经广泛应用于各个领域,为人们的生活带来了极大的便利。以下是一些主要的应用领域: 安全监控:在商场、银行
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值