文章目录
反射机制
- 反射机制的作用
-通过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);
}
}
}