java集合类是哪个加载器加载_Java——类加载器,反射

类加载器

281e1f973d943efe59d25841da08b2af.png

e9fde6c28ec5380c10c5cd774a5caca4.png

反射

获取字节码对象的3种方式中的第一个就是传说中的反射。

1、基本使用

public void func() throws Exception{

// 1.获取字节码对象

Class clazz = Class.forName("cn.x5456.domain.Person");

// 2.获取类中的构造方法

// a.返回一个构造方法数组

Constructor[] constructors = clazz.getConstructors();

for(Constructor c : constructors){

System.out.println(c); // public cn.x5456.domain.Person(...)

}

// b.获取指定的构造方法

Constructor constructor = clazz.getConstructor(String.class,int.class); // public cn.x5456.domain.Person(java.lang.String,int)

System.out.println(constructor);

// 3.运行构造方法,创建Person类的对象

Object obj = constructor.newInstance("计震宇", 22);

System.out.println(obj); // cn.x5456.domain.Person [name=计震宇, age=22]

}

2、直接使用空参构造,直接建立对象

/*

有前提:

被反射的类,必须具有空参数构造方法

构造方法权限必须public

*/

public void func1() throws Exception{

// 1.获取字节码对象

Class clazz = Class.forName("cn.x5456.domain.Person");

// 2.直接获取空参构造,执行创建Person类对象

Object obj = clazz.newInstance();

System.out.println(obj); // cn.x5456.domain.Person [name=null, age=0]

}

3、获取私有(加上Declared字段)构造

/*

反射获取私有的构造方法运行

不推荐,破坏了程序的封装性,安全性

暴力反射

*/

public void func2() throws Exception{

// 1.获取字节码对象

Class clazz = Class.forName("cn.x5456.domain.Person");

// 2.获取私有构造

// 获取所有的构造方法(包括私有)

Constructor[] allCons = clazz.getDeclaredConstructors();

// 获取指定(私有)构造

Constructor constructor = clazz.getDeclaredConstructor(int.class,String.class);

System.out.println(constructor);

// 3.设置忽略Java的 字段 检查

constructor.setAccessible(true);

// 4.执行私有方法

Object obj = constructor.newInstance(18, "计震宇");

System.out.println(obj);

}

5140eb2c4bc3a6101eea0a1e5f06d640.png

4、获取/设置类内字段的值

/*

* 反射获取成员变量,并修改值

* Person类中的成员String name

*/

public void func() throws Exception {

// 1.获取字节码对象

Class clazz = Class.forName("cn.x5456.demo.Person");

// 2.获取字节码对象内的(公有)成员变量

// a.获取所有

Field[] fields = clazz.getFields();

System.out.println(Arrays.toString(fields)); //[public java.lang.String cn.x5456.demo.Person.name]

// b.获取指定字段的值

Field field = clazz.getField("name");

System.out.println(field); // public java.lang.String cn.x5456.demo.Person.name

// 3.设置字节码对象内字段的值

// Object obj 必须有对象的支持, Object value 修改后的值

Object obj = clazz.newInstance();

field.set(obj,"计宝宝");

}

5、获取类内方法并执行

public void func1() throws Exception {

// 1.获取字节码对象

Class clazz = Class.forName("cn.x5456.demo.Person");

// 2.获取字节码对象内方法

// 获取所有class文件中的所有公共成员方法,包括继承的

Method[] methods = clazz.getMethods();

System.out.println(Arrays.toString(methods));

// 获取指定的方法eat,Method getMethod(String methodName,Class...c)

Method method = clazz.getMethod("sleep", String.class, int.class, double.class);

// 3.执行方法,需要obj

Object obj = clazz.newInstance();

method.invoke(obj,"计宝宝",1,123.456);

}

6、跳过集合的泛型

/*

* 定义集合类,泛型String

* 要求向集合中添加Integer类型

*

* 反射方式,获取出集合ArrayList类的class文件对象

* 通过class文件对象,调用add方法

*

* 反射是修改字节码对象,和编译过程没有关系

* Java中泛型是伪泛型,只是编译器在编译过程中会检查

* 编译成.class文件后,就没有泛型这个概念了

*/

public void func2() throws Exception{

List list = new ArrayList<>();

list.add("计宝宝");

// 1.获取当前类的字节码(类)对象

Class clazz = list.getClass();

// 2.获取字节码(类)对象的add方法

Method method = clazz.getMethod("add", Object.class);

// 3.执行add方法

method.invoke(list,1);

method.invoke(list,2);

method.invoke(list,3);

System.out.println(list); //[计宝宝, 1, 2, 3]

}

反射的作用——注册JDBC驱动

733d619cffa82d71449212755aac4b67.png

面向接口编程

最大的作用:解耦(少修改Java代码,多修改配置文件)

配置文件+反射+接口 来实现

ac8870cd52476317aa3246ba71dcce93.png

使用反射实现excel2entity的工具类

import org.apache.commons.lang3.StringUtils;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;

import org.apache.poi.ss.usermodel.Cell;

import org.apache.poi.ss.usermodel.Row;

import org.apache.poi.ss.usermodel.Sheet;

import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.File;

import java.io.FileInputStream;

import java.lang.reflect.Field;

import java.util.ArrayList;

import java.util.List;

/**

* excel导入数据库工作类

*

* 参数:类.class,input流

* 返回值:一个列表,中是类.class类型,需要自己调用dao层的save方法

* @author x5456

*/

public class ExcelUtils {

public static List Xls2Entity(Class c, String filePath) throws Exception {

return parseExcel(c,filePath);

}

private static List parseExcel(Class c,String filePath) throws Exception{

ArrayList ts = new ArrayList<>();

// 获取文件后缀名

String ext = filePath.substring(filePath.lastIndexOf(".") + 1);

Sheet sheet;

if (ext.equals("xlsx")){

XSSFWorkbook workbook = new XSSFWorkbook(new FileInputStream(new File(filePath)));

//读取文件中第一个Sheet标签页

sheet = workbook.getSheetAt(0);

}else{

HSSFWorkbook workbook = new HSSFWorkbook(new FileInputStream(new File(filePath)));

//读取文件中第一个Sheet标签页

sheet = workbook.getSheetAt(0);

}

// 获取实体类中的所有字段

Field[] fields = c.getDeclaredFields();

List fieldNameList = new ArrayList<>();

for (Field field : fields) {

String name = field.getName();

fieldNameList.add(name);

}

//遍历标签页中所有的行

for (Row row : sheet) {

// 第一行(标题),不导入数据库

int rowNum = row.getRowNum();

if (rowNum == 0) {

continue;

}

// 创建一个实体对象

T t = c.newInstance();

// 一定要重新获取这个对象的字节码对象

// revise:上面的注释是错的,我们需要的是new一个新的对象,但是这个类的class对象都是相同的

Class clazz = t.getClass();

// 循环当前行的每列

for (int i = 0; i < row.getPhysicalNumberOfCells(); i++) {

// // 第一列是id,选择主键自增,可以注释掉

// if (i == 0){

// continue;

// }

String fieldName = fieldNameList.get(i);

// 通过字段名获取字段

Field declaredField = clazz.getDeclaredField(fieldName);

// 获取字段类型的字节码

Class parameterType = declaredField.getType();

Cell cell = row.getCell(i);

cell.setCellType(Cell.CELL_TYPE_STRING); // 将cell设置为string类型

Object value = cell.getStringCellValue();

// 对字段类型进行判断,进行转换

if(StringUtils.isNotBlank((String)value)){

if (parameterType.equals(Double.class)){

value = Double.valueOf((String) value);

}else if(parameterType.equals(Integer.class)){

// 基线导出的excel的坑

double v = Double.valueOf((String) value);

value = (int) v;

}

} else {

value = null;

}

// 忽略java的private字段检查

declaredField.setAccessible(true);

// 调用相应字段的set方法

declaredField.set(t,value);

}

ts.add(t);

}

return ts;

}

}

优化版:建议把上面的看懂,虽然上面写复杂(错:请看revise部分注释)了,但是使用到的知识还是挺重要的。

import org.apache.commons.lang3.StringUtils;

import org.apache.poi.hssf.usermodel.HSSFWorkbook;

import org.apache.poi.ss.usermodel.Cell;

import org.apache.poi.ss.usermodel.Row;

import org.apache.poi.ss.usermodel.Sheet;

import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.File;

import java.io.FileInputStream;

import java.lang.reflect.Field;

import java.util.ArrayList;

import java.util.List;

/**

* excel导入数据库工作类

*

* 参数:类.class,input流

* 返回值:一个列表,中是类.class类型,需要自己调用dao层的save方法

* @author x5456

*/

public class ExcelUtils222 {

public static List Xls2Entity(Class c, String filePath) throws Exception {

return parseExcel(c,filePath);

}

private static List parseExcel(Class c,String filePath) throws Exception{

ArrayList ts = new ArrayList<>();

// 获取文件后缀名

String ext = filePath.substring(filePath.lastIndexOf(".") + 1);

Sheet sheet;

if (ext.equals("xlsx")){

XSSFWorkbook workbook = new XSSFWorkbook(new FileInputStream(new File(filePath)));

//读取文件中第一个Sheet标签页

sheet = workbook.getSheetAt(0);

}else{

HSSFWorkbook workbook = new HSSFWorkbook(new FileInputStream(new File(filePath)));

//读取文件中第一个Sheet标签页

sheet = workbook.getSheetAt(0);

}

// 获取实体类中的所有字段

Field[] fields = c.getDeclaredFields();

//遍历标签页中所有的行

for (Row row : sheet) {

// 第一行(标题),不导入数据库

int rowNum = row.getRowNum();

if (rowNum == 0) {

continue;

}

// 创建一个实体对象

T t = c.newInstance();

// 循环当前行的每列

for (int i = 0; i < fields.length; i++) {

Field declaredField = fields[i];

// 获取字段类型的字节码

Class parameterType = declaredField.getType();

Cell cell = row.getCell(i);

cell.setCellType(Cell.CELL_TYPE_STRING); // 将cell设置为string类型

Object value = cell.getStringCellValue();

// 对字段类型进行判断,进行转换

if(StringUtils.isNotBlank((String)value)){

if (parameterType.equals(Double.class)){

value = Double.valueOf((String) value);

}else if(parameterType.equals(Integer.class)){

// 基线导出的excel的坑

double v = Double.valueOf((String) value);

value = (int) v;

}

} else {

value = null;

}

// 忽略java的private字段检查

declaredField.setAccessible(true);

// 调用相应字段的set方法

declaredField.set(t,value);

}

ts.add(t);

}

return ts;

}

}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值