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 对象,依照正则表达式,该对象可以与任意字符序列匹配.执行匹配所涉及的所有状态都驻留在匹配器中,所以多个 ...
随机推荐
- 配置DNS域名解析服务
概: DNS技术作为互联网基础设施中的重要一环,为用户提供不间断.稳定且快速的域名查询服务,保证互联网正常运转.在互联网中,用户基本上都是基于DNS服务,使用域名访问网络上的计算机,DNS服务是我 ...
- 齐博x1文本代码标签的使用
文本标签虽然简单,但是使用的地方确实非常多的. {qb:tag name="XXXX" type="text"}推荐新闻{/qb:tag} 类似这种使用的频率是 ...
- breakout靶机
breakout:https://www.vulnhub.com/entry/empire-breakout,751/ 开机显示ip也可以不用扫描 首先使用nmap扫描 去访问网页 使用dirb扫描这 ...
- 【高并发】深度解析ScheduledThreadPoolExecutor类的源代码
在[高并发专题]的专栏中,我们深度分析了ThreadPoolExecutor类的源代码,而ScheduledThreadPoolExecutor类是ThreadPoolExecutor类的子类.今天我 ...
- JS中对DOM元素的操作
https://www.runoob.com/jquery/jquery-ref-html.html 1.each 遍历 //遍历所有class为checksingle的DOM元素 $(" ...
- iOS- 最全的真机测试教程
想要上架的同学请看:<iOS-最全的App上架教程> 因为最近更新了Xcode 8 ,证书的创建都大同小异,只是在Xcode 8中的设置有一些变化,我就在下面补充,如有什么疑问,请联系 ...
- 【lwip】07-链路层收发以太网数据帧源码分析
目录 前言 7.1 链路层概述 7.2 MAC地址的基本概念 7.3 以太网帧结构 7.4 以太网帧结构 7.5 以太网帧报文数据结构 7.6 发送以太网数据帧 7.7 接收以太网数据帧 7.8 虚拟 ...
- JS 学习笔记(一)常用的字符串去重方法
要求:从输入框中输入一串字符,按回车后输出去重后的字符串 方法一: <body> <input type="text" id="input" ...
- Spring三级缓存解决循环依赖
前提知识 1.解决循环依赖的核心依据:实例化和初始化步骤是分开执行的 2.实现方式:三级缓存 3.lambda表达式的延迟执行特性 spring源码执行逻辑 核心方法refresh(), popula ...
- 如何使用webgl(three.js)实现3D储能,3D储能站,3D智慧储能、储能柜的三维可视化解决方案——第十七课
前言 上节课我们讲了<3D光伏发电>,与之配套的就是能量存储 这节课我们主要讲讲储能,储能站,在分布式能源系统中起到调节用对电的尖峰平谷进行削峰填谷的作用.特别是小型储能站,更加灵活,因地 ...