J2EE从入门到入土08.Java反射机制

目录

反射机制的概念

反射的优缺点

反射的本质

获取Class对象的方法

反射实例化对象

反射调用方法

反射读写属性

BeanUtils


反射机制的概念

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

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

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

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

早在我们使用jdbc连接数据库时就使用到了java的反射机制

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

反射的优缺点

优点

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

与动态编译结合;

缺点

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

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

解决方案

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

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

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

反射的本质

拿Student举例(如下图),当Student被实例化时,实际是通过JVM(Java虚拟机)编译成.class文件,而反射机制就是在类被加载出来时,会生成一个Class对象,而这个被编译完成的.class文件生成的Student模型相当于是Class对象的子类(每一个class文件都有一个对应的Class模型,Class模型用于表示这个类的类型信息),并且Student类对于Class模型来说是全透明的,包括private属性或方法都是可以直接修改或者调用的。所以反射实际上是在被编译后的文件上动手脚

获取Class对象的方法

创建一个测试用的Student类

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.test.reflect.Student");
		
	//2. 类.class
	Class clazz02 = Student.class;
			
	//3. 对象.getClass()
	Student stu = new Student();
	Class clazz03 = stu.getClass();

反射实例化对象

//获取无参构造,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);

BeanUtils

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

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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值