学习JavaEE的日子 Day40 反射案例

Day40

1.反射案例 之 万能数组扩容

设置泛型的copyof仅支持引用数据类型,即任意类型,直接new数组不行,利用反射实现扩容;

打印调用toString也进行编写,利用StringBuffer或者StringBiulder进行字符串拼接

public class Test01 {
	public static void main(String[] args) {
		
		String[] ss = {"小希","小空","小丽","小光","小爱"};
		String[] newSS = MyArrays.copyOf(ss, 8);
		System.out.println(MyArrays.toString(newSS));
		
		int[] is = {1,2,3,4,5};
		int[] newIS = MyArrays.copyOf(is, 8);
		System.out.println(MyArrays.toString(newIS));
	}
}

MyArrays类

public class MyArrays {
	
	/**
	 * 拷贝数组(以前的方法)
	 * @param original 目标数组
	 * @param newLength 新数组的长度
	 * @return 新数组
	 */
	public static int[] copyOf(int[] original, int newLength){
		
		int copyLength = original.length;
		if(copyLength > newLength){
			copyLength = newLength;
		}
		
		int[] newArr = new int[newLength];
		
		for (int i = 0; i < copyLength; i++) {
			newArr[i] = original[i];
		}
		return newArr;
	}
	
	/**
	 * 反射的方法
	 * 引用数据类型数组的扩容(不支持基本数据类型)
	 * @param original
	 * @param newLength
	 * @return
	 */
	public static <T> T[] copyOf(T[] original , int newLength){
		
		int copyLength = original.length;
		if(copyLength > newLength){
			copyLength = newLength;
		}
		
		//获取元素的类型
		Class<? extends Object[]> clazz = original.getClass();//String[].class
		Class<?> componentType = clazz.getComponentType();//String.clss
		
		//利用反射创建数组
		@SuppressWarnings("unchecked")
		T[] ts = (T[]) Array.newInstance(componentType, newLength);
		
		//遍历源数组,将数据复制到新数组中
		for (int i = 0; i < copyLength; i++) {
			//获取源数组的数据
			Object element = Array.get(original, i);
			//赋值给新数组
			Array.set(ts, i, element);
		}
		return ts;
	}
	
	/**
	 * 将数组转换为字符串
	 * @param a 目标数组
	 * @return 转换后的字符串
	 */
	public static String toString(int[] is) { 
		StringBuffer sb = new StringBuffer();
		
		sb.append("[");
		
		for (int element : is) {
			if(sb.length() != 1){
				sb.append(",");
			}
			sb.append(element);
		}
		sb.append("]");
		return sb.toString();
	}
	
	/**
	 * 将数组转换为字符串
	 * @param a 目标数组
	 * @return 转换后的字符串
	 */
	public static <T> String toString(T[] a){
		
		StringBuffer sb = new StringBuffer();
		
		sb.append("[");
		
		for (int i = 0; i < Array.getLength(a); i++) {
			if(sb.length() != 1){
				sb.append(",");
			}
			Object element = Array.get(a, i);
			sb.append(element);
		}
		
		sb.append("]");
		return sb.toString();
	}
	
}

2.反射案例 之 业务与逻辑分离 的思想

invoke方法参数的意义

参数一:表示代理对象,一般不用(了解)

参数二:就是方法名,我们可以对方法名进行判断,是增强还是拦截

参数三:调用方法时,传递的参数

需求:用户选择获取数据的方式(本地数据、网络数据)

public class Test01 {
	public static void main(String[] args) {
		
		Scanner scan = new Scanner(System.in);
		showMenu();
		int num = scan.nextInt();
		
		DataSource dataSource = getDataSourceObject(num);
		dataSource.getDataSource();
		
		scan.close();
	}
	
	public static void showMenu(){
		System.out.println("请选择获取数据的方式:");
		ArrayList<String> menulist = DataCenter.menuList;
		for (String element : menulist) {
			System.out.println(element);
		}
	}
	
	public static DataSource getDataSourceObject(int num){
		DataSource dataSource = DataCenter.dataSourceList.get(num-1);
		return dataSource;
	}
}

配置文件

dataSourceConfig.properties

data=com.qf.reflex02.LocalDataSource,com.qf.reflex02.NetworkDataSource,com.qf.reflex02.OtherDataSource

menuConfig.properties

data=1-\u83B7\u53D6\u672C\u5730\u6570\u636E,2-\u83B7\u53D6\u7F51\u7EDC\u6570\u636E,3-\u83B7\u53D6\u5176\u4ED6\u6570\u636E
public abstract class DataSource {

	public abstract void getDataSource();
	
}

数据中心类(选择1,2,3,继续第几个操作)

//数据中心
public class DataCenter {

	public static final ArrayList<String> menuList;
	public static final ArrayList<DataSource> dataSourceList;
	
	//初始化菜单数据
	static{
		
		menuList = new ArrayList<>();
		
		Properties p = new Properties();
		try {
			p.load(DataCenter.class.getClassLoader().getResourceAsStream("menuConfig.properties"));
		} catch (IOException e) {
			e.printStackTrace();
		}
		String data = p.getProperty("data");
		String[] split = data.split(",");
		Collections.addAll(menuList, split);
	}
	
	//初始化数据源数据
	static{
		
		dataSourceList = new ArrayList<>();
		
		Properties p = new Properties();
		try {
			p.load(DataCenter.class.getClassLoader().getResourceAsStream("dataSourceConfig.properties"));
		} catch (IOException e) {
			e.printStackTrace();
		}
		String data = p.getProperty("data");
		String[] split = data.split(",");
		for (String classPath : split) {
			try {
				Class<?> clazz = Class.forName(classPath);
				DataSource dataSouce = (DataSource) clazz.newInstance();
				dataSourceList.add(dataSouce);
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}		
		}
	}
}

获取本地资源的类(第一个选择)

//获取本地资源的类
public class LocalDataSource extends DataSource{

	private Scanner scan;
	
	public LocalDataSource() {
		scan = new Scanner(System.in);
	}
	
	@Override
	public void getDataSource() {
		
		System.out.println("请填写需要拷贝文件的路径:");
		String path = scan.next();
		File file = new File(path);
		BufferedInputStream bis = null;
		BufferedOutputStream bos = null;
		try {
			bis = new BufferedInputStream(new FileInputStream(path));
			bos = new BufferedOutputStream(new FileOutputStream(file.getName()));
			
			byte[] bs = new byte[1024];
			int len;
			while((len=bis.read(bs)) != -1){
				bos.write(bs, 0, len);
			}
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if(bis != null){
				try {
					bis.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if(bos != null){
				try {
					bos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}

}

获取网络资源的类(第二个选择)

//获取网络资源的类
public class NetworkDataSource extends DataSource{

	private Scanner scan;
	
	public NetworkDataSource() {
		scan = new Scanner(System.in);
	}

	@Override
	public void getDataSource() {
		//https://wx2.sinaimg.cn/mw690/e2438f6cly1hoo3qpm7vrj21111jk4mn.jpg
		System.out.println("请填写下载图片的网址:");
		String path = scan.next();
		
		try {
			//创建链接对象
			URL url = new URL(path);
			//获取连接对象
			HttpURLConnection connection = (HttpURLConnection) url.openConnection();
			
			//设置参数
			connection.setConnectTimeout(5000);//设置连接超时时间
			connection.setReadTimeout(5000);//设置读取数据超时时间
			connection.setDoInput(true);//设置是否允许使用输入流
			connection.setDoOutput(true);//设置是否允许使用输出流
			
			//获取响应状态码
			int code = connection.getResponseCode();
			if(code == HttpURLConnection.HTTP_OK){
				
				//文件名
				String fileName = path.substring(path.lastIndexOf("/")+1);
				
				BufferedInputStream bis = new BufferedInputStream(connection.getInputStream());
				BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(fileName));
				byte[] bs = new byte[1024];
				int len;
				while((len = bis.read(bs)) != -1){
					bos.write(bs, 0, len);
				}
				
				bis.close();
				bos.close();
				
			}else if(code == HttpURLConnection.HTTP_NOT_FOUND){
				System.out.println("页面未找到");
			}
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}


其他数据(第三个选择)

//其他数据
public class OtherDataSource extends DataSource{

	@Override
	public void getDataSource() {
		System.out.println("获取其他数据");
	}

}


3.反射案例 之 操作注解

利用注解使Student类的属性与数据库表名一致,与mybatis的起别名差不多

简单涉及注解开发,没有遵循注解规范就报错,当然这里处理是随便抛的异常

注意:这里为前面反射获取注解信息及实际运用做了补充

工具类里,利用反射,设置权限,获取注解,属性的数据拿到
数据字符串拼接用StringBuilder或者Strinngbuffer

public class Test01 {
	public static void main(String[] args) {
		
		Student stu = new Student("小威", "男", 18);
		
		String sql = DBUtil.generateInsertSQL(stu);
		System.out.println(sql);
		//INSERT INTO s_student(s_name,s_sex,s_age) VALUES('小威','男',18);
	}
}


类名注解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TableInfo {
	
	String name();
}


属性注解

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldInfo {
	String name();
	String type();
}


Student类

@TableInfo(name="s_student")
public class Student {

	@FieldInfo(name="s_name",type="varchar")
	private String name;
	
	@FieldInfo(name="s_sex",type="varchar")
	private String sex;
	
	@FieldInfo(name="s_age",type="int")
	private int age;
	
	//有参构造,无参构造,get,set方法省略
}


数据库SQL拼接:INSERT INTO s_student(s_name,s_sex,s_age) VALUES(‘小威’,‘男’,18);

public class DBUtil {
	public static String generateInsertSQL(Object obj){
		
		Class<? extends Object> clazz = obj.getClass();
		
		//获取表名
		TableInfo tableInfo = clazz.getAnnotation(TableInfo.class);
		if(tableInfo == null){
			throw new RuntimeException();
		}
		String tableName = tableInfo.name();
		
		StringBuffer names = new StringBuffer();
		StringBuffer values = new StringBuffer();
		
		//获取属性数据
		Field[] fields = clazz.getDeclaredFields();
		for (Field field : fields) {
			field.setAccessible(true);
			
			FieldInfo fieldInfo = field.getAnnotation(FieldInfo.class);
			String name = fieldInfo.name();
			String type = fieldInfo.type();
			
			if(names.length() != 0){
				names.append(",");
			}
			names.append(name);
			
			try {
				
				if(values.length() != 0){
					values.append(",");
				}
				
				Object fieldData = field.get(obj);
				if(type.equals("varchar")){
					values.append("'");
				}
				values.append(fieldData);
				if(type.equals("varchar")){
					values.append("'");
				}
				
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
		
		String sql = "INSERT INTO " + tableName + "(" + names.toString() + ") VALUES(" + values.toString() + ");";
		return sql;
	}
	
}


你觉得反射好不好?好,有两个方向

第一个方向:无视修饰符访问类中的内容。但是这种操作在开发中一般不用,都是框架底层来用的。

第二个方向:反射可以跟配置文件结合起来使用,动态的创建对象,动态的调用方法。

总结

1.反射案例 – 万能数组扩展
注意:
1.泛型的使用
2.利用Array操作数组

2.反射案例 – 业务与逻辑分离的思想
注意:
1.理解思想
2.灵活使用配置文件
3.理解数据中心DataCenter

3.反射案例 – 操作注解
注意:
1.理解注解是可以给类、属性、方法提供额外信息

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

A 北枝

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值