Java的反射机制(易学版)

本期精彩:

目录

反射的概念

概念

反射的优缺点

Class类

概念

获取Class对象的方法

反射实例化对象

反射调用方法

反射读写属性


上期回顾:手把手教会:XML建模_小阿飞_的博客-CSDN博客

这是上期文章需要解析的config.xml文件👇

通过观察我们发现,如果画红圈处的 “ / ” 没有的话,在解析文件时如果传入一个没有“ / ” 的path,显然是会被解析成功的,但是config.xml文件中path的格式必须以“ / ”开头,所以我们要做的优化就是:让没有“ / ”的path在config.xml在运行时第一个报错

具体操作:发现action和forward中都有path,则在相对应的模型类中加上类似如下的代码即可👇

    private static final long serialVersionUID = 4907025244685971932L;
	private static Pattern pattern = Pattern.compile("^/.+$");
    
    public void checkPath(String path) {
		Matcher matcher = pattern.matcher(path);
		boolean b = matcher.matches();
		if (!b) {
			throw new RuntimeException("ForwardModel.path[" + path + "]必须以/开头");
		}
	}

本期内容:

反射的概念

概念

反射机制是在运行时,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意个对象,都能够调用它的任意一个方法

在java中,只要给定类的名字,就可以通过反射机制来获得类的所有信息

反射是Java语言中的一种机制,通过这种机制可以动态地实例化对象、读写属性、调用方法

反射也是很多框架开发的基础,比如hibernate,struts等框架

 jdbc就是典型的反射👇(还有XML文件中也存在反射)

Class.forName('com.mysql.jdbc.Driver.class');//加载MySQL的驱动类

反射的优缺点

优点:

能够运行时动态获取类的实例,提高灵活性;

与动态编译结合;

缺点:

使用反射性能较低,需要解析字节码(.class文件),将内存中的对象进行解析;

相对不安全,破坏了封装性(因为通过反射可以获得私有方法和属性);

解决方案:

1、通过setAccessible(true)关闭JDK的安全检查来提升反射速度;

2、多次创建一个类的实例时,有缓存会快很多;

3、ReflectASM工具类,通过字节码生成的方式加快反射速度 ;

Class类

概念

Java中,每个class都有一个相应的Class对象

也就是说,当我们编写一个类,编译完成后,在生成的.class文件中,就会产生一个Class对象,用于表示这个类的类型信息

理解:我们在Eclipse中创建的类( .Java )会被编译成.class文件给JVM读取,当.class文件被读到内存中后就会变成Class模型(中有之前编写的公有或者私有的属性、方法、构造函数等),通过Class就可以点出里面的对象

获取Class对象的方法

后面的代码都以下面这个学生类( .Java )为例子👇

public class Student {	
		private String sid;
		private String sname;
		public Integer age;
		
		static{
			System.out.println("加载进jvm中!");
		}
		public Student() {
			super();
			System.out.println("调用无参构造方法创建了一个学生对象");
		}
		public Student(String sid) {
			super();
			this.sid = sid;
			System.out.println("调用带一个参数的构造方法创建了一个学生对象");
		}
		public Student(String sid, String sname) {
			super();
			this.sid = sid;
			this.sname = sname;
			System.out.println("调用带二个参数的构造方法创建了一个学生对象");
		}
		@SuppressWarnings("unused")
		private Student(Integer age) {
			System.out.println("调用Student类私有的构造方法创建一个学生对象");
			this.age = age;
		}
		public String getSid() {
			return sid;
		}
		public void setSid(String sid) {
			this.sid = sid;
		}
		public String getSname() {
			return sname;
		}
		public void setSname(String sname) {
			this.sname = sname;
		}
		public void hello() {
			System.out.println("你好!我是" + this.sname);
		}
		public void hello(String name) {
			System.out.println(name + "你好!我是" + this.sname);
		}
		@SuppressWarnings({ "unused", "deprecation" })
		private Integer add(Integer a, Integer b) {
			return new Integer(a.intValue() + b.intValue());
		}
		@Override
		public String toString() {
			return "Student [sid=" + sid + ", sname=" + sname + ", age=" + age + "]";
		}	
	}

获取这个学生类的Class对象的三种方法👇

    //1.Class.forName("类的权限命名") 获取Class
	Class<Student> clazz =(Class<Student>)Class.forName("com.reflect.Student");
		
	//2. 类.class
	Class clazz02 = Student.class;
			
	//3. 对象.getClass()
	Student stu = new Student();
	Class clazz03 = stu.getClass();

补充:如何获取类的权限命名👇

先找到

再右键 

反射实例化对象

还是以上面的学生类为例,通过反射进行实例化学生对象的方式有👇    

其步骤是先通过学生类的Class对象点出其构造方法,再通过构造方法点出实例化对象的方法

补充:出于安全考虑,在通过反射获取方法、属性时可以使用 Declared 获取

            //获取无参构造,Constructor:构造函数
            Constructor<Student> c1 = clazz.getConstructor();
            //实例学生对象
			Student stu01 = c1.newInstance();
			stu01.setSname("小明");
			System.out.println(stu01);
			
            //获取有参构造
			Constructor<Student> c2 = clazz.getConstructor(String.class);
			Student stu02 = c2.newInstance("1");
			stu02.setSname("小黑");
			System.out.println(stu02);
			
            //获取有参构造
			Constructor<Student> c3 = clazz.getConstructor(String.class,String.class);
			Student stu03 = c3.newInstance("2", "小哈");
			System.out.println(stu03);
			
			//获取私有化的有参构造:Declared
			Constructor<Student> c4 = clazz.getDeclaredConstructor(Integer.class);
            //允许访问,Accessible访问控制符
			c4.setAccessible(true);
			Student stu04 = c4.newInstance(22);
			System.out.println(stu04);

补充:反射获取构造函数中判断参数个数的方法:使用可变参数(如果前面还有参数,必须放在最后),查看clazz.getConstructor源码即可发现:

反射调用方法

通过反射获取上面学生类中方法的代码👇

            Method method = clazz.getMethod("hello");
			stu04.setSname("lihao");
            //调用方法
			method.invoke(stu04);
			
			Method method02 = clazz.getMethod("hello",String.class);
			method02.invoke(stu04, "zengfanyan");
			
            //获取私有方法
			Method method03 = clazz.getDeclaredMethod("add",Integer.class, Integer.class);
			method03.setAccessible(true);
			int rv = (int)method03.invoke(stu04, 1,1);
			System.out.println(rv);

反射读写属性

通过反射获取上面学生类中属性的代码👇

            Field f = clazz.getField("age");
			f.set(stu04, 78);
			System.out.println(stu04);
			System.out.println(f.get(stu04));
			
            //获取私有属性
			Field f01 = clazz.getDeclaredField("sname");
			f01.setAccessible(true);
            //调用属性
			f01.set(stu04, "lihao is hao ren");
			System.out.println(stu04);

补充:
Bean对象

除了上述获取属性的方法之外,还可以通过BeanUtil.getproperty(对象名,“属性”)的方式获取属性,其原理是先调用类中的公开get属性的方法获取再通过反射机制进行获取

👆和JavaBean的封装的设计有关:一个对象类中私有属性,公开get(得到值)、set(注入值)方法的意义是提供统一控制获取和处理类中私有属性的方法入口

  • 11
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值