文章目录
-
- 反射机制有什么用?
- 反射机制的相关类在哪个包下?
- 反射机制相关的重要的类有哪些?
- 获取Class的三种方式:
- 获取Class,能干什么?
- 反射机制的灵活性。
- Class.forName()发生了什么?
- 怎么获取一个文件的绝对路径。
- 文件路径直接以流的形式返回:
- 通过反射获取属性值Field(以Student类举例)
- 通过反射机制,反编译一个类的属性Field
- 怎么通过反射机制访问一个java对象的属性?
- 通过反射获取Method
- 通过反射反编译对象方法Method
- 重点:通过反射机制怎么调用一个对象的方法?
- 反编译一个类的Constructor构造方法。
- 通过反射机制调用构造方法实例化java对象。
- 通过反射机制怎么获取这个类的父类,和它自己已经实现的接口
- 资源绑定器
反射机制有什么用?
通过java语言中的反射机制可以操作字节码文件。
优点类似于黑客。(可以读和修改字节码文件。)
通过反射机制可以操作代码片段。(class文件。)
反射机制的相关类在哪个包下?
java.lang.reflect.*;
反射机制相关的重要的类有哪些?
-
java.lang.Class:代表整个字节码,代表一个类型,代表整个类。
-
java.lang.reflect.Method:代表字节码中的方法字节码。代表类中的方法。
-
java.lang.reflect.Constructor:代表字节码中的构造方法字节码。代表类中的构造方法
-
java.lang.reflect.Field:代表字节码中的属性字节码。代表类中的成员变量(静态变量+实例变量)。
获取Class的三种方式:
java中获取Class的三种方式?要操作一个类的字节码,需要首先获取到这个类的字节码,怎么获取java.lang.Class实例
第一种:
Class c = Class.forName("完整类名");
第二种:
Class c = 对象.getClass();
第三种:
Class c = int.class;
Class c = String.class;
示例代码01:
public class ReflectTest01 {
public static void main(String[] args) throws ClassNotFoundException {
/*
Class.forName()
1、静态方法
2、方法的参数是一个字符串。
3、字符串需要的是一个完整类名。
4、完整类名必须带有包名。java.lang包也不能省略。
*/
Class c1 = Class.forName("java.lang.String");// c1代表String.class文件,或者说c1代表String类型。
Class c2 = Class.forName("java.util.Date");// c2代表Date类型
Class c3 = Class.forName("java.lang.Integer");// c3代表Integer类型
Class c4 = Class.forName("java.lang.System");// c4代表System类型
// java中任何一个对象都有一个方法:getClass()
String s = "abc";
Class x = s.getClass();// x代表String.class字节码文件,x代表String类型。
System.out.println(c1 == x);// true(==判断的是对象的内存地址。)
Date date = new Date();
Class d = date.getClass();
System.out.println(c2 == d);// true (c2和y两个变量中保存的内存地址都是一样的,都指向方法区中的字节码文件。)
// 第三种方式,java语言中任何一种类型,包括基本数据类型,它都有.class属性。
Class z = String.class;//z代表String类型
Class k = Date.class;//k代表Date类型
Class f = int.class;//f代表int类型
Class e = double.class;//e代表double类型
System.out.println(x == z);// true
}
}
运行结果:
获取Class,能干什么?
- 通过Class的newInstance()方法来实例化对象
- 注意:newInstance()方法内部实际上调用了无参构造方法,必须保证无参构造存在。
示例代码02:
public class ReflectTest {
public static void main(String[] args) {
//不使用反射创建对象
User user = new User();
System.out.println(user);
Class c;
{
try {
//使用反射创建对象,通过反射机制,获取Class,通过Class来实例化对象
c = Class.forName("com.newstudy.javase.bean.User");//c代表User类型
//newInstance()这个方法会调用User这个类的无参构造方法,完成对象的创建!
//重点是:newInstance()调用的是无参构造方法,必须保证无参构造是存在的
Object o = c.newInstance();
System.out.println(o);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
class User {
public User(){
System.out.println("无参构造方法执行!");
}
/*public User(){
}*/
}
运行结果:
反射机制的灵活性。
java代码写一遍,再不改变java源代码的基础之上,可以做到不同对象的实例化。
非常之灵活。(符合OCP开闭原则:对扩展开放,对修改关闭。)
示例代码02:
public class ReflectTest03 {
public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
// 这种方式代码就写死了。只能创建一个User类型的对象
//User user = new User();
// 以下代码是灵活的,代码不需要改动,可以修改配置文件,配置文件修改之后,可以创建出不同的实例对象。
// 通过IO流读取classinfo.properties文件
FileReader reader = new FileReader("reflect/src/classinfo.properties");
//在创建properties对象
// 创建属性类对象Map
Properties pro = new Properties();
//把文件通过流方式加载到properties集合中
pro.load(reader);
// 关闭流
reader.close();
//通过key获取value
String classname = pro.getProperty("classname");
System.out.println(classname);
//通过反射创建对象,实例化对象
Class c = Class.forName(classname);
Object o = c.newInstance();
System.out.println(o);
}
}
运行结果:
Class.forName()发生了什么?
记住,重点:
如果你只是希望一个类的静态代码块执行,其它代码一律不执行,
你可以使用:
Class.forName(“完整类名”);
这个方法的执行会导致类加载,类加载时,静态代码块执行。
示例代码03:
public class ReflectTest04 {
public static void main(String[] args) {
try {
// Class.forName()这个方法的执行会导致:类加载。
Class c = Class.forName("com.newstudy.javase.reflect.MyClass");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
public class MyClass {
static{
// 静态代码块在类加载时执行,并且只执行一次。
System.out.println("MyClass的静态代码块执行了!");
}
}
运行结果:
怎么获取一个文件的绝对路径。
Thread.currentThread() 当前线程对象
getContextClassLoader() 是线程对象的方法,可以获取到当前线程的类加载器对象。
getResource() 【获取资源】这是类加载器对象的方法,当前线程的类加载器默认从类的根路径下加载资源。
示例代码04:
public class AboutPathTest {
public static void main(String[] args) {
// 这种方式的路径缺点是:移植性差,在IDEA中默认的当前路径是project的根。
// 这个代码假设离开了IDEA,换到了其它位置,可能当前路径就不是project的根了,这时这个路径就无效了。
//FileReader reader = new FileReader("chapter25/classinfo2.properties");
// 接下来说一种比较通用的一种路径。即使代码换位置了,这样编写仍然是通用的。
// 注意:使用以下通用方式的前提是:这个文件必须在类路径下。
// 什么类路径下?方式在src下的都是类路径下。【记住它】
// src是类的根路径。
/*
解释:
Thread.currentThread() 当前线程对象
getContextClassLoader() 是线程对象的方法,可以获取到当前线程的类加载器对象。
getResource() 【获取资源】这是类加载器对象的方法,当前线程的类加载器默认从类的根路径下加载资源。
*/
// 这种方式获取文件绝对路径是通用的。
String path1 = Thread.currentThread().getContextClassLoader().getResource("classinfo2.properties").getPath();
// 采用以上的代码可以拿到一个文件的绝对路径。
// /C:/Users/Administrator/IdeaProjects/javase/out/production/chapter25/classinfo2.properties
System.out.println(path1);
// 获取db.properties文件的绝对路径(从类的根路径下作为起点开始)
String path2 = Thread.currentThread().getContextClassLoader().getResource("com/newstudy/javase/bean/db.properties").getPath();
System.out.println(path2);
}
}
运行结果:
文件路径直接以流的形式返回:
InputStream in = Thread.currentThread().getContextClassLoader()
.getResourceAsStream(“com/bjpowernode/test.properties”);
示例代码05:
public class IoPropertiesTest {
public static void main(String[] args) throws IOException {
// 获取一个文件的绝对路径了!!!!!
/*String path = Thread.currentThread().getContextClassLoader()
.getResource("classinfo2.properties").getPath();
FileReader reader = new FileReader(path);*/
//直接以流的方式返回
InputStream reader = Thread.currentThread().getContextClassLoader()
.getResourceAsStream("classinfo2.properties");
Properties pro = new Properties();
pro.load(reader);
reader.close();
//通过key获取value
String classname = pro.getProperty("classname");
System.out.println(classname);
}
}
运行结果:
通过反射获取属性值Field(以Student类举例)
示例代码06:
public class ReflectTest05 {
public static void main(String[] args) throws ClassNotFoundException {
// 获取整个类
Class student = Class.forName("com.newstudy.javase.bean.Student");
//获取完整类名
String studentName = student.getName();
System.out.println("完整类名:" + studentName);
//获取简单类名
String studentSimpleName = student.getSimpleName();
System.out.println("简单类名:" + studentSimpleName);
//获取类属性
/*Field[] fields = student.getFields();
System.out.println(fields.length); // 测试数组中只有1个元素
Field field = fields[0];
System.out.println(field.getName());*/
//获取所有属性字段
Field[] fs = student.getDeclaredFields();
for(Field fieldo : fs) {
//获取字段修饰符列表
int i = fieldo.getModifiers();// 返回的修饰符是一个数字,每个数字是修饰符的代号!!!
// 可以将这个“代号”数字转换成“字符串”吗?
String s = Modifier.toString(i);
System.out.println(s);
//获取字段类型名字
/*Class type = fieldo.getType();
System.out.println(type.getName());*/
//获取字段类型简单名字
Class type1 = fieldo.getType();
System.out.println(type1.getSimpleName());
//获取字段名字
System.out.println(fieldo.getName());
}
}
}
public class Student {
public int no;
private String name;
protected int age;
boolean sex;
}
运行结果:
通过反射机制,反编译一个类的属性Field
示例代码07:
public class ReflectTest06 {
public static void main(String[] args) throws ClassNotFoundException {
//获取整个类
Class student = Class.forName("java.lang.Thread");
//创建字符串拼接对象// 创建这个是为了拼接字符串。
StringBuilder sb = new StringBuilder();
sb.append(Modifier.toString(student.getModifiers()) + " class " + student.getSimpleName() + "{\n");
Field[] fields = student.getDeclaredFields();
for(Field field : fields) {
sb.append("\t");
sb.append(Modifier.toString(field.getModifiers()));
sb.append(" ");
sb.append(field.getType().getSimpleName());
sb.append(" ");
sb.append(field.getName());
sb.append(";\n");
}
sb.append("}");
System.out.println(sb);
}
}
运行结果:
怎么通过反射机制访问一个java对象的属性?
给属性赋值set
获取属性的值get
示例代码08:
public class ReflectTest07 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchFieldException {
//不使用反射修改获取对象值
Student student1 = new Student();
// 给属性赋值
student1.no = 123456789;//三要素:给s对象的no属性赋值1111
//要素1:对象s
//要素2:no属性
//要素3:1111
// 读属性值
// 两个要素:获取s对象的no属性的值。
System.out.println(student1.no);
//获取Student对象// 使用反射机制,怎么去访问一个对象的属性。(set get)
Class student = Class.forName("com.newstudy.javase.bean.Student");
//实例化对象
Object o = student.newInstance();
//获取其中一个属性值// 获取no属性(根据属性的名称来获取Field)
Field nofield = student.getDeclaredField("no");
//给属性设置值
// 给obj对象(Student对象)的no属性赋值
/*
虽然使用了反射机制,但是三要素还是缺一不可:
要素1:obj对象
要素2:no属性
要素3:2222值
注意:反射机制让代码复杂了,但是为了一个“灵活”,这也是值得的。
*/
nofield.set(o,382155);// 给obj对象的no属性赋值382155
//获取修改后的属性值
// 读取属性的值
// 两个要素:获取obj对象的no属性的值。
System.out.println(nofield.get(o));
//可以访问私有属性吗
Field namefield = student.getDeclaredField("name");
//打破封装
namefield.setAccessible(true);
namefield.set(o,"wangyilin");
System.out.println(namefield.get(o));//此处如果不打破分装,会报权限访问异常
}
}
public class Student {
public int no;
private String name;
protected int age;
boolean sex;
}
运行结果:
通过反射获取Method
示例代码09:
public class ReflectTest08 {
public static void main(String[] args) throws ClassNotFoundException {
//获取UserService类型
Class userService = Class.forName("com.newstudy.javase.bean.UserService");
//获取方法名字// 获取所有的Method(包括私有的!)
Method[] methods = userService.getDeclaredMethods();
for(Method method :methods){
//获取方法的修饰符
System.out.println(Modifier.toString(method.getModifiers()));
//获取方法的返回类型
System.out.println(method.getReturnType().getSimpleName());
//获取方法的名字
System.out.println(method.getName());
//获取方法的参数列表(方法可以有多个参数)
Class[] parameterTypes = method.getParameterTypes();
for(Class parameterType : parameterTypes){
System.out.println(parameterType.getSimpleName());
}
}
}
}
运行结果:
通过反射反编译对象方法Method
示例代码10:
public class ReflectTest09 {
public static void main(String[] args) throws ClassNotFoundException {
StringBuilder s = new StringBuilder();
//Class userServiceClass = Class.forName("com.bjpowernode.java.service.UserService");
Class userServiceClass = Class.forName("java.lang.String");
s.append(Modifier.toString(userServiceClass.getModifiers()) + " class "+userServiceClass.getSimpleName()+" {\n");
Method[] methods = userServiceClass.getDeclaredMethods();
for(Method method : methods){
//public boolean login(String name,String password){}
s.append("\t");
s.append(Modifier.toString(method.getModifiers()));
s.append(" ");
s.append(method.getReturnType().getSimpleName());
s.append(" ");
s.append(method.getName());
s.append("(");
// 参数列表
Class[] parameterTypes = method.getParameterTypes();
for(Class parameterType : parameterTypes){
s.append(parameterType.getSimpleName());
s.append(",");
}
// 删除指定下标位置上的字符
s.deleteCharAt(s.length() - 1);
s.append("){}\n");
}
s.append("}");
System.out.println(s);
}
}
运行结果:
重点:通过反射机制怎么调用一个对象的方法?
反射机制,让代码很具有通用性,可变化的内容都是写到配置文件当中,
将来修改配置文件之后,创建的对象不一样了,调用的方法也不同了,
但是java代码不需要做任何改动。这就是反射机制的魅力。
示例代码11:
public class ReflectTest10 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
// 不使用反射机制,怎么调用方法
// 创建对象
UserService userService1 = new UserService();
// 调用方法
/*
要素分析:
要素1:对象userService
要素2:login方法名
要素3:实参列表
要素4:返回值
*/
boolean loginSuccess = userService1.login("admin","123");
//System.out.println(loginSuccess);
System.out.println(loginSuccess ? "登录成功" : "登录失败");
//获取类型
Class userService = Class.forName("com.newstudy.javase.bean.UserService");
//实例化对象
Object o = userService.newInstance();
//获取方法
Method login = userService.getMethod("login", String.class, String.class);
//Method login = userService.getMethod("login", int.class);
// 调用方法
// 调用方法有几个要素? 也需要4要素。
// 反射机制中最最最最最重要的一个方法,必须记住。
/*
四要素:
loginMethod方法
obj对象
"admin","123" 实参
retValue 返回值
*/
//调用方法
Object reValue = login.invoke(o, "admin", "123");
System.out.println(reValue);
}
}
public class UserService {
public boolean login(String username,String password){
if("123".equals(username) && "admian".equals(password)){
return true;
}
return false;
}
public void loginout(){
System.out.println("退出系统,欢迎下次光临!");
}
public void login(int age){
}
}
运行结果:
反编译一个类的Constructor构造方法。
示例代码12:
public class ReflectTest11 {
public static void main(String[] args) throws Exception{
StringBuilder s = new StringBuilder();
Class vipClass = Class.forName("java.lang.String");
s.append(Modifier.toString(vipClass.getModifiers()));
s.append(" class ");
s.append(vipClass.getSimpleName());
s.append("{\n");
// 拼接构造方法
Constructor[] constructors = vipClass.getDeclaredConstructors();
for(Constructor constructor : constructors){
//public Vip(int no, String name, String birth, boolean sex) {
s.append("\t");
s.append(Modifier.toString(constructor.getModifiers()));
s.append(" ");
s.append(vipClass.getSimpleName());
s.append("(");
// 拼接参数
Class[] parameterTypes = constructor.getParameterTypes();
for(Class parameterType : parameterTypes){
s.append(parameterType.getSimpleName());
s.append(",");
}
// 删除最后下标位置上的字符
if(parameterTypes.length > 0){
s.deleteCharAt(s.length() - 1);
}
s.append("){}\n");
}
s.append("}");
System.out.println(s);
}
}
运行结果:
通过反射机制调用构造方法实例化java对象。
示例代码13:
public class ReflectTest12 {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
//不使用反射通过构造器创建对象
Vip vip1 = new Vip();
Vip vip = new Vip(110,"zhagnsan","1997-09-19",true);
//获取类型
Class Vip2 = Class.forName("com.newstudy.javase.bean.Vip");
//通过无参构造方法反射实例化Vip对象
Object o = Vip2.newInstance();
System.out.println(o);
//通过反射调用构造器创建方法
//调用有参构造方法
//先获取有参构造方法
Constructor constructor = Vip2.getDeclaredConstructor(int.class, String.class, String.class, boolean.class);
Object o1 = constructor.newInstance(100,"jiameihong","2022-19-9",false);
System.out.println(o1);
}
}
public class Vip {
private int no;
private String name;
private String birth;
boolean sex;
public Vip() {
}
public Vip(int no, String name, String birth, boolean sex) {
this.no = no;
this.name = name;
this.birth = birth;
this.sex = sex;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getBirth() {
return birth;
}
public void setBirth(String birth) {
this.birth = birth;
}
public boolean isSex() {
return sex;
}
public void setSex(boolean sex) {
this.sex = sex;
}
@Override
public String toString() {
return "Vip{" +
"no=" + no +
", name='" + name + '\'' +
", birth='" + birth + '\'' +
", sex=" + sex +
'}';
}
}
运行结果:
通过反射机制怎么获取这个类的父类,和它自己已经实现的接口
示例代码14:
public class RefectTest13 {
public static void main(String[] args) throws ClassNotFoundException {
//获取类型
Class stringclass = Class.forName("java.lang.String");
//获取类型的父类
Class superclass = stringclass.getSuperclass();
System.out.println(superclass.getName());
// 获取String类实现的所有接口(一个类可以实现多个接口。)
Class[] interfaces = stringclass.getInterfaces();
for(Class in : interfaces){
//输出实现接口的名字
System.out.println(in.getName());
}
}
}
运行结果:
资源绑定器
java.util包下提供了一个资源绑定器,便于获取属性配置文件中的内容。
使用以下这种方式的时候,属性配置文件xxx.properties必须放到类路径下。
示例代码15:
public class ResourceBundleTest4 {
public static void main(String[] args) {
// 资源绑定器,只能绑定xxx.properties文件。并且这个文件必须在类路径下。文件扩展名也必须是properties
// 并且在写路径的时候,路径后面的扩展名不能写。
ResourceBundle bundle = ResourceBundle.getBundle("classinfo2");
ResourceBundle bundle1 = ResourceBundle.getBundle("com/newstudy/javase/bean/db");
//通过key获取value
String classname = bundle.getString("classname");
System.out.println(classname);
String classname1 = bundle1.getString("classname");
System.out.println(classname1);
}
}
运行结果:
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/94238.html