8.2(java学习笔记)反射
一、基础知识
对象是表示或封装一些数据,一个类被加载后JVM会创建一个对应该类的Class对象,
类的整个结构信息会被放在对应的对象中,通过这个对象我们可以获取改类的全部信息,
而这些操作称为反射。
二、反射基本操作
2.1获取对象类
上面说了每一个类在加载时会创建一个对应该类的Class对象,这个对象中存放着这个类相对应的信息。我们通过反射可以对这个类进行操作。
那么首先我们要获取这个类对应的Class对象,
我们可以通过Class.forName(path);也可以直接调用该对象getClass()方法。
User类
public class User {
private String userName;
private int age;
private String sex;
private String pass; public User() { } public User(String userName, int age, String sex, String pass) {
super();
this.userName = userName;
this.age = age;
this.sex = sex;
this.pass = pass;
} public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getPass() {
return pass;
}
public void setPass(String pass) {
this.pass = pass;
} }
public class TestGetInfo {
public static void main(String[] args) throws ClassNotFoundException{
User u = new User();
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);//获取指定属性
import java.lang.reflect.Field; public class TestGetInfo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException{
User u = new User();
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:private java.lang.String GetClassInfo.User.userName
f1:private int GetClassInfo.User.age
f1:private java.lang.String GetClassInfo.User.sex
f1:private java.lang.String GetClassInfo.User.pass
f3:private int GetClassInfo.User.age
2.3获取方法
Method[] getDeclaredMethods();//获取该类所有方法
//获取指定方法,name为方法名,paremeterTypes为参数类型对应的Class对象
方法可能有重名的情况,这时需要方法名加参数类型确定具体方法。
Method[] getDeclaredMethod(String name, Class<?>... parameterTypes);
import java.lang.reflect.Method; public class TestGetInfo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException{
User u = new User();
Class<User> u1 = (Class<User>) 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 void GetClassInfo.User.setSex(java.lang.String)
m:public void GetClassInfo.User.setPass(java.lang.String)
m:public java.lang.String GetClassInfo.User.getSex()
m:public java.lang.String GetClassInfo.User.getPass()
m:public int GetClassInfo.User.getAge()
m:public void GetClassInfo.User.setUserName(java.lang.String)
m:public java.lang.String GetClassInfo.User.getUserName()
m1:public void GetClassInfo.User.setAge(int)
由于类中方法都是public修饰的所以也可以用getMethod等方法获取。
2.4获取构造器
Constructor[] getDeclaredConstructors();//获取所有构造器
Constructor<T> getConstructor(Class<?>... parameterTypes);//获取指定参数的构造器
public class TestGetInfo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException{
User u = new User();
Class<User> u1 = (Class<User>) Class.forName("GetClassInfo.User");
Constructor<User>[] con = (Constructor<User>[]) u1.getDeclaredConstructors();//获取所有构造器
Constructor<User> 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(Constructor<User> temp:con){
System.out.println("con:" + temp);
}
System.out.println("con1:"+con1);
}
}
运行结果:
con:public GetClassInfo.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方法实例化对象(此时调用的是该类的无参构造进行实例化)
import java.lang.reflect.Constructor; public class TestGetInfo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException{
User u = new User();
Class<User> u1 = (Class<User>) Class.forName("GetClassInfo.User");
User user = u1.newInstance();
user.setAge(19);
System.out.println(user.getAge());
}
}
运行结果:
19
2.5.2调用指定有参构造方法构造对象
1)、获取对应有参构造方法
2)、通过获取的有参构造方法构造对象
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException; public class TestGetInfo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException{
User u = new User();
Class<User> u1 = (Class<User>) Class.forName("GetClassInfo.User");
Constructor<User> 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...
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; public class TestGetInfo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException{
User u = new User();
Class<User> u1 = (Class<User>) 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);//表示不做访问检查,直接访问。
import java.lang.reflect.Field; public class TestGetInfo {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException{
User u = new User();
Class<User> u1 = (Class<User>) 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
使用反射可以完成平常无法完成的一些操作,但反射会造成程序效率低下。
下面举个例子看下使用反射与不使用反射直接的差距:
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Date; public class TestGetInfo {
public static void test1(){
Date start = new Date();
User u = new User();
for(int i = 0; i < 1000000000L; i++){
u.getAge();
}
Date end = new Date();
System.out.println("不使用反射直接调用所消耗时间:" + (end.getTime() - start.getTime()));
} public static void test2(){
Date start = new Date();
User u = new User();
Class<User> clazz = (Class<User>) 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 = new Date();
System.out.println("使用反射调用所消耗时间(做访问检查):" + (end.getTime() - start.getTime()));
} public static void test3(){
Date start = new Date();
User u = new User();
Class<User> clazz = (Class<User>) 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 = new Date();
System.out.println("使用反射调用所消耗时间(不做访问检查):" + (end.getTime() - start.getTime()));
}
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException{
test1();
test2();
test3();
}
}
运行结果:
不使用反射直接调用所消耗时间:607
使用反射调用所消耗时间(做访问检查):2529
使用反射调用所消耗时间(不做访问检查):1967
我们可以看到使用反射后效率非常低,但是如果设置不进行访问检查效率会有一定的提高。
如果某一段反射进行频繁的操作,设置不进行安全检查,效率会有较大提升。
3.反射机制读取注解
到这里我们就可以结合前面的注解,将一个类和SQL表关联起来(ORM对象关系映射)。
首先我把一个类看做是一个表中一行数据的集合,那么我们要为这个类和对应的表关联起来。
其次我们还需要类中的属性与表中的属性关联起来。
例如我有这样一张表,其中id为主键会自动设置,regTime数据库会自动设置这两个不需要我们负责。
那么就剩下username 和pwd了
我们可以建一个User类,其中有username和pwd。
再为这个类设置一个注解主要标识表名,为类中属性也设置一个注解主要标识列名和类型。
这样我们创建的类就和这个表对应起来了。
注解:
1.@TableName
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Target(value={ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)//可以被反射读取
public @interface TableName {
String value();
}
2.@FieldName
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldName {
String cloName();
String type();
}
User类
@TableName(value="t_user")//为类添加注解
public class User {
//为属性添加注解
@FieldName(cloName = "username", type = "varchar")
private String userName;
@FieldName(cloName = "pwd", type = "varchar")
private String pass;
public User() { } public User(String userName, int age, String sex, String pass) {
super();
this.userName = userName;
this.pass = pass;
} public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
} public String getPass() {
return pass;
}
public void setPass(String pass) {
this.pass = pass;
}
}
读取注解,建立SQL插入语句:
读取注解需要用到:public <T extends Annotation> T getAnnotation(Class<T> annotationClass)获取注解;
annotationClass为注解对应的类对象(注解名.Class),返回类型是注解类型。
例如调用的是xxx.getAnnotation(TableName.class),那么返回的就是TableName类型,即对应的注解,通过这个就可以获取注解中具体的值。
要想获取类的注解,要先获取类,同样获取属性的注解要想获取属性。
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedType;
import java.lang.reflect.Field; public class TestGetInfo {
public static void main(String[] args) throws ClassNotFoundException, 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的用户。
8.2(java学习笔记)反射的更多相关文章
- Java学习笔记--反射
什么是Java反射 概念 java反射是指java能够在运行时确定类的类型信息,包括其方法.字段.构造函数等,并能够通过反射调用类或者类对象的方法.在Java中,java.lang.Class类与ja ...
- 0034 Java学习笔记-反射-初步2-操作对象
通过反射创建对象 通过反射创建对象有两种方式,一种通过Class对象的newInstance()方法,一种是获取到Class对象的Constructor后,再调用newInstance()方法,前者要 ...
- 0033 Java学习笔记-反射-初步1
先看看通过反射能干嘛 示例:修改对象的private实例变量 package testpack; import java.lang.reflect.Field; public class Test1 ...
- Java学习笔记--反射API
反射API 1.反射API的介绍 通过反射API可以获取Java程序在运行时刻的内部结构.比如Java类中包含的构造方法.域和方法等元素,并可以与这些元素进行交换. 按照 一般地面向对象的设计 ...
- Java 学习笔记 反射与迭代器
反射 使用反射获得类 Class cls = Class.forName("全类名") //包括包名 Class cls = xx.Class;//xx代表类名 使用反射获得构造方 ...
- JAVA 学习笔记 - 反射机制
1. JAVA反射机制的概念 2. 怎样实例化一个 Class对象 Class.forName(包名.类名); 对象.getClass(); 类.class; ================== ...
- Java学习笔记——反射
反射就是把Java类中的各种成分映射成相应的java类. Class类-->java程序中的各个java类属于同一事物,描述这类事物的Java类名就是Class. Class.forName的作 ...
- Java学习笔记-反射机制
Java反射机制实在运行状态时,对于任意一个类,都能够知道这个类的属性和方法,对于任意一个对象,都能够调用他的任意一个属性和方法 获取Class对象的三种方式 Object类中的getClass()方 ...
- 0035 Java学习笔记-注解
什么是注解 注解可以看作类的第6大要素(成员变量.构造器.方法.代码块.内部类) 注解有点像修饰符,可以修饰一些程序要素:类.接口.变量.方法.局部变量等等 注解要和对应的配套工具(APT:Annot ...
- JAVA学习笔记—review基本知识[反射与异常]
JAVA学习笔记—review基本知识[反射与异常] 1.异常: 1.1异常的分类: Java会将所有的异常封装成对象,其根本父类为Throwable. Throwable有两个子类:Error 和E ...
随机推荐
- Robot POJ - 1376
The Robot Moving Institute is using a robot in their local store to transport different items. Of co ...
- ansible 批量修改root密码
[root@sz_fy_virt_encrypt_33_239 fetch]# cat /opt/passwd.yml - hosts: web vars: path: /home/opsadmin ...
- Ecplise添加XML自动提示
这里以struts.xml为例 第一步: 首先找到 struts2的核心jar包,我这里是struts2-core-2.3.20.jar用压缩工具打开或者解压下来
- BigDecimal与Long、int之间的互换
在实际开发过程中BigDecimal是一个经常用到的数据类型,它和int Long之间可以相互转换. 转换关系如下代码展示: int 转换成 BigDecimal 数据类型 //int 转换成 big ...
- [洛谷P2127] 序列排序
洛谷题目链接:序列排序 题目描述 小C有一个N个数的整数序列,这个序列的中的数两两不同.小C每次可以交换序列中的任意两个数,代价为这两个数之和.小C希望将整个序列升序排序,问小C需要的最小代价是多少? ...
- EL遍历集合
jstl EL表达式遍历集合 博客分类: JSTL/EL JSTLEL遍历集合 在EL中,方括号运算符用来检索数组和集合的元素.对于实现 java.util.Map 接口的集合,方括号运算符使用关联 ...
- 【Foreign】树 [prufer编码][DP]
树 Time Limit: 10 Sec Memory Limit: 256 MB Description Input Output Sample Input 3 2 2 1 Sample Outp ...
- bzoj4886 [Lydsy2017年5月月赛]叠塔游戏
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=4886 [题解] 跟bzoj4883:http://www.cnblogs.com/galax ...
- POJ3682 King Arthur's Birthday Celebration
King Arthur is an narcissist who intends to spare no coins to celebrate his coming K-th birthday. Th ...
- iOS 中捕获程序崩溃日志 (2014-04-22 17:35:59)
http://blog.sina.com.cn/s/blog_b71d24920101ky2d.html iOS开发中遇到程序崩溃是很正常的事情,如何在程序崩溃时捕获到异常信息并通知开发者,是大多数软 ...