java中8<<2_8.2(java学习笔记)反射

一、基础知识

对象是表示或封装一些数据,一个类被加载后JVM会创建一个对应该类的Class对象,

类的整个结构信息会被放在对应的对象中,通过这个对象我们可以获取改类的全部信息,

而这些操作称为反射。

二、反射基本操作

2.1获取对象类

上面说了每一个类在加载时会创建一个对应该类的Class对象,这个对象中存放着这个类相对应的信息。我们通过反射可以对这个类进行操作。

那么首先我们要获取这个类对应的Class对象,

我们可以通过Class.forName(path);也可以直接调用该对象getClass()方法。

cfafcaebabc7821b43141398dde46b21.png

User类

public classUser {privateString userName;private intage;privateString sex;privateString pass;publicUser() {

}public User(String userName, intage, String sex, String pass) {super();this.userName =userName;this.age =age;this.sex =sex;this.pass =pass;

}publicString getUserName() {returnuserName;

}public voidsetUserName(String userName) {this.userName =userName;

}public intgetAge() {returnage;

}public void setAge(intage) {this.age =age;

}publicString getSex() {returnsex;

}public voidsetSex(String sex) {this.sex =sex;

}publicString getPass() {returnpass;

}public voidsetPass(String pass) {this.pass =pass;

}

}

public classTestGetInfo {public static void main(String[] args) throwsClassNotFoundException{

User u= newUser();

Class u1=u.getClass();//对应对象.getClass()获取类对象

Class u2= Class.forName("GetClassInfo.User");//Class.forName("包名+类名")获取对象

System.out.println(u2.getName()+"\n"+u1.getName());//getName是获取完整路径名

System.out.println(u1.getSimpleName());//只获取类名

}

}

运行结果:

GetClassInfo.User

GetClassInfo.User

User

2.2获取属性名称

Filed[] getFields()//获取该类对象所代表类中所有属性,只能获取public修饰的属性,不能获取private修饰的属性。

Filed[] getDeclaredFields();//获取该类对象所代表类中所有属性和方法,包括private修饰的属性。

Filed getDeclaredFields(String name);//获取指定属性

importjava.lang.reflect.Field;public classTestGetInfo {public static void main(String[] args) throwsClassNotFoundException, NoSuchFieldException, SecurityException{

User u= newUser();

Class u1= Class.forName("GetClassInfo.User");

Field[] f1=u1.getDeclaredFields();

Field[] f2= u1.getFields();//只能访问public修饰的属性

Field f3 = u1.getDeclaredField("age");//如果用getField("age")获取会出错,无法访问私有属性

for(Field temp:f1){

System.out.println("f1:"+temp);

}for(Field temp:f2){

System.out.println("f2:"+temp);

}

System.out.println("f3:" +f3);

}

}

运行结果:

f1:privatejava.lang.String GetClassInfo.User.userName

f1:private intGetClassInfo.User.age

f1:privatejava.lang.String GetClassInfo.User.sex

f1:privatejava.lang.String GetClassInfo.User.pass

f3:private int GetClassInfo.User.age

2.3获取方法

Method[] getDeclaredMethods();//获取该类所有方法

//获取指定方法,name为方法名,paremeterTypes为参数类型对应的Class对象

方法可能有重名的情况,这时需要方法名加参数类型确定具体方法。

Method[] getDeclaredMethod(String name, Class>... parameterTypes);

importjava.lang.reflect.Method;public classTestGetInfo {public static void main(String[] args) throwsClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException{

User u= newUser();

Class u1 = (Class) Class.forName("GetClassInfo.User");

Method[] m=u1.getDeclaredMethods();

Method m1= null;try{

m1= u1.getDeclaredMethod("setAge",int.class);//如果对应类中除了setAget(int age)还有setAge(){}方法,将参数设置为null获取的是setAge()方法

}catch(NoSuchMethodException e) {//TODO Auto-generated catch block

e.printStackTrace();

}for(Method temp:m){

System.out.println("m:" +temp);

}

System.out.println("m1:" +m1);

}

}

运行结果:

m:public void GetClassInfo.User.setAge(int)

m:public voidGetClassInfo.User.setSex(java.lang.String)

m:public voidGetClassInfo.User.setPass(java.lang.String)

m:publicjava.lang.String GetClassInfo.User.getSex()

m:publicjava.lang.String GetClassInfo.User.getPass()

m:public intGetClassInfo.User.getAge()

m:public voidGetClassInfo.User.setUserName(java.lang.String)

m:publicjava.lang.String GetClassInfo.User.getUserName()

m1:public void GetClassInfo.User.setAge(int)

由于类中方法都是public修饰的所以也可以用getMethod等方法获取。

2.4获取构造器

Constructor[] getDeclaredConstructors();//获取所有构造器

Constructor getConstructor(Class>... parameterTypes);//获取指定参数的构造器

public classTestGetInfo {public static void main(String[] args) throwsClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException{

User u= newUser();

Class u1 = (Class) Class.forName("GetClassInfo.User");

Constructor[] con = (Constructor[]) u1.getDeclaredConstructors();//获取所有构造器

Constructor con1 = null;try{

con1= u1.getDeclaredConstructor(String.class,int.class,String.class,String.class);//获取指定构造器

}catch(NoSuchMethodException e) {//TODO Auto-generated catch block

e.printStackTrace();

}for(Constructortemp:con){

System.out.println("con:" +temp);

}

System.out.println("con1:"+con1);

}

}

运行结果:

con:publicGetClassInfo.User()

con:public GetClassInfo.User(java.lang.String,int,java.lang.String,java.lang.String)

con1:public GetClassInfo.User(java.lang.String,int,java.lang.String,java.lang.String)

2.5反射构造对象

2.5.1调用无参构造方法构造对象

1)、获取对应类对象

2)、调用newInstance方法实例化对象(此时调用的是该类的无参构造进行实例化)

importjava.lang.reflect.Constructor;public classTestGetInfo {public static void main(String[] args) throwsClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException{

User u= newUser();

Class u1 = (Class) Class.forName("GetClassInfo.User");

User user=u1.newInstance();

user.setAge(19);

System.out.println(user.getAge());

}

}

运行结果:19

2.5.2调用指定有参构造方法构造对象

1)、获取对应有参构造方法

2)、通过获取的有参构造方法构造对象

importjava.lang.reflect.Constructor;importjava.lang.reflect.InvocationTargetException;public classTestGetInfo {public static void main(String[] args) throwsClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException{

User u= newUser();

Class u1 = (Class) Class.forName("GetClassInfo.User");

Constructor con1 = null;

User user= null;try{//获取对应构造器

con1 = u1.getDeclaredConstructor(String.class,int.class,String.class,String.class);//通过构造器实例化对象

user = con1.newInstance("hcf",19,"man","123455");

}catch(IllegalArgumentException e) {//TODO Auto-generated catch block

e.printStackTrace();

}catch(InvocationTargetException e) {//TODO Auto-generated catch block

e.printStackTrace();

}catch(NoSuchMethodException e) {//TODO Auto-generated catch block

e.printStackTrace();

}

System.out.println("姓名:" + user.getUserName()+ "年龄" +user.getAge());

}

}

运行结果:

姓名:hcf年龄19

2.6反射调用方法

1)、获取对应方法

2)、通过方法对象的invoke()方法调用

Object invoke(Object obj, Object... args);//将该方法作用于obj对象,参数为args...

importjava.lang.reflect.InvocationTargetException;importjava.lang.reflect.Method;public classTestGetInfo {public static void main(String[] args) throwsClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException{

User u= newUser();

Class u1 = (Class) Class.forName("GetClassInfo.User");

User user=u1.newInstance();

Method m= null;try{//获取setAge方法

m = u1.getDeclaredMethod("setAge", int.class);//调用setAget方法,作用对象是user,参数为19

m.invoke(user, 19);

}catch(NoSuchMethodException e) {//TODO Auto-generated catch block

e.printStackTrace();

}catch(IllegalArgumentException e) {//TODO Auto-generated catch block

e.printStackTrace();

}catch(InvocationTargetException e) {//TODO Auto-generated catch block

e.printStackTrace();

}

System.out.println(user.getAge());

}

}

运行结果:19

2.7反射操作属性

1)、获取指定属性

2)、调用void set(Object obj, Object value)方法设置属性值

ps:如果属性是private修饰的则需要添加setAccessible(true);//表示不做访问检查,直接访问。

importjava.lang.reflect.Field;public classTestGetInfo {public static void main(String[] args) throwsClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException{

User u= newUser();

Class u1 = (Class) Class.forName("GetClassInfo.User");//获取对应类对象

User user=u1.newInstance();//通过反射实例化对象

Field f= u1.getDeclaredField("age");

f.setAccessible(true);//true表示反射对象在使用时不进行访问检查

f.set(user,20);

System.out.println(user.getAge());

}

}

运行结果:20

使用反射可以完成平常无法完成的一些操作,但反射会造成程序效率低下。

下面举个例子看下使用反射与不使用反射直接的差距:

importjava.lang.reflect.Field;importjava.lang.reflect.InvocationTargetException;importjava.lang.reflect.Method;importjava.util.Date;public classTestGetInfo {public static voidtest1(){

Date start= newDate();

User u= newUser();for(int i = 0; i < 1000000000L; i++){

u.getAge();

}

Date end= newDate();

System.out.println("不使用反射直接调用所消耗时间:" + (end.getTime() -start.getTime()));

}public static voidtest2(){

Date start= newDate();

User u= newUser();

Class clazz = (Class) u.getClass();

User user= null;

Method m= null;try{

user=clazz.newInstance();

m= clazz.getDeclaredMethod("getAge",null);for(int i = 0; i < 1000000000L; i++){

m.invoke(user,null);

}

}catch(InstantiationException e) {//TODO Auto-generated catch block

e.printStackTrace();

}catch(IllegalAccessException e) {//TODO Auto-generated catch block

e.printStackTrace();

}catch(NoSuchMethodException e) {//TODO Auto-generated catch block

e.printStackTrace();

}catch(SecurityException e) {//TODO Auto-generated catch block

e.printStackTrace();

}catch(IllegalArgumentException e) {//TODO Auto-generated catch block

e.printStackTrace();

}catch(InvocationTargetException e) {//TODO Auto-generated catch block

e.printStackTrace();

}

Date end= newDate();

System.out.println("使用反射调用所消耗时间(做访问检查):" + (end.getTime() -start.getTime()));

}public static voidtest3(){

Date start= newDate();

User u= newUser();

Class clazz = (Class) u.getClass();

User user= null;

Method m= null;try{

user=clazz.newInstance();

m= clazz.getDeclaredMethod("getAge",null);

m.setAccessible(true);//设置为true不做访问检查

for(int i = 0; i < 1000000000L; i++){

m.invoke(user,null);

}

}catch(InstantiationException e) {//TODO Auto-generated catch block

e.printStackTrace();

}catch(IllegalAccessException e) {//TODO Auto-generated catch block

e.printStackTrace();

}catch(NoSuchMethodException e) {//TODO Auto-generated catch block

e.printStackTrace();

}catch(SecurityException e) {//TODO Auto-generated catch block

e.printStackTrace();

}catch(IllegalArgumentException e) {//TODO Auto-generated catch block

e.printStackTrace();

}catch(InvocationTargetException e) {//TODO Auto-generated catch block

e.printStackTrace();

}

Date end= newDate();

System.out.println("使用反射调用所消耗时间(不做访问检查):" + (end.getTime() -start.getTime()));

}public static void main(String[] args) throwsClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException{

test1();

test2();

test3();

}

}

运行结果:

不使用反射直接调用所消耗时间:607使用反射调用所消耗时间(做访问检查):2529使用反射调用所消耗时间(不做访问检查):1967

我们可以看到使用反射后效率非常低,但是如果设置不进行访问检查效率会有一定的提高。

如果某一段反射进行频繁的操作,设置不进行安全检查,效率会有较大提升。

3.反射机制读取注解

到这里我们就可以结合前面的注解,将一个类和SQL表关联起来(ORM对象关系映射)。

首先我把一个类看做是一个表中一行数据的集合,那么我们要为这个类和对应的表关联起来。

其次我们还需要类中的属性与表中的属性关联起来。

46902c5ba4eb21488c22c797712754fb.png

例如我有这样一张表,其中id为主键会自动设置,regTime数据库会自动设置这两个不需要我们负责。

那么就剩下username 和pwd了

我们可以建一个User类,其中有username和pwd。

再为这个类设置一个注解主要标识表名,为类中属性也设置一个注解主要标识列名和类型。

这样我们创建的类就和这个表对应起来了。

注解:

1.@TableName

importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;

@Target(value={ElementType.TYPE})

@Retention(RetentionPolicy.RUNTIME)//可以被反射读取

public @interfaceTableName {

String value();

}

2.@FieldName

importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;

@Target(ElementType.FIELD)

@Retention(RetentionPolicy.RUNTIME)public @interfaceFieldName {

String cloName();

String type();

}

User类

@TableName(value="t_user")//为类添加注解

public classUser {//为属性添加注解

@FieldName(cloName = "username", type = "varchar")privateString userName;

@FieldName(cloName= "pwd", type = "varchar")privateString pass;publicUser() {

}public User(String userName, intage, String sex, String pass) {super();this.userName =userName;this.pass =pass;

}publicString getUserName() {returnuserName;

}public voidsetUserName(String userName) {this.userName =userName;

}publicString getPass() {returnpass;

}public voidsetPass(String pass) {this.pass =pass;

}

}

读取注解,建立SQL插入语句:

读取注解需要用到:public T getAnnotation(Class annotationClass)获取注解;

annotationClass为注解对应的类对象(注解名.Class),返回类型是注解类型。

例如调用的是xxx.getAnnotation(TableName.class),那么返回的就是TableName类型,即对应的注解,通过这个就可以获取注解中具体的值。

要想获取类的注解,要先获取类,同样获取属性的注解要想获取属性。

importjava.lang.annotation.Annotation;importjava.lang.reflect.AnnotatedType;importjava.lang.reflect.Field;public classTestGetInfo {public static void main(String[] args) throwsClassNotFoundException, InstantiationException, IllegalAccessException {

Class clazz= Class.forName("GetClassInfo.User");

User user= (User)clazz.newInstance();//实例化对象

user.setUserName("gcmh");//设置信息

user.setPass("123456");

Field fName= null;

Field fPass= null;

FieldName annoFieldName= null;//属性对应的注解类型

FieldName annoFieldPass = null;//属性对应的注解类型

TableName tableName = null;//类对应的注解类型

try{//获取类的注解

tableName = (TableName) clazz.getAnnotation(TableName.class);

fName= clazz.getDeclaredField("userName");//获取Name属性

annoFieldName = fName.getAnnotation(FieldName.class);//获取Name属性的注解

fPass = clazz.getDeclaredField("pass");//获取pass属性

annoFieldPass = fPass.getAnnotation(FieldName.class);//获取pass属性的注解

} catch(NoSuchFieldException e) {//TODO Auto-generated catch block

e.printStackTrace();

}catch(SecurityException e) {//TODO Auto-generated catch block

e.printStackTrace();

}

String sqlName= "testjdbc";//数据库名//拼凑SQL插入语句

String sqlInsert = "INSERT INTO" +" `" + sqlName +"`." +

"`"+ tableName.value() + "`" +"(`" +annoFieldName.cloName()+ "`,`" +annoFieldPass.cloName()+ "`)Value("+

"'"+user.getUserName()+"','" + user.getPass()+"');";

System.out.println(sqlInsert);//输出插入语句

}

}

运行结果:

INSERT INTO `testjdbc`.`t_user`(`username`,`pwd`)Value('gcmh','123456');

在SQL中执行这个语句即可插入一个名称为gcmh密码为 123456的用户。

c5b5cf62bfc535233635e676bc487c8d.png

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值