泛型动态代理基础
动态代理的实现方法

动态代理的实现方法1. 引言1.1 什么是动态代理动态代理是一种在运行时创建代理对象的技术,可以动态地将一些额外的逻辑添加到实际对象的方法调用中。
通俗地讲,动态代理允许程序在运行时创建一个代理类,代理类可以处理原始对象的方法调用,执行额外的操作,然后再将控制传递给原始对象。
动态代理的作用非常广泛,可以用于在不修改原始代码的情况下增加额外的逻辑,比如日志记录、性能监控等。
动态代理还可以用于实现面向切面编程(AOP),通过代理实现横切关注点的代码重用。
动态代理有两种主要实现方式:基于Java反射的JDK动态代理和基于字节码操作库Cglib的动态代理。
这两种方式各有优劣,选择合适的方式取决于具体的应用场景。
无论哪种方式,动态代理都是一种非常强大的技术,可以帮助我们简化代码结构,提高系统的灵活性和可维护性。
1.2 动态代理的作用1. 隐藏真实对象的实现细节:动态代理可以使客户端无需关心真实对象的具体实现细节,只需要与代理对象进行交互即可,这样可以有效保护真实对象的实现细节和安全性。
2. 实现横切关注点:动态代理可以在不改变原有代码的基础上,灵活地添加一些公共功能,例如日志记录、性能监控、事务管理等,这样可以提高代码的复用性和可维护性。
3. 实现远程调用:动态代理可以通过网络实现远程对象的访问,例如RMI(远程方法调用)和Web服务。
4. 在运行时扩展对象功能:动态代理可以在运行时为对象添加新的功能,不需要修改原有代码,可以大大减少系统的耦合度和复杂性。
动态代理可以帮助程序员在更高层次上对对象进行控制和管理,提高代码的灵活性和可扩展性,是面向对象编程中非常重要的一部分。
1.3 动态代理的实现方式动态代理的实现方式有两种主要的方法,分别是Java动态代理和Cglib动态代理。
在Java中,动态代理是通过反射机制来实现的,它主要依靠Proxy类和InvocationHandler接口。
通过Proxy.newProxyInstance()方法可以创建一个代理对象,同时需要传入一个InvocationHandler对象来处理代理对象的方法调用。
Java开发工程师招聘面试题与参考回答2025年

2025年招聘Java开发工程师面试题与参考回答面试问答题(总共10个问题)第一题:请描述一下Java中的反射机制及其在Java编程中的应用场景。
答案:Java的反射机制是指在运行时,程序能够取得任何类或对象的内部信息,并且动态创建对象、调用对象的方法以及获取对象的属性。
以下是反射机制的一些关键点:1.反射机制允许在运行时动态地加载和调用类的方法。
2.反射机制可以获取类的构造方法、字段、方法和注解等信息。
3.反射机制提供了访问和修改类内部状态的能力。
应用场景:1.创建对象:通过反射机制,可以在运行时创建任意类的实例。
2.方法调用:在运行时动态调用任意对象的方法。
3.获取类信息:在运行时获取类的名称、父类、接口等信息。
4.动态代理:在实现动态代理时,通过反射机制动态创建代理对象。
5.脚本语言集成:某些脚本语言可以通过反射机制与Java代码进行交互。
解析:反射机制在Java编程中具有广泛的应用,以下是几个具体的例子:•在框架开发中,如Spring框架,反射机制被用来动态地注册和管理Bean。
•在插件系统中,反射机制允许在运行时动态加载和调用插件。
•在测试框架中,如JUnit,反射机制被用来动态调用测试方法。
•在JDBC编程中,反射机制可以用来动态创建数据库连接和执行SQL语句。
反射机制虽然功能强大,但也存在一些缺点,如性能开销大、代码难以理解等。
因此,在使用反射时,应尽量减少不必要的反射操作。
第二题:请简述Java中的多态性及其实现方式,并举例说明在Java中如何通过多态来简化代码设计。
答案:多态性是面向对象编程中的一个核心概念,它允许同一个接口或父类在不同的情况下表现出不同的行为。
在Java中,多态性主要通过继承和接口实现。
1.继承:当一个子类继承了父类后,子类对象可以调用父类的方法和属性,如果子类对父类的方法进行了重写(即子类提供了与父类方法相同签名但不同实现的方法),那么在调用该方法时,就会根据对象的实际类型来执行对应的方法。
JAVA反射机制与动态代理

JAVA反射机制与动态代理Java反射机制和动态代理是Java语言中重要的特性,能够在运行时获取和操作类、对象和方法的信息,以及在运行时生成代理对象,实现对目标对象的间接访问和控制。
下面将详细介绍反射机制和动态代理的原理、应用场景和使用方法。
##反射机制的原理和应用场景Java反射机制是指在运行时动态地获取和操作Java对象、类、方法和属性的能力。
它允许我们在编译时期不知道具体的类和方法,而是在运行时进行动态判断和调用。
反射机制提供了一种访问和操作Java对象的底层机制,其主要功能包括:1.获取类的信息:通过反射可以获取一个类的名称、访问修饰符、实现的接口、父类、字段和方法等信息。
2. 创建对象的实例:通过反射可以在运行时动态地创建一个类的实例,例如通过Class对象的newInstance(方法或Constructor类的newInstance(方法。
3.调用方法和访问属性:通过反射可以动态地调用一个对象的方法,包括公有和私有方法,并且可以对对象的属性进行修改和访问。
4.操作数组和泛型:通过反射可以获取和操作数组的元素,以及获取泛型的类型信息。
反射机制的应用场景非常广泛,特别是在框架和开发工具中经常使用到。
一些常见的应用场景包括:1.动态加载和实例化类:通过反射可以根据类的名称动态地加载和创建类的实例,可以实现类似动态代理和插件机制的功能。
2.配置文件的读取和解析:通过反射可以根据配置文件中的类和属性信息动态地创建对象,并初始化对象的属性。
3.注解的处理:通过反射可以获取类、方法和属性上的注解信息,并根据注解的定义进行相应的处理。
4.测试和调试:通过反射可以在运行时动态地获取和调用对象的方法和属性,方便进行测试和调试。
##反射机制的使用方法Java反射机制主要涉及到三个类:Class、Constructor和Method。
其中Class类表示一个类或接口的运行时类型,Constructor类表示一个构造方法,Method类表示一个方法。
《Java基础知识》Java动态代理(InvocationHandler)详解

《Java基础知识》Java动态代理(InvocationHandler)详解1. 什么是动态代理对象的执⾏⽅法,交给代理来负责。
⽐如user.get() ⽅法,是User对象亲⾃去执⾏。
⽽使⽤代理则是由proxy去执⾏get⽅法。
举例:投资商找明星拍⼴告,投资商是通过经纪⼈联系的,经纪⼈可以帮明星接这个⼴告,也可以拒绝。
做不做,怎么做都叫给经纪⼈和投资商谈。
2. 实际场景应⽤2.1 校验⽤户权限,每⼀个菜单请求,都要判断⼀下请求的⽤户是否有该菜单权限。
菜单多了,代码冗余,且容易遗漏。
通过动态代理就可以实现为:每⼀个⽤户,每⼀个菜单的请求,都经过代理(proxy),由他判断是否有权限,调⽤者只需要调⽤,实现⾃⼰的逻辑,不关⼼权限问题。
3. 动态代理完整案例:/*** 创建⽤户接⼝*/public interface UserBean {String getUser();}import erBean;public class UserBeanImpl implements UserBean {private String user = null;//flag:0 ⽆权限,1有权限。
private String flag = null;public String getFlag() {return flag;}public void setFlag(String flag) {this.flag = flag;}public UserBeanImpl(String user,String flag){er = user;this.flag = flag;}public String getUserName(){return user;}public String getUser(){System.out.println("this is getUser() method!");return user;}public void setUser(String user){er = user;System.out.println("this is setUser() method!");}}import ng.reflect.InvocationHandler;import ng.reflect.Method;public class UserBeanProxy implements InvocationHandler {private Object targetObject;public UserBeanProxy(Object targetObject){this.targetObject = targetObject;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {UserBeanImpl userBean = (UserBeanImpl) targetObject;String flag = userBean.getFlag();Object result = null;//权限判断if("1".equals(flag) ){result = method.invoke(targetObject, args);}else{System.out.println("sorry , You don't have permission");}return result;}}import erBean;import ng.reflect.Proxy;public class TestSection {public static void main(String[] args) {UserBeanImpl targetObject = new UserBeanImpl("蕾蕾","1");UserBeanProxy proxy = new UserBeanProxy(targetObject);//⽣成代理对象UserBean object = (UserBean) Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), proxy);String userName = object.getUser();System.out.println("userName: " + userName);}}运⾏结果:代理代理核⼼代码UserBean object = (UserBean) Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),targetObject.getClass().getInterfaces(), proxy);public interface InvocationHandler {public Object invoke(Object proxy, Method method, Object[] args)throws Throwable;}接⼝:InvocationHandler,代理需要实现该接⼝,并且实现⽅法:invoke。
手绘6张图彻底搞懂动态代理

手绘6张图彻底搞懂动态代理在讲解动态代理前我们先聊聊什么是静态代理。
静态代理假设有一天领导突发奇想,给你下发了一个需求:统计项目中所有类的方法执行耗时。
在拿到需求的那一刻,脑海中冒出来的第一个想法是:在每个方法的第一行和最后一行加上时间埋点,再打印一行□志不就完事了。
抄起键盘准备开干,想了想又开始犹豫了:在每个方法都加几行代码,这不是侵入式修改吗?听架构师大佬说这样的场景可以用代理模式,那尝试一下,具体做法如下。
[静态代理的实剧(1)为工程里每个类都写一个代理类,让它与目标类实现同一个接口。
图中标红色的就是代理类。
«lnterface»BAProxy Almpl BProxy♦ wofk() + wofk()(2)在代理类里面维护一个Fl标实现类,调用代理类的方法时还是会去调用目标类的方法,只不过在前后加了一些其他逻辑代码。
也就是说后面客户端不需要直接调用目标实现类,只需要调用代理类即可,这样就间接调用了对应方法。
用一个公式总结一下:代理类=增强代码+目标实现类。
下面这个图中,计算耗时的逻辑就是增强代码。
(3)在所有new目标类的地方都替换为new代理类,并将目标类作为构造方法参数传入;所有使用目标类调用的地方全部都替换为代理类调用。
如果你看懂了上面的实现方法,那么恭喜你已经掌握了静态代理的核心思想。
[静态代理的缺司静态代理的思路非常简单,就是给每一个目标实现类写一个对应的代理实现类,但是如果一个项目有几千甚至有几万个类,这个工作量可想而知。
前面我们还隐藏了一个假设:每个类都会实现一个接口。
那如果一个类没有实现任何接口,代理类如何实现呢?好了,我们来总结一下静态代理的缺点:静态代理需要针对每个目标实现类写一个对应的代理类,如果目标类的方法有变动,代理类也要跟着动,维护成本非常高。
静态代理必须依赖接口。
既然知道了静态代理的缺点,那有没有办法实现少些或者不写代理类来实现代理功能呢?答案是有,动态代理。
jdk动态代理底层原理

jdk动态代理底层原理
JDK动态代理是Java中重要的代理方式之一,它可以在运行时动态地创建代理类和代理对象,实现对目标对象进行增强的功能。
JDK 动态代理是通过反射机制来实现的,它可以在运行时动态地生成代理类,从而实现对目标对象的代理操作。
JDK动态代理的底层原理是基于Java的反射机制和接口实现的。
在JDK动态代理中,首先需要定义接口,并实现该接口的类为目标类。
然后,通过Proxy类的newProxyInstance方法生成代理对象,该方法需要传入三个参数:类加载器、代理类的接口数组和InvocationHandler对象。
其中InvocationHandler是代理对象的调用处理器,它实现了invoke方法,用于增强代理对象的方法。
在生成代理对象时,JDK动态代理会在内存中生成一个代理类,并动态地实现了目标类所实现的接口,并且重写了目标类中的方法。
在代理对象调用方法时,实际上是通过代理类的方法调用了InvocationHandler中的invoke方法,在invoke方法中可以实现对目标类方法的增强。
总体来说,JDK动态代理实现的原理就是在运行时动态生成代理类,并通过反射机制实现对目标类方法的代理和增强。
这种代理方式简单易懂,并且可以实现对不同接口的类进行代理操作,是Java中非常重要的代理方式之一。
- 1 -。
动态代理模式的原理和使用方式

动态代理模式的原理和使用方式动态代理模式是一种常用的设计模式,可以在运行时动态地生成代理对象,使我们更加方便地访问原始对象并进行一些额外的操作,比如日志记录和安全控制等。
本文将介绍动态代理模式的原理和使用方式,帮助读者更好地理解和使用该模式。
一、动态代理模式的原理动态代理模式是指,在程序运行时动态地生成代理对象,而不是在编译时指定代理对象。
在 Java 中,可以通过反射机制和 Java 自带的 Proxy 类来实现动态代理。
1. 反射机制Java 中的反射机制是指在程序运行时动态地获取类信息、方法信息等,并能够在运行时调用这些信息。
在使用反射创建动态代理时,可以通过 Class 对象的 getInterfaces() 方法获取目标对象实现的所有接口信息,并通过 Proxy 的 newProxyInstance() 方法生成代理对象。
2. Proxy 类Java 自带的 Proxy 类可以用于创建动态代理。
它提供了一个静态方法newProxyInstance(),能够动态地生成代理对象。
在使用时,需要指定两个参数:一个是类加载器(ClassLoader),用于加载目标对象和代理类;一个是目标对象实现的接口,用于确定代理类实现的接口。
二、动态代理模式的应用动态代理模式在实际应用中非常常见。
以下是一些常见的应用场景。
1. AOPAOP(Aspect Oriented Programming)是一种编程范式,它主要关注的是纵向的业务流程,通过对业务流程的拦截和增强来实现横向的功能复用。
动态代理是 AOP 的关键技术之一,通过代理拦截目标对象的方法调用,并在方法执行前后进行一些额外的操作,实现日志记录、安全控制等功能。
2. RPCRPC(Remote Procedure Call)是一种远程过程调用的协议,它可以让两个不同的进程之间进行通信。
在 RPC 实现中,动态代理可以用于客户端和服务端之间的通信,通过代理实现对远程方法的调用,并将结果返回给调用方。
java泛型详解-绝对是对泛型方法讲解最详细的,没有之一

java泛型详解-绝对是对泛型⽅法讲解最详细的,没有之⼀1. 概述泛型在java中有很重要的地位,在⾯向对象编程及各种设计模式中有⾮常⼴泛的应⽤。
什么是泛型?为什么要使⽤泛型?泛型,即“参数化类型”。
⼀提到参数,最熟悉的就是定义⽅法时有形参,然后调⽤此⽅法时传递实参。
那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,类似于⽅法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使⽤/调⽤时传⼊具体的类型(类型实参)。
泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。
也就是说在泛型使⽤过程中,操作的数据类型被指定为⼀个参数,这种参数类型可以⽤在类、接⼝和⽅法中,分别被称为泛型类、泛型接⼝、泛型⽅法。
2. ⼀个栗⼦⼀个被举了⽆数次的例⼦:1 List arrayList = new ArrayList();2 arrayList.add("aaaa");3 arrayList.add(100);45for(int i = 0; i< arrayList.size();i++){6 String item = (String)arrayList.get(i);7 Log.d("泛型测试","item = " + item);8 }毫⽆疑问,程序的运⾏结果会以崩溃结束:1 ng.ClassCastException: ng.Integer cannot be cast to ng.StringArrayList可以存放任意类型,例⼦中添加了⼀个String类型,添加了⼀个Integer类型,再使⽤时都以String的⽅式使⽤,因此程序崩溃了。
为了解决类似这样的问题(在编译阶段就可以解决),泛型应运⽽⽣。
我们将第⼀⾏声明初始化list的代码更改⼀下,编译器会在编译阶段就能够帮我们发现类似这样的问题。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
泛型(Generic) —泛形的作用JDK5中的泛形允许程序员在编写集合代码时,就限制集合的处理类型,从而把原来程序运行时可能发生问题,转变为编译时的问题,以此提高程序的可读性和稳定性(尤其在大型程序中更为突出)。
注意:泛型是提供给javac编译器使用的,它用于限定集合的输入类型,让编译器在源代码级别上,即挡住向集合中插入非法数据。
但编译器编译完带有泛形的java程序后,生成的class文件中将不再带有泛形信息,以此使程序运行效率不受到影响,这个过程称之为“擦除”。
泛形的基本术语,以ArrayList<E>为例:<>念着typeofArrayList<E>中的E称为类型参数变量ArrayList<Integer>中的Integer称为实际类型参数整个称为ArrayList<E>泛型类型整个BaseDao<Type>ParameterizedType/Type自定义泛形——泛型类和反射泛形如果一个类多处都要用到同一个泛型,这时可以把泛形定义在类上(即类级别的泛型),语法格式如下:public class GenericDao<T> {private T field1;public void save(T obj){}public T getId(int id){}}泛形的典型应用:BaseDao和反射泛型Annotation(注解) 概述从JDK 5.0 开始, Java 增加了对元数据(MetaData) 的支持, 也就是Annotation(注解)。
什么是Annotation,以及注解的作用?三个基本的Annotation:@Override: 限定重写父类方法, 该注解只能用于方法@Deprecated: 用于表示某个程序元素(类, 方法等)已过时@SuppressWarnings: 抑制编译器警告.Annotation 其实就是代码里的特殊标记, 它用于替代配置文件,也就是说,传统方式通过配置文件告诉类如何运行,有了注解技术后,开发人员可以通过注解告诉类如何运行。
在Java 技术里注解的典型应用是:可以通过反射技术去得到类里面的注解,以决定怎么去运行类。
掌握注解技术的要点:如何自定义注解如何反射注解,并根据反射的注解信息,决定如何去运行类自定义Annotation定义新的Annotation 类型使用@interface 关键字声明注解的属性注解属性的作用:原来写在配置文件中的信息,可以通过注解的属性进行描述。
Annotation 的属性声明方式:String name()或String[] likes();属性默认值声明方式:String name() default “xxx”;特殊属性value:如果注解中有一个名称value的属性,那么使用注解时可以省略value=部分,如@MyAnnotation(“xxx")特殊属性value[];枚举值之间使用逗号分隔@MyAnnotation(name="jack",age=30,likes={"唱歌","跳舞"})JDK 的元Annotation元Annotation指修饰Annotation的Annotation。
JDK中定义了如下元Annotation:@Retention: 只能用于修饰一个Annotation 定义, 用于指定该Annotation 可以保留的域, @Rentention 包含一个RetentionPolicy 类型的成员变量, 通过这个变量指定域。
RetentionPolicy.CLASS: 编译器将把注解记录在class 文件中. 当运行Java 程序时, JVM 不会保留注解. 这是默认值RetentionPolicy.RUNTIME:编译器将把注释记录在class 文件中. 当运行Java 程序时, JVM 会保留注解. 程序可以通过反射获取该注释RetentionPolicy.SOURCE: 编译器直接丢弃这种策略的注释JDK 的元Annotation@Target:指定注解用于修饰类的哪个成员. @Target 包含了一个名为value,类型为ElementType(JDK6)的成员变量。
@Documented: 用于指定被该元Annotation 修饰的Annotation 类将被javadoc 工具提取成文档。
@Inherited: 被它修饰的Annotation 将具有继承性.如果某个类使用了被@Inherited 修饰的Annotation, 则其子类将自动具有该注解。
提取Annotation 信息JDK 5.0 在ng.reflect 包下新增了AnnotationElement 接口, 该接口代表程序中可以接受注释的程序元素当一个Annotation 类型被定义为运行时Annotation 后, 该注释才是运行时可见, 当class 文件被载入时保存在class 文件中的Annotation 才会被虚拟机读取程序可以调用AnnotationElement 对象的如下方法来访问Annotation 信息动态代理(代理类产生代理对象)明确两个概念:代理对象存在的价值:主要用于拦截对真实业务对象的访问。
代理对象有什么方法?与真实对象相同,只是无业务代码。
现在要生成某一个对象的代理对象,这个代理对象通常也要编写一个类来生成,所以首先要编写用于生成代理对象的类。
如何编写生成代理对象的类,两个要素:代理谁如何生成代理对象代理谁?设计一个类变量,以及一个构造函数,记住代理类代理哪个对象。
如何生成代理对象?(invoke方法)设计一个方法生成代理对象(在方法内编写代码生成代理对象是此处编程的难点)动态代理(JDK提供)ava提供了一个Proxy类,调用它的newInstance方法可以生成某个对象的代理对象,使用该方法生成代理对象时,需要三个参数:1.生成代理对象使用哪个类加载器2.生成哪个对象的代理对象,通过接口指定3.生成的代理对象的方法里干什么事,由开发人员编写handler接口的实现来指定。
初学者必须记住的2件事情:Proxy类负责创建代理对象时,如果指定了handler(处理器),那么不管用户调用代理对象的什么方法,该方法都是调用处理器的invoke方法。
由于invoke方法被调用需要三个参数:代理对象、方法、方法的参数,因此不管代理对象哪个方法调用处理器的invoke方法,都必须把自己所在的对象、自己(调用invoke方法的方法)、方法的参数传递进来。
动态代理应用在动态代理技术里,由于不管用户调用代理对象的什么方法,都是调用开发人员编写的处理器的invoke方法(这相当于invoke方法拦截到了代理对象的方法调用)。
并且,开发人员通过invoke方法的参数,还可以在拦截的同时,知道用户调用的是什么方法,因此利用这两个特性,就可以实现一些特殊需求,例如:拦截用户的访问请求,以检查用户是否有访问权限、动态为某个对象添加额外的功能。
c3p0-config.xml<c3p0-config><default-config><property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql:///jdbc_demo</property> <property name="user">root</property><property name="password">root</property><property name="initialPoolSize">5</property><property name="maxPoolSize">10</property></default-config><named-config name="oracleConfig"><property name="driverClass">com.mysql.jdbc.Driver</property> <property name="jdbcUrl">jdbc:mysql:///day17</property><property name="user">root</property><property name="password">root</property><property name="initialPoolSize">5</property><property name="maxPoolSize">10</property></named-config></c3p0-config>log4j1泛型package cn.itcast.a_generic;import java.util.ArrayList;import java.util.List;import org.junit.Test;/*** 泛型基本用法* @author Jie.Yuan**/public class App {// 运行时期异常@Testpublic void testGeneric() throws Exception {// 集合的声明List list = new ArrayList();list.add("China");list.add(1);// 集合的使用String str = (String) list.get(1);}// 使用泛型@Testpublic void testGeneric2() throws Exception {// 声明泛型集合的时候指定元素的类型List<String> list = new ArrayList<String>();list.add("China");// list.add(1);// 编译时期报错String str = list.get(1);}/** 泛型擦除实例public void save(List<Person> p){}public void save(List<Dept> d){ // 报错:与上面方法编译后一样}*/// 泛型写法@Testpublic void testGeneric3() throws Exception {// 声明泛型集合,集合两端类型必须一致List<Object> list = new ArrayList<Object>();List<String> list1 = new ArrayList<String>();List list2 = new ArrayList<String>();List<Integer> list3 = new ArrayList();// 错误//List<Object> list4 = new ArrayList<String>();// 错误:泛型类型必须是引用类型,不能为基本类型// List<int> list5 = new ArrayList<int>();}}2package cn.itcast.a_generic;import java.util.ArrayList;import java.util.List;import org.junit.Test;/*** 泛型, 涉及到一些关键字** Ctrl + shift + R 查看当前项目中类* Ctrl + shift + T 查看源码jar包中的类* @author Jie.Yuan**/public class App_extends {/*** list集合只能处理Double/Float/Integer等类型* 限定元素范围:元素的类型要继承自Number类(上限) * @param list*/public void save(List<? extends Number> list) {}@Testpublic void testGeneric() throws Exception {List<Double> list_1 = new ArrayList<Double>();List<Float> list_2 = new ArrayList<Float>();List<Integer> list_3 = new ArrayList<Integer>();List<String> list_4 = new ArrayList<String>();// 调用save(list_1);save(list_2);save(list_3);//save(list_4);}}3package cn.itcast.a_generic;import java.util.ArrayList;import java.util.List;import org.junit.Test;/*** 泛型, 涉及到一些关键字** Ctrl + shift + R 查看当前项目中类* Ctrl + shift + T 查看源码jar包中的类* @author Jie.Yuan**/public class App_super {/*** super限定元素范围:必须是String父类【下限】* @param list*/public void save(List<? super String> list) {}@Testpublic void testGeneric() throws Exception {// 调用上面方法,必须传入String的父类List<Object> list1 = new ArrayList<Object>();List<String> list2 = new ArrayList<String>();List<Integer> list3 = new ArrayList<Integer>();//save(list3);}}4package cn.itcast.a_generic;/*** 抽象的类* @author Jie.Yuan* @param <T>*/public class BaseDao<T> implements IBaseDao<T> {@Overridepublic void save(T t) {// TODO Auto-generated method stub }@Overridepublic void update(T t) {// TODO Auto-generated method stub}}5package cn.itcast.a_generic;public class Dept {}6package cn.itcast.a_generic;import org.junit.Test;/*** 泛型方法/泛型类* @author Jie.Yuan**/public class GenericDemo<T> {// 定义泛型方法public <K> T save(T t,K k) {return null;}public void update(T t) {}// 测试方法@Testpublic void testMethod() throws Exception {// 泛型类:在创建爱泛型类对象的时候,确定类型GenericDemo<String> demo = new GenericDemo<String>();demo.save("test", 1);}}7package cn.itcast.a_generic;/*** 泛型接口* @author Jie.Yuan** @param <T>*/public interface IBaseDao<T> {void save(T t );void update(T t );}8package cn.itcast.a_generic;public class Person {}9package cn.itcast.a_generic;/*** 具体业务模块* @author Jie.Yuan**/public class PersonDao implements IBaseDao<Person>{public void save(Person p){}@Overridepublic void update(Person t) {}}2 反射1package cn.itcast.b_reflect;public class Account {private int id;private String accountName;private double money;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getAccountName() {return accountName;}public void setAccountName(String accountName) { this.accountName = accountName;}public double getMoney() {return money;}public void setMoney(double money) {this.money = money;}}2package cn.itcast.b_reflect;public class AccountDao extends BaseDao<Account> {// 只需要写父类没有实现的方法(个性化需求) }3package cn.itcast.b_reflect;public class Admin {private int id;private String userName;private String pwd;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getUserName() {return userName;}public void setUserName(String userName) {erName = userName;}public String getPwd() {return pwd;}public void setPwd(String pwd) {this.pwd = pwd;}@Overridepublic String toString() {return "Admin [id=" + id + ", pwd=" + pwd + ", userName=" + userName + "]";}}4package cn.itcast.b_reflect;public class AdminDao extends BaseDao<Admin> {// 根据主键查询}5package cn.itcast.b_reflect;import org.junit.Test;public class App {@Testpublic void testSave() throws Exception {AdminDao adminDao = new AdminDao();Admin admin = adminDao.findById(8);System.out.println(admin);System.out.println(adminDao.getAll());}}6package cn.itcast.b_reflect;import ng.reflect.ParameterizedType;import ng.reflect.Type;import java.sql.SQLException;import java.util.List;import mons.dbutils.handlers.BeanHandler;import mons.dbutils.handlers.BeanListHandler;/*** 所有dao的公用的方法,都在这里实现* @author Jie.Yuan**/public class BaseDao<T>{// 保存当前运行类的参数化类型中的实际的类型private Class clazz;// 表名private String tableName;// 构造函数:1. 获取当前运行类的参数化类型;2. 获取参数化类型中实际类型的定义(class)public BaseDao(){// this 表示当前运行类(AccountDao/AdminDao)// this.getClass() 当前运行类的字节码(AccountDao.class/AdminDao.class)// this.getClass().getGenericSuperclass(); 当前运行类的父类,即为BaseDao<Account>// 其实就是“参数化类型”,ParameterizedTypeType type = this.getClass().getGenericSuperclass();// 强制转换为“参数化类型”【BaseDao<Account>】ParameterizedType pt = (ParameterizedType) type;// 获取参数化类型中,实际类型的定义【new Type[]{Account.class}】Type types[] = pt.getActualTypeArguments();// 获取数据的第一个元素:Accout.classclazz = (Class) types[0];// 表名(与类名一样,只要获取类名就可以)tableName = clazz.getSimpleName();}/*** 主键查询* @param id 主键值* @return 返回封装后的对象*/public T findById(int id){/** 1. 知道封装的对象的类型* 2. 表名【表名与对象名称一样,且主键都为id】** 即,* ---》得到当前运行类继承的父类BaseDao<Account>* ----》得到Account.class*/String sql = "select * from " + tableName + " where id=? ";try {return JdbcUtils.getQuerrRunner().query(sql, new BeanHandler<T>(clazz), id);} catch (SQLException e) {throw new RuntimeException(e);}}/*** 查询全部* @return*/public List<T> getAll(){String sql = "select * from " + tableName ;try {return JdbcUtils.getQuerrRunner().query(sql, new BeanListHandler<T>(clazz));} catch (SQLException e) {throw new RuntimeException(e);}}}7package cn.itcast.b_reflect;import javax.sql.DataSource;import mons.dbutils.QueryRunner;import boPooledDataSource;/*** 封装常用的操作* @author Jie.Yuan**/public class JdbcUtils {// 初始化连接池private static DataSource dataSource;static {dataSource = new ComboPooledDataSource();}public static DataSource getDataSource() {return dataSource;}/*** 创建DbUtils常用工具类对象*/public static QueryRunner getQuerrRunner() {return new QueryRunner(dataSource);}}8package cn.itcast.c_reflect;public class Admin {// Fieldprivate int id = 1000;private String name = "匿名";// Constructorpublic Admin(){System.out.println("Admin.Admin()");}public Admin(String name){System.out.println("Admin.Admin()" + name);}// Methodpublic int getId() {return id;}public void setId(int id) {this.id = id;}public String getName() {return name;}public void setName(String name) { = name;}}9package cn.itcast.c_reflect;import ng.reflect.Constructor;import ng.reflect.Field;import ng.reflect.Method;import org.junit.Test;// 反射技术public class App {// 1. 创建对象@Testpublic void testInfo() throws Exception {// 类全名String className = "cn.itcast.c_reflect.Admin";// 得到类字节码Class<?> clazz = Class.forName(className);// 创建对象1: 默认构造函数简写//Admin admin = (Admin) clazz.newInstance();// 创建对象2:通过带参数构造器创建对象Constructor<?> constructor = clazz.getDeclaredConstructor(String.class);Admin admin = (Admin) constructor.newInstance("Jack");}@Test//2. 获取属性名称、值public void testField() throws Exception {// 类全名String className = "cn.itcast.c_reflect.Admin";// 得到类字节码Class<?> clazz = Class.forName(className);// 对象Admin admin = (Admin) clazz.newInstance();// 获取所有的属性名称Field[] fs = clazz.getDeclaredFields();// 遍历:输出每一个属性名称、值for (Field f : fs) {// 设置强制访问f.setAccessible(true);// 名称String name = f.getName();// 值Object value = f.get(admin);System.out.println(name + value);}}@Test//3. 反射获取方法public void testMethod() throws Exception {// 类全名String className = "cn.itcast.c_reflect.Admin";// 得到类字节码Class<?> clazz = Class.forName(className);// 对象Admin admin = (Admin) clazz.newInstance();// 获取方法对象public int getId() {Method m = clazz.getDeclaredMethod("getId");// 调用方法Object r_value = m.invoke(admin);System.out.println(r_value);}}Anno1package cn.itcast.d_anno;import java.util.List;import org.junit.Test;/*** 常用的注解* @author Jie.Yuan**/public class App_1 {// 重写父类的方法@Overridepublic String toString() {return super.toString();}// 抑制编译器警告@SuppressWarnings(value = {"unused","unchecked"}) private void save() {List list = null;}// 标记方法以及过时@Deprecatedprivate void save1() {}@Testpublic void testMain() throws Exception {}}2package cn.itcast.d_anno;import ng.reflect.Field;import ng.reflect.Method;import javax.persistence.Table;import org.junit.Test;/*** 测试:自定义注解的语法* @author Jie.Yuan**/public class App_2 {private String test;@Id@Author(remark = "保存信息!!!", age = 19)public void save() throws Exception {// 获取注解信息:name/age/remark// 1. 先获取代表方法的Method类型;Class clazz = App_2.class;Method m = clazz.getMethod("save");// 2. 再获取方法上的注解Author author = m.getAnnotation(Author.class);// 获取输出注解信息System.out.println(author.authorName());System.out.println(author.age());System.out.println(author.remark());}@Testpublic void testMain() throws Exception {save();}}3package cn.itcast.d_anno;import static ng.annotation.ElementType.CONSTRUCTOR;import static ng.annotation.ElementType.FIELD;import static ng.annotation.ElementType.LOCAL_VARIABLE;import static ng.annotation.ElementType.METHOD;import static ng.annotation.ElementType.PARAMETER;import static ng.annotation.ElementType.TYPE;import ng.annotation.Retention;import ng.annotation.RetentionPolicy;import ng.annotation.Target;import ng.reflect.Type;/*** 自定义注解(描述一个作者)* @author Jie.Yuan**/// 元注解- 1. 定义注解的可用范围@Target({TYPE,FIELD , METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) //@Target({METHOD,FIELD,TYPE}) 指定只能在方法、字段、类上用;// 元注解- 2. 指定注解的声明周期@Retention(RetentionPolicy.RUNTIME) // 字节码级别有效public @interface Author {String authorName() default "Jet";int age() default 30;String remark();}4package cn.itcast.d_anno;public @interface Id {}Eg1package cn.itcast.e_eg;import cn.itcast.utils.Column;import cn.itcast.utils.Id;import cn.itcast.utils.Table;// Admin=a_admin@Table(tableName="a_admin")public class Admin {@Id@Column(columnName = "a_id")private int id;@Column(columnName = "a_userName")private String userName;@Column(columnName = "a_pwd")private String pwd;public int getId() {return id;}public void setId(int id) {this.id = id;}public String getUserName() {return userName;}public void setUserName(String userName) {erName = userName;}public String getPwd() {return pwd;}public void setPwd(String pwd) {this.pwd = pwd;}@Overridepublic String toString() {return "Admin [id=" + id + ", pwd=" + pwd + ", userName=" + userName + "]";}}2package cn.itcast.e_eg;public class AdminDao extends BaseDao<Admin> {}3package cn.itcast.e_eg;import org.junit.Test;public class App {@Testpublic void testDao() throws Exception {AdminDao adminDao = new AdminDao();// Admin admin = adminDao.findById(8);// System.out.println(admin);System.out.println(adminDao.findById(8));System.out.println(adminDao.getAll());}}4package cn.itcast.e_eg;import ng.reflect.Field;import ng.reflect.ParameterizedType;import ng.reflect.Type;import java.sql.ResultSet;import java.sql.SQLException;import java.util.ArrayList;import java.util.List;import mons.beanutils.BeanUtils;import mons.dbutils.ResultSetHandler;import cn.itcast.b_reflect.JdbcUtils;import cn.itcast.utils.Column;import cn.itcast.utils.Id;import cn.itcast.utils.Table;/*** 解决优化的问题:* 1. 当数据库表名与类名不一致、* 2. 字段与属性不一样、* 3. 主键不叫id**/public class BaseDao<T> {// 当前运行类的类型private Class<T> clazz;// 表名private String tableName;// 主键private String id_primary;// 拿到当前运行类的参数化类型中实际的类型( BaseDao<Admin> , Admin.class) public BaseDao(){Type type = this.getClass().getGenericSuperclass();ParameterizedType pt = (ParameterizedType) type;Type[] types = pt.getActualTypeArguments();clazz = (Class<T>) types[0];//已经拿到:Admin.class/*******1. 获取表名*******/Table table = clazz.getAnnotation(Table.class);tableName = table.tableName();/*******2. 获取主键字段*******///获取当前运行类的所有字段、遍历、获取每一个字段上的id注解Field[] fs = clazz.getDeclaredFields();for (Field f : fs) {// 设置强制访问f.setAccessible(true);// 获取每一个字段上的id注解Id anno_id = f.getAnnotation(Id.class);// 判断if (anno_id != null) {// 如果字段上有id注解,当前字段(field)是主键;再获取字段名称Column column = f.getAnnotation(Column.class);// 主键id_primary = column.columnName();// 跳出循环break;}}System.out.println("表:" + tableName);System.out.println("主键:" + id_primary);}public T findById(int id){try {String sql = "select * from " + tableName + " where " + id_primary +"=?";/** DbUtils的已经封装好的工具类:BeanHandler? 属性=字段*/return JdbcUtils.getQuerrRunner().query(sql, new BeanHandler<T>(clazz), id);} catch (Exception e) {throw new RuntimeException(e);}}public List<T> getAll(){try {String sql = "select * from " + tableName;return JdbcUtils.getQuerrRunner().query(sql, new BeanListHandler<T>(clazz));} catch (Exception e) {throw new RuntimeException(e);}}}/*** 自定义结果集:封装单个Bean对象*/class BeanHandler<T> implements ResultSetHandler<T>{// 保存传入的要封装的类的字节码private Class<T> clazz;public BeanHandler(Class<T> clazz) {this.clazz = clazz;}// 封装结果集的方法@Overridepublic T handle(ResultSet rs) throws SQLException {try {// 创建要封装的对象‘1’T t = clazz.newInstance();// 向下读一行if (rs.next()) {// a. 获取类的所有的Field字段数组Field[] fs = clazz.getDeclaredFields();// b. 遍历,得到每一个字段类型:Fieldfor (Field f : fs) {// c. 获取”属性名称“String fieldName = f.getName();// e. 获取Field字段上注解【@Column(columnName = "a_userName")】Column column = f.getAnnotation(Column.class);// f. ”字段名“String columnName = column.columnName(); // 数据库中字段a_userName// g. 字段值Object columnValue = rs.getObject(columnName);// 设置(BeanUtils组件)BeanUtils.copyProperty(t, fieldName, columnValue);}}return t;} catch (Exception e) {throw new RuntimeException(e);}}}/*** 自定义结果集:封装多个Bean对象到List集合*/class BeanListHandler<T> implements ResultSetHandler<List<T>>{// 要封装的单个对象private Class<T> clazz;public BeanListHandler(Class<T> clazz){this.clazz = clazz;}// 把从数据库查询到的没一行记录,封装为一个对象,再提交到list集合,返回List<T> @Overridepublic List<T> handle(ResultSet rs) throws SQLException {List<T> list = new ArrayList<T>();try {// 向下读一行while (rs.next()) {// 创建要封装的对象‘1’T t = clazz.newInstance();// a. 获取类的所有的Field字段数组Field[] fs = clazz.getDeclaredFields();// b. 遍历,得到每一个字段类型:Fieldfor (Field f : fs) {// c. 获取”属性名称“String fieldName = f.getName();// e. 获取Field字段上注解【@Column(columnName = "a_userName")】Column column = f.getAnnotation(Column.class);// f. ”字段名“String columnName = column.columnName(); // 数据库中字段a_userName// g. 字段值Object columnValue = rs.getObject(columnName);// 设置(BeanUtils组件)BeanUtils.copyProperty(t, fieldName, columnValue);}// 对象添加到集合list.add(t);}return list;} catch (Exception e) {throw new RuntimeException(e);}}}Log4lpackage cn.itcast.f_log4j;import mons.logging.Log;import mons.logging.LogFactory;import org.junit.Test;public class App {Log log = LogFactory.getLog(App.class);@Testpublic void save() {try {("保存:开始进入保存方法");int i = 1/0;("保存:执行保存结束,成功");} catch (Exception e) {log.error("执行App类Save()方法出现异常!"); // 异常e.printStackTrace();}}/** 思考:日志的输出级别作用?* ----> 控制日志输出的内容。