目录

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. 洛谷P3391 文艺平衡树 (Splay模板)

    模板题. 注意标记即可,另外,涉及区间翻转操作,记得设立首尾哨兵. 1 #include<bits/stdc++.h> 2 using namespace std; 3 const int ...

  2. HDU2041 超级楼梯 (线性DP)

    fn[i]表示走上第i级台阶的所有走法. 方程:fn[i]=fn[i-1]+fn[i-2]; 1 #include<cstdio> 2 #define MAXN 40 3 using na ...

  3. POJ3260 The Fewest Coins(混合背包)

    支付对应的是多重背包问题,找零对应完全背包问题. 难点在于找上限T+maxv*maxv,可以用鸽笼原理证明,实在想不到就开一个尽量大的数组. 1 #include <map> 2 #inc ...

  4. 关于.Net 7.0 RC gRPC JSON 转码为 Swagger/OpenAPI文档的注意事项

    大家好,我是失业在家,正在找工作的博主Jerry,找工作之余,看到.Net 7.0 RC2发布了,就想测试下.Net 7.0 RC2 gRPC JSON 转码为 Swagger/OpenAPI文档的特 ...

  5. echarts的使用 超好用的报表制作、数据的图形化展示

    地址链接:https://echarts.apache.org/zh/index.html 1.图形选择 2.对应的js代码

  6. Spring 深入——IoC 容器 02

    IoC容器的实现学习--02 目录 IoC容器的实现学习--02 回顾 IoC 容器的初始化过程: BeanDefinition 的 Resource 定位 小结: 回顾 前面学习了 IoC 模式的核 ...

  7. Abp.Zero 手机号免密登录验证与号码绑定功能的实现(一):验证码模块

    这是一篇系列博文,我将使用Abp.Zero搭建一套集成手机号免密登录验证与号码绑定功能的用户系统: Abp.Zero 手机号免密登录验证与号码绑定功能的实现(一):验证码模块 Abp.Zero 手机号 ...

  8. vs 自定义代码块

    代码自动生成,让代码飞~ 我目前用的是vs2013,c,c++用的多,vs自带了一套代码块规则,下面我们就以for举例子. 1 原生代码块怎么使用 输入for后按Tab键: 这时候可以修改 size_ ...

  9. Oracle:ORA-00911: invalid character解决办法

    问题记录:用jmeter执行sql语句,报错:ORA-00911: invalid character. 解决方法:sql语句末尾";"导致,去掉即可解决. 过程记录: 使用jme ...

  10. Oracle数据泵导入dmp文件,报UDI-00013、UDI-00019错误原因

    这个问题挺简单,想了想,还是记录下吧. [root@ufdb165 bin]# ./impdp cwy_init0914/cwy_123456789@ufgovdb1 directory=DATA_P ...