Java面试题-Java核心基础-第十天(反射)

news/2024/5/19 4:00:58 标签: java核心基础, java面试, 反射

目录

一、反射是什么?

二、反射的优缺点?

三、反射中常用的API

四、反射的应用场景


一、反射是什么?

就是一种可以动态获取类中所有信息以及可以操作类中的这些成员的这样一种能力。

正是由于这种特性才使得Java这种静态语言也具备一定的动态性。在框架底层得到大量使用

二、反射的优缺点?

优点:反射能让我们有了分析操作类的能力,可以获取到类中的所有结构

缺点:能让其避免掉泛型检查,因为反射是在运行时,而泛型检查在编译的时候,这样会有类型的安全隐患,另外反射还可以无视权限修饰符的限定,可以直接操作private的属性

三、反射中常用的API

首先要获取并操作那些类中的结构,首先就得获得字节码对象 也就是Class对象,利用类加载器将字节码装载成运行时数据区中的Class对象

有四种获取方式:

1. 调用对象的getClass()方法

2. 调用类的class属性

3. 通过全类名获取,调用Class类中的forName静态方法

4. 通过类加载器

ReflectionTest1.class.getClassLoader().loadClass("com.at guigi.java.Student")

获取到字节码对象之后,调用字节码的相应结构的get方法就能获取到相应的结构

获取相应结构:

获取基本结构:获取构造器、属性、方法  还可以获取一些详细结构,比如说属性上面的注解、方法上面的方法的修饰符,返回值类型,方法名,形参类型,抛出的异常,方法上面的注解,方法参数的注解都可以获取到

Field:

getFields():获取父类及本类中所有公共的属性

getDeclaredFields():获取到本类中所有的属性

getField(String name):获取父类及本类中名称为name的属性,注意只能获取公共的属性,如果属性不公共,那么会报错

getDeclaredField(String name):获取到本类中名称为name的属性,注意这里只是获取,如果对象要访问该属性,还得打开属性通道,field.setAccessible (true)

Method:

getMethods():获取父类及本类中所有公共的方法

getDeclaredMethods():获取本类中所有的方法

getMethod(String name,这里是Class类型的可变形参,也就是放方法形参的类型):获取本类及父类中,方法名为name,形参为指定形参的方法,注意只 能获取公共的方法

getDeclaredMethod(String name,这里是Class类型的可变形参,也就是放方法形参的类型):获取本类中方法名为name,形参为指定形参的方法

Class<?> clazz = Class.forName("com.atguigi.java.Student");
Method[] methods = clazz.getDeclaredMethods();
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(clazz.getSimpleName()+"{\n");
for(Method method : methods){
//获取方法上面的注解
Annotation[] annotations = method.getAnnotations();
//System.out.println(annotations.length);
for(Annotation annotation : annotations){
stringBuilder.append(" "+annotation.toString()+"\n");
}
stringBuilder.append(" ");
// System.out.print(Modifier.toString(method.getModifiers()));
stringBuilder.append(Modifier.toString(method.getModifiers()));
//System.out.print(" ");
stringBuilder.append(" ");
//System.out.print(method.getReturnType().getSimpleName());
stringBuilder.append(method.getReturnType().getSimpleName());
// System.out.print(" ");
stringBuilder.append(" ");
//System.out.print(method.getName());
stringBuilder.append(method.getName());
// System.out.print("(");
stringBuilder.append("(");
Class<?>[] parameterTypes = method.getParameterTypes();
// for(Class clazz1 : parameterTypes){
// //System.out.print(clazz1.getSimpleName()+",");
// stringBuilder.append(clazz1.getSimpleName()+",");
// }
Annotation[][] parameterAnnotations = method.getParameterAnnotations();
//System.out.println(method.getName()+""+parameterAnnotations.length);
for(int i=0;i<parameterTypes.length;i++){
System.out.println(method.getName()+":"+parameterTypes[i].getSimpleName()+":"+parameterAnnotations[i].length);
if(parameterAnnotations[i].length==0){
stringBuilder.append(parameterTypes[i].getSimpleName()+",");
}else{
for(int j=0;j< parameterAnnotations[i].length;j++){
stringBuilder.append(parameterAnnotations[i]+" ");
}
stringBuilder.append(parameterTypes[i].getSimpleName()+",");
}
}
if(parameterTypes.length!=0) {
stringBuilder.deleteCharAt(stringBuilder.length()-1);
}
stringBuilder.append(")");
Class<?>[] exceptionTypes = method.getExceptionTypes();
if(exceptionTypes.length!=0){
stringBuilder.append(" throws ");
for(Class clazz2 : exceptionTypes){
stringBuilder.append(clazz2.getSimpleName()+",");
}
stringBuilder.deleteCharAt(stringBuilder.length()-1);
}
stringBuilder.append("{}\n");
}
stringBuilder.append("}");
System.out.println(stringBuilder);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}

获取方法的所有修饰符:method.getModifiers()      Modifier.toString(method.getModifiers())显示修饰符

获取方法的返回值:method.getReturnType() 获取到的是Class对象,可以调用.getSimpleName()获取到返回值的简单名字

获取方法上面的所有注解:Annotation[] annotations = method.getAnnotations()

获取方法名字:method.getName())

获取方法参数类型列表:Class[] parameterTypes = method.getParameterTypes() 不能获取到参数名

获取到方法参数上面所有的注解:Annotation[][] parameterAnnotations = method.getParameterAnnotations();

获取到方法上面的所有异常:Class[] exceptionTypes = method.getExceptionTypes();

Construct:

getDeclaredMethods():可以获取所有的构造器

getDeclaredMethod(构造器形参的参数类型列表):可以获取指定构造器

操作相应结构:

操作属性:

Class<?> clazz = Class.forName("com.atguigi.java.Student");
Constructor<?> constructor = clazz.getDeclaredConstructor(String.class, Integer.class);
Object o = constructor.newInstance("张三", 1001);
Field name = clazz.getDeclaredField("name");
//访问私有属性,要打开通道
name.setAccessible(true);
//因为是私有方法,无法直接调用,报 IllegalAccessException错误
Object o1 = name.get(o);
System.out.println("对象o的name属性值是:"+o1);
System.out.println("将对象o的name属性值重新设置为:王五");
name.set(o,"王五");
System.out.println("对象o的name属性值是:"+o);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}

操作方法:

Class<?> clazz = Class.forName("com.atguigi.java.Student");
Constructor<?> constructor = clazz.getDeclaredConstructor(String.class, Integer.class);
Object o = constructor.newInstance("张三", 1001);
//注意:只能使用getDeclaredMethod()才能获取私有的方法,否则报错NoSuchMethodException
Method method = clazz.getDeclaredMethod("food", String.class, Integer.class);
//调用方法
//method.invoke(o,"苹果",20); //因为是私有方法,无法直接调用,报 IllegalAccessException错误
//需要打开通道
method.setAccessible(true);
method.invoke(o,"香蕉",20);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}

 操作构造器,通过构造器造对象:

Class<?> clazz = Class.forName("com.atguigi.java.Student");
Constructor<?> constructor = clazz.getDeclaredConstructor(String.class, Integer.class);
Object o = constructor.newInstance("张三", 1001);
//建议使用这种方式造对象,而非直接运行时对象调newInstance方法
Constructor<?> declaredConstructor = clazz.getDeclaredConstructor();
Object o1 = declaredConstructor.newInstance();
System.out.println(o1);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}

还可以直接用Class对象调用newInstances()方法,调用无参构造常见对象 

四、反射的应用场景

在Oracle官方说的是:

1. 可以通过解析xml创建对象

2. 可以枚举类中的所有属性,便于程序员开发

3. 可以访问私有结构,便于测试到所有结构

主要是框架中大量使用。

1. jdbc中先要加载驱动  就是利用反射加载  

public static final String DBDRIVER = "com.mysql.jdbc.Driver";

Class.forName(DBDRIVER) 这样能加载类 加载类中的静态结构 运行静态代码块

2. Spring中Xml创建Bean

<bean id="mystudent" class="com.bjpowernode.ba01.Student">
              <property name="name" value="张三"/>
              <property name="age" value="20"/>
              <property name="email" value="zs@qq.com"/>
</bean>


http://www.niftyadmin.cn/n/5116441.html

相关文章

SpringBoot 统一响应返回格式格式 数组

RequestMapping("/update")public Result login() {List<String> arr new ArrayList<>();arr.add("123");arr.add("456");return Result.success("获取成功",arr);}public class Result {public Result(int code,String …

【PG】PostgreSQL数据库管理

目录 数据库概念 查看现有数据库 创建数据库 模板数据库 数据库配置 删除数据库 表空间 概念 表空间优势 注意 查看表空间 创建表空间 在指定表空间下创建表 temp_tablespaces 默认表空间 删除表空间 数据库概念 少量的对象&#xff0c;例如角色、数据库和表空间…

Golang 中 Error 的设计及最佳实践

如果你对于 Go 的 Error 设计不太熟悉也不习惯&#xff0c;为什么许多接口都需要返回 error 接口类型的值呢&#xff1f;什么时候该处理 error&#xff0c;什么时候该抛出 error&#xff0c;什么时候又该忽略 error &#xff1f;Go 设计者又为什么要这样设计 error 呢&#xff…

基于OpenCV批量分片高像素影像

基于OpenCV批量分片高像素影像 为了更加精确的诊断和治疗&#xff0c;医疗影像往往是大像素&#xff08;1920x1080&#xff09;或超大像素图像&#xff08;4k图像4096x2160&#xff09;。这类图像的尺寸与深度学习实验数据常见尺寸&#xff08;227x227&#xff0c;或32x32&…

论坛议程|COSCon'23开源商业(V)

众多开源爱好者翘首期盼的开源盛会&#xff1a;第八届中国开源年会&#xff08;COSCon23&#xff09;将于 10月28-29日在四川成都市高新区菁蓉汇举办。本次大会的主题是&#xff1a;“开源&#xff1a;川流不息、山海相映”&#xff01;各位新老朋友们&#xff0c;欢迎到成都&a…

VRPTW(MATLAB):蜘蛛蜂优化算法SWO求解带时间窗的车辆路径问题VRPTW(提供参考文献及MATLAB代码)

一、VRPTW简介 带时间窗的车辆路径问题(Vehicle Routing Problem with Time Windows, VRPTW)是车辆路径问题(VRP)的一种拓展类型。VRPTW一般指具有容量约束的车辆在客户指定的时间内提供配送或取货服务&#xff0c;在物流领域应用广泛&#xff0c;具有重要的实际意义。VRPTW常…

平衡二叉树(AVL)【java实现+图解】

目录 一、平衡二叉树(AVL) 二、平衡二叉树的四种旋转 1.右旋转 2.左旋转 3. 左右旋转 4. 右左旋转 三、基于二叉搜索树之平衡二叉树的代码实现 1.具体方法思路 2.java代码实现 一、平衡二叉树(AVL) 一种自平衡二叉搜索树&#xff0c;它是在每个节点上增加一个平衡因子…

Oracle Enterprise Manager 认证列表

认证列表的查找方法参见Accessing the Enterprise Manager Certification Matrix。 认证分为对于OMS的&#xff0c;和对于Agent的。 OMS和Agent的描述见这里。 Oracle Management Agent The Management Agent is an integral software component that enables you to conver…