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>

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值