-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcontent.json
1 lines (1 loc) · 22.5 KB
/
content.json
1
{"meta":{"title":"Pirate5946","subtitle":"coding world, coding life.","description":"a coder","author":"Pirate5946","url":"http://yoursite.com","root":"/"},"pages":[{"title":"categories","date":"2020-05-23T05:22:48.000Z","updated":"2020-05-23T05:23:08.000Z","comments":false,"path":"categories/index.html","permalink":"http://yoursite.com/categories/index.html","excerpt":"","text":""},{"title":"tags","date":"2020-05-23T05:21:46.000Z","updated":"2020-05-23T05:22:41.000Z","comments":false,"path":"tags/index.html","permalink":"http://yoursite.com/tags/index.html","excerpt":"","text":""}],"posts":[{"title":"Java知识体系 -- JVM篇","slug":"JVM-2017-09-21-Java知识体系-JVM篇","date":"2020-05-23T04:49:31.000Z","updated":"2020-05-23T04:49:31.000Z","comments":true,"path":"2020/05/23/JVM-2017-09-21-Java知识体系-JVM篇/","link":"","permalink":"http://yoursite.com/2020/05/23/JVM-2017-09-21-Java%E7%9F%A5%E8%AF%86%E4%BD%93%E7%B3%BB-JVM%E7%AF%87/","excerpt":"","text":"参考文章 类加载机制(类加载过程和类加载器) JVM加载class文件的原理类加载机制 类加载机制的定义 JVM 通过 ClassLaoder 将 主机硬盘里的 Class文件(8字节为单位的二进制流,任何编程语言通过各自的编译器都能编译成对应的Class文件) 加载到 JVM的方法区,并对方法区中 Class字节码进行 校验、解析、和初始化、最终形成可以被JVM直接使用的 数据类型 类加载的过程 类文件的加载 通过一个类的名字==获取此类的二进制字节流==(PS:不限于从文件中读取) 从EAR包、WAR包、JAR包中获取 从网络中获取,这种场景最典型的应用就是Applet 运行时计算生成,这种场景使用得最多的就是动态代理技术,在java.lang.reflect.Proxy 中,就是用了ProxyGenerator.generateProxyClass来为特定接口生成形式为“*$Proxy”的代理类 的二进制字节流。 将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。(运行时数据结构是什么,由具体的虚拟机自己定义) 在内存中==生成一个代表这个类的java.lang.Class对象==,作为方法区这个类的各种数据的访问入口。 当类加载完成后,系统会给为之生成一个对象 ==(对象的实例化,还没有被栈里的指针引用)==defineClass方法可以把二进制流字节组成的文件转换为一个java.lang.Class(只要二进制字节流的内容符合Class文件规范)。==这个对象作为程序访问方法区中的这些类型数据的外部接口== ==随后进入链接阶段,链接阶段负责把类的二进制数据添加到JRE中。== 类的链接 Class文件的==字节流验证==: 文件格式验证 元数据验证(语义分析,类与类的继承关系等) 字节码验证(数据流和控制流分析) 符号引用验证(对类自身以外的信息进行匹配校验) 准备 正式为类变量分配内存并设置默认初始值,这里类变量指的是被static修饰的变量。例外:如果类字段是常量 (被final修饰),则在这里会被初始化为表达式指定的值 解析:将常量池内的符号引用替换为直接引用。符号引用:类似于OS中的逻辑地址;直接引用:类似于OS中的物理地址,直接指向目标的指针、相对偏移量或一个能间接定位到目标的句柄。 类的初始化 初始化: 真正开始执行类中定义的Java程序代码;初始化用于执行Java类的构造方法。初始化阶段是执行类构造器()方法的过程。 在以下四种情况下初始化过程会被触发执行: 遇到new、getstatic、putstatic或invokestatic这4条字节码指令时,如果类没有进行过初始化,则需先触发其初始化。生成这4条指令的最常见的java代码场景是: 使用new关键字实例化对象、 读取或设置一个类的静态字段的时候 (被final修饰、已在编译器把结果放入常量池的静态字段除外[intern()方法]), 调用类的静态方法的时候。 使用java.lang.reflect包的方法对类进行反射调用的时候 当初始化一个类的时候,如果发现其父类还没有进行过初始化、则需要先出发其父类的初始化 jvm启动时,用户指定一个执行的主类(包含main方法的那个类),虚拟机会先初始化这个类 举个栗子:在上面准备阶段 public static int value = 12; 在准备阶段完成后 value的值为0,而在初始化阶段调用了类构造器()方法,这个阶段完成后value的值为12。 类初始化的过程是不可逆的,如果中间一步出错,则无法执行下一步 类加载器与双亲委派模型深入探讨 Java 类加载器 Bootstrap ClassLoader :将存放于\\lib目录中的,或者被-Xbootclasspath参数所指定的路径中的,并且是虚拟机识别的(仅按照文件名识别,如 rt.jar 名字不符合的类库即使放在lib目录中也不会被加载)类库加载到虚拟机内存中。启动类加载器无法被Java程序直接引用 Extension ClassLoader :将\\lib\\ext目录下的,或者被java.ext.dirs系统变量所指定的路径中的所有类库加载。开发者可以直接使用扩展类加载器。 Application ClassLoader :负责加载用户类路径(ClassPath)上所指定的类库,开发者可直接使用。 工作过程:如果一个类加载器接收到了类加载的请求,它首先把这个请求委托给他的父类加载器去完成,每个层次的类加载器都是如此,因此所有的加载请求都应该传送到顶层的启动类加载器中,只有当父加载器反馈自己无法完成这个加载请求(它在搜索范围中没有找到所需的类)时,子加载器才会尝试自己去加载。 好处: 安全性避免用户编写的类动态替换Java的一些核心类 java类随着它的类加载器一起具备了一种带有优先级的层次关系。例如类java.lang.Object,它存放在rt.jar中,无论哪个类加载器要加载这个类,最终都会委派给启动类加载器进行加载,因此Object类在程序的各种类加载器环境中都是同一个类。2. 避免类的重复加载 JVM中区分不同类,不仅仅是根据类名,相同的 class文件被不同的 ClassLoader加载就是不同的两个类。 相反,如果用户自己写了一个名为java.lang.Object的类,并放在程序的Classpath中,那系统中将会出现多个不同的Object类,java类型体系中最基础的行为也无法保证,应用程序也会变得一片混乱。 缓存机制所有加载过的类都会缓存在内存中,如果程序中尝试使用某个class时,先从缓存中查找这个类;如果不存在,则读取该类对应的二进制文件并将其转换为class对象并存入缓存区。这就是为什么类修改后需要重启的原因。 自定义类加载器java.lang.ClassLoader类的基本职责就是根据一个指定的类的名称,找到或者生成其对应的字节代码,然后从这些字节代码中定义出一个 Java 类,即 java.lang.Class类的一个实例 从上面源码看出,调用loadClass时会先根据委派模型在父加载器中加载,如果加载失败,则会调用当前加载器的findClass来完成加载。 因此我们自定义的类加载器只需要继承ClassLoader,并覆盖findClass方法,下面是一个实际例子,在该例中我们用自定义的类加载器去加载我们事先准备好的class文件。 ClassLoader.defineClass()方法可以把二进制流字节组成的文件转换为一个java.lang.Class 优秀文章 - 类加载分析,自定义类加载器 为什么要自定义类加载器 对代码进行加密 从指定来源加载类 综合前两种情况 类的实例化 Class.forName(“包名.类名”).newInstance(); // 类加载机制 new 类名(); // 类加载的初始化阶段 newInstance()实际上是把new这个方式分解为两步,即首先调用Class加载方法加载某个类,然后实例化。这样分步的好处是显而易见的。类的加载 和 类实例化 分开处理。我们可以在调用class的静态加载方法forName时获得更好的灵活性,提供给了一种解耦的手段。 区别: Class下的newInstance()的使用有局限,因为它生成对象只能调用无参的构造函数;使用 new关键字生成对象没有这个限制。 newInstance( )是一个方法,而new是一个关键字; 参考文章: 垃圾回收机制 && 弱引用GC 参考文章 Java虚拟机学习 - 体系结构 内存模型JVM内存模型 JDK1.7以前 常量池是放在Java JVM中的方法区中的,许多人也叫它“永久代” JDK1.7中,这个常量池是移动到了java堆中去了 JDK1.8中,移除整个永久代(常量池),取而代之的是一个叫元空间(Metaspace)的区域,(使用本地内存来存储类元数据信息) 内存分为哪几部分1.","categories":[{"name":"JVM","slug":"JVM","permalink":"http://yoursite.com/categories/JVM/"},{"name":"Java基础与提高","slug":"JVM/Java基础与提高","permalink":"http://yoursite.com/categories/JVM/Java%E5%9F%BA%E7%A1%80%E4%B8%8E%E6%8F%90%E9%AB%98/"}],"tags":[{"name":"JVM","slug":"JVM","permalink":"http://yoursite.com/tags/JVM/"},{"name":"Java知识体系","slug":"Java知识体系","permalink":"http://yoursite.com/tags/Java%E7%9F%A5%E8%AF%86%E4%BD%93%E7%B3%BB/"}]},{"title":"动态代理原理分析","slug":"Java基础与提高-2017-08-30-动态代理机制","date":"2020-05-23T04:49:31.000Z","updated":"2020-05-23T04:49:31.000Z","comments":true,"path":"2020/05/23/Java基础与提高-2017-08-30-动态代理机制/","link":"","permalink":"http://yoursite.com/2020/05/23/Java%E5%9F%BA%E7%A1%80%E4%B8%8E%E6%8F%90%E9%AB%98-2017-08-30-%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%E6%9C%BA%E5%88%B6/","excerpt":"","text":"动态代理动态代理类的字节码是在程序运行期间由JVM根据反射等机制动态的生成,所以==不存在代理类的class文件==。代理类和委托类的关系是在程序运行时确定。 Java 动态代理机制分析及扩展,第 1 部分 动态代理分析2 动态代理分析 相关的类和接口 java.lang.reflect.Proxy:这是 Java 动态代理机制的主类,它提供了一组静态方法来==为一组接口动态地生成代理类及其对象== // 方法 1: 该方法用于获取指定代理对象所关联的调用处理器static InvocationHandler getInvocationHandler(Object proxy) // 方法 4:该方法用于为指定类装载器、一组接口及调用处理器==生成动态代理类实例==static Object newProxyInstance(ClassLoader loader, Class[] interfaces,InvocationHandler h) java.lang.reflect.InvocationHandler:这是调用处理器接口,它自定义了一个 invoke 方法,用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对委托类的代理访问。 // 该方法负责集中处理动态代理类上的所有方法调用。第一个参数既是代理类实例,第二个参数是被调用的方法对象// 第三个方法是调用参数。调用处理器根据这三个参数进行预处理或分派到委托类实例上发射执行Object invoke(Object proxy, Method method, Object[] args) ==动态代理类==与普通类的唯一区别就是其字节码是由 ==JVM 在运行时动态生成的而非预存在于任何一个 .class 文件中==。通过类装载器来进行装载才能使用 具体实现步骤 通过实现 InvocationHandler 接口==创建自己的调用处理器==; 通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来==创建动态代理类==; 通过反射机制==获得动态代理类的构造函数==,其唯一参数类型是调用处理器接口类型; 通过构造函数==创建动态代理类实例,==构造时调用处理器对象作为参数被传入==== 实际使用过程更加简单,因为 Proxy 的静态方法 newProxyInstance 已经为我们封装了步骤 2 到步骤 4 的过程,所以简化后的过程如下 // InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发InvocationHandler handler = new InvocationHandlerImpl(..); // 通过 Proxy 直接创建动态代理类实例Interface proxy = (Interface)Proxy.newProxyInstance( classLoader,new Class[] { Interface.class }, handler ); Java 动态代理机制的一些特点。 包:如果所代理的接口都是 public 的,那么它将被定义在顶层包(即包路径为空)如果所代理的接口中有非 public 的接口(因为接口不能被定义为 protect 或 private,所以除 public 之外就是默认的 package 访问级别),那么它将被定义在该接口所在包(假设代理了 com.ibm.developerworks 包中的某非 public 接口 A,那么新生成的代理类所在的包就是 com.ibm.developerworks),这样设计的目的是为了最大程度的保证动态代理类不会因为包管理的问题而无法被成功定义并访问; 类修饰符:==该代理类具有 final 和 public 修饰符==,意味着它可以被所有的类访问,但是不能被再度继承; 类名:格式是“$ProxyN”,其中 N 是一个逐一递增的阿拉伯数字,代表 Proxy 类第 N 次生成的动态代理类,值得注意的一点是,并不是每次调用 Proxy 的静态方法创建动态代理类都会使得 N 值增加,原因是如果对同一组接口(包括接口排列的顺序相同)试图重复创建动态代理类,它会很聪明地返回先前已经创建好的代理类的类对象,而不会再尝试去创建一个全新的代理类,这样可以节省不必要的代码重复生成,提高了代理类的创建效率。 4)类继承关系:该类的继承了Proxy类、实现了一组接口","categories":[{"name":"设计模式","slug":"设计模式","permalink":"http://yoursite.com/categories/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"},{"name":"Java基础与提高","slug":"设计模式/Java基础与提高","permalink":"http://yoursite.com/categories/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/Java%E5%9F%BA%E7%A1%80%E4%B8%8E%E6%8F%90%E9%AB%98/"}],"tags":[{"name":"设计模式","slug":"设计模式","permalink":"http://yoursite.com/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"}]},{"title":"封装,继承,多态","slug":"Java基础与提高-2017-09-12-封装,继承,多态","date":"2020-05-23T04:49:31.000Z","updated":"2020-05-23T04:49:31.000Z","comments":true,"path":"2020/05/23/Java基础与提高-2017-09-12-封装,继承,多态/","link":"","permalink":"http://yoursite.com/2020/05/23/Java%E5%9F%BA%E7%A1%80%E4%B8%8E%E6%8F%90%E9%AB%98-2017-09-12-%E5%B0%81%E8%A3%85%EF%BC%8C%E7%BB%A7%E6%89%BF%EF%BC%8C%E5%A4%9A%E6%80%81/","excerpt":"","text":"Java提高篇1 - 封装 Java特性 - 封装 隐藏类的属性和内部方法,只暴露必要的访问接口 调整类的属性或者方法时,接口方法不用改动,调整内部实现就可以 可以对成员变量的访问进行控制,(进行逻辑判断检查输入的数据是否符合要求),提高代码健壮性 Java特性 - 继承1、子类拥有父类==非private==的属性和方法。 2、子类可以拥有自己属性和方法,即子类可以对父类进行扩展。 3、子类可以用自己的方式实现父类的方法。 不支持多继承的原因:==如果多个父类有共同方法,会产生调用不确定性== this : 代表一个本类对象的引用super : 代表一个父类空间 子类重写父类方法 注意事项 子类重写父类方法时,子类权限必须要大于等于父类的权限 静态只能覆盖静态,或者被静态覆盖应用场景对一个类进行子类的扩展时,子类需要保留父类的方法声明,但是要定义子类中该方法的特有内容时,使用重写操作 子类的实例化过程==子类中所有的构造函数默认都会访问父类中的空参数的构造函数== 子类实例化的时候为什么要访问父类中的构造函数因为子类继承了父类,获取到了父类中的内容,所有在使用父类内容之前,要先看父类是如何对自己内容进行初始化的,所以子类在构造对象时,必须访问父类中的构造函数 如果父类中没有定义空参构造函数,那么子类==必须在子类构造函数第一行,显式写super语句==,如果使用了this调用本类的构造函数,那么就没有super了,子类中的其他构造函数会访问父类的构造函数 讲到继承一定少不了这三个东西:构造器、protected关键字、向上转型 构造器 通过前面我们知道子类可以继承父类的属性和方法,除了那些private的外还有一样是子类继承不了的—构造器。对于构造器而言,它只能够被调用,而不能被继承。 ==对于继承来说,子类会默认调用父类的构造器,但是如果没有默认的父类构造器,子类必须要显示的指定父类的构造器==,而且必须是在子类构造器中做的第一件事(第一行代码)。 调用父类的构造方法我们使用super()即可。 protected关键字protected修饰的类,只可以被==子类==以及与它位于==同一个包的类==访问到 向上转型将子类转换成父类,在继承关系上面是向上移动的,所以一般称之为向上转型。由于向上转型是从一个叫专用类型向较通用类型转换,所以它总是安全的,唯一发生变化的可能就是属性和方法的丢失。 谨慎使用继承继承存在如下缺陷:1、父类变,子类就必须变。 2、继承破坏了封装,对于父类而言,它的实现细节对与子类来说都是透明的。 3、继承是一种强耦合关系。 问一问自己是否需要从子类向父类进行向上转型。==如果必须向上转型,则继承是必要的==,但是如果不需要,则应当好好考虑自己是否需要继承。 Java特性 - 多态多态原理父类或者接口的引用指向其子类的对象 只有在运行的时候才会知道引用变量所指向的具体实例对象。 多态的好处 提高了代码的扩展性原来代码传入一个接口或者类扩展时,传入一个子类,原来的代码不用变,==由子类重写原来的方法,原来的引用会指向子类重写后的方法==不用重新定义一个方法,传入新的对象 由于继承了父类的子类对象可以==向上转型==为父类对象,所以可以定义==一个父类对象的引用指向子类对象== 指向子类的父类引用由于向上转型了,它只能访问父类中拥有的方法和属性,而==对于子类中存在而父类中不存在的方法,该引用是不能使用的==,尽管是重载该方法。若==子类重写==了父类中的某些方法,在调用该些方法的时候,必定是使用子类中定义的这些方法(动态连接、动态调用)。 多态时成员的特点Animal cat = new Cat; 成员变量编译和运行都参考等号的左边 成员函数(非静态)编译看左边,运行看右边 静态方法编译和运行都看左边,==静态方法和类绑定,类名直接调用==覆盖重写只发生在方法上,父类的属性无法被覆盖 为了在父类引用中使用子类的特有方法,可以将父类对象==向下转型==,转换成对应的子类引用 判断对象具体类型的关键字==instanceof==,通常用于向下转型前进行健壮性的判断 多态的三个必要条件 继承、实现:在多态中必须存在有继承关系的子类和父类或者实现类接口的类。 重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。 向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法。 多态的实现形式 继承对于引用子类的父类类型,在处理该引用时,它适用于继承该父类的所有子类,子类对象的不同,对方法的实现也就不同,执行相同动作产生的行为也就不同。==如果父类是抽象类,那么子类必须要实现父类中所有的抽象方法==,这样该父类所有的子类一定存在统一的对外接口,但其内部的具体实现可以各异。这样我们就可以使用顶层类提供的统一接口来处理该层次的方法。 接口继承都是单继承,只能为一组相关的类提供一致的服务接口。但是接口可以是多继承多实现,它能够利用一组相关或者不相关的接口进行组合与扩充,能够对外提供一致的服务接口。所以它相对于继承来说有更好的灵活性。 根据继承链中方法调用的优先级来确认方法,该优先级为: this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。","categories":[{"name":"Java基础与提高","slug":"Java基础与提高","permalink":"http://yoursite.com/categories/Java%E5%9F%BA%E7%A1%80%E4%B8%8E%E6%8F%90%E9%AB%98/"}],"tags":[{"name":"Java基础特性","slug":"Java基础特性","permalink":"http://yoursite.com/tags/Java%E5%9F%BA%E7%A1%80%E7%89%B9%E6%80%A7/"}]},{"title":"Hello World","slug":"hello-world","date":"2020-05-22T15:03:10.000Z","updated":"2020-05-22T15:03:10.000Z","comments":true,"path":"2020/05/22/hello-world/","link":"","permalink":"http://yoursite.com/2020/05/22/hello-world/","excerpt":"","text":"Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub. Quick StartCreate a new post1$ hexo new \"My New Post\" More info: Writing Run server1$ hexo server More info: Server Generate static files1$ hexo generate More info: Generating Deploy to remote sites1$ hexo deploy More info: Deployment","categories":[],"tags":[]}],"categories":[{"name":"JVM","slug":"JVM","permalink":"http://yoursite.com/categories/JVM/"},{"name":"Java基础与提高","slug":"JVM/Java基础与提高","permalink":"http://yoursite.com/categories/JVM/Java%E5%9F%BA%E7%A1%80%E4%B8%8E%E6%8F%90%E9%AB%98/"},{"name":"设计模式","slug":"设计模式","permalink":"http://yoursite.com/categories/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"},{"name":"Java基础与提高","slug":"设计模式/Java基础与提高","permalink":"http://yoursite.com/categories/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/Java%E5%9F%BA%E7%A1%80%E4%B8%8E%E6%8F%90%E9%AB%98/"},{"name":"Java基础与提高","slug":"Java基础与提高","permalink":"http://yoursite.com/categories/Java%E5%9F%BA%E7%A1%80%E4%B8%8E%E6%8F%90%E9%AB%98/"}],"tags":[{"name":"JVM","slug":"JVM","permalink":"http://yoursite.com/tags/JVM/"},{"name":"Java知识体系","slug":"Java知识体系","permalink":"http://yoursite.com/tags/Java%E7%9F%A5%E8%AF%86%E4%BD%93%E7%B3%BB/"},{"name":"设计模式","slug":"设计模式","permalink":"http://yoursite.com/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/"},{"name":"Java基础特性","slug":"Java基础特性","permalink":"http://yoursite.com/tags/Java%E5%9F%BA%E7%A1%80%E7%89%B9%E6%80%A7/"}]}