Java反射应用(面试题反射的几种应用)

news/2024/11/29 23:36:27/

反射应用一:创建运行时类的对象

1.代码举例
Class<Person> clazz = Person.class;Person obj = clazz.newInstance();
System.out.println(obj);2.说明
newInstance():调用此方法,创建对应的运行时类的对象。内部调用了运行时类的空参的构造器。要想此方法正常的创建运行时类的对象,要求:
1.运行时类必须提供空参的构造器
2.空参的构造器的访问权限得够。通常,设置为public。在javabean中要求提供一个public的空参构造器。原因:
1.便于通过反射,创建运行时类的对象
2.便于子类继承此运行时类时,默认调用super()时,保证父类此构造器

反射应用二:获取运行时类的完整结构

我们可以通过反射,获取对应的运行时类中所有的属性、方法、构造器、父类、接口、父类的泛型、包、注解、异常等。。。。
典型代码:
@Test
public void test1(){Class clazz = Person.class;//获取属性结构//getFields():获取当前运行时类及其父类中声明为public访问权限的属性Field[] fields = clazz.getFields();for(Field f : fields){System.out.println(f);}System.out.println();//getDeclaredFields():获取当前运行时类中声明的所属性。(不包含父类中声明的属性Field[] declaredFields = clazz.getDeclaredFields();for(Field f : declaredFields){System.out.println(f);}
}@Test
public void test1(){Class clazz = Person.class;//getMethods():获取当前运行时类及其所父类中声明为public权限的方法Method[] methods = clazz.getMethods();for(Method m : methods){System.out.println(m);}System.out.println();//getDeclaredMethods():获取当前运行时类中声明的所方法。(不包含父类中声明的方法Method[] declaredMethods = clazz.getDeclaredMethods();for(Method m : declaredMethods){System.out.println(m);}
}/*获取构造器结构*/@Testpublic void test1(){Class clazz = Person.class;//getConstructors():获取当前运行时类中声明为public的构造器Constructor[] constructors = clazz.getConstructors();for(Constructor c : constructors){System.out.println(c);}System.out.println();//getDeclaredConstructors():获取当前运行时类中声明的所的构造器Constructor[] declaredConstructors = clazz.getDeclaredConstructors();for(Constructor c : declaredConstructors){System.out.println(c);}}/*获取运行时类的父类*/@Testpublic void test2(){Class clazz = Person.class;Class superclass = clazz.getSuperclass();System.out.println(superclass);}/*获取运行时类的带泛型的父类*/@Testpublic void test3(){Class clazz = Person.class;Type genericSuperclass = clazz.getGenericSuperclass();System.out.println(genericSuperclass);}/*获取运行时类的带泛型的父类的泛型代码:逻辑性代码  vs 功能性代码*/@Testpublic void test4(){Class clazz = Person.class;Type genericSuperclass = clazz.getGenericSuperclass();ParameterizedType paramType = (ParameterizedType) genericSuperclass;//获取泛型类型Type[] actualTypeArguments = paramType.getActualTypeArguments();
//        System.out.println(actualTypeArguments[0].getTypeName());System.out.println(((Class)actualTypeArguments[0]).getName());}/*获取运行时类实现的接口*/@Testpublic void test5(){Class clazz = Person.class;Class[] interfaces = clazz.getInterfaces();for(Class c : interfaces){System.out.println(c);}System.out.println();//获取运行时类的父类实现的接口Class[] interfaces1 = clazz.getSuperclass().getInterfaces();for(Class c : interfaces1){System.out.println(c);}}/*获取运行时类所在的包*/@Testpublic void test6(){Class clazz = Person.class;Package pack = clazz.getPackage();System.out.println(pack);}/*获取运行时类声明的注解*/@Testpublic void test7(){Class clazz = Person.class;Annotation[] annotations = clazz.getAnnotations();for(Annotation annos : annotations){System.out.println(annos);}}

反射应用三:调用运行时类的指定结构

调用指定的属性:
@Test
public void testField1() throws Exception {Class clazz = Person.class;//创建运行时类的对象Person p = (Person) clazz.newInstance();//1. getDeclaredField(String fieldName):获取运行时类中指定变量名的属性Field name = clazz.getDeclaredField("name");//2.保证当前属性是可访问的name.setAccessible(true);//3.获取、设置指定对象的此属性值name.set(p,"Tom");System.out.println(name.get(p));
}
调用指定的方法:@Testpublic void testMethod() throws Exception {Class clazz = Person.class;//创建运行时类的对象Person p = (Person) clazz.newInstance();/*1.获取指定的某个方法getDeclaredMethod():参数1 :指明获取的方法的名称  参数2:指明获取的方法的形参列表*/Method show = clazz.getDeclaredMethod("show", String.class);//2.保证当前方法是可访问的show.setAccessible(true);/*3. 调用方法的invoke():参数1:方法的调用者  参数2:给方法形参赋值的实参invoke()的返回值即为对应类中调用的方法的返回值。*/Object returnValue = show.invoke(p,"CHN"); //String nation = p.show("CHN");System.out.println(returnValue);System.out.println("*************如何调用静态方法*****************");// private static void showDesc()Method showDesc = clazz.getDeclaredMethod("showDesc");showDesc.setAccessible(true);//如果调用的运行时类中的方法没返回值,则此invoke()返回null
//        Object returnVal = showDesc.invoke(null);Object returnVal = showDesc.invoke(Person.class);System.out.println(returnVal);//null}调用指定的构造器:
@Test
public void testConstructor() throws Exception {Class clazz = Person.class;//private Person(String name)/*1.获取指定的构造器getDeclaredConstructor():参数:指明构造器的参数列表*/Constructor constructor = clazz.getDeclaredConstructor(String.class);//2.保证此构造器是可访问的constructor.setAccessible(true);//3.调用此构造器创建运行时类的对象Person per = (Person) constructor.newInstance("Tom");System.out.println(per);}

反射应用四:动态代理

1.代理模式的原理:

使用一个代理将对象包装起来, 然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。

2.静态代理

2.1 举例:

package com.atguigu.java;/*** 静态代理举例** 特点:代理类和被代理类在编译期间,就确定下来了。** @author shkstart* @create 2019 上午 10:11*/
interface ClothFactory{void produceCloth();}//代理类
class ProxyClothFactory implements ClothFactory{private ClothFactory factory;//用被代理类对象进行实例化public ProxyClothFactory(ClothFactory factory){this.factory = factory;}@Overridepublic void produceCloth() {System.out.println("代理工厂做一些准备工作");factory.produceCloth();System.out.println("代理工厂做一些后续的收尾工作");}
}//被代理类
class NikeClothFactory implements ClothFactory{@Overridepublic void produceCloth() {System.out.println("Nike工厂生产一批运动服");}
}public class StaticProxyTest {public static void main(String[] args) {//创建被代理类的对象ClothFactory nike = new NikeClothFactory();//创建代理类的对象ClothFactory proxyClothFactory = new ProxyClothFactory(nike);//开辟的是(new) ProxyClothFactory代理类的空间 所以先调用代理类的produceCloth方法,然后传入的参数是代理类的对象nike,在代理类的produceCloth方法中用 被代理类 的对象Nike调用 被代理类 的produceCloth方法。proxyClothFactory.produceCloth();}
}

2.2 静态代理的缺点:

① 代理类和目标对象的类都是在编译期间确定下来,不利于程序的扩展。
② 每一个代理类只能为一个接口服务,这样一来程序开发中必然产生过多的代理。

3.动态代理的特点:

动态代理是指客户通过代理类来调用其它对象的方法,并且是在程序运行时根据需要动态创建目标类的代理对象。

4.动态代理的实现

4.1 需要解决的两个主要问题:
问题一:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象。
(通过Proxy.newProxyInstance()实现)
问题二:当通过代理类的对象调用方法a时,如何动态的去调用被代理类中的同名方法a。
(通过InvocationHandler接口的实现类及其方法invoke())

每日一考:

1.	写出获取Class实例的三种常见方式Class clazz1 = String.class;Class clazz2 = person.getClass(); //sout(person); //xxx.yyy.zzz.Person@...Class clazz3 = Class.forName(String classPath);//体现反射的动态性2.谈谈你对Class类的理解Class实例对应着加载到内存中的一个运行时类。3.创建Class对应运行时类的对象的通用方法,代码实现。以及这样操作,需要对应的运行时类构造器方面满足的要求。Object obj = clazz.newInstance();//创建了对应的运行时类的对象1.必须有空参的构造器
2.权限修饰符的权限要够。通常设置为public4.在工程或module的src下有名为”jdbc.properties”的配置文件,文件内容为:name=Tom。如何在程序中通过代码获取Tom这个变量值。代码实现
答案在题为:5.使用Classloader加载src目录下的配置文件5. 如何调用方法show()  
类声明如下:
package com.atguigu.java;
class User{public void show(){System.out.println(“我是一个中国人!”);  
}  }User user = (User)clazz.newInstance();
Method show = clazz.getDeclaredMethod("show");
show.setAccessiable(true);
show.invoke(user);

http://www.ppmy.cn/news/500580.html

相关文章

【用户增长】找到用户增长的根本动因

找到用户增长的根本动因 1.没有痛点的用户增长是不持久的 近几年创业的人越来越多&#xff0c;在这些创业失败的案例中&#xff0c;不乏一些 UI 设计非常漂亮的产品&#xff0c;但最终却因为用户增长做不起来而导致创业失败。这些产品失败的最主要原因就是没有找对痛点。 没有…

Android之增量更新详解

前言&#xff1a;自从 Android 4.1 开始&#xff0c; Google Play 引入了应用程序的增量更新功能&#xff0c;App使用该升级方式&#xff0c;可节省约2/3的流量。现在国内主流的应用市场也都支持应用的增量更新了&#xff0c;最常见的应用宝省流量更新。 什么是增量更新&#x…

角雷达“突破”天线设计瓶颈,巨大增量市场机会爆发

毫米波雷达正在受益整车搭载数量提升的利好&#xff0c;其中&#xff0c;和前向雷达&#xff08;市场份额集中于少数几家&#xff09;不同&#xff0c;角雷达市场份额集中度相对较低&#xff0c;量产供应商数量也更多。 近年来角雷达&#xff08;盲区预警及变道辅助&#xff0…

全民营销时代,让私域流量变成业务增量需要几步?

本篇文章暨 CSDN《中国 101 计划》系列数字化转型场景之一。 《中国 101 计划——探索企业数字化发展新生态》为 CSDN 联合《新程序员》、GitCode.net 开源代码仓共同策划推出的系列活动&#xff0c;寻访一百零一个数字化转型场景&#xff0c;聚合呈现并开通评选通道&#xff0…

增量型博客

增量型博客-- 一种全新的博客模式 随着牛人越来越多&#xff0c;我们看到网上的技术博客也是与日俱增。但是大部分的博客都是一种模式&#xff0c;write one&#xff0c;run everywhere&#xff01; ( java说&#xff0c;谁在夸我&#xff1f;:-). 也就是说&#xff0c;一旦博…

数据同步之全量同步与增量同步

一、什么是数据同步 业务数据是数据仓库的重要数据来源&#xff0c;我们需要每日定时从业务数据库中抽取数据&#xff0c;传输到数据仓库中&#xff0c;之后再对数据进行分析统计。 为保证统计结果的正确性&#xff0c;需要保证数据仓库中的数据与业务数据库是同步的&#xff0…

增量模型优缺点

1、增量模型的优点&#xff1a; 整个项目的资金不会被提前消耗&#xff0c;因为首先开发和交付了主要功能和高风险功能。每个增量交付一个可操作的产品。每次增量交付过程中获取的经验&#xff0c;有利于后面的改进&#xff0c;客户也有机会对建立好的模型作出反应。采用连续增…

品牌策划:“增量市场”枯竭,城市品牌打造刻不容缓

文 | 公关之家 作者&#xff1a;小5 引言&#xff1a;在这个富有创造力的21世纪&#xff0c;每个人都不甘平庸&#xff0c;都有一颗成为主角的心。人如此&#xff0c;城市亦如此。 见惯了风花雪月&#xff0c;见惯了物是人非&#xff0c;见惯了人来人往&#xff0c;这一切的行…