java中的反射机制Reflect
1.反射机制有什么用呢?
通过java语言中的反射机制可以操作字节码文件
让程序更加灵活
2.反射机制的相关类在哪一个包下?
java.lang.reflect.*
3.反射机制相关的类有哪些?
java.lang.Class 字节码文件
java.lang.reflect.Method 字节码中的方法字节码
java.lang.reflect.Constructor 字节码中的构造方法字节码
java.lang.reflect.Field 字节码中的属性字节码
4.在java中获取Class的三种方式
1.Class.forName("完整类名带包名")
2.Class c = 对象.getClass()
3.Class c = 任何类型.class
5.获取了Class之后,可以调用无参数构造方法来实例化对象
//c是一个User类型
Class c = Class.forName("bean.User");
//实例化一个User类型的对象
Object obj = c.newInstance();
//底层会调用User这个类的无参数构造方法,完成对象的创建
//必须保证User的无参数构造方法是存在的,否则会出现"实例化异常"
6.希望一个类的静态代码块执行,其他不执行:
使用Class.forName(这个类的完整类名),在执行时类会加载
7.IO + Properties怎么快速绑定属性配置文件
java.util.ResourceBundle包下提供了一个资源绑定器,便于获取配置文件中的信息
//资源绑定器只能绑定xxx.properties文件,并且文件必须在类路径下(必须省略后缀)
ResourceBundle bundle = ResourceBundle.getBundle("xxx");
System.out.println(bundle.getString("key"));
8.关于JDK中自带的类加载器(了解)
1.什么是类加载器?
专门负责加载类的命令/工具
ClassLoader
2.JDK中自带了三个类加载器
代码在开始执行之前,会将所需要类全部加载到JVM中
java为了保证类加载的安全,使用了双亲委派机制
按照加载的优先级依次加载,每当加载不到时才进行下一次加载
1.启动类加载器 C:\Program Files\Java\jdk1.8.0_144\jre\lib\rt.jar(JDK最核心的类库)
2.扩展类加载器 C:\Program Files\Java\jdk1.8.0_144\jre\lib\ext\*.jar
3.应用类加载器 classpath中的jar包(class文件)
一图流:
1.获取一个类的字节码class的方法
要操作一个类的字节码,首先需要获取这个类的字节码,如何获取呢?
三种方式
1.Class.forName("完整类名带包名")
2.Class c = 对象.getClass()
3.Class c = 任何类型.class
package reflect;
import java.util.Date;
public class ReflectTest01 {
public static void main(String[] args) {
// TODO Auto-generated method stub
/*
1.Class.forName()
1.静态方法
2.方法的参数是一个字符串
3.字符串需要的是一个完整类名
4.完整类名必须带有包名
*/
Class c1 = null;
Class c2 = null;
Class c3 = null;
Class c4 = null;
try {
c1 = Class.forName("java.lang.String");//String.class文件/String类型
c2 = Class.forName("java.util.Date");
c3 = Class.forName("java.lang.Integer");
c4 = Class.forName("java.lang.System");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//2.java中任何一个对象都有一个方法:getClass()
String s = "abc";
Class x = s.getClass();
System.out.println(c1 == x);//true,内存地址相同
Date time = new Date();
Class y = time.getClass();
System.out.println(c2 == y);//true,变量中保存的内存地址都是一样的,都指向方法区中的字节码
//3.java语言中任何一个类都有.class属性
Class z = String.class;//String类型
Class k = Date.class;//Date类型
Class f = int.class;
Class e = double.class;
}
}
2.在获取了class之后我们可以做什么
package reflect;
import bean.User;
public class ReflectTest02 {
public static void main(String[] args) {
// TODO Auto-generated method stub
//不使用反射机制来创建对象
User user = new User();
System.out.println(user);
//通过反射机制获取class,从而实例化对象
try {
Class c = Class.forName("bean.User");
Object obj = c.newInstance();
//底层会调用User这个类的无参数构造方法,完成对象的创建
//必须保证User的无参数构造方法是存在的
System.out.println(obj);//bean.User@6108b2d7
} 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();
}
}
}
3.剖析Class.forName()发生了什么?
类会加载
希望一个类的静态代码块执行,其他不执行:
使用Class.forName(这个类的完整类名)
package reflect;
public class ReflectTest04 {
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
Class.forName("reflect.MyClass");//类会加载
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class MyClass{
//静态代码块在类加载时执行,并且只执行一次
static {
System.out.println("MyClass的静态代码执行了");
}
}
4.※怎么通过反射机制访问一个java对象的属性?
必须掌握:
怎么通过反射机制访问一个java对象的属性?
1.获取对象
2.获取属性值get
3.给属性赋值set
反射机制虽然让代码复杂了,但是为了“灵活”,这也是值得的
package bean;
//反射属性Field
public class Student {
//Field翻译为字段,其实就是属性/成员
//4个Field,分别采用了不同的访问控制权限修饰符
public int no;
private String name;
protected int age;
boolean sex;
public static final double MATH_PI = 3.1415926;
}
package reflect;
import java.lang.reflect.Field;
import bean.Student;
public class ReflectTest07_Focus {
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
//不使用反射机制,怎么访问一个对象的属性
Student s = new Student();
//赋值
s.no = 1111;
//读取
System.out.println(s.no);
//使用反射机制,访问对象属性
Class c = Class.forName("bean.Student");
Object obj = c.newInstance();//obj是Student对象(调用无参数构造方法)
//获取no属性(根据属性名称)
//c.getField("sex");//这种方式只能获取public属性
Field noField = c.getDeclaredField("no");
//给obj对象的no属性赋值
noField.set(obj, 2222);
//读取属性值
System.out.println(noField.get(obj));
//可以访问私有数据吗
//获取
Field nameField = c.getDeclaredField("name");
//打破封装(反射机制的缺点:在外部可以访问private)
nameField.setAccessible(true);
//赋值
nameField.set(obj, "jackson");
System.out.println(nameField.get(obj));
}
}
5.※怎么通过反射机制调用方法?
重点:通过反射机制怎么去调用方法
要素分析:
1.对象userService
2.login方法名
3.实参列表
4.返回值
作用:
代码具有通用性
package bean;
/**
* 用户业务类
* @author 余晖
*
*/
public class UserService {
/**
* 登录方法
* @param name 用户名
* @param password 密码
* @return true表示登录成功,false表示登录失败
*/
public boolean login(String name,String password) {
if("admin".equals(name)&&"123".equals(password)) {
return true;
}
return false;
}
/**
* 退出系统的方法
*/
public void logout() {
System.out.println("系统已经安全退出!");
}
}
package reflect;
import java.lang.reflect.Method;
import bean.UserService;
public class ReflectTest10_Focus {
public static void main(String[] args) throws Exception{
//不使用反射机制,调用方法
//创建对象
UserService userService = new UserService();
//调用方法
boolean loginSuccess = userService.login("admin", "123");
System.out.println(loginSuccess?"登录成功":"登录失败");
//使用反射机制来调用方法
Class userServiceClass = Class.forName("bean.UserService");
//创建对象
Object obj = userServiceClass.newInstance();
//获取method
Method loginMethod = userServiceClass.getDeclaredMethod("login", String.class,String.class);
//调用方法※
/**
* 1.obj
* 2.loginMethod
* 3."admin", "123"
* 4.retVlaue
*/
Object retValue = loginMethod.invoke(obj, "admin", "123");
}
}
6.通过反射机制访问构造方法创建对象
package bean;
public class Vip {
int no;
String name;
String birth;
boolean sex;
public Vip() {
}
public Vip(int no) {
this.no = no;
}
public Vip(int no, String name) {
this.no = no;
this.name = name;
}
public Vip(int no, String name, String birth, boolean sex) {
this.no = no;
this.name = name;
this.birth = birth;
this.sex = sex;
}
@Override
public String toString() {
return "Vip [no=" + no + ", name=" + name + ", birth=" + birth + ", sex=" + sex + "]";
}
}
package reflect;
import java.lang.reflect.Constructor;
import bean.Vip;
/**
* 比上一个例子重要一点
* 通过反射机制访问构造方法创建对象
* @author 余晖
*
*/
public class ReflectTest12 {
public static void main(String[] args) throws Exception{
//不使用反射机制怎么创建对象
Vip v1 = new Vip();
Vip v2 = new Vip(110,"zhangsan","2000-01-12",true);
//使用反射机制怎么创建对象
Class c = Class.forName("bean.Vip");
//调用无参数构造方法
Object o1 = c.newInstance();
System.out.println(o1);
//调用有参数构造方法
//1.获取有参数的构造方法Constructor
Constructor con = c.getDeclaredConstructor(int.class,String.class,String.class,boolean.class);
//2.调用构造方法new对象
Object o2 = con.newInstance(110,"zhangsan","2000-01-12",true);
System.out.println(o2);
//获取无参数构造方法
Constructor con2 = c.getDeclaredConstructor();
Object o3 = con2.newInstance();
System.out.println(o3);
}
}
7.获取一个类的父类和实现的接口
package reflect;
public class ReflectTest13 {
public static void main(String[] args) throws Exception{
// TODO Auto-generated method stub
//String举例
Class stringClass = Class.forName("java.lang.String");
//获取父类
System.out.println(stringClass.getSuperclass().getName());
//获取接口(多个接口)
Class[] interfaces = stringClass.getInterfaces();
for(Class in : interfaces) {
System.out.println(in.getName());
}
}
}