最全Java反射专题笔记总结:一篇文章带你理清反射(1),Java岗面试12家大厂成功跳槽

言尽于此,完结

无论是一个初级的 coder,高级的程序员,还是顶级的系统架构师,应该都有深刻的领会到设计模式的重要性。

  • 第一,设计模式能让专业人之间交流方便,如下:

程序员A:这里我用了XXX设计模式

程序员B:那我大致了解你程序的设计思路了

  • 第二,易维护

项目经理:今天客户有这样一个需求…

程序员:明白了,这里我使用了XXX设计模式,所以改起来很快

  • 第三,设计模式是编程经验的总结

程序员A:B,你怎么想到要这样去构建你的代码

程序员B:在我学习了XXX设计模式之后,好像自然而然就感觉这样写能避免一些问题

  • 第四,学习设计模式并不是必须的

程序员A:B,你这段代码使用的是XXX设计模式对吗?

程序员B:不好意思,我没有学习过设计模式,但是我的经验告诉我是这样写的

image

从设计思想解读开源框架,一步一步到Spring、Spring5、SpringMVC、MyBatis等源码解读,我都已收集整理全套,篇幅有限,这块只是详细的解说了23种设计模式,整理的文件如下图一览无余!

image

搜集费时费力,能看到此处的都是真爱!

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

Constructor的使用:

//获得无参构造器

Constructor<?> Noconstructor = clazz.getConstructor();

System.out.println(“无参constructor:”+Noconstructor);

//获得有参构造器

Constructor<?> Allconstructor = clazz.getConstructor(String.class);

System.out.println(“无参constructor:”+Allconstructor);

3.反射优点和缺点:


优点:

可以动态的创建和使用对象(也是框架底层核心),使用灵活,没有反射机制,框架技术就失去底层支撑

缺点

使用反射基本是解释执行,对执行速度有印象,直接new出对象速度是反射出对象的几十倍

4.传统方式与反射的效率对比:


package com.hspedu.reflection;

import com.hspedu.Cat;

import java.io.FileInputStream;

import java.io.InputStreamReader;

import java.lang.reflect.Method;

import java.util.Properties;

/**

  • Description:测试反射的性能和优化方案

  • User:

  • Date:

  • Time:

*/

public class Reflection02 {

public static void main(String[] args) throws Exception {

m1();

m2();

}

public static void m1(){

//普通new

Cat cat = new Cat();

long Newstart = System.currentTimeMillis();

for (int i =0;i<1000000;i++){

cat.hi();

}

long Newend = System.currentTimeMillis();

System.out.println(“传统方式耗时:”+(Newend-Newstart));

}

public static void m2() throws Exception{

//反射创建

Properties properties = new Properties();

properties.load(new FileInputStream(“src\re.properties”));

String classfullpath = properties.get(“classfullpath”).toString();

Class<?> clazz = Class.forName(classfullpath);

Method hi = clazz.getMethod(“hi”);

Cat cat2 = (Cat)clazz.newInstance();

long Refstart = System.currentTimeMillis();

for (int i =0;i<1000000;i++){

hi.invoke(cat2);

}

long Refend = System.currentTimeMillis();

System.out.println(“反射方式耗时:”+(Refend-Refstart));

}

}

在这里插入图片描述

对反射方式进行优化:

setAccessible(true)

反射调用优化-关闭访问检查:

  1. Method和Field、Constructor对象都有setAccessible()方法
  1. setAccessible作用是启动和禁用访问安全检查的开关
  1. 参数为true表示反射的对象在使用时取消访问检查,提高反射的效率。参数值为false则表示反射的对象执行访问检查

优化之后:

在这里插入图片描述

三、Class类

======================================================================

1.Class也是类,因此也继承Object类


Class类图结构

在这里插入图片描述

2.Class类对象不是new出来的,而是系统创建的


传统的new出对象的方式

Cat cat = new Cat();

我们进入创建过程:

在这里插入图片描述

反射的方式

在这里插入图片描述

由此可见:

两者都是通过ClassLoader类加载Class对象

3.对于某个类的Class类对象,在内存中只有一份,因为类只加载一次


分别执行下面图中的代码

图一:

在这里插入图片描述

图二:

在这里插入图片描述

随着图一debug我们进入了loadClass方法:

在这里插入图片描述

随着图二debug我们没有进入loadClass方法

这是因为图二在执行Cat cat = new Cat()时已经将Cat类加载到内存中,在堆中只会存在一份Class类对象,所以执行时不会再次进入loadClass方法,

对象.getClass()

4.通过Class对象可以完整地得到一个类的完整结构,通过一系列API


每个类的实例都会记得自己是由哪个Class实例所生成


  1. Class getSuperClass() 返回当前Class对象的父类的Class对象
  1. Class[] getInterfaces() 返回当前Class对象的所有接口
  1. ClassLoader getClassLoader()返回该类的类加载器
  1. Class getSuperclass() 返回表示此Class所表示的实体的超类的Class

5.类的字节码二进制数据,是放在方法区的,有的地方称为类的元数据(包括方法代码,变量名,方法名,访问权限等等)


当类加载完毕后,我们的字节码对应的二进制数据加载到方法去中,除此之外在堆中会产生

一个Class类对象,这其实是一种数据结构,可以把成员变量映射成一个对象并对其操作

Class类方法演示:


创建Car类

public class Car {

public String brand=“品牌”;

public int price;

public String color;

}

package com.hspedu.reflection.class_;

import com.hspedu.Car;

import java.lang.reflect.Field;

/**

  • Description:演示Class类的常用方法

  • User:

  • Date:

  • Time:

*/

public class Class02 {

public static void main(String[] args) throws Exception {

String classAllPath = “com.hspedu.Car”;

Class<?> clazz = Class.forName(classAllPath);

//1.输出clazz

System.out.println(clazz);//显示clazz对象,是哪个类的Class对象 com.hspedu.Car

System.out.println(clazz.getClass());//输出clazz运行类型 java.lang.Class

//2.得到包名

System.out.println(clazz.getPackage().getName());

//3.得到全类名

System.out.println(clazz.getName());

//4.通过clazz创建对象实例

Car o = (Car)clazz.newInstance();

//5.通过反射获取属性

Field brand = clazz.getDeclaredField(“brand”);

System.out.println(brand.get(o));

//通过反射给属性赋值

brand.set(o,“奔驰”);

System.out.println(brand.get(o));

//遍历得到所有的属性

Field[] fields = clazz.getFields();

for (Field field : fields) {

System.out.println(field.get(o));

}

}

}

获取反射的四种方式


不同阶段获取Class的不同方式

1.前提:已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException

创建方式: Class.forName()

应用场景:多用于配置文件,读取类全路径,加载类

2.前提:若已知具体的类,通过类的class获取,该方式最为安全可靠,程序性能最高

创建方式: 类.class

应用场景:多用于参数传递,比如通过反射得到对应构造器对象

3.前提:已知某个类的实例,调用该实例的geiClass()方法获取Class对象

创建方式:对象.getClass()

应用场景:通过创建好的对象,获取Class对象

4.其他方式

ClassLoader cl = 对象.getClass().getClassLoader();

创建方式:Class clazz =cl.getloadClass(“类的全类名”);

代码示例:

package com.hspedu.reflection.class_;

import com.hspedu.Car;

/**

  1. Description:演示获取Class对象的四种方式

  2. User:

  3. Date:

  4. Time:

*/

public class GetClass {

public static void main(String[] args) throws Exception {

//1.Class.forName()

Class<?> cls1 = Class.forName(“com.hspedu.Car”);

//2.类名.class,应用场景:多用于参数传递

Class cls2 = Car.class;

//3.对象名.getClass()

Car car = new Car();

Class<? extends Car> cls3 = car.getClass();

//4.通过类加载器来获取类的Class对象

//先得到类加载器

ClassLoader classLoader = car.getClass().getClassLoader();

Class<?> cls4 = classLoader.loadClass(“com.hspedu.Car”);

}

}

四、哪些类型有Class对象

============================================================================

如下类型有Class对象

  1. 外部类,成员内部类,静态内部类,局部内部类,匿名内部类

  2. interface:接口

  3. 数组

  4. enum:枚举

  5. annotation:注解

  6. 基本数据类型

  7. void

五、动态加载和静态加载:

==========================================================================

类加载基本说明:


反射机制是java实现动态语言的关键,也就是通过反射实现类动态加载

  1. 静态加载:编译时加载相关的类,如果没有则报错,依赖性太强

  2. 动态加载:运行时加载需要的类,如果运行时不用该类,即使不存在该类,也不会报错,降低了依赖性

类加载时机:


  1. 当创建对象时(new)//静态加载

  2. 当子类被加载时,父类也加载//静态加载

  3. 调用类中的静态成员时//静态加载

  4. 通过反射//动态加载

代码示例:


在这里插入图片描述

也就是说,静态加载是不论程序是否会执行A代码,A都会被加载,而动态加载是说,只有在真正要用到A段代码时,A代码才会被加载

类加载过程图:


在这里插入图片描述

类加载的三个阶段的任务:

在这里插入图片描述

类加载各个阶段的介绍:


一、加载阶段Loading

JVM在该阶段的主要目的时将字节码从不同的数据源(可能是class文件、也可能是jar包,甚至网络)转化为二进制字节流加载到内存中,并生成一个代表该类的java.lang.Class对象

二、连接阶段Linking

连接阶段-验证:
  1. 目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机中的要求,并且不会危害虚拟机自身的安全

  2. 包括:文件格式验证(是否以魔数oxcafebabe开头)、元数据校验、字节码验证和符号饮用验证

  3. 可以考虑使用-Xverify:none参数来关闭大部分的类验证措施,缩短虚拟机类加载的时间

连接阶段-准备:

代码案例:

class A{

//连接阶段-准备

//1.n1是实例属性,不是静态变量,因此在连接阶段-准备时不会被分配内存

//2.n2是静态变量,分配内存 n2 是默认在此阶段初始化,值为0,只有在连接阶段后的初始化阶段值才会被初始化为20

//3.n3是常量,他和静态变量不一样,因为一旦赋值就不会改变,所以n3此阶段值为30

public int n1=10;

public static int n2=20;

public static final int n3=30;

}

连接阶段-解析:

虚拟机将常量池内的符号引用替换为直接引用的过程

比如A类中有B类的引用,但只作为符号存在,只有在解析阶段才会将这类的符号引用解析为直接引用

三、初始化阶段Initialization

  1. 到初始化阶段,才真正开始执行类中定义的Java程序代码,此阶段是执行()方法的过程

  2. clinit()方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中所有静态变量的赋值动作和静态代码块中的语句,并进行合并

  3. 虚拟机会保证一个类的()方法在多线程环境中被正确地加锁,同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的()方法,其他线程都需要阻塞等待,直到活动线程执行()方法完毕

代码展示:

package com.hspedu.reflection.classload_;

/**初始化过程

  • Description

  • User:

  • Date:

  • Time:

*/

public class ClassLoad03 {

public static void main(String[] args) {

//1.加载B类,并生成B的Class对象

//2.连接 num = 0;

//3.初始化

// 依次自动收集类中所有静态变量的赋值动作和静态代码块中的语句,并合并,

//先执行静态代码块中的代码,再执行静态变量

/*

clinit() {

System.out.println(“B 静态代码块被执行”);

num = 300;

static int num = 100;

}

合并:num=100

*/

// new B();

System.out.println(B.num);

}

}

class B{

static {

System.out.println(“B 静态代码块被执行”);

num = 300;

}

static int num = 100;

public B(){

System.out.println(“B() 构造器被执行”);

}

}

JVM对于clinit方法的加锁机制,在加载类的时候有同步机制控制


protected Class<?> loadClass(String name, boolean resolve)

throws ClassNotFoundException

{

synchronized (getClassLoadingLock(name)) {

}

六、通过反射获取类的结构信息

============================================================================

java.lang.Class类方法:


  1. 1.getName:获取全类名

  2. getSimpleName:获取简单类名

  3. getFields:获取所有public 修饰的属性,包括本类以及父类的

  4. getDeclareFields:获取本类中的所有属性

  5. getMethods:获取所有public修饰的方法,包括本类以及父类的

  6. getDeclaredMethods:获取本类中的所有方法

  7. getConstructors:获取所有public修饰的构造器

  8. getDeclaredConstructors:获取本类中所有构造器

  9. getPackage:以Package形式返回包信息

  10. getSuperClass:以Class形式返回父类信息

  11. getInterfaces:以Class[]形式返回接口信息

  12. getAnnotations:以Annotation[]形式返回注解信息

代码示例:

package com.hspedu.reflection;

import java.lang.annotation.Annotation;

import java.lang.reflect.Constructor;

import java.lang.reflect.Field;

import java.lang.reflect.Method;

/**

  • Description:演示如何通过

  • User:

  • Date:

  • Time:

*/

public class ReflectionUtils {

public static void main(String[] args) throws Exception {

api1();

}

public static void api1() throws Exception{

Class<?> clazz = Class.forName(“com.hspedu.reflection.A”);

Object o = clazz.newInstance();

// 1. getName:获取全类名

System.out.println(“获取全类名:”+clazz.getName());

// 2. getSimpleName:获取简单类名

System.out.println(“获取简单类名:”+clazz.getSimpleName());

// 3. getFields:获取所有public 修饰的属性,包括本类以及父类的

Field[] fields = clazz.getFields();

for (Field field : fields) {

System.out.println(“public属性:”+field.getName());

}

// 4. getDeclareFields:获取本类中的所有属性

Field[] fields2 = clazz.getDeclaredFields();

for (Field field : fields2) {

System.out.println(“全部属性:”+field.getName());

}

// 5. getMethods:获取所有public修饰的方法,包括本类以及父类的

Method[] methods = clazz.getMethods();

for (Method method : methods) {

System.out.println(“public修饰的方法:”+method.getName());

}

// 6. getDeclaredMethods:获取本类中的所有方法

Method[] declaredMethods = clazz.getDeclaredMethods();

for (Method declaredMethod : declaredMethods) {

System.out.println(“本类中的方法:”+declaredMethod.getName());

}

// 7. getConstructors:获取所有public修饰的构造器,包括本类

Constructor<?>[] constructors = clazz.getConstructors();

for (Constructor<?> constructor : constructors) {

System.out.println(“public修饰的构造器:”+constructor.getName());

}

// 8. getDeclaredConstructors:获取本类中所有构造器

Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();

for (Constructor<?> declaredConstructor : declaredConstructors) {

System.out.println(“获取本类中所有构造器”);

}

// 9. getPackage:以Package形式返回包信息

Package aPackage = clazz.getPackage();

System.out.println(“包名:”+aPackage);

// 10. getSuperClass:以Class形式返回父类信息

Class<?> superclass = clazz.getSuperclass();

System.out.println(“以class形式返回父类信息:”+superclass);

// 11. getInterfaces:以Class[]形式返回接口信息

Class<?>[] interfaces = clazz.getInterfaces();

for (Class<?> anInterface : interfaces) {

System.out.println(“接口信息:”+anInterface.getName());

}

// 12. getAnnotations:以Annotation[]形式返回注解信息

Annotation[] annotations = clazz.getAnnotations();

for (Annotation annotation : annotations) {

System.out.println(“注解信息:”+annotation.toString());

}

}

}

class B{

public String bb;

}

class A extends B{

public String name;

protected int age;

String job;

private double sal;

public void m1(){

}

protected void m2(){

}

void m3(){

}

private void m4(){

}

}

java.lang.reflect.Field类方法:


  1. getModifiers:以int形式返回修饰符[说明:默认修饰符是0,public 是1,private是2,protected是4,static是8,final是16]

  2. getType:以Class形式返回类型

  3. getName:返回属性名

代码展示:

public static void api2() throws Exception{

Class<?> clazz = Class.forName(“com.hspedu.reflection.A”);

Object o = clazz.newInstance();

Field[] declaredFields = clazz.getDeclaredFields();

for (Field declaredField : declaredFields) {

// 1. getModifiers:以int形式返回修饰符[说明:默认修饰符是0,public 是1,private是2,protected是4,static是8,final是16]

int modifiers = declaredField.getModifiers();

System.out.println(declaredField.getName()+“:”+modifiers);

//2. getType:以Class形式返回类型

Class<?> type = declaredField.getType();

System.out.println(declaredField.getName()+“:”+type.getName());

//3. getName:返回属性名

String name = declaredField.getName();

System.out.println(declaredField.getName()+“:”+name);

}

}

java.lang.reflect.Method类方法:


  1. getModifiers:以int类型返回修饰符[说明:默认修饰符是0,public 是1,private是2,

protected是4,static是8,final是16]

  1. getReturnType:以Class形式获取返回类型

  2. getName:返回方法名

  3. getParameterTypes:以Class[]返回参数类型数组

代码示例:

最后

一次偶然,从朋友那里得到一份“java高分面试指南”,里面涵盖了25个分类的面试题以及详细的解析:JavaOOP、Java集合/泛型、Java中的IO与NIO、Java反射、Java序列化、Java注解、多线程&并发、JVM、Mysql、Redis、Memcached、MongoDB、Spring、Spring Boot、Spring Cloud、RabbitMQ、Dubbo 、MyBatis 、ZooKeeper 、数据结构、算法、Elasticsearch 、Kafka 、微服务、Linux。

这不,马上就要到招聘季了,很多朋友又开始准备“金三银四”的春招啦,那我想这份“java高分面试指南”应该起到不小的作用,所以今天想给大家分享一下。

image

请注意:关于这份“java高分面试指南”,每一个方向专题(25个)的题目这里几乎都会列举,在不看答案的情况下,大家可以自行测试一下水平 且由于篇幅原因,这边无法展示所有完整的答案解析

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

“:”+type.getName());

//3. getName:返回属性名

String name = declaredField.getName();

System.out.println(declaredField.getName()+“:”+name);

}

}

java.lang.reflect.Method类方法:


  1. getModifiers:以int类型返回修饰符[说明:默认修饰符是0,public 是1,private是2,

protected是4,static是8,final是16]

  1. getReturnType:以Class形式获取返回类型

  2. getName:返回方法名

  3. getParameterTypes:以Class[]返回参数类型数组

代码示例:

最后

一次偶然,从朋友那里得到一份“java高分面试指南”,里面涵盖了25个分类的面试题以及详细的解析:JavaOOP、Java集合/泛型、Java中的IO与NIO、Java反射、Java序列化、Java注解、多线程&并发、JVM、Mysql、Redis、Memcached、MongoDB、Spring、Spring Boot、Spring Cloud、RabbitMQ、Dubbo 、MyBatis 、ZooKeeper 、数据结构、算法、Elasticsearch 、Kafka 、微服务、Linux。

这不,马上就要到招聘季了,很多朋友又开始准备“金三银四”的春招啦,那我想这份“java高分面试指南”应该起到不小的作用,所以今天想给大家分享一下。

[外链图片转存中…(img-LRT9Uspp-1715566707468)]

请注意:关于这份“java高分面试指南”,每一个方向专题(25个)的题目这里几乎都会列举,在不看答案的情况下,大家可以自行测试一下水平 且由于篇幅原因,这边无法展示所有完整的答案解析

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

  • 20
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值