Java类文件编译后,会在类中添加一个静态属性,这个属性就是Class类的实例,用于描述类型信息。描述类信息的架构图如:
Class对象提供了一组方法,让我们可以方便获取类的属性,方法,构造方法等信息,并且用Field,Method,Constructor类来描述,可以用这些类来分析类型信息和运行类型信息来进行一些动态操作,例如反射,动态代理,依赖注入/控制反转等
Class类
Classl类的对象用来表示运行时的类或接口信息,可以通过Class对象获取类名,父类信息,还可以通过Class类获取该类的属性,方法,构造方法等
1. 通过.class属性
2. 通过getClass()方法
3. 通过forName()方法
package xls;
public class ClassTest {
public void print(String str){
System.out.println("Hello "+str);
}
}
- 1
- 2
- 3
- 4
- 5
- 6
package xls;
public class ClassTestMain {
public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
//通过.class属性
Class<ClassTest> clazz1 = ClassTest.class;
System.out.println("通过.class属性: "+clazz1.getCanonicalName());
//通过getClass()方法
ClassTest classTest = new ClassTest();
Class<? extends ClassTest> clazz2 = classTest.getClass();
System.out.println("通过getClass()方法: "+clazz2.getCanonicalName());
//通过forName(className)方法 className为完整名字
Class<?> clazz3 = Class.forName("xls.ClassTest");
System.out.println("通过forName()方法: "+clazz3.getCanonicalName());
//用三种方法获取的Class对象实例化ClassTest
ClassTest classTest1 = clazz1.newInstance();
classTest1.print("classTest1");
ClassTest classTest2 = clazz2.newInstance();
classTest2.print("classTest2");
ClassTest classTest3 = (ClassTest) clazz3.newInstance();
classTest3.print("classTest3");
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
运行结果:
获取Constructor对象
有四种方式获取构造方法的Constructor对象
1. getConstructor(Class,parameterTypes…)用于获取指定参数类型的Constructor对象
但是不能获取私有的构造方法的对象
2. getDeclaredConstructor(Class,paramerterTypes..) 用于获取指定参数类型的Constructor对象
但是能获取公有和私有的构造方法的Constructor对象
3. getConstructors()用于获取所有公有构造方法描述对象,若没有共有构造函数时返回长度为0的数组
4. getDeclaredConstructors()用于获取所有公有和被保护的构造方法描述对象
package xls;
import java.lang.reflect.Constructor;
public class ConstructorTest {
/**
* 构造函数发生重载时,下方的无参构造方法被注释掉的话,则变成没有无参构造方法,
* 当使用Constructor constructor1 = clazz1.getConstructor();就会报错
* 因为这种情况并没有无参构造方法
* 但是当没有写构造方法时,则会有一个默认的无参构造方法使用
* Constructor constructor1 = clazz1.getConstructor();则没有问题
*/
public ConstructorTest(){}
public ConstructorTest(String name){}
public ConstructorTest(String name,int age){}
protected ConstructorTest(int age){}
private ConstructorTest(double salary){}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
package xls;
import java.lang.reflect.Constructor;
public class ConstructorTestMain {
public static void main(String[] args) throws NoSuchMethodException, SecurityException {
/**
* 1.getConstructor(Class...parameterTypes)用于获取指定参数类型的Constructor对象
* 但是不能获取私有的构造方法的对象
*
* 2.getDeclaredConstructor(Class...paramerterTypes) 用于获取指定参数类型的Constructor对象
* 但是能获取公有和私有的构造方法的Constructor对象
*/
Class clazz1 = ConstructorTest.class;//有三种方式获取Class对象
//获取无参构造方法,要注意有没有无参构造方法
Constructor constructor1 = clazz1.getConstructor();
System.out.println(constructor1.toString());
//获取指定参数类型的Constructor对象
Constructor constructor2= clazz1.getConstructor(String.class);
System.out.println(constructor2.toString());
Constructor constructor3= clazz1.getConstructor(String.class,int.class);
System.out.println(constructor3.toString());
//下方的代码会报错,因为getConstructor()不能获取私有属性的
//Constructor constructor4= clazz1.getConstructor(int.class);
//System.out.println(constructor4.toString());
//Constructor constructor5= clazz1.getConstructor(double.class);
//System.out.println(constructor5.toString());
System.out.println("<===============2===============>");
//获取指定类型的被保护的构造方法的对象
Constructor constructor6 = clazz1.getDeclaredConstructor(int.class);
System.out.println(constructor6.toString());
Constructor constructor7 = clazz1.getDeclaredConstructor(double.class);
System.out.println(constructor7.toString());
System.out.println("<===============3===============>");
/**
* 3.getConstructors()用于获取所有公有构造方法描述对象,若没有共有构造函数时返回长度为0的数组
* 4.getDeclaredConstructors()用于获取所有公有和被保护的构造方法描述对象
*/
Constructor[] constructor8 = clazz1.getConstructors();
for(Constructor c :constructor8){
System.out.println(c.toString());
}
System.out.println("<===============4===============>");
Constructor[] constructor9 = clazz1.getDeclaredConstructors();
for(Constructor c :constructor9){
System.out.println(c.toString());
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
运行结果:
获取Method对象
Method的对象用于描述类的单个方法(不包构造方法),可以通过它来获取方法的访问权限,参数类型,返回值的类型等信息,还可以根据Method的对象来动态执行。
package xls;
public class MethodTest {
public void hello(){}
private void student(String name){}
public void teacher(String name){
System.out.println("Hello "+name);
}
public final void school(){}
}
package xls;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MethodMain {
public static void main(String[] args) throws ClassNotFoundException,
NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
/**
* 获取Method的四种方法与获取Constructor的四种方法相似,用法相似
* 1.getMthod(String name,Class...parameterTypes)用于获取指定名称和参数类型的公有方法的描述对象,
* ,不能用来获取私有和被保护的对象
* 2.getDeclaredMethod(String name,Class...parameterTypes)作用和第一个相同,
* 但可以获取来获取非公有的方法描述对象
*/
Class<?> clazz = Class.forName("xls.MethodTest");
Method method1 = clazz.getMethod("hello", null);
Method method3 = clazz.getMethod("teacher", String.class);
// Method method2 = clazz.getMethod("student", String.class);
Method method4 = clazz.getMethod("school", null);
System.out.println("<===================1===================>");
System.out.println(method1.toString());
// System.out.println(method2.toString());
System.out.println(method3.toString());
System.out.println(method4.toString());
Method method5 = clazz.getDeclaredMethod("hello", null);
Method method6 = clazz.getDeclaredMethod("teacher", String.class);
Method method7 = clazz.getDeclaredMethod("student", String.class);
Method method8 = clazz.getDeclaredMethod("school", null);
System.out.println("<===================2===================>");
System.out.println(method5.toString());
System.out.println(method6.toString());
System.out.println(method7.toString());
System.out.println(method8.toString());
/**
* 3.getMethods()获取公有的方法描述对象列表,还包括继承父类或接口的方法描述对象,
* 4.getDeclaredMethods()获取公有和非公有的所有方法描述对象列表,但只能获取
* 自己定义的方法描述对象
*/
Method[] method9 = clazz.getMethods();
System.out.println("<===================3===================>");
for(Method m : method9){
System.out.println(m.toString());
}
Method[] method10 = clazz.getDeclaredMethods();
System.out.println("<===================4===================>");
for(Method m : method10){
System.out.println(m.toString());
}
/**
* 获取Method的对象,可以获取它的方法名,返回类型,执行方法
*/
System.out.println("<======================================>");
System.out.println(method3.getName());//方法名
System.out.println(method3.getReturnType());//返回类型
//还可以通过Method的invoke(Object obj,Object...args)执行方法
//首先需要通过Class对象实例化一个对象
MethodTest metodTest = (MethodTest) clazz.newInstance();
//前面我们已经获取了方法的对象,我们要执行teacher(String name)方法的话,可以用method3
method3.invoke(metodTest, "wto");//执行teacher方法打印出“Hello wto”
//注意我想要获取非公有方法对象的方法名,返回类型,不能直接获取,要先修改访问权限
//method3.setAccessible(true);Method的对象可使用setAccessible修改访问权限true为可访问
//因为Method,Contructor,Field都实现了AccessibleObject的接口,所以Constructor和Field
//可以通过.setAccessible(true);来修改访问权限
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
运行结果:
获取Field对象
package xls;
public class FieldTest {
public String name = "luxi";
public int num =1202020;
private int age;
private double salary;
public String sit;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
package xls;
import java.lang.reflect.Field;
public class FieldTestMain {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException,
SecurityException, InstantiationException, IllegalAccessException {
/**
* Class提供4种方式来获取Field对象
* 这四种方式前面提到获取Constructor和Method的4种方式类似
* 1.getField(String name) 获取指定的公有的属性,name为属性名
* 2.getDeclaredField(String name) 获取指定的属性包括非公有属性,但必须定义在类内部
*/
System.out.println("========================1===================");
Class clazz = Class.forName("xls.FieldTest");
//使用getField(String name)获取
Field field1 = clazz.getField("name");//获取FieldTest名为name的属性对象
//获取到属性对象后,可以获取属性的类型,值,属性名
System.out.println(field1.getType());//获取属性类型
//获取属性的值,必须要传入一个实例化的对象,只有在实例化对象才会有值
FieldTest obj = (FieldTest) clazz.newInstance();
System.out.println(field1.get(obj));
//修改属性的值,不是通过类中的方法赋值,与Method中的invoke(obj,value)执行方法不同
field1.set(obj, "lcy");//把name的值修改为lcy
System.out.println(field1.get(obj));
System.out.println("========================2===================");
//使用getDeclaredField()可以获取非公有的属性值
Field field2 = clazz.getDeclaredField("age");//获取FieldTest名为name的属性对象
//获取到属性对象后,可以获取属性的类型,值,属性名,但是非公有
System.out.println(field2.getType());//获取属性类型
//获取属性的值,必须要传入一个实例化的对象,只有在实例化对象才会有值
FieldTest obj1 = (FieldTest) clazz.newInstance();
field2.setAccessible(true);//修改访问权限
System.out.println(field2.get(obj));
//修改属性的值,不是通过类中的方法赋值,与Method中的invoke(obj,value)执行方法不同
field2.set(obj1, 3);//把name的值修改为lcy
System.out.println(field2.get(obj1));
/**
* 3.getField()获取所有公有属性的对象
* 4.getDeclaredFields()获取所有的属性对象,包括非公有属性
*/
System.out.println("========================3===================");
Field[] field3 = clazz.getFields();
for(Field f : field3){
System.out.println(f.toString());
}
System.out.println("========================4===================");
Field[] field4 = clazz.getDeclaredFields();
for(Field f : field4){
System.out.println(f.toString());
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
运行结果
用反射机制编写通用的Excel导入导出
反射机制
反射机制是指在运行状态中,对任意的一个类,都能知道这个类的所有属性和方法;对任意的一个对象,都能调用它的任意一个方法,修改它的任意属性,这种动态获取的信息以及动态调用对象成员的功能就是java的反射机制。
编写通用的Excel导入导出
假设当一个图书关系管理系统项目中,需要导出图书,成员等信息时,我们不可能为每一个需要导出的对象都写一个导出导入Excel的代码,这会有很多重复性的代码,也没有必要,因此可以写一个通用的Excel导入导出。我的思路是将要导出的数据封装在每一个对象当中,因而我们就可以对对象进行操作,利用反射的机制在代码运行时动态的对这些对象进行操作。
package xls;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import jxl.Cell;
import jxl.Sheet;
import jxl.Workbook;
import jxl.read.biff.BiffException;
import jxl.write.Label;
import jxl.write.WritableSheet;
import jxl.write.WritableWorkbook;
import jxl.write.WriteException;
public class Xls {
/**
* @param arrayList 把要导出的数据封装到一个个对象中,把对象存储到ArrayList中
* @param path 文件的路径
* @param list 第一行为数据的名称
*/
public static void out(ArrayList<?> arrayList,String path,ArrayList<String> list) throws
IllegalArgumentException, IllegalAccessException, IOException, WriteException{
//打开文件
WritableWorkbook book = Workbook.createWorkbook(new File(path));
//创建选项卡
WritableSheet sheet = book.createSheet("sheet1", 0);
//excel中第一行为数据名称
for(int i=0;i<list.size();i++){
Label label = new Label(i,0,(String) list.get(i));
sheet.addCell(label);
}
//j为list的元素个数,数据从第2行还是,第一行为数据的名称
for(int j = 1;j<=arrayList.size();j++){
//根据实例对象获取该对象的Class对象,下表从0开始j-1
Class<? extends Object> clazz = arrayList.get(j-1).getClass();
//获取所有属性值,公有属性和私有属性
Field[] fields = clazz.getDeclaredFields();
int i=0;
for(Field ff : fields){
//私有属性不能被访问和修改,要进行权限的修改
ff.setAccessible(true);
/**
* ff.getType()获取属性类型
* ff.getName()获取属性名
* ff.get()获取属性值
* System.out.println(ff.getType()+" "+ff.getName()+" "+ff.get(list.get(j)));
*/
//Label(0(代表列),1(行), "hello") 代表第二行第一个的值为hello
Label label = new Label(i++,j, String.valueOf(ff.get(arrayList.get(j-1))));
sheet.addCell(label);
}
}
book.write();
book.close();
}
/**
* @param clazz Class的对象
* @param path 文件路径
* @return ArrayList
*/
public static ArrayList<?> in(Class<?> clazz,String path) throws BiffException, IOException, NoSuchMethodException,
SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException{
ArrayList<Object> list = new ArrayList<Object>();
Workbook book = Workbook.getWorkbook(new File(path));
//获取第一个选项卡
Sheet sheet = book.getSheet(0);
//根据Class的对象获取所有属性
Field[] fields = clazz.getDeclaredFields();
//获取行数,每一行为每一个对象的数据
int row = sheet.getRows();
for(int j=1;j<row;j++){
int i = 0;
//实例化一个对象
Object obj = clazz.newInstance();
for(Field ff : fields){
//ff.getName()获取属性名,把属性名的首字母大写。例如属性名为name,那么它set的方法名为setName
String methodName = "set"+ff.getName().substring(0, 1).toUpperCase()+ff.getName().substring(1);
//j为行,i为列,获取文件中的值,类型为String
String value;
Cell cell = sheet.getCell(i++,j);
value = cell.getContents();
//根据实例化的对象的Class对象获取实例对象的方法 ,getMethod的参数为要获取的方法的方法名,和参数的类型也即是要赋值的属性的类型
Method method = obj.getClass().getMethod(methodName,ff.getType());
//在excel中获取的值都是String,所以要根据属性的类型进行值的转换
if(ff.getType().toString().equals("class java.lang.String")){
//调用实例对象obj的set方法进行对属性的数值
method.invoke(obj, value);
}else if(ff.getType().toString().equals("int")||ff.getType().toString().equals("Integer")){
method.invoke(obj, Integer.valueOf(value));
}
}
list.add(obj);//把值赋值到对象中,加入到ArrayList中
}
book.close();
return list;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
package xls;
public class Student {
private String name;
private int num;
private String className;
private String age;
private String major;
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getMajor() {
return major;
}
public void setMajor(String major) {
this.major = major;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String toString() {
return "姓名:" + name + " 学号:" + num + " 班级:"
+ className + " 年龄:" + age + " 专业:" + major;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
package xls;
public class Teacher {
private String name;
private String sex;
private String phone;
private int salary;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String toString() {
return "姓名:"+name+" "+sex+" 手机:"+phone+" 工资:"+salary;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
测试类
package xls;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import jxl.read.biff.BiffException;
import jxl.write.WriteException;
public class XlsTest {
@SuppressWarnings("unchecked")
public static void main(String[] args) throws IllegalArgumentException,
IllegalAccessException, WriteException, IOException, BiffException,
NoSuchMethodException, SecurityException, InvocationTargetException,
InstantiationException {
//把数据导入excel中
ArrayList<Teacher> arrayList = new ArrayList<Teacher>();
Teacher teacher = new Teacher();
teacher.setName("张海");
teacher.setSex("男");
teacher.setPhone("13058993353");
teacher.setSalary(7000);
arrayList.add(teacher);
Teacher teacher1 = new Teacher();
teacher1.setName("张萍");
teacher1.setSex("女");
teacher1.setPhone("15013983453");
teacher1.setSalary(7340);
arrayList.add(teacher1);
Teacher teacher2 = new Teacher();
teacher2.setName("李依芬");
teacher2.setSex("女");
teacher2.setPhone("13550934483");
teacher2.setSalary(8000);
arrayList.add(teacher2);
ArrayList<String> list = new ArrayList<String>();
list.add("姓名");
list.add("性别");
list.add("手机");
list.add("工资");
Xls.out(arrayList,"f:/teacher.xls",list);
//把f:/teacher2.xls的数据导进来
ArrayList<Teacher> arrayList2 = new ArrayList<Teacher>();
arrayList2 = ((ArrayList<Teacher>) Xls.in(Teacher.class,"f:/teacher2.xls"));
for(Teacher t : arrayList2){
System.out.println(t.toString());
}
System.out.println("===================================================================");
Student student = new Student();
student.setName("詹三");
student.setNum(2013363232);
student.setClassName("3班");
student.setAge("21");
student.setMajor("计算机");
ArrayList<Student> arrayList3 = new ArrayList<Student>();
arrayList3.add(student);
ArrayList<String> list1 = new ArrayList<String>();
list1.add("姓名");
list1.add("学号");
list1.add("班级");
list1.add("年龄");
list1.add("专业");
Xls.out(arrayList3,"f:/student.xls",list1);//导出
//导入
arrayList3 = ((ArrayList<Student>) Xls.in(Student.class,"f:/student.xls"));
for(Student t : arrayList3){
System.out.println(t.toString());
}
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
导出到f:/teacher.xls的结果
把f:/teacher.xls表中的数据导入
把f:/student.xls表中的数据导入
导入的结果
深入理解动态代理和深入理解Java Proxy机制点击这里查看