一、反射
1.什么是反射?
将类的各个部分封装成其他对象,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制
2.java代码在计算机中会经历三个阶段
源代码阶段:java文件经过编译在硬盘中生成字节码文件 如Student.class
类对象阶段:通过类加载器将class文件中的成员变量、构造方法、成员方法加载到内存中
运行时阶段:可以创建对象和调用对象里的方法了
3.反射的应用
①我们在使用JDBC连接数据库时使用Class.forName()通过反射加载数据库的驱动程序;②Spring框架也用到很多反射机制,最经典的就是xml的配置模式。Spring 通过 XML 配置模式装载 Bean 的过程:1) 将程序内所有 XML 或 Properties 配置文件加载入内存中; 2)Java类里面解析xml或properties里面的内容,得到对应实体类的字节码字符串以及相关的属性信息; 3)使用反射机制,根据这个字符串获得某个类的Class实例; 4)动态配置实例的属性
4.反射的代码(模拟spring注解初始化IOC容器)
package cn.mrhan.frames.spring.factory;
import cn.mrhan.frames.spring.BeanDefinition;
import cn.mrhan.frames.spring.annotation.ComponentScan;
import cn.mrhan.frames.spring.annotation.Lazy;
import cn.mrhan.frames.spring.annotation.Service;
import cn.mrhan.frames.spring.config.SpringConfig;
import cn.mrhan.frames.spring.service.SysLogService;
import java.io.File;
import java.io.FileFilter;
import java.lang.reflect.Constructor;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
public class AnnotationConfigApplicationContext {
private Map<String,BeanDefinition> beanMap = new HashMap<>();
private Map<String,Object> instanceMap = new HashMap<>();
public AnnotationConfigApplicationContext(Class<?> configs) throws Exception {
//1.读取配置类指定的包名
ComponentScan cs =configs.getDeclaredAnnotation(ComponentScan.class);//获取注解
String pkg = cs.value();
System.out.println(pkg);
//2.扫描指定包中的类
String classPath = pkg.replace(".","/");
System.out.println(classPath);
URL url = configs.getClassLoader().getSystemResource(classPath);
System.out.println(url);
File fileDir = new File(url.getPath());
File[] classFile = fileDir.listFiles(new FileFilter() {
@Override
public boolean accept(File file) {
return file.isFile()&&file.getName().endsWith(".class");
}
});
//3.封装文件信息
processClassFiles(pkg,classFile);
}
private void processClassFiles(String pkg,File[] classFiles) throws Exception {
for(File f:classFiles){
String pkgClass = pkg +"."+f.getName().substring(0,f.getName().lastIndexOf("."));
Class<?> targetCls = Class.forName(pkgClass);
System.out.println(pkgClass);
if(targetCls.isAnnotationPresent(Service.class)){
continue;
}
//拿到注解
Service service = targetCls.getDeclaredAnnotation(Service.class);
BeanDefinition bd = new BeanDefinition();
bd.setId(service.value());
bd.setPkgClass(pkgClass);
Lazy lazy =
targetCls.getDeclaredAnnotation(Lazy.class);
if(lazy!=null){
bd.setLazy(lazy.value());
}
System.out.println(bd);
beanMap.put(bd.getId(),bd);
if(!bd.getLazy()){
Object obj = newBeanInstance(targetCls);
instanceMap.put(bd.getId(),obj);
}
}
}
public Object newBeanInstance(Class<?> targetCls ) throws Exception {
Constructor<?> con = targetCls.getDeclaredConstructor();
con.setAccessible(true);
return con.newInstance();
}
public <T> T getBean(String key,Class<T> cls) throws Exception {
Object obj = instanceMap.get(key);
if(obj!=null){
return (T)obj;
}
obj = newBeanInstance(cls);
instanceMap.put(key,obj);
return (T)obj;
}
public static void main(String[] args) throws Exception {
AnnotationConfigApplicationContext ctx =
new AnnotationConfigApplicationContext(SpringConfig.class);
SysLogService logService = ctx.getBean("sysLogService",SysLogService.class);
System.out.println(logService);
}
}
package cn.mrhan.frames.spring.config;
import cn.mrhan.frames.spring.annotation.ComponentScan;
@ComponentScan("cn.mrhan.frames.spring.service")
public class SpringConfig {
}
5、解析xml方式
package cn.mrhan.frames.spring;
import org.w3c.dom.Document;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class ClassPathXmlApplicationContext {
//通过map存储文件中定义的bean对象的配置信息
private Map<String,BeanDefinition> beanMap = new HashMap<>();
//通过map存储bean的实例
private Map<String,Object> instanceMap = new HashMap<>();
public ClassPathXmlApplicationContext(String file) throws Exception{
//1.读取配置文件
InputStream in = getClass().getClassLoader().getResourceAsStream(file);
//2.解析文件封装数据
parse(in);
//3.封装数据
}
//本次xml的解析基于dom实现
private void parse(InputStream in) throws Exception {
//1.创建解析器对象(负责读取xml文件内容)
DocumentBuilder builder =
DocumentBuilderFactory.newInstance().newDocumentBuilder();
//2.解析流对象
Document doc = builder.parse(in);
//3.处理document
processDocument(doc);
}
private void processDocument(Document doc) throws Exception {
//1.获取所有bean元素
NodeList list =doc.getElementsByTagName("bean");
//2.迭代bean元素,对其配置信息进行封装
for(int i=0;i<list.getLength();i++){
Node node = list.item(i);
//一个node对象对应一个BeanDefinition对象
BeanDefinition bd = new BeanDefinition();
NamedNodeMap nMap = node.getAttributes();
bd.setId(nMap.getNamedItem("id").getNodeValue());
bd.setPkgClass(nMap.getNamedItem("class").getNodeValue());
bd.setLazy(Boolean.valueOf(nMap.getNamedItem("lazy").getNodeValue()));
//存储配置信息
beanMap.put(bd.getId(),bd);
//基于配置信息中Lazy属性的只 判定此类的实例是否要延迟加载
if(!bd.getLazy()){
Object obj = newBeanInstance(bd.getPkgClass());
instanceMap.put(bd.getId(),obj);
}
System.out.println(instanceMap);
}
}
//基于反射技术构建类的实例对象
public Object newBeanInstance(String pkgClass) throws Exception {
Class<?> cls = Class.forName(pkgClass);
Constructor<?> con = cls.getDeclaredConstructor();
con.setAccessible(true);
return con.newInstance();
}
@SuppressWarnings("unchecked")
public <T>T getBean(String key,Class<T> t) throws Exception {
//1.判定当前InstanceMap中是否有bean的实例
Object obj =instanceMap.get(key);
if(obj!=null){
return (T)obj;
}
//如果没有则创建对象
obj = newBeanInstance(t.getName());
instanceMap.put(key,obj);
return (T)obj ;
}
public static void main(String[] args) throws Exception {
//1.初始化spring容器
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("spring-configs.xml");
//2.从spring容器中获取bean实例
Object obj = ctx.getBean("obj",Object.class);
Date date = ctx.getBean("date",Date.class);
System.out.println(obj);
System.out.println(date);
}
}
二、泛型
1.什么是泛型?
泛型的本质是参数化类型,也就是说锁操作的数据类型被指定为一个参数
2.为什么使用泛型?
如果使用Object来实现通用、不同类型的处理,有两个缺点:每次使用时都需要强制转换成想要的类型、在编译时并不知道类型转换是否正常,运行时才知道 不安全
泛型主要目标是提高java程序的类型安全 编译时期就可以检查出因Java类型不正确导致的异常
消除强制转换。
3.泛型类型擦除
泛型只在编译期起作用,在运行时无效,当编译器对带有泛型的java代码进行编译时,会去执行泛型检查和类型判断 然后生成普通的不带泛型的字节码,这种普通的字节码可以被一般的java虚拟机接收并执行
4.泛型的简单应用 如
public <T> T getObject(String key, Class<T> clazz) {
try (Jedis jedis = (Jedis) pool.getResource()) {
String value = jedis.get(key);
log.debug("redis.get, key: {}, value: {}", key, value);
if (StringUtils.isBlank(value)) {
return null;
} else {
return JSONObject.parseObject(value, clazz);
}
}
}
public static<T> String getInvokeString(String reqPath, String methodCode, String traceLogId, T obj) throws Exception {
String str = JSONObject.toJSONString(obj);
}
三、序列化
1.序列化概念
1)序列化:将对象转换为字节或字符的过程
2)反序列化:将字节转换为对象的过程
2.序列化的应用场景
1)网络通讯
2)数据存储
3.java对象的序列化与反序列化
1)对象要实现Serializable接口
2)添加序列化id 为反序列化提供保障
3)借助流对象实现序列化和反序列化
4.java中的序列化存在安全问题如何解决?
1)添加writeObject方法 对内容进行加密再执行序列化
2)添加readBoject方法对内容先静心反序列化然后再执行解密操作
private void writeObject(ObjectOutputStream out) throws IOException {
x = x+2;//加密
out.defaultWriteObject();//序列化
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();//反序列化
x=x-2;//解密
}
5.Java中序列化的粒度如何控制?
1)transiant:当少量属性不需要序列化时,使用此关键字修饰\
private transient int y;
2)Externalizable(当只有少量属性需要序列化时实现此接口然后自己进行序列化操作
但是要序列化的对象必须是public修饰)
6.java中序列化的性能问题如何 优化?
1)java中默认序列化相对较差 底层默认会将数据以及对应的元数据都进行序列化
2)可以自己或借助第三方框架只将对象数据序列化

369

被折叠的 条评论
为什么被折叠?



