Java反射、JDK动态代理、注解
- 1. Java反射机制
-
- 1.1 含义
- 1.2 实现成员
- 2. Class类
-
- 2.1 实现
-
- 2.1.1 对象名实现
- 2.1.2 类名实现
- 2.1.3 全限定名实现
- 3. Field类
-
- 3.1 实现指定属性
- 3.2 实现所有属性
- 4. Method类
-
- 4.1 实现指定方法
- 4.2 实现所有方法
- 5. Constructor类
-
- 5.1 实现
- 6. JDK动态代理
-
- 6.1 作用
- 6.2 特点
- 6.3 实例_优化连接池
- 7. 注解
-
- 7.1 作用
- 7.2 类型
-
- 7.2.1 元注解
- 7.2.2 内置注解
- 7.2.3 自定义注解
-
- 7.2.3.1 实现
- 7.2.3.2 ORM案例_使用注解将类信息转换成数据表格的SQL语句
1. Java反射机制
1.1 含义
通过Java反射机制,可以动态的访问、操作一个类的信息
1.2 实现成员
Java反射机制通过创建四种对象来实现
- Class类_字节码对象类
其实例为某个类的字节码
- Field类_属性类
其实例为某个类的属性
- Method类_方法类
其实例为某个类的方法
- Constructor类_构造方法类
其实例为某个类的构造方法
2. Class类
Class类可以创建某个类的字节码对象
要创建属性类、方法类、构造方法类的对象,需要先创建字节码对象类的对象
2.1 实现
2.1.1 对象名实现
public class Test {
public static void main(String[] args){
//创建Person类的对象
Person person=new Person();
//通过对象名创建Class对象
Class class1=person.getClass();
}
}
-------------------------------------------------------------
//Person类
class Person{
private String name;
private int age;
//无参构造方法
public Person(){
}
//有参构造方法
public Person(String name,int age){
this.name=name;
this.age=age;
}
//learn方法-无参
public void learn(){
System.out.println(name+"在教室学习");
}
//learn方法-有参
public void learn(String sub){
System.out.println(name+"在教室学习"+sub);
}
//重写toString方法
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
2.1.2 类名实现
public class Test {
public static void main(String[] args){
//通过类名创建Class对象
Class class2=Person.class;
}
}
2.1.3 全限定名实现
public class Test {
public static void main(String[] args){
//通过类名创建Class对象
try {
Class class3=Class.forName("cn.khue.csdn.Person");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
3. Field类
3.1 实现指定属性
public class Test {
public static void main(String[] args) throws Exception {
//1.创建该类的字节码对象
Class class3=Class.forName("cn.khue.csdn.Person");
//2.创建该类的指定属性的对象
Field fieldName=class3.getDeclaredField("name");
//输出该属性对象的名称
System.out.println(fieldName.getName());
//输出该属性对象的类型
System.out.println(fieldName.getType());
//输出该属性对象的类型名称
System.out.println(fieldName.getType().getName());
//给该属性数值
Person p=new Person();
fieldName.setAccessible(true);//因为name属性为private,所以需要获取访问权限
fieldName.set(p,"khue");//set需要先指定给哪一个对象的属性赋值,所以需要先创建Person类的对象
System.out.println(p.getName());
}
}
3.2 实现所有属性
public class Test {
public static void main(String[] args) throws Exception {
//1.创建该类的字节码对象
Class class3=Class.forName("cn.khue.csdn.Person");
//2.创建该类的指定属性的对象
Field[] fields=class3.getDeclaredFields();
//查看所有属性信息
for(Field field:fields){
System.out.print(field.getName()+"\t");//查看属性名
System.out.println(field.getType());//查看属性类型
}
}
}
4. Method类
4.1 实现指定方法
public class Test {
public static void main(String[] args) throws Exception {
//1.创建该类的字节码对象
Class class3=Class.forName("cn.khue.csdn.Person");
//2.创建该类的指定方法的对象
Method methodLearn=class3.getDeclaredMethod("learn");//无参方法
Method methodLearn2=class3.getDeclaredMethod("learn",String.class);//有参方法
//查看方法的信息
System.out.println(methodLearn.getName());//打印方法名
System.out.println(methodLearn2.getReturnType());//打印返回值类型
System.out.println(methodLearn.getParameterCount());//打印形参个数
System.out.println(Arrays.toString(methodLearn2.getParameterTypes()));//打印形参类型
//调用方法
Person person=new Person();
Object obj=methodLearn.invoke(person);
Object obj1=methodLearn2.invoke(person,"Java");
}
}
4.2 实现所有方法
public class Test {
public static void main(String[] args) throws Exception {
//1.创建该类的字节码对象
Class class3=Class.forName("cn.khue.csdn.Person");
//2.创建该类所有方法的对象
Method[] methods=class3.getDeclaredMethods();
//查看方法的信息
for(Method method:methods){
System.out.print(method.getName()+"\t");//打印方法的名称
System.out.print(method.getParameterCount()+"\t");//打印方法的形参个数
System.out.print(Arrays.toString(method.getParameterTypes())+"\t");//打印方法的形参类型
System.out.println(method.getReturnType());//打印方法的返回值类型
}
}
}
5. Constructor类
5.1 实现
public class Test {
public static void main(String[] args) throws Exception {
//1.创建该类的字节码对象
Class class3=Class.forName("cn.khue.csdn.Person");
//2.创建该类指定构造方法的对象
Constructor constructor=class3.getDeclaredConstructor();//无参构造方法
Constructor constructor1=class3.getDeclaredConstructor(String.class,int.class);//有参构造方法
//3.创建所有构造方法
Constructor[] constructors=class3.getConstructors();
}
}
6. JDK动态代理
6.1 作用
在不修改被代理类源码的情况下,增强其功能
6.2 特点
-
面向接口
只能增强接口中 被实现类实现的方法
只能读取到接口中方法的注解
- 基于反射机制
6.3 实例_优化连接池
- 初始版本
public class ConnectionPool {
private final static String URL;//数据库地址
private final static String UNAME;//数据库登录用户名
private final static String PWD;//数据库登录密码
private final static int initSize;//连接池初始连接数量
private final static int maxSize;//连接池最大连接数量
private static LinkedList<Connection> pool;//存放连接的池
//初始化连接池
static{
//获取驱动
Class.forName("com.mysql.jdbc.Driver");
//定义连接池
pool=new LinkedList<Connection>();
//创建连接并存放入池
for(int i=0;i<initSize;i++){
pool.add(initConnection());
}
}
//创建一个连接
public static Connection initConnection(){
return DriverManager.getConnection(URL,UNAME,PWD);
}
//获取一个连接
public static Connection getConnection(){
if(pool.size()>0){
return pool.removeFirst();//如果池中还有连接就直接取出
}else{
return initConnection();//如果池中没有连接就直接新建
}
}
//归还连接
public static void returnConnection(Connection ... conn){//可一次归还多个连接
for(Connection c:conn){
if(pool.size()<maxSize){
pool.addLast(c);//如果连接池未满就直接入池
}else{
c.close();//如果连接池已满就之间关闭
}
}
}
}
- 优化版本
public class ConnectionPool {
private final static String URL;//数据库地址
private final static String UNAME;//数据库登录用户名
private final static String PWD;//数据库登录密码
private final static int initSize;//连接池初始连接数量
private final static int maxSize;//连接池最大连接数量
private static LinkedList<Connection> pool;//存放连接的池
//初始化连接池
static{
//获取驱动
Class.forName("com.mysql.jdbc.Driver");
//定义连接池
pool=new LinkedList<Connection>();
//创建连接并存放入池
for(int i=0;i<initSize;i++){
pool.add(initConnection());
}
}
//创建一个连接
public static Connection initConnection(){
Connection connection=DriverManager.getConnection(URL,UNAME,PWD);
//创建动态代理
Connection proxyConnection=(Connection) Proxy.newProxyInstance(
connection.getClass().getClassLoader(),//被代理类的类加载器
connection.getClass().getInterfaces(),//被代理类所实现的接口
new InvocationHandler() {//InvocationHandler的匿名内部类
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object obj=null;
if(method.getName().equals("close")){//如果调用了close方法,就直接执行连接回收方法
if(pool.size()<maxSize){
pool.addLast((Connection)proxy);
}else{
connection.close();
}
}else{//否则执行其它正常的方法
obj=method.invoke(connection,args);
}
return obj;
}
}
);
return proxyConnection;
}
//获取一个连接
public static Connection getConnection(){
if(pool.size()>0){
return pool.removeFirst();//如果池中还有连接就直接取出
}else{
return initConnection();//如果池中没有连接就直接新建
}
}
}
7. 注解
7.1 作用
- 生成文档
- 在编译时进行格式检查
- 替代配置文件gongn
7.2 类型
- 元注解
- 内置注解
- 自定义注解
7.2.1 元注解
元注解只能用于注解
-
@Target
用于限定注解的只用范围
@Target(ElementType.TYPE)//被使用的注解只能用于类
@Target(ElementType.FIELD)//被使用的注解只能用于属性
@Target(ElementType.METHOD)//被使用的注解只能用于方法
@Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD})//被使用的注解可以用于类、属性、方法
...
-
@Retention
用于限定注解的生命周期
@Retention(RetentionPolicy.RUNTIME)//被使用的注解在运行时有效
@Retention(RetentionPolicy.CLASS)
@Retention(RetentionPolicy.SOURCE)
...
- @Documented
- @Inherited
7.2.2 内置注解
-
@Override
重写注解
-
@Decprecated
过时注解
-
@SuressWarning
抑制(关闭)警告注解
- …
7.2.3 自定义注解
7.2.3.1 实现
@Target(限定范围)
@Retention(限定生命周期)
@interface 注解名{
String value();//参数
int age() default 25;//设定默认值的参数
...
}
7.2.3.2 ORM案例_使用注解将类信息转换成数据表格的SQL语句
Object Relationship Mapping指对象关系映射
public class Test {
public static void main(String[] args) throws Exception {
//1.给定一个类的全限定名
String str=generateSql("cn.khue.annotation2.Student");
//2.输出该类的数据库表格创建的SQL语句
System.out.println(str);
}
//给定类的全限定名,生成该类对应数据库表格的SQL语句
public static String generateSql(String className) throws Exception {
StringBuilder sb=new StringBuilder("create table ");
//1.获取该类的字节码对象
Class clazz=Class.forName(className);
//2.获取该类的表名
TableAnn ann=(TableAnn) clazz.getAnnotation(TableAnn.class);
sb.append(ann.name()+"(");
//3.获取该类的属性
Field[] field=clazz.getDeclaredFields();
for(int i=0;i<field.length;i++){
FieldAnn fieldAnn=field[i].getAnnotation(FieldAnn.class);
//字段名
sb.append(field[i].getName()+" ");
//字段类型
sb.append(fieldAnn.type()+" ");
//字段长度
sb.append("("+fieldAnn.length()+") ");
//字段约束
sb.append(fieldAnn.constraint());
//字段分隔
if(i<field.length-1){
sb.append(",");
}
}
sb.append(")");
return sb.toString();
}
}
//学生类
@TableAnn(name = "student")
class Student{
@FieldAnn(type = "int",length = 10,constraint = "primary key auto_increment")
private int id;
@FieldAnn(type = "varchar",length = 20,constraint = "not null unique")
private String name;
@FieldAnn(type = "int",length = 10,constraint = "not null")
private int age;
}
//学生类注解
@Target(ElementType.TYPE)//限定注解用于类
@Retention(RetentionPolicy.RUNTIME)//限定注解在运行时有效
@interface TableAnn{
String name();//表名
}
//学生属性注解
@Target(ElementType.FIELD)//限定注解用于属性
@Retention(RetentionPolicy.RUNTIME)//限定注解在运行时有效
@interface FieldAnn{
String type();//字段类型
int length();//字段类型长度
String constraint() default "";//字段的约束
}