java反射基础知识整理
目录
3、使用Class.forName()方法加载类的静态代码块
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反射基础知识整理的更多相关文章
- java部分基础知识整理----百度脑图版
近期发现,通过百度脑图可以很好的归纳总结和整理知识点,本着学习和复习的目的,梳理了一下java部分的知识点,不定期更新,若有不恰之处,请指正,谢谢! 脑图链接如下:java部分基础知识整理----百度 ...
- java反射基础知识(五)反射应用实践
详解Java反射各种应用 Java除了给我们提供在编译期得到类的各种信息之外,还通过反射让我们可以在运行期间得到类的各种信息.通过反射获取类的信息,得到类的信息之后,就可以获取以下相关内容: Cl ...
- java反射基础知识(四)反射应用实践
反射基础 p.s: 本文需要读者对反射机制的API有一定程度的了解,如果之前没有接触过的话,建议先看一下官方文档的Quick Start. 在应用反射机制之前,首先我们先来看一下如何获取一个对象对应的 ...
- java反射基础知识(三)
原文地址:http://tutorials.jenkov.com/java-reflection/index.html http://www.cnblogs.com/penghongwei/p/329 ...
- java反射基础知识(二)
1. 了解 Java 中的反射 1.1 什么是 Java 的反射 Java 反射是可以让我们在运行时获取类的函数.属性.父类.接口等 Class 内部信息的机制.通过反射还可以让我们在运行期实例化对象 ...
- java反射基础知识(一)
一.反射 反射:JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为 ...
- java注解基础知识整理
目录 1.注解的定义 1.1.定义一个注解 1.2.注解的使用 2.JDK内置注解 2.1.java.lang包下的注释类型 2.2.元注解 2.3.Deprecated注解 3.在注解中定义属性 3 ...
- Java反射基础知识
反射机制就是可以把一个类,类的成员(属性.方法)当成一个对象来操作,也就是说,类,类的成员,我们在运行的时候可以动态的去操作它们. 所有的Java类都继承了Object类,在Object类中定义了一个 ...
- Java正则表达式基础知识整理
指定为字符串的正则表达式必须首先被编译为此类的实例.然后,可将得到的模式用于创建 Matcher 对象,依照正则表达式,该对象可以与任意字符序列匹配.执行匹配所涉及的所有状态都驻留在匹配器中,所以多个 ...
随机推荐
- CentOS 7.9 安装 rocketmq-4.9.2
一.CentOS 7.9 安装 rocketmq-4.9.2 地址: https://rocketmq.apache.org https://github.com/apache/rocketmq ht ...
- 洛谷P2866 [USACO06NOV]Bad Hair Day S (单调栈)
看到这道题很容易想到单调栈,但我一开始想的是从后往前扫,但发现会有问题(因为这样会对后面牛的答案造成影响),所以这时我们要及时换一个思路,从前往后扫. 维护一个单调递减的栈,插入h[i]时,小等于它的 ...
- CVPR2022 Oral OGM-GE阅读笔记
标题:Balanced Multimodal Learning via On-the-fly Gradient Modulation(CVPR 2022 Oral) 论文:https://arxiv. ...
- 基于SqlSugar的开发框架循序渐进介绍(15)-- 整合代码生成工具进行前端界面的生成
在前面随笔<基于SqlSugar的开发框架循序渐进介绍(12)-- 拆分页面模块内容为组件,实现分而治之的处理>中我们已经介绍过,对于相关的业务表的界面代码,我们已经尽可能把不同的业务逻辑 ...
- Charles的安装与使用
Charles是一款抓包工具,可以用来截取和发送手机APP上的各种请求 在windows上安装Charles,确保手机和电脑在同一个WIFI下,加上一些配置,就可以抓取手机上的APP请求 有能力的同学 ...
- 成功解决:Can‘t find Python executable “python“, you can set the PYTHON env variable.
今天跑公司新项目的时候.运行前端vue.报了一个关于python的错误.就离谱 1.问题报错全部代码 actual version of core-js. npm ERR! code 1 npm ER ...
- 了解 Flutter 开发者们的 IDE 使用情况
作者 / JaYoung Lee, UX Researcher at Google Google 的 Flutter 团队负责构建和维护 Android Studio (基于 IntelliJ-IDE ...
- 1.-Django项目结构
一.Django简介 Django是一个开放源代码的Web应用框架,由Python写成.采用了MTV的框架模式,即模型M,视图V和模版T. Django基本组件: 1.基本配置文件/路由系统 2. ...
- vim常用快捷键总结一(光标移动命令)
vim编辑器的工作模式分为3种即(命令模式,编辑模式和尾行模式),具体定义这里就不在赘述了,这里只简单介绍各工作模式下对应的操作和快捷方式. 通常来说三三种模式功能划分大致如下 命令模式:定位.翻页. ...
- 秀++视频算法仓库-厂家对接规约V5
一.概要 (1)每个算法厂家在秀++云平台上会有一个厂商标识,譬如CS101:算法厂家可能有多个算法引擎,每个引擎有一个标识譬如Q101,引擎可以理解为一个可执行程序,可以同时分析多路算法:每个算法在 ...