一旦一个共享变量(类的成员变量、类的静态成员变量)被volatile修饰以后,那么就具有了两层语义:
(1) 保证了不一样线程对这个变量进行操做时的可见性,即一个线程修改了某个变量的值,这新值对其余线程来讲是当即可见的。
(2) 禁止进行指令重排序。
volatile只提供了保证访问该变量时,每次都是从内存中读取最新值,并不会使用寄存器缓存该值—每次都会从内存中读取。
而对该变量的修改,volatile并不提供原子性的保证。
因为及时更新,极可能致使另外一线程访问最新变量值,没法跳出循环的状况, 多线程下计数器必须使用锁保护。程序员
(1) 调用super()必须写在子类构造方法的第一行,不然编译不经过。每一个子类构造方法的第一条语句,都是隐含地调用super(),若是父类没有这种形式的构造函数,那么在编译的时候就会报错。
(2) super()和this()相似, 区别是: super从子类中调用父类的构造方法,this()在同一类内调用其它方法。
(3) super()和this()均需放在构造方法内第一行。
(4) 尽管能够用this调用一个构造器,但却不能调用两个。
(5) this和super不能同时出如今一个构造函数里面,由于this必然会调用其它的构造函数,其它的构造函数必然也会有super语句的存在,因此在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会经过。
(6) this()和super()都指的是对象,因此,均不能够在static环境中使用。包括:static变量, static方法,static语句块。
(7) 从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字。web
1) 为何使用内部类?
使用内部类最吸引人的缘由是:每一个内部类都能独立地继承一个(接口的)实现,因此不管外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。
使用内部类最大的优势就在于它可以很是好的解决多重继承的问题,使用内部类还可以为咱们带来以下特性:
(1) 内部类能够用多个实例,每一个实例都有本身的状态信息,而且与其余外围对象的信息相互独。
(2) 在单个外围类中,可让多个内部类以不一样的方式实现同一个接口,或者继承同一个类。
(3) 建立内部类对象的时刻并不依赖于外围类对象的建立。
(4) 内部类并无使人迷惑的“is-a”关系,他就是一个独立的实体。
(5) 内部类提供了更好的封装,除了该外围类,其余类都不能访问。
2) 内部类分类:
(一) 成员内部类:
(1) Inner 类定义在 Outer 类的内部,至关于 Outer 类的一个成员变量的位置,Inner 类可使用任意访问控制符,如 public 、 protected 、 private 等。
(2) Inner 类中定义的 show() 方法能够直接访问 Outer 类中的数据,而不受访问控制符的影响,如直接访问 Outer 类中的私有属性age。
(3) 定义了成员内部类后,必须使用外部类对象来建立内部类对象,而不能直接去 new 一个内部类对象,即:内部类 对象名 = 外部类对象.new 内部类( );
(4) 编译上面的程序后,会发现产生了两个.class 文件: Outer.class,Outer$Inner.class{}。
(5) 成员内部类中不能存在任何static 的变量和方法, 能够定义常量:
● 由于非静态内部类是要依赖于外部类的实例,而静态变量和方法是不依赖于对象的,仅与类相关, 简而言之:在加载静态域时,根本没有外部类,所在在非静态内部类中不能定义静态域或方法,编译不经过; 非静态内部类的做用域是实例级别。
● 常量是在编译器就肯定的, 放到所谓的常量池了。
★ 外部类是不能直接使用内部类的成员和方法的,可先建立内部类的对象,而后经过内部类的对象来访问其成员变量和方法;
★ 若是外部类和内部类具备相同的成员变量或方法,内部类默认访问本身的成员变量或方法,若是要访问外部类的成员变量,可使用 this 关键字,如:Outer.this.name。
(二) 静态内部类: 是 static 修饰的内部类。
(1) 静态内部类不能直接访问外部类的非静态成员,但能够经过 new 外部类().成员 的方式访问
(2) 若是外部类的静态成员与内部类的成员名称相同,可经过“类名.静态成员”访问外部类的静态成员;若是外部类的静态成员与内部类的成员名称不相同,则可经过“成员名”直接调用外部类的静态成员。
(3) 建立静态内部类的对象时,不须要外部类的对象,能够直接建立 内部类 对象名 = new 内部类()。
(三) 方法内部类:访问仅限于方法内或者该做用域内。
(1) 局部内部类就像是方法里面的一个局部变量同样,是不能有 public、protected、private 以及 static 修饰符的。
(2) 只能访问方法中定义的 final 类型的局部变量, 由于: 当方法被调用运行完毕以后,局部变量就已消亡了。但内部类对象可能还存在, 直到没有被引用时才会消亡。此时就会出现一种状况,就是内部类要访问一个不存在的局部变量; 使用final修饰符不只会保持对象的引用不会改变,并且编译器还会持续维护这个对象在回调方法中的生命周期. 局部内部类并非直接调用方法传进来的参数,而是内部类将传进来的参数经过本身的构造器备份到了本身的内部,本身内部的方法调用的实际是本身的属性而不是外部类方法的参数; 防止被篡改数据,而致使内部类获得的值不一致。在内部类中的属性和外部方法的参数二者从外表上看是同一个东西,但实际上却不是,因此他们二者是能够任意变化的,也就是说在内部类中我对属性的改变并不会影响到外部的形参,而然这从程序员的角度来看这是不可行的,毕竟站在程序的角度来看这两个根本就是同一个,若是内部类该变了,而外部方法的形参却没有改变,这是难以理解和不可接受的,因此为了保持参数的一致性,就规定使用 final来避免形参的不改变。
(四) 匿名内部类:
(1) 匿名内部类是直接使用 new 来生成一个对象的引用;
(2) 对于匿名内部类的使用它是存在一个缺陷的,就是它仅能被使用一次,建立匿名内部类时它会当即建立一个该类的实例,该类的定义会当即消失,因此匿名内部类是不可以被重复使用;
(3) 使用匿名内部类时,咱们必须是继承一个类或者实现一个接口,可是二者不可兼得,同时也只能继承一个类或者实现一个接口;
(4) 匿名内部类中是不能定义构造函数的,匿名内部类中不能存在任何的静态成员变量和静态方法;
(5) 匿名内部类中不能存在任何的静态成员变量和静态方法,匿名内部类不能是抽象的,它必需要实现继承的类或者实现的接口的全部抽象方法;
(6) 匿名内部类初始化:使用构造代码块!利用构造代码块可以达到为匿名内部类建立一个构造器的效果。缓存
PROPAGATION_REQUIRED--支持当前事务,若是当前没有事务,就新建一个事务。这是最多见的选择。
PROPAGATION_SUPPORTS--支持当前事务,若是当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY--支持当前事务,若是当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW--新建事务,若是当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED--以非事务方式执行操做,若是当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER--以非事务方式执行,若是当前存在事务,则抛出异常。多线程
Servlet的生命周期分为5个阶段:加载、建立、初始化、处理客户请求、卸载。
(1) 加载:容器经过类加载器使用servlet类对应的文件加载servlet。
(2) 建立:经过调用servlet构造函数建立一个servlet对象。
(3) 初始化:调用init方法初始化。
(4) 处理客户请求:每当有一个客户请求,容器会建立一个线程来处理客户请求。
(5) 卸载:调用destroy方法让servlet本身释放其占用的资源。app
Java反射机制概念:Java反射机制是在运行状态中,对于任意一个类,都可以知道这个类的全部属性和方法;对于任意一个对象,都可以调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
Java反射机制主要提供了如下功能:
(1) 在运行时判断任意一个对象所属的类;
(2) 在运行时构造任意一个类的对象;
(3) 在运行时判断任意一个类所具备的成员变量和方法;
(4) 在运行时调用任意一个对象的方法;
(5) 生成动态代理。框架
Struts的工做流程: 在web应用启动时就会加载初始化ActionServlet, ActionServlet从struts-config.xml文件中读取配置信息, 把它们存放到各类配置对象, 当ActionServlet接收到一个客户请求时, 将执行以下流程.
(1) 检索和用户请求匹配的ActionMapping实例, 若是不存在, 就返回请求路径无效信息;
(2) 若是ActionForm实例不存在, 就建立一个ActionForm对象, 把客户提交的表单数据保存到ActionForm对象中;
(3) 根据配置信息决定是否须要表单验证. 若是须要验证, 就调用ActionForm的validate()方法;
(4) 若是ActionForm的validate()方法返回或返回一个不包含ActionMessage的ActuibErrors对象, 就表示表单验证成功;
(5) ActionServlet根据ActionMapping所包含的映射信息决定将请求转发给哪一个Action, 若是相应的Action实例不存在, 就先建立这个实例, 而后调用Action的execute()方法;
(6) Action的execute()方法返回一个ActionForward对象, ActionServlet在把客户请求转发给ActionForward对象指向的JSP组件;
(7) ActionForward对象指向JSP组件生成动态网页, 返回给客户;
为何要用Struts?
JSP、Servlet、JavaBean技术的出现给咱们构建强大的企业应用系统提供了可能。但用这些技术构建的系统很是的繁乱,因此在此之上,咱们须要一个规则、一个把这些技术组织起来的规则,这就是框架,Struts便应运而生。 基于Struts开发的应用由3类组件构成:控制器组件、模型组件、视图组件(MVC)。jvm
1) JAVA的JVM的内存:函数
堆区:
(1) 存储的所有是对象, 每一个对象都包含一个与之对应的class的信息。(class的目的是获得操做指令) .
(2) jvm只有一个堆区(heap)被全部线程共享,堆中不存放基本类型和对象引用,只存放对象自己.
栈区:
(1) 每一个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象),对象都存放在堆区中.
(2) 每一个栈中的数据(原始类型和对象引用)都是私有的, 其余栈不能访问.
(3) 栈分为3个部分:基本类型变量区、执行环境上下文、操做指令区(存放操做指令).ui
2) 栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方。与C++不一样,Java自动管理栈和堆, 程序员不能直接地设置栈或堆。
3) 栈的优点是, 存取速度比堆要快, 仅次于直接位于CPU中的寄存器。但缺点是, 存在栈中的数据大小与生存期必须是肯定的, 缺少灵活性。另外, 栈数据能够共享。堆的优点是能够动态地分配内存大小,生存期也没必要事先告诉编译器,Java的垃圾收集器会自动收走这些再也不使用的数据。但缺点是,因为要在运行时动态分配内存,存取速度较慢。this
4) 在C语言里堆(heap)和栈(stack)里的区别:
heap:是由malloc之类函数分配的空间所在地。地址是由低向高增加的。
stack:是自动分配变量,以及函数调用的时候所使用的一些空间。地址是由高向低减小。
(1) 管理方式不一样:栈(stack)由编译器管理;堆(heap)由程序员管理。
(2) 空间大小不一样:win32中,堆(heap)可达4G;VC中栈默认1M(能够修改)。
(3) 碎片问题:堆(heap)易产生;栈(stack)不会。
(4) 生长方向不一样:堆(heap)生长方向是向上的,也就是向着内存增长的方向;栈(stack)相反。
(5) 分配方式不一样:堆(heap)是动态的,没有静态的堆;栈(stack)有两种:动态和静态。
(6) 分配效率不一样:栈(stack),系统提供底层支持,有专门的寄存器存放栈地址,效率高;堆(heap),由库函数提供支持,效率底。