学习笔记day04(反射、泛型、序列化)

一、反射

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)可以自己或借助第三方框架只将对象数据序列化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值