关于java反射基础知识/编码经验的一些总结(代码片段)

山河已无恙 山河已无恙     2022-12-27     757

关键词:

写在前面


  • 温习一下毕业以来学习的东西。准备做成一个系列。所以对于每一部分技术点进行一个笔记整理。更多详见 java面试的一些总结
  • 笔记主要是以网上开源的一本《Java核心面试知识整理》面试笔记为原型,结合工作中学习的知识。《Effective Java》《编写高质量代码(改善Java程序的151个建议)》这两本书为方向进行整理。
  • 笔记立足DevOps。开发+运维+测试三个方向 ,面向对JAVA有一定了解的小伙伴用于温习,因为理论较多一点在不断更新,博文内容理解不足之处请小伙伴留言指正

傍晚时分,你坐在屋檐下,看着天慢慢地黑下去,心里寂寞而凄凉,感到自己的生命被剥夺了。当时我是个年轻人,但我害怕这样生活下去,衰老下去。在我看来,这是比死亡更可怕的事。--------王小波


二、JAVA 反射

动态语言

动态语言,是指程序在运行时可以改变其结构:新的函数可以引进,已有的函数可以被删除等结构上的变化。比如常见的 JavaScript 就是动态语言,除此之外 Ruby,Python 等也属于动态语言,而 C、C++则不属于动态语言。从反射角度说 JAVA 属于半动态语言

反射机制概念(运行状态中知道类所有的属性和方法)

反射(Reflection)机制允许程序在运行时借助Reflection API取得任何内部信息,并不能直接操作对象的内部属性及方法。反射被视为动态语言的关键

白话讲解:在 Java 中的反射机制是指在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法;并且对于任意一个对象,都能够调用它的任意一个方法;这种动态获取信息以及动态调用对象方法的功能成为Java 语言的反射机制

JAVA 反射 API

如果面试被问到,对于反射API了你了解多少?怎么回答。

Reflection API提供了ConstructorFieldMethod类,这三个类定义在java.lang.reflect包中,分别用于描述类的构造方法属性方法JAVA8之后在在java.lang.reflect包中添加了Executable抽象类,parameterl类这两个API,Executable描述类的执行对象parameter描述方法参数信息。

当然,获取这些反射APl的实例信息,还需要一个最重要对象元类Classjava.lang.Class类封装一个对象和接口运行时的状态。当类加载Class类型的对象自动创建Class没有公共构造方法,其对象是JVM在类加载时通过类加载器中的defineClass()方法自动构造的,不能显示的实例化一个class对象

如果面试被问到你刚才说了类加载,你可以讲讲类加载么?

所谓类加载,就是指将class文件读入内存,并为之创建一个Java.lang.class对象。即当线程使用任何一个类时,系统都会为之创建一个java.lang.Class对象。java可以使用使用forName动态加载类文件动态加载(Dynamic Loading)是指在程序运行时加载需要的类库文件,对Java程序来说,一般情况下,一个类文件启动时或首次初始化时会被加载到内存中,而反射则可以在运行时决定是否要加载一个类,一个类文件只有在被加载到内存中才可能生成实例对象,即加载到内存中,生成Class对象,通过new关键字生成实例对象

每个类被加载之后,会生成一个Class对象,通过Class对象可以访问JVM中该类的信息,一旦类被载入JVM中同一个类将不会被再次载入,被载入的类都有一个唯一的标识,是该得到全限定类名(包括包名和类名)


Class

Class常用方法:

如果面试被问到你对Class对象了解多少,说几个常用方法,怎么回答?

Class常用方法描述
static Class forName(String className)返回指定类名Class对象
T newInstance()调用默认的构造方法,返回该Class对象的一个实例
String getName()返回Class对象锁对应的类名
构造器相关方法描述
Constructor<?>[] getConstructors()返回Class对象所对应类的所有public构造方法
Constructor<T>getConstructors(Class<?>...parameterType)返回Class对象所对应的类的指定参数列表的public构造方法
Constructor<?>[]getDeclaredConstructors()返回Class对象所对应的所有构造方法,与访问权限无关
Constructor<T>getDeclaredConstructors(Class<?>...parameterTypes)返回Class对象所对应类的指定参数列表的所有构造方法
访问权限无关,如果使用私有构造器
构造,需要开启访问权限setAccessible(true)
设置通过反射访问该成员变量时取消访问权限检查。
方法相关方法描述
Method[] getMethod()返回Class对象所对应类的所有public方法
Method getMethod(String name,Class<?>...parameterType)返回Class对象所对应的指定参数列表public方法
Method[] getDeclaredMechods()返回Class对象所对应的所有方法,与访问权限无关
Method getDeclaredMethod(String name,Class<?>...parameterTypes)返回Class对象对应类的指定参数列表的方法,与访问权限无关
属性相关方法描述
Field[] getFields()返回Class对象所对应类的所有public成员变量
Field getField(String name)返回Class对象所对应的类的指定参数public成员变量
Field[] getDeclaredFields( )返回Class对象所对应类的所有成员变量,与访问权限无关
Field getDeclaredField(String name)返回Class对象所对应类指定参数成员变量,与访问权限无关

这里需要注意的是(MethodConstructor的也一样):

  • 调用getDeclaredFields()方法可以获取包括私有受保护所有属性,但不包括父类的属性
  • 调用getField()方法可以获得所有的public属性。包括从父类继承的。
注解相关方法描述
Annotation [] getAnnotation()返回Class对象所对应类上存在的所有注解
< A extends Annotation>A getAnnotation(Class < A >annotationClass )返回Class对象所对应类上存在的指定类型的注解
Class自身信息相关方法描述
Class<?>getDeclaringClasses()返回Class对象所对应的外部类
Class<?>[] getDeclaredClasses()返回Class对象所对应的类里包含的所有内部类
Class<? super T>getSuperclass()返回Class对象所对应的类里的父类的Class对象
int getModifiers()返回Class对象所对应类的修饰符,返回的整数是修饰符的对应常量,需要是使用Modified工具类解码
Class [] getInterfaces()返回Class对象所对应类实现的所用接口
Class LoadergetClassLoader()返回该类的类加载器
包相关方法描述
Package getPackage()返回Class对象所对应的
Class谓词相关方法描述
boolean isArray()判断Class对象是否表示一个数组类
boolean isEnum()判断Class对象是否表示一个枚举
boolean isInterface()判断Class对象是否表示一个接口
boolean isInstance(Object obj)判断obj对象是否是该Class对象的一个实例
boolean isAnnottation()返回Class对象是否标识一个注解类型

获取Class对象的四种方式:

如果面试被问到如何获取Class对象,怎么回答?

  1. 使用Class类forName(String classNmae)静态方法,参数class代表所需要类的全限定类名forName()方法声明抛出ClassNotFoundException受检异常,调用必须捕获或抛出异常
Class<?> reflection_demoClass = Class.forName("com.liruilong.Reflection.Reflection_Demo");
  1. 调用某个类的class属性来获取该类对应的Class对象对象.class;类的Class属性获得该类所对应的Class对象,会始代码更安全程序性更好string类型的字符串不能使用String.class方式。需要使用Class.forName(“java.lang.String”)Object类的.class文件默认是不包含参数信息的。
Class<Reflection_Demo> reflection_demoClass = Reflection_Demo.class;
  1. 调用某个类的getclass()方法来获取该类对应的class对象,该方法是Object类中的一个方法
Class<? extends Reflection_Demo> aClass = new Reflection_Demo().getClass();
  1. 调用元类Class对应的getClassLoader()获取类加载器,ClassLoader,这个有点牵强,姑且算一种吧,嘻嘻。。
 ClassLoader classLoader = Reflection_Demo.class.getClassLoader();
 Class<?> bClass = classLoader.loadClass("com.liruilong.Reflection.Reflection_Demo");

下面我们看看剩下的API吧!


Executable

Executable抽象类JAVA8java.lang.reflect包下新增了一个Executable抽象类,代表可执行的类成员。Executable抽象类派生了ConstructorMethod两个子类。Executable抽象类提供了大量方法来获取参数修饰符注解等信息。

方法描述
parameter [] getparameters()获取所有形参,返回一个parameter [] 数组
int getParameterCount()获取形参个数
abstract int getModifiers()获取修饰符,返回的整数是修饰符关键字对应的常量
boolean isVarArgs()判断是否包含数量可变的形参

Constructor

Constructor类:用于表示类的构造方法。通过ClassgetConstructor()方法来获取构造方法集合

方法描述
String getName()返回构造器的名称
Class [] getParameterTypes()返回当前构造方法的参数类型
int getModifiers()返回修饰符整型标识,返回的整数是修饰符是标识常量,需要使用Modified工具类方法解码Modified.toSting(int mod),可以通过Modified.PUBLIC 查看对应的值

Method

Method类:用于封装方法的信息,调用Class对象的getMethods()方法或getMethod()可以获取当前类的所有方法或指定的方法。

常用方法功能描述
String getName()返回方法的名称
Class[] getparameterType()返回方法的参数类型
int getModifieds()返回修饰符整型标识
Class getReturnType()返回当前方法的返回类型

Field

Field类:用于封装属性信息,调用Class对象的getFields()getField()方法可以获取当前类的所有属性指定属性

常用方法描述
String getName()获取属性的名称
int getMOdifiers()返回修饰符的整型标识
getXxx(Object obj)获取属性的值,此处的Xxx对应的java8中的基本类型,如果属性是引用类型,直接使用get(Object obj)方法
setXxx(Object obj,Xxx val)设置属性的值,此处的Xxx对应Java8中的基本类型,如果属性是引用类型,直接使用set(Object obj,Object val)方法
Class [] getType()返回当前属性的类型

parameter

parameter类:是JAVA8中新增的API,每个paramtete 对象代表一个参数。Parameter类提供许多方法来获取参数信息

方法功能
int getModifiers()获取参数的修饰符
String getName()获取参数的形参名
Type getparameterizedType()获取带泛型形参类型
Class<?>getType()获取形参类型
boolean isVarArgs()判断该参数是否为可变参数
boolean isNamePreaent()判断.class文件中是否包含方法的形参名信息

利用反射创建对象的的两种方式:

如果面试被问到使用反射如何创建对象,怎么回答?

  • Class 对象的 newInstance(): 使用 Class对象的 newInstance()方法来创建该Class 对象对应类的实例,但是这种方法要求该 Class对象对应的类有默认空构造器
 Class<?> reflection_demoClass = Class.forName("com.liruilong.Reflection.Reflection_Demo");
            Reflection_Demo o = (Reflection_Demo) reflection_demoClass.newInstance();

            System.out.println(o);// com.liruilong.Reflection.Reflection_Demo@677327b6
  • 调用Constructor对象的newInstance(): 先使用 Class对象获取指定的 Constructor对象,再调用Constructor对象的newInstance()方法来创建 Class 对象对应类的实例,通过这种方法可以选定构造方法创建实例
 Class<?> reflection_demoClass = Class.forName("com.liruilong.Reflection.Reflection_Demo");
  			Constructor<?> constructors = reflection_demoClass.getConstructor(null);
            Reflection_Demo o1 = (Reflection_Demo) constructors.newInstance(null);

            System.out.println(o1); // com.liruilong.Reflection.Reflection_Demo@14ae5a5

关于反射的一些其他编码经验:

如果面试问关于反射,平常开发中有哪些经验,要怎么回答?

  • 注意Class类本身的特殊性:Java语言把Java源文件编译为后缀为class字节码文件,然后通过ClassLocale机制把类文件加载内存中,最后生成实例执行,Java使用元类(MetaClass)来描述加载内存中类数据,即Class类,描述类对象,需要注意Class的一些特性
    • 无构造函数,不能主动实例化,Class对象在加载时由java虚拟机通过类加载器中的defineClass自动构造。
    • 可以描述基本类型 Class as=int.class;8个基本类型执行JVM中并不是一个对象,一般存在栈中,通过Class可以描述它们,可以使用int.calss描述int类型类对象
    • Class对象都是单例模式,一个Class对象描述一个类,只描述一个类,即一个类只有一个Class对象Class是java 的反射入口,只有在获得一个类的动态描述时才能动态的加载调用
  • 适时选择getDeclaredXXXgetXXXgetDeclaredMethod方法获得的是所有public访问级别的方法,包括从父类继承来的方法,而getDeclareMethod获得自身类的所有方法,包括公有的(public)私有(private),方法等,不受访问权限限制。如果需要列出所有继承自父类的方法,可以先获得父类,然后使用getDeclareMethods,之后持续递归
  • 反射访问属性方法时将Accessible设置为truejava中通过反射执行方法的步骤,获取一个对象的方法,然后根据isAccessible返回值确定是否能执行,如果返回false,则需要调用setAccessible(true),在调用invoke执行方法。
    • Access并不是语法层次理解的访问权限,而是指是否更容易获得是否进行安全检查。动态的修改一个类或方法或执行方法时都会受到Java安全体系的制约,而安全处理非常消耗资源,所以对于运行期要执行的方法或修改的属性就提供了Accessible可选项,由开发者决定是否要逃避安全体系的检查
    • AccessibleObjectfieldMethodconstructor父类决定是否可以快速访问而不进行访问控制检查AccessobleObject类中是以override变量保存该值的。
  • Accessible属性只是用来判断是否需要进行安全检查的,如果不需要则直接执行,可以提升系统性能. AccessibleObject的其他两个子类fieldconstructor也相似,所以要设置Accessibletrue
Method  method= genericDemo.class.getMethod("toArray");
		if(!method.isAccessible())
		   method.setAccessible(true);
		method.invoke(obj, args);
	
public class Foo 
	public final void doStuff() 
		System.out.println("Do liruilong ___$# ^_^");
	
	public static void main(String[] args) throws Exception, Throwable 
		Method method = Foo.class.getMethod("doStuff");
		System.out.println("可以访问吗!!"+method.isAccessible());
		method.invoke(new Foo());
		
  • 动态加载不适合数组,当使用forName加载一个类时,8个基本类型排除,它不是一个具体的类,还要具有可追索的类路径,否则包ClassNotFoundException异常。数组虽然是一个类,但没有定义类路径,可以加载编译后的对象动态动态加载一个对象数组,但是没有意义。在java中数组是定长的,没有长度的数组是不允许存在的。可以使用Array数组反射类来动态加载一个数组。
//动态创建一个数组
String [] strs = (String[]) Array.newInstance(String.class,8);
int[][] ints = (int [][])Array.newInstance(int.class,2,3);
元素类型编译后的类型
byte[][B
char[][C
Double[][D
Float[][F
Int[][I
Long[][J
Short[][S
Boolean[Z
引用类型(如String)[L引用类型
  • 动态可以让代理模式更灵活,java的反射框架提供了动态代理(Dynamic Proxy)机制,允许在运行期对目标对象生成代理,
    静态代理:通过代理主题角色具体主题角色共同实现抽象主题角色的逻辑的,只是代理主题角色把相关的执行逻辑委托给了具体主题角色而已。

静态代理:

interface  subject
    public void  request();

class RealSubject implements subject
    public void request()
        
    

class Proxy implements subject
    private subject subjects = null;
    public Proxy()
        subjects = new  RealSubject();
    
    public Proxy(subject subjects)
        this.subjects =subjects; 
    
    public void request()
        befoer();
        subjects.request();
        afert();
    
    public void befoer()
    public void afert()
        

java基于java.lang.reflect.Proxy用于实现动态代理,使SubjectHandler作为主要的逻辑委托对象,invoke是必须要实现的,完成对真实方法的调用。即通过InvocationHandler接口的实现类来实现,所有被代理的方法都是由InvocationHandler接管实际的处理任务

动态代理

interface  subject
    public void  request();

class RealSubject implements subject
    public void request()

    

class SubjectHandler implements InvocationHandler
    private subject subjects;
    
    private SubjectHandler(subject subjects) 
        this.subjects = subjects;
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 
        System.out.println("预处理");
        Object obj = method.invoke(subjects,args);
        System.out.println("后处理");
        return obj;
    

//场景类
 public static void main(String[] args)  
      
      subject subjects = new RealSubject();
      InvocationHandler handler = new SubjectHandler(subjects);
      //当前加载器
      ClassLoader cl = subjects.getClass().getClassLoader();
      //动态代理
      subject proxy = (subject) Proxy.newProxyInstance(cl,subjects.getClass().getInterfaces().request(),handler);
      //执行具体的角色方法
      proxy.request();
    
  • 使用反射增加装饰模式的普遍性装饰模式:动态的给一个对象添加一些额外的职责。使用动态代理可以实现装饰模式。
//动物
interface Animal
    public void doStuff();

//老鼠
class Rat implements Animal
    @Override
     public void doStuff()
        System.out.println("Jetty Tom");
     

//定义某种能力
interface  Featuer
    public void load();


class FlyFeatuer implements Featuer
    public void load()
        System.out.println("增加 一支翅膀");
    

class DigFeatuer implements Featuer
    public void load()
        System.out.println("增加钻地能力!");
    


class DecorateAnimal implements Animal
    private Animal animal;
    private Class<? extends Featuer> clz;
    public DecorateAnimal(Animal animal,Class<? extends Featuer> clz)
        this.animal = animal;
        this.clz = clz;
    
    @Override
    public  void doStuff()
        InvocationHandler handler = new InvocationHandler() 
            //具体的包装行为
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 
                Object obj = null;
            //设置包装
                // public class Modifier
                // extends ObjectModifier类提供了static方法和常量来解码类和成员访问修饰符。 修饰符集合被表示为具有表示不同修饰符的不同位位置的整数。
        //method.getModifiers()返回由该对象表示的可执行文件的Java语言modifiers 。
         if (Modifier.isPublic(method.getModifiers()))
                obj = method.invoke(clz.newInstance(),args);
         
         animal.doStuff();
                return obj;
            
        ;
        ClassLoader cl = getClass().getClassLoader();
        Featuer Proxy = (Featuer) java.lang.reflect.Proxy.newProxyInstance(cl,clz.getInterfaces(),handler);
        Proxy.load();
    


public class Demo 
    public static void main(String[] args)  
        //定义Jerry老树
        Animal Jerry = new Rat();
        Jerry = new DecorateAnimal(Jerry,深入解析java反射-基础

...其中的IOC部分非常依靠反射,因此趁这个机会来总结一下关于Java反射的一些知识。本篇为基本篇,基于JDK1.8。 一、回顾:什么是反射? 反射(Reflection)是Java程序开发语言的特征之一,它允许运行中的Java程序获取自身的信息,... 查看详情

java基础知识点笔记总结(十一)(代码片段)

文章目录1.反射机制2.创建Person类以及其他的一些注解接口等(方便后面测试其他方法使用)3.两个疑问(看自己理解)4.java.lang.Class类的理解5.如何获取Class实例的4中方式6.Class实例可以是哪些结构?7.类的加载与ClassLoader的理解7.1类... 查看详情

java基础---设计模式内部类反射

1.什么是设计模式  (1)设计模式(Designpattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结.  (2)此术语是在1990年代由ErichGamma等人从建筑设计领域引入到计算机科学中来的。  (3)... 查看详情

关于qt数据库相关开发的一些经验总结(代码片段)

一、前言近期花了两个多月时间,将数据库相关的代码重新封装成了各种轮子(这条路必须打通,打通以后,相关项目只需要引入这个组件pri即可),测试了从Qt4.7到Qt6.1的各种版本,测试了odbc、sqlite... 查看详情

c++11常用特性的使用经验总结(代码片段)

...结文章,在编写本博客之前,博主在工作和学习中学到的关于C++11方面的知识,也得益于很多其他网友的总结。本博客文章是在学习的基础上,加上博主在日常工作中的使用C++11的一些总结、经验和感悟,整理出来,分享给大家... 查看详情

总结django一些开发经验(代码片段)

...后端接口开发还是很高效的。特此总结一些Django开发的小经验。先说一些最最基础的吧。使用virtualenv隔离开发环境使用pip管理项目依赖,主要就是一个小技巧,使用pipfreeze>requirements.txt来保存依赖的模块和版本使用gitignore.io这... 查看详情

java基础知识总结--反射(代码片段)

反射:在程序运行期间,Java运行时系统始终为所有的对象维护一个被称为运行时的类型标识。这个信息跟踪着每一个对象所属的类。虚拟机利用运行时类型信息选择相应的方法执行。Java反射机制是在系统运行状态中,对于任意... 查看详情

java中反射知识点总结(代码片段)

1packageDemo;23importjava.lang.reflect.Constructor;4importjava.lang.reflect.Field;5importjava.lang.reflect.InvocationTargetException;6importjava.lang.reflect.Method;7importjava.lang.reflect.Modifier;8 查看详情

java基础知识总结18(反射)

反射技术:  其实就是动态加载一个指定的类,并获取该类中的所有的内容。而且将字节码文件封装成对象,并将字节码文件中的内容都封装成对象,这样便于操作这些成员。简单说:反射技术可以对一个类进行解剖。 反... 查看详情

关于动态规划的一些经验与总结

   动态规划是一个考验技巧性的算法,对于动态规划算法,浅谈几点经验。   首先是设计状态,我们肯定是要有一个一维或多维的状态的,那么如何设计它们的意义呢,首先我们可以分析出题目中的一些... 查看详情

java反射(3万字总结,最后的最后我想要一个赞,您的支持是我的动力)(代码片段)

文章目录前言一、关于反射与注解的那些话(了解)二、编程语言类型1.静态类型语言2.动态类型语言2.1Java与动态性三、反射1.反射的定义2.反射的应用场景3.关于反射学习的进程的科学安排四、类加载器1.类加载器的分类1... 查看详情

java基础之反射

...么新鲜花样来,但为了便于总结理解,还是说一句: 反射简单看来就是用一些特殊的类来表示普遍类中的一些成分(构造方法,成员属性,成员方法)。为什么?因为一切 皆对象嘛~由此就引出了Co 查看详情

实习总结java学习最佳实践!

...错的文章。前言目录**Java基础****Java进阶****编码规范****反射****注解****泛型****多线程****异常****集合框架****JVM相关****Class文件结构****类加载过程****GC垃圾回收原理、策略****Java8新特性****Stream****Lambda****Optional类****方法引用****单... 查看详情

关于deepin装机的一些经验总结

最近win10用的有一点腻,虚拟机很久之前就装上了deepin,乌班图,红帽等隶属于Linux一些操作系统,但是终究还是虚拟机所以还是想在真机上试试,所以照着deepin网上的流程装好了deepin并且成功开机运行,在这里分享一些经验。1.... 查看详情

java的反射机制,看完这篇轻松应对高级框架(超详细总结)(代码片段)

导读:很多优秀的高级框架都是通过反射完成的,反射的重要性,由此可见一斑。反射机制可以使得程序更加灵活,只有学习好反射的基础语法,这样才能自己写出优秀的框架。好了一起打卡学习吧,别忘记了素质三连哦!往期... 查看详情

java基础java反射机制浅解(代码片段)

文章目录反射的某场景说明反射代码应用代码安全问题总结基础知识类、实例、Class实例(第2行代码)参考反射的某场景说明应用场景:当我们在使用IDE,比如Ecplise时,当我们输入一个对象或者类,并想调用他... 查看详情

关于集合中一些常考的知识点总结(代码片段)

本章主要总结了集合的一些基础但有重点的知识点,例如他们的底层数据结构以及集合之间的区别,其中HashMap最为重点。集合Java的集合框架中可以分为两大类:第一类是按照单个元素存储的Collection集合,其中Set,List,Queue都实... 查看详情

java题库错题总结(代码片段)

...射的语言,基于反射为Java提供了丰富的动态性支持,下面关于Java反射的描述,哪些是错误的:( ADF      )AJava反射主要涉及的类如Class, Method, Filed,等,他们都在java.lang.reflet包下B通过反射可以动态... 查看详情