JAVA泛型、注解和反射培训
- 格式:pptx
- 大小:150.44 KB
- 文档页数:40
反射和注解的使⽤⼀、反射1. 什么是反射反射:是⼀种机制,利⽤该机制可以在程序运⾏过程中对类进⾏解剖并操作类中的⽅法,属性,构造⽅法等成员。
是另外⼀种调⽤构造⽅法、普通⽅法、属性的⽅式。
对⽐普通⽅式:功能更强但是更⿇烦反射操作的统⼀步骤:1. 获取Class字节码对象2. 要操作什么,就获取什么:getxxx(), getDeclaredXXX()要操作构造⽅法,就获取Constructor对象要操作普通⽅法,就获取Method对象要操作属性字段,就获取Field对象3. 如果操作是private类型,就提前设置允许暴⼒反射:setAccessible(true)4. 反射调⽤反射调⽤Constructor:newInstance()反射调⽤Method:invoke()反射调⽤Filed: set(), get()2. Class对象2.1 如何获取⼀个类的Class对象//1. 类名.classClass clazz = Student.class;//2. 对象.getClass()Class clazz = student.getClass();//3. 静态⽅法Class.forName("全限定类名")Class clazz = Class.forName("com.itheima._01reflect.Student");2.2 Class对象的常⽤⽅法//获取简单类名:不包含包的类名String simpleName = clazz.getSimpleName();//获取全限定类名String name = clazz.getName();//⽣成类的实例对象Object object = clazz.newInstance();3. Constructor对象3.1 获取到Constructor对象clazz.getConstructor(Class... parameterTypes):获取public类型的Constructor对象参数parameterTypes:构造⽅法的参数类型clazz.getDeclaredConstructor(Class... parameterTypes):获取任意类型的Constructor对象clazz.getConstructors():获取所有的public类型Constructor数组clazz.getDeclaredConstructors():获取所有任意类型的Constructor数组//1. 获取public类型的构造⽅法Constructor constructor = clazz.getConstructor(String.class, Integer.class);//2. 获取private类型的构造⽅法Constructor constructor = clazz.getDeclaredConstructor();3.2 反射调⽤Constructor⽣成类实例constructor.newInstance(Object... parameterValues):反射调⽤构造⽅法,⽣成类实例对象参数parameterValues:构造⽅法需要的实参值注意:只能操作public类型的构造⽅法,如果要操作private类型的,需要提前设置暴⼒反射setAccessible(true):设置允许暴⼒反射4. Method对象4.1 获取Method对象clazz.getMethod(String methodName, Class... parameterTypes):获取public类型的⽅法clazz.getDeclaredMethod(String methodName, Class... parameterTypes):获取任意类型的⽅法clazz.getMethods():获取所有的public类型⽅法(⾃⼰的,和⽗类的)clazz.getDeclaredMethods():获取所有的任意类型⽅法(⾃⼰的)Class<Student> clazz = Student.class;//获取student⾥的study⽅法:public,⽆参Method method = clazz.getMethod("study");//获取student⾥的eat⽅法:private,⽆参method = clazz.getDeclaredMethod("eat");//获取student⾥的sleep⽅法:public,有参:Stringmethod = clazz.getMethod("sleep", String.class);4.2 反射调⽤Methodmethod.invoke(Object target, Object... parameterValues):反射调⽤⽅法参数:target:调⽤哪个对象的⽅法parameterValues:⽅法的实参返回值:⽅法执⾏的返回值只能调⽤public类型的⽅法。
泛型、反射、注解泛型:泛型,也就是参数化类型,在运⾏时由具体的类型来替换这个泛型参数。
它是在JDK5.0才加⼊的⼀个新功能,它主要带来的好处是安全简单,它可以在编译时检查我们的类型安全,并且消除了类型的强制转换。
(注意:Java中的泛型是在编译后就会擦除掉,也就是说在编译时,编译器可以检查的泛型参数类型是否合法,如果不合法,编译将⽆法通过。
但是编译通过通过,这种泛型参数类型就会擦出掉,变为原始的Object类型)泛型主要涵盖以下⼏点:1)泛型类2)泛型接⼝3)泛型⽅法反射:JAVA反射机制是在运⾏状态中,对于任意⼀个类(Class对象),都能够知道这个类的所有属性和⽅法,也可以通过这个Class对象来创建类的实例;JVM---类加载--->class⽂件----创建--->Class对象---->构建类的实例--->instance(实例)重点在运⾏时动态的操作Class对象1.获取Class对象的三种⽅式1)Class.forName("com.sqlserver.driver.SQLServerDriver");2) Xxxx.class3) 对象.getClass()2.通过Class对象创建实例clazz.newInstance();//相当于new了⼀个对象出来(注意:newInstance⽅法要求相应的类必须提供⼀个⽆参的并且是public的构造⽅法) 3.Class类的常⽤API1)getName() //返回的是⼀个完整类名2)getSimpleName()//返回⼀个简单的类名,不包含包名3) getPackage().getName() //获取类的包名4)getSuperClass() //返回⽗类的Class对象5)getField(String name) //返回指定名称的公共(public)属性6)getDeclaredField(String name)//返回指定名称的属性(包括公共和私有的)7)getFields() //访问所有使⽤public修饰的属性8)getDeclaredFields() //返回所有的属性(包括公共和私有的)9) getMethd(String name, Class paramType) // 根据⽅法名获取具体使⽤public修饰的某个⽅法对象,返回的是⼀个Method对象10) getDeclaredMethd(String name, Class paramType) // 根据⽅法名获取具体的某个⽅法对象(可以是公共的和私有的),返回的是⼀个Method对象11)getMethods() //返回当前类所有public修饰的⽅法,包含继承⾃Object的⽅法12) getDeclaredMethds() // 返回当前类的所有⽅法,包括公共和私有的,但是不包括继承⾃Object的⽅法4.Field类常⽤API(代表Class中的属性)1)setAccessible(true) //当访问私有成员时,调⽤此⽅法打开访问开关2)getName()// 获取属性的名字3)get(object) //获取属性的值,object参数为当前类的实例4)set(object)//给属性赋值,同上5.Method类常⽤API1)getName() //获取⽅法的名字2)invoke(Object instance, Object methodParam) //回调⽅法,invoke返回值就是具体⽅法的返回值3)setAccessible(true) //打开访问开关。
java基础(反射,注解,多线程,juc)JAVA基础java反射class对象三种⽅式获取class加载时对象1.class.forName("全类名"):将字节码⽂件加载进内存,返回class对象2.类名.class:通过类名的属性class获取3.对象.getClass():getClass()⽅法是object中的静态⽅法同⼀个字节码⽂件(*.class)在运⾏过程中只会被加载⼀次class对象功能1.获取成员变量2.获取构造⽅法3.获取成员⽅法4.获取类名Field成员变量⼀般的get⽅法获取public修饰符下的,getDeclared⽆论是什么修饰符都能获取但要获取或改变值需要设置忽略权限修饰符的安全检查setAccessible称为暴⼒反射获取值和改变值都需要给⼀个相应的对象访问修饰符\作⽤范围所在类同⼀包内其他类其他包内⼦类其他包内⾮⼦类private可以访问不可以不可以不可以缺省可以可以不可以不可以protected可以可以可以不可以public可以可以可以可以Constructor构造⽅法⼀样拥有get,可以根据构造器中的参数类型获取newInstance可以创建对象,如果是空参构造可以直接使⽤class对象newInstance⽅法Method成员⽅法⼀样拥有get,可以根据⽅法名,参数获取,获取的时候会获取所有的⽅法包括⽗类invoke⽅法是执⾏相应⽅法,需传⼀个对象如果有参数需要传相应参数getName获取⽅法名propertis配置⽂件propertis对象.load可以加载⼀个配置⽂件并获取配置⽂件中的值可以通过类名.class.getClassLoader可以获取类加载器,然后通过类加载器的⽅法获取资源路径下的资源路径或相应的字节流JAVA注解JDK中⾃定义的注解@Override:检测该注解标注的⽅法是否是继承⾃⽗类或⽗接⼝的@Deprecated:将该注解标注的内容,表⽰已过时@SupperessWarnings:压制警告⾃定义注解格式:元注解public @interface 注解名称{}本质:注解本质上就是接⼝public interface 注解名称 extends ng.annotation.Annotation{}属性:接⼝中的抽象⽅法要求:属性的返回值类型基本数据类型、String、枚举、注解,及上⾯的数组类型定义了属性就要给属性赋值,也可以使⽤default给默认值,如果只有⼀个value要赋值就可以省略元注解:⽤于描述注解的注解@Target:描述注解能够作⽤的位置ElementType取值:TYPE:可以作⽤于类上METHOD:可以作⽤于⽅法上FIELD:可以作⽤在成员变量上@Retention:描述注解被保留的阶段RetentionPolicy.SOURCE/CLASS/RUNTIME表⽰java 的三个阶段,源代码,字节码,运⾏时被jvm读到@Documented:描述注解是否被抽取到api⽂档中@Inherited:描述注解是否被⼦类继承解析注解获取标有注解的类的字节码⽂件对象Class<类> 名称 = 类.class获取该类上⾯标注的注解。
java高级知识点总结ppt一、泛型1. 为什么需要泛型- 早期的Java中,集合类中的元素都是Object类型,需要进行类型转换导致代码冗余和安全隐患- 泛型可以在编译时进行类型检查,提高代码的安全性和可读性2. 泛型的相关概念- 泛型类:class MyClass<T> {}- 泛型接口:interface MyInterface<T> {}- 泛型方法:public <T> void myMethod(T t) {}- 泛型通配符:List<?>、List<? extends Number>、List<? super Number>3. 泛型的继承和通配符- extends关键字用于指定类型上限- super关键字用于指定类型下限- PECS(Producer Extends, Consumer Super)原则4. 类型擦除- Java中的泛型是通过擦除实现的- 泛型在编译时会被擦除为Object类型- 泛型参数的实际类型信息会丢失5. 泛型使用的注意事项- 泛型数组的创建是不允许的- 泛型类型参数不能是基本类型- 无法创建参数化类型的数组二、注解1. 什么是注解- 注解是一种用于向编译器、开发工具和其他程序读取信息的标记- 可以用于标记方法、字段、类等2. 常用的注解- @Override:用于标记重写父类的方法- @Deprecated:用于标记已过时的方法或类- @SuppressWarnings:用于忽略编译器警告- @FunctionalInterface:用于标记函数式接口- @Target:用于指定注解的作用目标- @Retention:用于指定注解的生命周期- @Documented:用于指定注解是否包含在JavaDoc中3. 自定义注解- 定义注解:@interface MyAnnotation {}- 注解元素:可以是基本数据类型、枚举类型、Class类型,或者其他注解类型 - 使用注解:@MyAnnotation4. 注解处理器- 注解处理器是用来处理注解的工具- 可以在编译时、运行时或者在自定义工具中处理注解5. 元注解- 元注解用于标记其他注解的注解- 常用的元注解有:@Target、@Retention、@Inherited、@Documented三、反射1. 什么是反射- 反射是指程序在运行时能够获取自身的信息,并能够对自身进行操作的能力2. Class类- 反射的核心是Class类,代表了一个类的属性和方法- 通过Class类可以获取类的构造函数、字段、方法等信息- 可以通过Class类创建类的对象3. 反射的应用- 动态代理:通过反射实现动态生成代理类- 注解处理器:通过反射获取注解信息并进行相应处理- 类加载器:通过反射加载指定路径下的类文件4. 反射的性能问题- 反射在性能上有一定的损耗- 应尽量避免在性能敏感的代码中大量使用反射5. 相关类和接口- Field:代表类的字段- Method:代表类的方法- Constructor:代表类的构造函数- Modifier:提供了用于反射的访问修饰符常量四、Lambda表达式1. 什么是Lambda表达式- Lambda表达式是一种匿名函数,可以作为参数传递给其他方法- 包含三个部分:参数列表、箭头符号、方法体2. Lambda表达式的特点- 简洁:去除了冗余的语法- 方便:可以直接以函数式接口变量接收Lambda表达式3. 函数式接口- 函数式接口是指只包含一个抽象方法的接口- 可以使用@FunctionalInterface注解来标记一个接口为函数式接口 - Java中内置了一些常用的函数式接口,如Runnable、Comparator等4. Lambda表达式的应用- 可以使用Lambda表达式来简化匿名内部类的写法- 可以用于简化集合类的遍历、排序等操作- 可以用于简化线程的创建和启动5. Lambda表达式的限制- 只能用于函数式接口- 不能使用break和continue关键字- 不能改变非final的局部变量的值五、并发编程1. 线程安全性- 多线程程序的最大挑战之一是确保数据的一致性和正确性- synchronized关键字和Lock接口是保证线程安全性的常用手段2. 并发容器- Java中提供了一些线程安全的集合类,如ConcurrentHashMap、CopyOnWriteArrayList 等- 这些集合类在多线程环境下能够安全地进行并发访问3. 线程池- 线程池可以管理和复用线程,避免线程频繁创建和销毁的开销- Executors类提供了创建线程池的工厂方法- ThreadPoolExecutor类提供了更灵活的线程池配置4. 原子操作- 原子操作是指不可被中断的一个或一系列操作- Java中提供了一些原子操作的类,如AtomicInteger、AtomicLong等5. 并发工具类- Java提供了一些并发工具类,如CountDownLatch、Semaphore、CyclicBarrier等,用于解决特定的并发问题总结本次总结了Java中的一些高级知识点,包括泛型、注解、反射、Lambda表达式和并发编程。
java高级语法Java高级语法Java是一种面向对象的编程语言,由于其跨平台性和安全性,成为了广泛使用的编程语言之一。
在Java中,高级语法是指一些比较复杂的特性和技巧,这些特性和技巧可以提高程序的效率、可读性和可维护性。
本文将介绍Java高级语法的几个方面。
1.泛型泛型是Java中一个重要的特性,它可以让程序员在编写代码时指定数据类型,在运行时再进行类型检查。
泛型可以应用于类、接口、方法等各种场景。
1.1 泛型类泛型类是指具有一个或多个类型参数的类。
例如:```public class MyList<T> {private List<T> data;public MyList() {data = new ArrayList<>();}public void add(T item) {data.add(item);}public T get(int index) {return data.get(index);}}```在上面的代码中,MyList类有一个类型参数T,表示该类可以存储任意类型的数据。
在创建MyList对象时,需要指定T的具体类型。
```MyList<String> list = new MyList<>();list.add("hello");String str = list.get(0);```上面的代码演示了如何使用MyList类存储字符串,并获取第一个字符串。
1.2 泛型方法泛型方法是指具有一个或多个类型参数的方法。
例如:```public class MyUtils {public static <T> T max(T a, T b) {if (pareTo(b) > 0) {return a;} else {return b;}}}```在上面的代码中,max方法有一个类型参数T,表示该方法可以比较任意类型的数据。
java⾼级-泛型T和注解封装与使⽤⼀、java泛型其实就是约束我们的集合和接⼝和类为什么要泛型:规范我数据的操作和类型,它常⽤语⼀些接⼝和⽗⼦关系中(继承)泛型能很好体现java的继承,封装这两个特点⽤途:泛型、反射---->做项⽬,搭框架-》模仿和揣测ssh ssi 散列的数据结构 Vector<E>//comparator comparable 排序//Integer Long Float Double Character Boolean ByteArrayList<类> list = new ArrayList<类>();list.add("x");//Spring -->⾯向接⼝编程-->以接⼝为导向-->延伸出很多规范和⼦类---⽐如:数据库业务的增删改查//注解、反射、设计模式(编程思想)、线程池(jvm)//⽅法注解、类注解、属性注解===低耦合==就是为了拿到类本⾝//⽇志统计:我要统计出你的请求是来⾃哪个类,哪个⽅法,并且执⾏了多长时间,以及他们的模块名称是什么。
//id name class_name user_name create_name description model update_time user_id⼆、注解封装与使⽤注解+Aop注解+Filter①封装package com.steven.demo;import ng.annotation.Documented;import ng.annotation.ElementType;import ng.annotation.Retention;import ng.annotation.RetentionPolicy;import ng.annotation.Target;/*⿊认情况下⼀个⾃定义的 Annotation可以在任意地⽅使⽤,如⾃定义的 MyAnnotatlon,如果没有指定 Target,则可以在任意地⽅使⽤1、只能在 Annotation中出现: ANNOTATION_TYPE2、只能在构造⽅法中出现: CONSTRUCTOR3、在属性中出现: FIELD4、只能在本地变量中出现: LOCAL_VARIIABLE5、在⽅法上出现: METHOD6、在包声明中出现: PACKAGE7、在参数声明中出现: PARAMETER8、类、接⼝(包括注释类型)或枚举声明中使⽤:TYPE@Documented在java.1ang, annotation中定义的注解类型 Documented,指⽰某⼀类型的注释将通过 javadoc和类似的默认⼯具进⾏⽂档化。
Java之reflection(反射机制)——通过反射操作泛型,注解⼀、反射操作泛型(Generic) Java采⽤泛型擦除机制来引⼊泛型。
Java中的泛型仅仅是给编译器Javac使⽤的,确保数据的安全性和免去强制类型转换的⿇烦。
但是编译⼀旦完成,所有和泛型有关的类型全部被擦除。
为了通过反射操作这些类型以迎合实际开发的需要,Java新增了ParameterizedType,GenericArrayType,TypeVariable和WildcardType⼏种类型来代表不能被归⼀到Class类中的类型但是⼜和原始类型齐名的类型。
ParameterizedType:表⽰⼀种参数化的类型,⽐如Collection< String >GenericArrayType:表⽰⼀种元素类型是参数化类型或者类型变量的数组类型TypeVariable:是各种类型变量的公共⽗接⼝WildcardType:代表⼀种通配符类型表达式,⽐如?、? extends Number、? super Integer。
(wildcard是⼀个单词:就是”通配符“)代码⽰例:package reflection;import ng.reflect.Method;import ng.reflect.ParameterizedType;import ng.reflect.Type;import java.util.List;import java.util.Map;/*** 通过反射获取泛型信息**/public class Demo{//定义两个带泛型的⽅法public void test01(Map<String,Person> map,List<Person> list){System.out.println("Demo.test01()");}public Map<Integer,Person> test02(){System.out.println("Demo.test02()");return null;}public static void main(String[] args) {try {//获得指定⽅法参数泛型信息Method m = Demo.class.getMethod("test01", Map.class,List.class);Type[] t = m.getGenericParameterTypes();for (Type paramType : t) {System.out.println("#"+paramType);if(paramType instanceof ParameterizedType){//获取泛型中的具体信息Type[] genericTypes = ((ParameterizedType) paramType).getActualTypeArguments();for (Type genericType : genericTypes) {System.out.println("泛型类型:"+genericType);}}}//获得指定⽅法返回值泛型信息Method m2 = Demo.class.getMethod("test02", null);Type returnType = m2.getGenericReturnType();if(returnType instanceof ParameterizedType){Type[] genericTypes = ((ParameterizedType) returnType).getActualTypeArguments();for (Type genericType : genericTypes) {System.out.println("返回值,泛型类型:"+genericType);}}} catch (Exception e) {e.printStackTrace();}}}输出结果:#java.util.Map< ng.String, reflection.Person >泛型类型:class ng.String泛型类型:class reflection.Person#java.util.List< reflection.Person >泛型类型:class reflection.Person返回值,泛型类型:class ng.Integer返回值,泛型类型:class reflection.Person⼆、反射操作注解(Annotation)Method/Constructor/Field/Element 都继承了 AccessibleObject , AccessibleObject 类中有⼀个setAccessible⽅法:具体使⽤可以就看我的之前的⽂章好了,介绍了两个简单的反射的应⽤,在顺便讲⼀下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的代码更改⼀下,编译器会在编译阶段就能够帮我们发现类似这样的问题。
java泛型、反射与注解通常我们在开发的时候会遇到各种相似的问题,这种问题如果不⽤⼀种⽅法解决的话,会造成代码冗余。
例如,我们在审批的时候,有些简单的流程只需要改变状态,我们可以有以下⽅法解决:⼀、泛型类public class UpdateEntityUtils<T,V extends IService<T>>{public T setStatus(V v,String id,String status){T t = v.getById(id);Class clazz = t.getClass();try{Method method = clazz.getDeclaredMethod("setStatus",String.class);method.setAccessible(true);method.invoke(t,status);return t;} catch (NoSuchMethodException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}finally {return t;}}}这种在类名后⾯加上泛型的就是泛型类,实例化该类时需要传⼊对应的类型。
⼆、泛型⽅法public class UpdateEntityUtils{public <T,V extends IService<T>> T setStatus(V v,String id,String status){T t = v.getById(id);Class clazz = t.getClass();try{Method method = clazz.getDeclaredMethod("setStatus",String.class);method.setAccessible(true);method.invoke(t,status);return t;} catch (NoSuchMethodException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} catch (InvocationTargetException e) {e.printStackTrace();}finally {return t;}}}这种在⽅法的返回值前⾯加上泛型的就是泛型⽅法,⽽泛型⽅法可以传⼊任何满⾜的类型。
java注解和反射实训结论
在进行java注解和反射实训后,我们得出以下结论:
1. Java注解是在代码层面上的标记,在运行时不会影响程序的实际逻辑,但是可以通过反射获取注解信息,从而根据注解信息进行特定的处理。
2. Java反射可以在运行时获取类的信息,包括类名、字段、方法和注解等,然后可以根据这些信息进行特定的处理,比如动态创建对象、调用方法等。
3. 在实际应用中,Java注解和反射可以结合使用,通过注解标记特定的类、字段、方法等信息,然后使用反射获取这些信息并进行特定的处理,从而达到自动化的目的。
4. Java注解和反射的应用在企业级应用中非常广泛,比如Spring框架就大量使用了注解和反射,从而实现了自动化的配置、依赖注入等功能。
总之,Java注解和反射是Java语言中非常重要的特性,它们可以帮助我们实现自动化的目的,提高开发效率和代码质量。
- 1 -。
java通过注解和泛型,反射获取泛型,并实例化JAVA 的泛型加⼤了编程的灵活性,在配合上反射,可以让我们省去⼤量的重复代码,当你⽤ SpringBoot 整合 JPA 的时候你会发现,你的 DAO 层只需要继承 BaseDao,在显⽰标明泛型的时候,你定义的接⼝就可以有⼀些常⽤的增删改查的⽅法笔者也想实现的类似的功能,但是在使⽤泛型的时候发现 T.calss 的语法是不成⽴的,这涉及到JVM虚拟机对于泛型的擦除,那我们要怎么样拿到 T 这个泛型的字节码和实例呢?1,其实 JDK 给我们提供了相应的⽅法如下:Type type = this.getClass().getGenericSuperclass();Type[] typeArr = ((ParameterizedType) type).getActualTypeArguments();Class<T> mtClass = (Class<T>) (typeArr[0]);2,以上代码我们就获得了 T 这个泛型在运⾏时的类型了,有了字节码,实例化,获取字段,获取注解什么的就不在话下了3,需要注意的是,只有满⾜以下的申明⽅式,在⽗类 A 中才能正常使⽤以上⽅法class A<T> {}class B extends A<User>{}5,这就导致我们对每个类进⾏操作是都需要创建⼀个对应的类来继承A类,好处就在于⼦类不需要写任何代码,6,不知道 JDK 什么时候能实现 T.class 的功能就好了(个⼈浅见)《⼆》下⾯做⼀个简单的列⼦1,声明两个注解 @KeyId @TableNamepackage com.hwq.annotate;import ng.annotation.*;@Documented // 是否出现在⽂档@Target(ElementType.FIELD) // 作⽤范围,常⽤ FIELD 字段等上 TYPE 类上@Retention(RetentionPolicy.RUNTIME) // 作⽤周期,⼀般为运⾏时public @interface KeyID {String value();}package com.hwq.annotate;import ng.annotation.*;@Documented@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface TableName {String value();}2,声明⼀个实体类,贴上⾃⼰写的注解,这⾥由于懒得写 get set ⽅法,笔者使⽤了 lombok 库package com.hwq.reflex;import com.hwq.annotate.KeyID;import com.hwq.annotate.TableName;import lombok.Getter;import lombok.Setter;@Getter@Setter@TableName("user")public class User {@KeyID("ID")Integer id;String name;Integer sex;}3,写⼀个基础类,就是那个实现公共⽅法的类,我在⾥⾯写了⼏个拼接增删改语句的⽅法,⼤家主要看 getTableInfo 这个核⼼⽅法package com.hwq.reflex;import com.hwq.annotate.KeyID;import com.hwq.annotate.TableName;import ng.reflect.Field;import ng.reflect.ParameterizedType;import ng.reflect.Type;import java.util.ArrayList;import java.util.List;public class SqlHelper<T> {protected String tableName = null; // 表名protected String id; // 主键在实体类的名称protected String key; // 主键在数据库的名称protected List<String> fieldList = new ArrayList<String>(); // 字段数据Field[] fieldArr; // 反射出来的字段对象,在取值的时候有⽤/*** 获取泛型类的⽅法,由于 JAVA 虚拟机的泛型擦除机制,我们⽆法获取对应的实体类* 该⽅法可以在⼦类明确表⽰实体类的情况下,获取到实体类注解以及字段* @return*/private synchronized void getTableInfo() {if (tableName == null) {Type type = this.getClass().getGenericSuperclass();Type[] typeArr = ((ParameterizedType) type).getActualTypeArguments();Class<T> mtClass = (Class<T>) (typeArr[0]);TableName table = (TableName) mtClass.getAnnotation(TableName.class); // 获取类上 @TableName 注解tableName = table.value();fieldArr = mtClass.getDeclaredFields();List<String> keyList = new ArrayList<String>();List<String> idList = new ArrayList<String>();for (int i = 0; i < fieldArr.length; i++) {fieldArr[i].setAccessible(true);KeyID keyID = fieldArr[i].getAnnotation(KeyID.class); // 获取类字段上的 @KeyId 注解if (keyID != null) {key = keyID.value();id = fieldArr[i].getName();}fieldList.add(fieldArr[i].getName()); // 获取类的所有字段}}}/*** 新增的⽅法*/public void save(T t) {getTableInfo();StringBuilder insertSql = new StringBuilder(192);StringBuilder filedStr = new StringBuilder(64);StringBuilder valueStr = new StringBuilder(64);insertSql.append("INSERT INTO ");insertSql.append(tableName);filedStr.append(" (");valueStr.append(" VALUE (");try {for (int i = 0; i < fieldList.size(); i++) {String field = fieldList.get(i);if (field == id) continue;filedStr.append(field);filedStr.append(",");valueStr.append("'");valueStr.append(fieldArr[i].get(t));valueStr.append("',");}} catch (Exception ex) {throw new RuntimeException(ex.getMessage());}insertSql.append(filedStr.substring(0, filedStr.length() - 1));insertSql.append(")");insertSql.append(valueStr.substring(0 ,valueStr.length() - 1));insertSql.append(")");String sql = insertSql.toString();System.out.println(insertSql.toString());}/*** 编辑的⽅法,根据主键编辑*/public void edit(T t) {getTableInfo();StringBuilder updateSql = new StringBuilder(192);updateSql.append("UPDATE ");updateSql.append(tableName);updateSql.append(" SET ");int count = 0;String idValue = null;try {for (int i = 0; i < fieldList.size(); i++) {Object value = fieldArr[i].get(t);if (value == null) continue;String field = fieldList.get(i);if (field == id) {idValue = value.toString();} else {updateSql.append(field);updateSql.append("='");updateSql.append(value);updateSql.append("',");count ++;}}} catch (Exception ex) {throw new RuntimeException(ex.getMessage());}if (count == 0 || idValue == null) {throw new RuntimeException("主键为空或实体类没有需要修改的字段");}String sql = updateSql.substring(0, updateSql.length() - 1);sql += " WHERE " + key + "='" + idValue + "'";System.out.println(sql);}/*** 删除的⽅法,根据主键,单个删除*/public void removeById(int id) {getTableInfo();StringBuilder deleteSql = new StringBuilder(128);deleteSql.append("DELETE FROM ");deleteSql.append(tableName);deleteSql.append(" WHERE ");deleteSql.append(key);deleteSql.append("=");deleteSql.append(id);String sql = deleteSql.toString();System.out.println(sql);}}4,写⼀个⼦类继承上⾯的类,⼦类不需要任何代码,记住⼀定要标明泛型的具体类型package com.hwq.reflex;public class Service extends SqlHelper<User> {}5,测试类package com.hwq.reflex;import ng.reflect.Field;public class Index {public static void main(String[] args) {Service sqlHelper = new Service(); // 记住使⽤继承了基类的⼦类,不要直接使⽤基类 User user = new User();user.setId(1);user.setName("张三");user.setSex(1);sqlHelper.save(user);sqlHelper.edit(user);sqlHelper.removeById(12);}}6,运⾏结果。
廖雪峰Java4反射与泛型-1反射-4调⽤构造⽅法1.Class.newInstance()只能调⽤public的⽆参数构造⽅法public class Main {public static void main(String[] args) throws InstantiationException,IllegalAccessException{String s = (String) String.class.newInstance();Integer n = (Integer) Integer.class.newInstance();//Interger没有⽆参数的public构造⽅法会提⽰实例化失败}}2.调⽤带参数的ConstructorConstructor对象包含⼀个构造⽅法的所有信息,可以⽤它来创建⼀个实例。
如Integer有2个构造⽅法,1个传⼊数字,1个传⼊字符串Main.javaimport ng.reflect.Constructor;import ng.reflect.Field;import ng.reflect.InvocationTargetException;public class Main {public static void main(String[] args) throws InvocationTargetException,InstantiationException, IllegalAccessException, NoSuchMethodException { Integer n1 = new Integer(123);Integer n2 = new Integer("123");System.out.println("n1:"+n1+"\t"+"n2:"+n2);Class cls = Integer.class;Constructor cons1 = cls.getConstructor(int.class);Integer n3 = (Integer) cons1.newInstance(123);Constructor cons2 = cls.getConstructor(String.class);Integer n4 = (Integer) cons2.newInstance("123");System.out.println("n3:"+n3+"\t"+"n4:"+n4);}}3.通过Class实例获取Constructor信息getConstructor(Class...):获取某个public的ConstructorgetDeclaredConstructor(Class...):获取某个Constructor,包括⾮public的getConstuctors():获取所有public的ConstructorgetDeclaredConstructors():获取所有的Constructor,包括⾮public的。
Java学习笔记之使⽤反射+泛型构建通⽤DAOPS:最近简单的学了学后台Servlet+JSP.也就只能学到这⾥了.没那么多精⼒去学SSH了,毕竟Android还有很多东西都没学完..学习内容:1.如何使⽤反射+泛型构建通⽤DAO.1.使⽤泛型+反射构建通⽤DAO.DAO的概念曾经写过.其实就是数据访问对象,Date Access Object.其实就是数据库中的数据和Java对象⾥的⼀种关联关系的⼀系列操作.由于以前写过这个概念.就不啰嗦了..简单说⼀说思想.⽐如说:有两张表 User表和Shop表.这是User表中需要进⾏的操作.public interface UserDao {void add(User user);void delete(User user);void update(User user);User select(User user);}这是Shop表中需要进⾏的操作.public interface ShopDao {void add(Shop shop);void delete(Shop shop);void update(Shop shop);Shop select(Shop shop);}不难发现,⼆者都有相同的操作.这样使得代码冗余度较⾼.那么能否将这两个DAO相同的⽅法封装成⼀个呢.这是可以的.这样就构建了⼀个BaseDao⾥⾯封装了⼆者相同的操作.当我们需要操作表的时候,我们将T换成User或者是Shop就可以了.当我们实际项⽬⾯对的表有⾮常多的时候,如果都具有相同的⽅法.那么就可以这样进⾏抽取.public interface BaseDao<T> {void add(T t);void delete(T t);void update(T t);T select(T t);}这样就构建了⼀个通⽤的DAO抽象接⼝.这⾥我拿User表来说,如果User表还有其他的业务逻辑呢(⽐如说查询所有信息等等).那么我们只需要这样.public interface UserDao extends BaseDao<User> {//按照⾏查询,额外的业务逻辑.List<User>findAll();}这样我们只需要定义⼀个新的UserDao就可以了,它继承了BaseDao中的所有⽅法,当有额外的业务逻辑的时候,只需要添加额外⽅法就可以了.这样光有接⼝当然是不⾏的.我们需要有具体的实现.我们先看BaseDao的实现类BaseDaoImp我们来看⼀下思路.先上⼀张原理图.1.⾸先我们如果想对User表进⾏操作,那么我们⾸先需要获取User类型.告诉BaseDaoImp,我们当前是需要对User表进⾏操作.因此构造函数就是⽤来⼲这个的.2. 当我们获取了User类型之后,如果想要对其进⾏操作,那么⾸先需要知道 sql 语句,因此我们需要对sql语句进⾏拼接.那么拼接过程中,我们需要知道User表内部到底声明了哪些变量.这样就需要使⽤反射机制.通过反射机制来获取 User实体类中声明的变量,然后对sql进⾏相关的拼接.那么getsql函数⽤来完成sql的拼接过程.3. 那么拼接完之后还是不⾏,因为拼接出来的sql语句是这样的:insert into User(id,username,password,email,grade) values(?,?,?,?,?)我们需要对占位符进⾏赋值操作.那么⾸先我们需要获取具体的值,那么setArgs就是来获取属性的具体值的.4.当获取了具体的值之后,我们就可以通过sql提供给我们的相关函数来执⾏sql语句了.这⾥函数其实都⾮常的简单,只要细看,还是能明⽩其中的道理的.package com.example.daoimp;import ng.reflect.Field;import ng.reflect.ParameterizedType;import java.sql.PreparedStatement;import java.sql.ResultSet;import com.example.dao.BaseDao;import com.example.helper.JdbcDaoHelper;//通⽤DAOpublic class BaseDaoImp<T> implements BaseDao<T> {/** 操作常量 */public static final String SQL_INSERT = "insert";public static final String SQL_UPDATE = "update";public static final String SQL_DELETE = "delete";public static final String SQL_SELECT = "select";private Class<T> EntityClass; // 获取实体类private PreparedStatement statement;private String sql;private Object argType[];private ResultSet rs;@SuppressWarnings("unchecked")public BaseDaoImp() {/*** 传递User就是 com.example.daoimp.BaseDaoImp<er>* 传递Shop就是 com.example.daoimp.BaseDaoImp<com.example.bean.Shop>* */ParameterizedType type = (ParameterizedType) getClass().getGenericSuperclass();/*** 这⾥如果传递的是User.那么就是class er* 如果传递的是Shop. 那么就是class com.example.bean.Shop* */EntityClass = (Class<T>) type.getActualTypeArguments()[0];}@Overridepublic void add(T t) {// TODO Auto-generated method stubsql = this.getSql(SQL_INSERT); //获取sql.// 赋值.try {argType = setArgs(t, SQL_INSERT);statement = JdbcDaoHelper.getPreparedStatement(sql); //实例化PreparedStatement. //为sql语句赋值.statement = JdbcDaoHelper.setPreparedStatementParam(statement,argType);statement.executeUpdate(); //执⾏语句.} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {JdbcDaoHelper.release(statement, null); //释放资源.}}@Overridepublic void delete(T t) {// TODO Auto-generated method stubsql = this.getSql(SQL_DELETE);try {argType = this.setArgs(t, SQL_DELETE);statement = JdbcDaoHelper.getPreparedStatement(sql);statement = JdbcDaoHelper.setPreparedStatementParam(statement,argType);statement.executeUpdate();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {JdbcDaoHelper.release(statement, null);}}@Overridepublic void update(T t) {// TODO Auto-generated method stubsql = this.getSql(SQL_UPDATE);try {argType = setArgs(t, SQL_UPDATE);statement = JdbcDaoHelper.getPreparedStatement(sql);statement = JdbcDaoHelper.setPreparedStatementParam(statement,argType);statement.executeUpdate();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();} finally {JdbcDaoHelper.release(statement, null);}}@Overridepublic T select(T t) {// TODO Auto-generated method stubsql = this.getSql(SQL_SELECT);T obj = null;try {argType = setArgs(t, SQL_SELECT);statement = JdbcDaoHelper.getPreparedStatement(sql);statement = JdbcDaoHelper.setPreparedStatementParam(statement,argType);rs = statement.executeQuery();Field fields[] = EntityClass.getDeclaredFields();while (rs.next()) {obj = EntityClass.newInstance();for (int i = 0; i < fields.length; i++) {fields[i].setAccessible(true);fields[i].set(obj, rs.getObject(fields[i].getName()));}}} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}return obj;}// sql拼接函数形如 : insert into User(id,username,password,email,grade) values(?,?,?,?,?) private String getSql(String operator) {StringBuffer sql = new StringBuffer();// 通过反射获取实体类中的所有变量Field fields[] = EntityClass.getDeclaredFields();// 插⼊操作if (operator.equals(SQL_INSERT)) {sql.append("insert into " + EntityClass.getSimpleName());sql.append("(");for (int i = 0; fields != null && i < fields.length; i++) {fields[i].setAccessible(true); //这句话必须要有,否则会抛出异常. String column = fields[i].getName();sql.append(column).append(",");}sql = sql.deleteCharAt(sql.length() - 1);sql.append(") values (");for (int i = 0; fields != null && i < fields.length; i++) {sql.append("?,");}sql.deleteCharAt(sql.length() - 1);// 是否需要添加分号sql.append(")");} else if (operator.equals(SQL_UPDATE)) {sql.append("update " + EntityClass.getSimpleName() + " set ");for (int i = 0; fields != null && i < fields.length; i++) {fields[i].setAccessible(true);String column = fields[i].getName();if (column.equals("id")) {continue;}sql.append(column).append("=").append("?,");}sql.deleteCharAt(sql.length() - 1);sql.append(" where id=?");} else if (operator.equals(SQL_DELETE)) {sql.append("delete from " + EntityClass.getSimpleName()+ " where id=?");} else if (operator.equals(SQL_SELECT)) {sql.append("select * from " + EntityClass.getSimpleName()+ " where id=?");}return sql.toString();}// 获取参数.private Object[] setArgs(T entity, String operator)throws IllegalArgumentException, IllegalAccessException {Field fields[] = EntityClass.getDeclaredFields();if (operator.equals(SQL_INSERT)) {Object obj[] = new Object[fields.length];for (int i = 0; obj != null && i < fields.length; i++) {fields[i].setAccessible(true);obj[i] = fields[i].get(entity);}return obj;} else if (operator.equals(SQL_UPDATE)) {Object Tempobj[] = new Object[fields.length];for (int i = 0; Tempobj != null && i < fields.length; i++) {fields[i].setAccessible(true);Tempobj[i] = fields[i].get(entity);}Object obj[] = new Object[fields.length];System.arraycopy(Tempobj, 1, obj, 0, Tempobj.length - 1);obj[obj.length - 1] = Tempobj[0];return obj;} else if (operator.equals(SQL_DELETE)) {Object obj[] = new Object[1];fields[0].setAccessible(true);obj[0] = fields[0].get(entity);return obj;} else if (operator.equals(SQL_SELECT)) {Object obj[] = new Object[1];fields[0].setAccessible(true);obj[0] = fields[0].get(entity);return obj;}return null;}}这样就对BaseDao进⾏了具体的实现.因为我们的User表还有其他额外的操作,那么我们只需要这样.它通过继承BaseDaoImp,然后实现UserDao接⼝,那么UserDaoImp就即具有了BaseDaoImp的通⽤⽅法,还具有了⾃⼰其他的额外⽅法.package com.example.daoimp;import ng.reflect.ParameterizedType;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.util.ArrayList;import java.util.List;import er;import erDao;import com.example.helper.JdbcDaoHelper;public class UserDaoImp extends BaseDaoImp<User> implements UserDao {private Class<?> EntityClass;private String sql;private PreparedStatement statement;private ResultSet rs;private List<User> list;public UserDaoImp() {ParameterizedType type = (ParameterizedType) getClass().getGenericSuperclass();EntityClass = (Class<?>) type.getActualTypeArguments()[0];}@Overridepublic List<User> findAll() {// TODO Auto-generated method stubStringBuffer b = new StringBuffer();list = new ArrayList<User>();sql = b.append("select * from " + EntityClass.getSimpleName()).toString();try {statement = JdbcDaoHelper.getPreparedStatement(sql);rs = statement.executeQuery();while (rs.next()) {User user = new User();user.setId(rs.getInt("id"));user.setPassword(rs.getString("password"));user.setEmail(rs.getString("email"));user.setUsername(rs.getString("username"));user.setGrade(rs.getInt("grade"));list.add(user);}} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}return list;}}有了他们,我们就可以进⾏具体的操作了,如果还有Shop表,那么同理我们可以去创建⼀个ShopDao去继承BaseDao,然后在⾃⼰的ShopDao 定义其他的额外⽅法就可以了.当表⾮常多的时候,我们就可以采⽤这种思想进⾏封装.这样写出的代码质量就显得⾮常的⾼,耦合度也⾮常的松散.在添加上⼯具类.package com.example.helper;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;public class JdbcDaoHelper {private static final String USER = "root";private static final String PASSWORD = "";private static final String URL = "jdbc:mysql://localhost:3306/usermanager"; private static Connection con;// 获取数据库连接对象public static Connection getConnection() {if (con == null) {try {Class.forName("com.mysql.jdbc.Driver");con = DriverManager.getConnection(URL, USER, PASSWORD); } catch (ClassNotFoundException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();}} else {return con;}return con;}public static PreparedStatement getPreparedStatement(String sql) throws SQLException {return getConnection().prepareStatement(sql);}public static PreparedStatement setPreparedStatementParam(PreparedStatement statement, Object obj[]) throws SQLException { for (int i = 0; i < obj.length; i++) {statement.setObject(i + 1, obj[i]);}return statement;}// 释放资源public static void release(PreparedStatement ps, ResultSet rs) {try {if (con != null) {con.close();con = null;}if (ps != null) {ps.close();ps = null;}if (rs != null) {rs.close();rs = null;}} catch (Exception e) {// TODO: handle exception}}}最后加上UserBean.package com.example.bean;public class User {private int id;private String username;private String password;private String email;private int grade;public User(){}public User(int id,String username,String password,String email,int grade){ this.id = id;ername = username;this.password = password;this.email = email;this.grade = grade;}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 getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}public int getGrade() {return grade;}public void setGrade(int grade) {this.grade = grade;}}测试类.package com.example.jdbc;import java.util.List;import er;import erDaoImp;public class Main {/*** @param args*/public static void main(String[] args) {// TODO Auto-generated method stubList<User>list = null;UserDaoImp imp = new UserDaoImp();list = imp.findAll();for(User user:list){System.out.println(user.getId()+" "+user.getUsername()+" "+user.getPassword()+" "+user.getEmail()+" "+user.getGrade()); }//insert操作.User user = new User();user.setId(1);user.setUsername("代码如风");user.setPassword("123456");user.setEmail("123");user.setGrade(5);imp.add(user);//update操作.User user_1 = new User();user.setId(1);user.setUsername("⼼静如⽔");user.setPassword("123456");user.setEmail("123");user.setGrade(5);imp.update(user_1);}}注意(别忘了引⼊mysql.jar包.)最后放上⼀个源代码:/files/RGogoing/JDBCDao.rar。