Java反射专题笔记总结:一篇文章带你理清反射,牛客网java面试题库

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Java开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip1024b (备注Java)
img

正文

  • 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[]返回参数类型数组

代码示例:

public static void api3() throws Exception{

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

Object o = clazz.newInstance();

Method[] declaredMethods = clazz.getDeclaredMethods();

for (Method declaredMethod : declaredMethods) {

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

System.out.println(declaredMethod.getName()+“:”+declaredMethod.getModifiers());

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

System.out.println(declaredMethod.getName()+“:”+declaredMethod.getReturnType());

//getName:返回方法名

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

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

Class<?>[] parameterTypes = declaredMethod.getParameterTypes();

for (Class<?> parameterType : parameterTypes) {

System.out.println(declaredMethod.getName()+“:”+parameterType);

}

}

}

java.lang.reflect.Contructor类的方法


  1. getModifiers:以int形式返回修饰符

  2. getName:返回构造器名(全类名)

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

public static void api4() throws Exception{

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

Object o = clazz.newInstance();

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

for (Constructor<?> declaredConstructor : declaredConstructors) {

Class<?>[] parameterTypes = declaredConstructor.getParameterTypes();

for (Class<?> parameterType : parameterTypes) {

System.out.println(declaredConstructor.getName()+“:”+declaredConstructor.getModifiers()+“:”+parameterType);

}

}

}

七、反射爆破创建实例:

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

通过反射创建对象的几种方式

  1. 方式一、调用类中的public修饰的无参构造器

  2. 方式二、调用类中的指定构造器

Class类相关方法

  1. newInstance:调用类中的无参构造器,获取对应类的对象

  2. getConsturctor(Class…clazz):根据参数列表,获取对应的public构造器对象

  3. getDecalaredConstructor(Class…clazz):根据参数列表,获取对应的所有构造器对象

Constructor类相关方法

  1. setAccessible:爆破

  2. newInstance(Object…obj):调用构造器

案例演示:


1 测试1:通过反射创建某类的对象,要求该类中必须有public的无参构造

2.测试2:通过调用某个特定构造器的方式,实现创建某类的对象

package com.hspedu.reflection;

import java.lang.reflect.Constructor;

/**

  • Description:演示通过反射机制创建实例

  • User:

  • Date:

  • Time:

*/

public class ReflecCreateInstance {

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

//1.先获取到User类的Class对象

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

//2.通过public的无参构造器创建实例

Object o = clazz.newInstance();

System.out.println(“无参构造创建的对象实例:”+o);

//3.通过public的有参构造器创建实例

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

Object ls = constructor.newInstance(“ls”);

System.out.println(“通过public的有参构造器创建实例:”+ls);

//4.通过非public的有参构造器创建实例

Constructor<?> constructor1 = clazz.getDeclaredConstructor(int.class, String.class);

//爆破

constructor1.setAccessible(true);//使用反射可以访问private构造器

Object wql = constructor1.newInstance(20, “wql”);

System.out.println(“通过非public的有参构造器创建实例:”+wql);

}

}

class User{

private int age=10;

private String name=“zs”;

public User(){

}

public User(String name) {

this.name = name;

}

private User(int age, String name){

this.age = age;

this.name = name;

}

@Override

public String toString() {

return “User{” +

“age=” + age +

“, name='” + name + ‘’’ +

‘}’;

}

}

通过反射访问类中的成员:


访问属性:ReflecAccessProperty.java

  1. 根据属性名获取Field对象Field f = clazz对象.getDeclaredField(属性名)

  2. 爆破:f.setAccessible(true);

  3. 访问f.set(o,值)//o表示对象

  4. 如果是静态属性,则set中的o,可以写成null

案例演示:

package com.hspedu.reflection;

import java.lang.reflect.Field;

/**

  1. Description:演示反射访问属性

  2. User:

  3. Date:

  4. Time:

*/

public class ReflecAccessProperty {

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

//1.得到Student类对应的Class对象

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

//2.创建对象

Object o = clazz.newInstance();

//3.得到age属性对象

Field age = clazz.getField(“age”);

age.set(o,20);

System.out.println(“age:”+age.get(o));

//4.得到name属性

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

name.setAccessible(true);

name.set(o,“zs”);

System.out.println(“name:”+name.get(o));

//5.静态变量设空

Field name2 = clazz.getDeclaredField(“name”);

name.setAccessible(true);

name.set(null,“ls”);

System.out.println(“name:”+name.get(o));

}

}

class Student{

public int age;

private static String name;

public Student(){

}

@Override

public String toString() {

return “Student{” +

“age=” + age +“,name=”+name+

‘}’;

}

}

完结

Redis基于内存,常用作于缓存的一种技术,并且Redis存储的方式是以key-value的形式。Redis是如今互联网技术架构中,使用最广泛的缓存,在工作中常常会使用到。Redis也是中高级后端工程师技术面试中,面试官最喜欢问的问题之一,因此作为Java开发者,Redis是我们必须要掌握的。

Redis 是 NoSQL 数据库领域的佼佼者,如果你需要了解 Redis 是如何实现高并发、海量数据存储的,那么这份腾讯专家手敲《Redis源码日志笔记》将会是你的最佳选择。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

nstance();

//3.得到age属性对象

Field age = clazz.getField(“age”);

age.set(o,20);

System.out.println(“age:”+age.get(o));

//4.得到name属性

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

name.setAccessible(true);

name.set(o,“zs”);

System.out.println(“name:”+name.get(o));

//5.静态变量设空

Field name2 = clazz.getDeclaredField(“name”);

name.setAccessible(true);

name.set(null,“ls”);

System.out.println(“name:”+name.get(o));

}

}

class Student{

public int age;

private static String name;

public Student(){

}

@Override

public String toString() {

return “Student{” +

“age=” + age +“,name=”+name+

‘}’;

}

}

完结

Redis基于内存,常用作于缓存的一种技术,并且Redis存储的方式是以key-value的形式。Redis是如今互联网技术架构中,使用最广泛的缓存,在工作中常常会使用到。Redis也是中高级后端工程师技术面试中,面试官最喜欢问的问题之一,因此作为Java开发者,Redis是我们必须要掌握的。

Redis 是 NoSQL 数据库领域的佼佼者,如果你需要了解 Redis 是如何实现高并发、海量数据存储的,那么这份腾讯专家手敲《Redis源码日志笔记》将会是你的最佳选择。

[外链图片转存中…(img-fLIdAZPQ-1713617246439)]

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Java)
[外链图片转存中…(img-Z0MCPAyj-1713617246439)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 24
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值