Day40
1.反射案例 之 万能数组扩容
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[].classClass<?> 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);}@Overridepublic 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);}@Overridepublic void getDataSource() {//https://wx2.sinaimg.cn/mw690/e2438f6cly1hoo3qpm7vrj21111jk4mn.jpgSystem.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{@Overridepublic void getDataSource() {System.out.println("获取其他数据");}}
3.反射案例 之 操作注解
利用注解使Student类的属性与数据库表名一致,与mybatis的起别名差不多
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.理解数据中心DataCenter3.反射案例 – 操作注解
注意:
1.理解注解是可以给类、属性、方法提供额外信息