反射 机制

反射机制

  • 反射机制的作用
    -通过java语言反射机制操作字节码文件
    可以读、修改字节码文件
  • 反射机制在java.lang.reflect包下
    • 反射机制重要的类
      • Class //字节码文件——代表一个类
      • Method //字节码中的方法字节码——类中的方法
      • Constructor //字节码中的构造方法字节码——类中的构造方法
      • Field //字节码中的属性字节码——类中的成员变量(静态+实例变量)‘

框架

  • 操作一个类的字节码首先需要获得该字节码

获得字节码方式

- Class.forName()
- getClass()
- Class属性

在这里插入图片描述

在这里插入图片描述

package Advance.reflect;

import Advance.reflect.bean.User;

public class ReflectTest02 {
	public static void main(String[] args) {
		//不使用反射机制,创建对象
		User user = new User();
		System.out.println(user);
		
		//使用反射机制,创建对象
		try {
			//通过反射机制,获取class 通过class实例化对象
			Class c1 = Class.forName("Advance.reflect.bean.User");
			
			//newInstance()会调用这个类的无参数构造方法  完成对象的创建
			//如果User类没有手动创建无参构造方法,程序会自动创建无参方法,并调用
			//如果手动创建含参构造方法,且没有创建无参方法,程序会出现异常
			//异常名称:InstantiationException
			Object obj = c1.newInstance();
			
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

文件路径问题

  • IO流部分
  • 使用以下通用方法的前提:文件必须存放在类路径下,凡是在src下的都是在类路径下
    在这里插入图片描述

在这里插入图片描述在这里插入图片描述

package Advance.reflect;

import java.io.FileReader;
import java.io.InputStream;
import java.util.Properties;

/**
 * @author 衣鱼
 *	验证反射机制的灵活性
 */
public class ReflectTest03 {
	public static void main(String[] args) throws Exception {
		//创建流
			//FileReader fr = new FileReader("src/Advance/reflect/classinfo.properties");
		//直接以流的方式返回
		InputStream fr = Thread.currentThread().getContextClassLoader()
				.getResourceAsStream("Advance/reflect/classinfo.properties");
		
		//创建属性类对象Map
		Properties pro = new Properties();
		//加载
		pro.load(fr);
		//关闭流
		fr.close();			//流关闭,之前通过流fr将User.java的数据加载到pro里面,流的作用执行完毕
		
		//通过Key获取Value
		String className = pro.getProperty("classname");
		System.out.println(className);
		
		
		//通过反射机制实例化对象
		Class c = Class.forName(className);
		System.out.println(c);
		//创建对象
		Object o =c.newInstance();  //c返回的是获取的User的字节码文件  
		System.out.println(o);
		
	}
}

资源绑定器 ResourceBundle

在这里插入图片描述

forName方法

  • Class.forName(“完整类名”);
  • Class.forName方法执行的时候,会导致类加载。类加载时静态代码块会执行。即调用forName方法可以只执行静态代码块
package Advance.reflect;
/**
 * @author 衣鱼
 *	Class.forName 
 *		在实际应用中,如果只希望某一个类的静态代码块执行,不希望其他的代码执行
 *		可以采用Class.forName方法。
 */
public class ReflectTest04 {
	public static void main(String[] args) {
		try {
			 Class.forName("Advance.reflect.myClass");
			
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
	}	
}

class myClass{
	int num;
	//静态代码块在类加载的时候执行,并且只执行一次
	static {
		System.out.println("myClass的静态代码块执行了!");
	}
	
}

通过读属性文件实例化对象
  • 结合IO流部分的Properties知识,反射机制的灵活性在于:java代码只写一遍,再不改变java源代码的基础之上,可以做到不同对象的实例化。【符合OCP原则:对扩展开放,对修改关闭】
  • 后期的高级框架底层的实现原理,采用了反射机制。
    • ssh、ssm
    • Spring、SpringMVC、Mybatis
    • Spring、Struts、Hibernate…

在这里插入图片描述

package Advance.reflect;

import java.io.FileReader;
import java.util.Properties;

/**
 * @author 衣鱼
 *	验证反射机制的灵活性
 */
public class ReflectTest03 {
	public static void main(String[] args) throws Exception {
		//创建流
		FileReader fr = new FileReader("src/Advance/reflect/classinfo.properties");
		//创建属性类对象Map
		Properties pro = new Properties();
		//加载
		pro.load(fr);
		//关闭流
		fr.close();			//流关闭,之前通过流fr将User.java的数据加载到pro里面,流的作用执行完毕
		
		//通过Key获取Value
		String className = pro.getProperty("classname");
		System.out.println(className);
		
		
		//通过反射机制实例化对象
		Class c = Class.forName(className);
		System.out.println(c);
		//创建对象
		Object o =c.newInstance();  //c返回的是获取的User的字节码文件  
		System.out.println(o);
		
	}
}

类加载器
  • 类加载器ClassLoader:专门负责加载类的命令/工具
  • jdk自带三个类加载器
    • 启动类加载器 ——父加载器
    • 扩展类加载器 ——母加载器
    • 应用类加载器
例如有这样一行代码:String s = “abc”;
	代码在开始执行之前,会将所需的类加载到JVM中。通过类加载器加载,看到上述代码,类加载器就会找String.class文件,找到就加载:
	①首先通过“启动类加载器”加载
		注意:启动类加载器专门加载rt.jar,rt.jar是jdk中的核心类库
	②如果启动类加载器找不到,就通过“扩展类加载器”加载
		注意:扩展类加载器专门加载:ext.jar
	③如果扩展类加载器找不到,将通过应用类加载器加载
		注意:应用类加载器加载classpath中的类
  • 双亲委派机制
  • java为了程序安全,使用了双亲委派机制。【如果自制一个带有病毒的String*,类加载器没有从标准加载器开始寻找,直接加载了应用加载器的String*。会造成安全问题】
  • 双亲委派机制:“父”启动类加载器加载不到;进一步到“母”扩展类加载器,最后到应用类加载器。

反射属性 Field

在这里插入图片描述- 任给一个.class字节码文件,利用反编译,找出该字节码文件对应源文件的属性
在这里插入图片描述

访问对象属性set

  • 给.calss文件的获取的属性进行赋值
    在这里插入图片描述
package Advance.reflect;

import java.lang.reflect.Field;

import Advance.reflect.bean.Student;

/**
 * @author 衣鱼
 *	
 */
public class reflectTest07 {
	public static void main(String[] args) throws Exception{
		//以往操作
		Student s = new Student();
		s.no=1000;
					/***
					 * 给对象属性赋值的要素
					 * 		对象s
					 * 		属性no
					 * 		赋值1000
					 * */
		
		//使用反射机制
		Class studentClass = Class.forName("Advance.reflect.bean.Student");
		//生成对象
		Object obj = studentClass.newInstance();
		//获得属性——利用属性名(唯一)来获取属性
		Field noField =studentClass.getDeclaredField("no");
		//给对象的属性赋值
		noField.set(obj, 1000);
		//获取属性的值
		System.out.println(noField.get(obj));
		
		Field nameField = studentClass.getDeclaredField("name");
		//获取私有属性的值——打破封装
		nameField.setAccessible(true);
		//之后就可以设置
		nameField.set(obj, "马小");
		System.out.println(nameField.get(obj));
	}
}


反射方法Method

可变长参数
在这里插入图片描述

  • 反射 类中的方法
    在这里插入图片描述

★Method调用方法★invoke

在这里插入图片描述

package Advance.reflect;

import java.lang.reflect.Method;

import Advance.reflect.bean.UserService;

/**
 * @author 衣鱼
 *	
 */
public class reflectTest10 {
	public static void main(String[] args) throws Exception{
		//以往调用方法
		UserService us = new UserService();
		boolean loginSucess =us.login("admin", "123");
		System.out.println(loginSucess?"登录成功":"登录失败");
		
		//使用反射机制调用方法
		Class  userServiceClass= Class.forName("Advance.reflect.bean.UserService");
		Object obj = userServiceClass.newInstance();
		
		//获得方法
		Method loginUserService =userServiceClass.getDeclaredMethod("login", String.class,String.class);
		
		//调用方法  对象 、方法、参数、返回值
		Object returnvalue = loginUserService.invoke(obj, "admin","123");
	
	}
}

反射构造方法Construct

package Advance.reflect;
import java.lang.reflect.Constructor;
import Advance.reflect.bean.Vip;

public class reflectTest11 {
	public static void main(String[] args) throws Exception{
		//不使用反射
		Vip v1 = new Vip(1010,"张三");
		Vip v2 = new Vip(1010,"张三","2010-10-10",true);
		//使用反射机制
		Class vipClass = Class.forName("Advance.reflect.bean.Vip");
			//调用无参
		Object obj = vipClass.newInstance();
		System.out.println(obj);
			//调用含参
		Constructor vipConstructors = vipClass.getDeclaredConstructor(int.class,String.class);
				//调用构造方法传对象
		Object obj2 =vipConstructors.newInstance(1001,"李四");
		//输出
		System.out.println(obj2);
		
	}
}

package Advance.reflect.bean;

public class Vip {
		int no;
		String name;
		String brith;
		boolean sex;
		public Vip(int no, String name, String brith, boolean sex) {
			super();
			this.no = no;
			this.name = name;
			this.brith = brith;
			this.sex = sex;
		}
		public Vip(int no, String name) {
			super();
			this.no = no;
			this.name = name;
		}
		public Vip() {
		}
	
		@Override
		public String toString() {
			return "Vip [no=" + no + ", name=" + name + ", brith=" + brith + ", sex=" + sex + "]";
		}	
		
}

获取父类和接口

package Advance.reflect;
/**
 * @author 衣鱼
 *		给一个类字节码文件
 *		获取该类的父类
 *		获取该类实现的哪些接口
 */
public class reflectTest12 {
	public static void main(String[] args) throws Exception{
		Class stringClass = Class.forName("java.lang.String");
		//获取String的父类
		Class superClass =stringClass.getSuperclass();
		System.out.println(superClass.getName());
		Class[] interfaces = stringClass.getInterfaces();
		for(Class interf :interfaces) {
			System.out.println(interf);
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值