目录

1、反射机制的作用

2、获取一个类的实例

3、使用Class.forName()方法加载类的静态代码块

4、获取配置文件的路径

5、java反编译

5.1、获取类中的成员变量

5.2、通过类名反编译出类的信息

5.3、使用反射机制去访问对象属性

5.4、使用反射获取类中的方法

5.5、通过反射机制调用类中的方法

5.6、通过反射调用构造方法

5.7、使用反射获取类的父类和父接口


1、反射机制的作用

通过java语言中的反射机制可以操作字节码文件,通过反射机制可以操作代码片段(class文件)

反射机制相关类

java.lang.reflect

java.lang,Class:代表整个字节符,代表一个类型

java.lang.reflect.Method:代表字节码中的方法字节码

java.lang.reflect.Constructor:代表字节码中的构造方法字节码

java.lang.reflect.Field:代表字节码中的属性字节码

在java中获取Class的三种方式

方式一:Class c=Class.forName("完整类名");

方式一:Class c=对象.getClass();

方式三:Class c=int.class;

package Reflect;

/*
在java中获取Class的三种方式
*/
public class ReflectTest01_1 {
public static void main(String[] args) throws ClassNotFoundException {
String ss = new String("abc");
Class c1 = Class.forName("java.lang.String"); //使用Class.forName()获取类
Class c2 = ss.getClass(); //使用getClass()获取对象的Class
Class c3 = String.class; //使用class获取类
System.out.println("使用Class.forName()获取类:" + c1);
System.out.println("使用getClass()获取对象的Class:" + c2);
System.out.println("使用class获取类:" + c3);
}
}

2、获取一个类的实例

要操作一个类的字节码,首先要获取这个类的字节码。

获取类的实例有三种方式

方式一、使用Class.forName获取类的实例

package Reflect;

/*
要操作一个类的字节码,需要首先获取到这个类的字节码
*/
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"); //获取String类的一个实例
Class c2 = Class.forName("java.util.Date"); //获取Date类的一个实例
Class c3 = Class.forName("java.lang.Integer"); //获取Integer类的一个实例
System.out.println(c1);
System.out.println(c2);
System.out.println(c3); String s = new String("abc");
Class x = s.getClass();
System.out.println(c1 == x); // "=="比较的是地址
}
}

方式二、通过反射机制获取Class,通过Class来实例化对象

User类

package Reflect;

public class User {
public User() {
}
}

主方法

package Reflect;

public class ReflectTest02 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
//通过反射机制,获取Class,通过Class来实例化对象
Class c = Class.forName("Reflect.User");
//newInstance方法会调用User类的无参数构造方法,完成对象的创建
Object obj = c.newInstance();
System.out.println(obj);
}
}

注:newInstance()底层调用的是该类的无参数构造方法。如果没有这个无参数构造方法会出现异常

Class类中的newInstance()方法

public T newInstance()
throws InstantiationException, IllegalAccessException

方式三、通过配置文件配置类,来获取类的实例

配置文件:classinfo.properties

package Reflect;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Date;
import java.util.Properties; public class ReflectTest03 {
public static void main(String[] args) throws IOException, ClassNotFoundException, IllegalAccessException, InstantiationException { //这种方式代码就写死了。只能创建一个Date类型的对象
Date d=new Date(); //通过IO流读取classinfo.properties文件 classinfo.properties D:\学习资料\java\java\classinfo.properties
FileReader reader=new FileReader("D:\\学习资料\\java\\java\\classinfo.properties");
//创建属性类对象Map
Properties pro=new Properties(); //key value都是String
//加载
pro.load(reader);
//关闭流
reader.close(); //通过key获取value
String className=pro.getProperty("className");
System.out.println(className); //通过反射机制实例化对象
Class c=Class.forName(className);
Object obj=c.newInstance(); //c.new Instance()会获取对象c的构造方法:public Date() {this(System.currentTimeMillis());返回当前时间 }
System.out.println(obj);
}
}

注:许多高级框架(ssm,SpringMVC,Springboot.....都采用了反射机制)

3、使用Class.forName()方法加载类的静态代码块

package Reflect;

public class ReflectTest04 {
public static void main(String[] args) throws ClassNotFoundException {
Class.forName("Reflect.MyClass"); //只加载 MyClass类的静态代码块
}
} class MyClass {
public static void main(String[] args) {
System.out.println("MyClass类非静态代码块执行了"); //不被加载
} static {
System.out.println("MyClass类静态代码块执行了");
}
}

延伸:在JDBC技术中也会使用到Class.forName()方法加载数据库驱动类

例:在数据库连接类中使用Class.forName()方法加载sqljdbc.jar包中的SQLServerDriver类的静态代码块

数据库连接类

private static String driver = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
private static String url = "jdbc:sqlserver://localhost:1433;databaseName = CivilAviationTicketSystem",
user = "AAA", password = "123456";
private static Connection conn = null;
static {
try {
Class.forName(driver); // 加载SQLServerDriver类中的静态代码块
} catch (Exception ex) {
ex.printStackTrace();
}
}

SQLServerDriver类

static
{
try
{
DriverManager.registerDriver(new SQLServerDriver());
}
catch (SQLException localSQLException) {
localSQLException.printStackTrace();
}
}

4、获取配置文件的路径

package Reflect;

/*
获取文件路径
可以通过以下方式获取文件的绝对路径,但前提是文件必须在类路径下(文件放在src目录下)
*/
public class Path {
public static void main(String[] args) {
/*
Thread.currentThread():当前线程对象
getContextClassloader():获取当前线程的类加载器对象
getResource():【获取资源】这是类加载数据对象的方法
*/
String path = Thread.currentThread().getContextClassLoader().
getResource("classinfo2.properties").getPath(); //!!! 获取的文件一定要放在类路径下(src路径下)
System.out.println(path);
}
}

5、java反编译

5.1、获取类中的成员变量

getFields()和 getDeclaredFields()方法
package Reflect;

import java.lang.reflect.Field;

public class ReflectTest05 {
public static void main(String[] args) throws ClassNotFoundException {
//获取整个类
Class studentClass = Class.forName("Reflect.Student"); Field[] fields = studentClass.getFields(); //getFields()只能获取类中的public修饰的Field
Field[] fields_all = studentClass.getDeclaredFields(); //getDeclaredFields()可以获取类中所有的Field
System.out.println("getFields方法获取的field个数:" + fields.length);
System.out.println("getDeclaredFields方法获取的field个数:" + fields_all.length);
//取出这个Field
Field f = fields[0];
//取出这个field它的名字
String fieldName = f.getName();
System.out.println("getFields方法获取的field:" + fieldName);
System.out.print("getDeclaredFields方法获取的field:");
for (Field field : fields_all) {
System.out.print(field.getName() + ",");
}
}
}

5.2、通过类名反编译出类的信息

获取java.lang.String类中的成员变量信息

package Reflect;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier; public class ReflectTest06 {
public static void main(String[] args) throws ClassNotFoundException {
//创建这个是为了拼接字符串
StringBuilder s = new StringBuilder();
Class studentClass = Class.forName("java.lang.String");
//获取public class Student {
s.append(Modifier.toString(studentClass.getModifiers()) + "class" + studentClass.getSimpleName() + "{\n");
Field[] fields = studentClass.getDeclaredFields();
//拿类的成员变量
for (Field field : fields) {
s.append("\t"); //修饰符前的缩进(制表符)
s.append(Modifier.toString(field.getModifiers())); //修饰符
s.append(" "); //修饰符后的空格
s.append(field.getType().getSimpleName()); //获取类型(getType为获取类型的复杂名字),getSimpleName为获取类型的简单名
s.append(field.getName()); //获取成员变量
s.append(";\n");
}
s.append("}");
System.out.println(s);
}
}

5.3、使用反射机制去访问对象属性

Student类

package Reflect;

public class Student {
public int no;
private String name;
protected int age;
boolean sex;
}
package Reflect;

import java.lang.reflect.Field;

/*
使用反射机制去访问一个对象的属性
*/
public class ReflectTest07 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
Class studentClass = Class.forName("Reflect.Student");
Object obj = studentClass.newInstance(); //obj是Student的对象(底层调用无参数构造方法)
//获取no属性(根据属性的名称来获取Field)
Field noField = studentClass.getDeclaredField("no"); //给obj对象(Student对象)的no属性赋值
noField.set(obj, 2020); //读取属性的值
//两个要素:获取obj对象的no属性的值
System.out.println(noField.get(obj));
}
}

通过反射打破封装,访问私有属性。

使用 setAccessible(true)打破封装,但会留下漏洞。

package Reflect;

import java.lang.reflect.Field;

public class ReflectTest07_1 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
Class studentClass = Class.forName("Reflect.Student");
Object obj = studentClass.newInstance(); //obj是Student的对象(底层调用无参数构造方法)
//获取no属性(根据属性的名称来获取Field)
Field noField = studentClass.getDeclaredField("name"); //打破封装(但使用反射机制打破封装会留下漏洞)
//这样设置完后,在外部也是可以访问private的
noField.setAccessible(true); //给obj对象(Student对象)的no属性赋值
noField.set(obj, "张三"); //读取属性的值
//两个要素:获取obj对象的no属性的值
System.out.println(noField.get(obj));
}
}

5.4、使用反射获取类中的方法

UserService类
package Reflect;

public class UserService {
public boolean login(String username, String password) {
return true;
} public boolean loginout() {
return true;
}
}

获取UserService类中的方法

package Reflect;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier; public class ReflectTest08 {
public static void main(String[] args) throws ClassNotFoundException {
//获取类
Class userServiceClass = Class.forName("Reflect.UserService"); //获取所有的 Method(包括私有)
Method[] methods = userServiceClass.getDeclaredMethods(); //遍历所有Method
for (Method method : methods) {
//获取修饰符
System.out.print(Modifier.toString(method.getModifiers()) + " ");
//获取方法的返回值类型
System.out.print(method.getReturnType().getSimpleName() + " "); //获取方法名
System.out.print(method.getName() + " "); //获取方法的形参
Class[] parameter = method.getParameterTypes();
for (Class p : parameter) {
System.out.print(p.getSimpleName() + " ");
}
System.out.println();
}
}
}

5.5、通过反射机制调用类中的方法

UserService类
package Reflect;

public class UserService {
public boolean login(String username, String password) {
if (username.equals("2020") && password.equals("123")) {
return true;
}
return false;
} public boolean loginout() {
return true;
}
}

使用反射调用UserService类中的login方法

package Reflect;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; /*
通过反射机制调用对象的方法
*/
public class ReflectTest9 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
//获取类
Class userServiceClass = Class.forName("Reflect.UserService");
//创建对象
Object obj = userServiceClass.newInstance();
//获取Method 方法名:login 形参 String,String
Method loginMethod = userServiceClass.getDeclaredMethod("login", String.class, String.class);
Object result = loginMethod.invoke(obj, "2020", "123"); //调用方法传入形参获取返回值
System.out.println(result);
}
}

通过反射机制,让代码更具有通用性,可变化的内容都是写在配置文件中的,将来修改配置文件后,创建的对象不一样,调用的方法也不同了。但是java代码不需要做任何改动。

5.6、通过反射调用构造方法

newInstance()可以调用无参构造方法(若对象的类中没有无参构造方法,会报错)
getDeclaredConstructor()可以获取有参数的构造方法

一个实例

User类

package Reflect;

public class User {
private int no;
private String sex;
private String name; public User() {
} public User(int no, String sex, String name) {
this.no = no;
this.sex = sex;
this.name = name;
} @Override
public String toString() {
return "User{" +
"no=" + no +
", sex='" + sex + '\'' +
", name='" + name + '\'' +
'}';
}
}
package Reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException; /*
使用反射机制获取构造方法
*/
public class ReflectTest10 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException {
Class c = Class.forName("Reflect.User"); //获取类对象
Object obj = c.newInstance(); //调用无参构造方法
System.out.println("调用无参构造方法:" + obj); /**
* 调用有参构造方法
*/
//先获取到这个有参数的构造方法
Constructor constructor = c.getDeclaredConstructor(int.class, String.class, String.class);
//调用构造方法new对象
Object newobj = constructor.newInstance(2020, "张三", "男");
System.out.println("调用有参构造方法:" + newobj.toString());
}
}

5.7、使用反射获取类的父类和父接口

获取String类的父类和实现的接口

package Reflect;

/*
使用反射机制获取父类和父接口
*/
public class ReflectTest11 {
public static void main(String[] args) throws ClassNotFoundException {
Class stringClass = Class.forName("java.lang.String"); //获取String的父类
Class superClass = stringClass.getSuperclass();
System.out.println("String的父类为:" + superClass.getName());
System.out.println();
//获取String类实现的所有接口
Class[] interfaces = stringClass.getInterfaces();
System.out.println("String类实现的接口:");
for (Class in : interfaces) {
System.out.println(in.getName());
}
}
}

java反射基础知识整理的更多相关文章

  1. java部分基础知识整理----百度脑图版

    近期发现,通过百度脑图可以很好的归纳总结和整理知识点,本着学习和复习的目的,梳理了一下java部分的知识点,不定期更新,若有不恰之处,请指正,谢谢! 脑图链接如下:java部分基础知识整理----百度 ...

  2. java反射基础知识(五)反射应用实践

    详解Java反射各种应用   Java除了给我们提供在编译期得到类的各种信息之外,还通过反射让我们可以在运行期间得到类的各种信息.通过反射获取类的信息,得到类的信息之后,就可以获取以下相关内容: Cl ...

  3. java反射基础知识(四)反射应用实践

    反射基础 p.s: 本文需要读者对反射机制的API有一定程度的了解,如果之前没有接触过的话,建议先看一下官方文档的Quick Start. 在应用反射机制之前,首先我们先来看一下如何获取一个对象对应的 ...

  4. java反射基础知识(三)

    原文地址:http://tutorials.jenkov.com/java-reflection/index.html http://www.cnblogs.com/penghongwei/p/329 ...

  5. java反射基础知识(二)

    1. 了解 Java 中的反射 1.1 什么是 Java 的反射 Java 反射是可以让我们在运行时获取类的函数.属性.父类.接口等 Class 内部信息的机制.通过反射还可以让我们在运行期实例化对象 ...

  6. java反射基础知识(一)

    一.反射 反射:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为 ...

  7. java注解基础知识整理

    目录 1.注解的定义 1.1.定义一个注解 1.2.注解的使用 2.JDK内置注解 2.1.java.lang包下的注释类型 2.2.元注解 2.3.Deprecated注解 3.在注解中定义属性 3 ...

  8. Java反射基础知识

    反射机制就是可以把一个类,类的成员(属性.方法)当成一个对象来操作,也就是说,类,类的成员,我们在运行的时候可以动态的去操作它们. 所有的Java类都继承了Object类,在Object类中定义了一个 ...

  9. Java正则表达式基础知识整理

    指定为字符串的正则表达式必须首先被编译为此类的实例.然后,可将得到的模式用于创建 Matcher 对象,依照正则表达式,该对象可以与任意字符序列匹配.执行匹配所涉及的所有状态都驻留在匹配器中,所以多个 ...

随机推荐

  1. 手把手教你玩转 Gitea|在 Windows 系统上安装 Gitea

    Gitea 支持在 Windows 系统上安装和使用.Gitea 本身作为一个单体应用程序,即点即用,如需长期驻留作为后台服务并开机运行就要依靠 Windows 服务工具 sc.exe. 通过本文,你 ...

  2. Docker | 容器互联互通

    上篇讲到创建自定义网络,我创建了 mynet 网络,并指定了网关和子网地址.在上篇结尾呢,我抛出了一个问题:其它网络下的容器可以直接访问mynet网络下的容器吗?今天就让我们一块看下怎么实现容器互联. ...

  3. 软件架构(六)MVC架构历史

    一.引子 一个系统可能由很多子系统组成.各子系统内部高度内聚,子系统之间低耦合.子系统关注自己的职责.实现:   职责分离,关注点分离.----MVC架构早期就是为了分离视图.模型而诞生的. 注:很多 ...

  4. 每日算法3:随机生成五个不同整数,将数字转换为RMB格式

    随机生成五个不同整数 点击查看代码 /* 题目解析: 1.采用Math对象的random()方法, 2.将每次生成的数跟之前的数判断相等则此次生成无效i-- */ function randomNum ...

  5. 二十二、Pod存储之volume

    Pod 的存储之volume ​容器磁盘上的文件的生命周期是短暂的,这就使得在容器中运行重要应用时会出现一些问题.首先,当容器崩溃时,kubelet 会重启它,但是容器中的文件将丢失--容器以干净的状 ...

  6. POC、EXP、SRC概念厘清

    「POC」 POC可以看成是一段验证的代码,就像是一个证据,能够证明漏洞的真实性,能证明漏洞的存在即可.     https://zhuanlan.zhihu.com/p/26832890 「EXP」 ...

  7. Arch Linux 的安装

    Arch Linux 的安装 作者:Grey 原文地址: 博客园:Arch Linux 的安装 CSDN:Arch Linux 的安装 版本 Arch Linux:2022.07.01 VMware ...

  8. 链表实现-回文palindrome判断

    1.数字回文判断(逆转,分离未位,砍掉个位,保存原来) s = s * 10 + a%10 a = a/10 2.字符串判断回文 package main //思路: 开发一个栈来来存放链表的上半段f ...

  9. 18道经典链表题刷题总结——WeetCode1 链表系列

    系列文章目录和关于我 前言: WeetCode = Week leetCode 寓意每周刷点leetCode 题目 链表是我恢复刷题手感最喜欢做的系列,其没用太多的算法思想,单纯考验对指针的理解,和c ...

  10. Springboot+Mybatis:启动报错 String index out of range: -37

    springBoot+Druid+Mybatis :启动错误描述 Error parsing SQL Mapper Configuration. Cause: java.lang.StringInde ...