代码混装5.30


1.强引用
这是使用最普遍的引用。如果一个对象具有强引用,那就类似于必不可少的生活用品,垃圾回收器绝不会回收它。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。


2.软引用(SoftReference)


如果一个对象只具有软引用,那就类似于可有可无的生活用品。如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。
软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。


3.弱引用(WeakReference)
如果一个对象只具有弱引用,那就类似于可有可无的生活用品。弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它 所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程, 因此不一定会很快发现那些只具有弱引用的对象。
弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。


4.虚引用(PhantomReference)
"虚引用"顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。
虚引用主要用来跟踪对象被垃圾回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列(ReferenceQueue)联合使用。当垃 圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是 否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。程序如果发现某个虚引用已经被加入到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。 
--------   --------   --------   --------   --------   --------   --------   --------   -------- 
方法一旦结束,栈中的局部变量立即销毁,但是堆中对象不一定销毁。因为可能有其他变量也指向了这个对象,直到栈中没有变量指向堆中的对象时,它才销毁,而且还不是马上销毁,要等垃圾回收扫描时才可以被销毁。
类的成员变量在不同对象中各不相同,都有自己的存储空间(成员变量在堆中的对象中)。而类的方法却是该类的所有对象共享的,只有一套,对象使用方法的时候方法才被压入栈,方法不使用则不占用内存。


栈有一个很重要的特性:栈中的数据可以共享。当我们定义了int i = 40;,再定义int i0 = 40;这时候会自动检查栈中是否有40这个数据,如果有,i0会直接指向i的40,不会再添加一个新的40。


基本类型包装类均实现了常量池技术,但他们维护的常量仅仅是【-128至127】这个范围内的常量,如果常量值超过这个范围,就会从堆中创建对象,不再从常量池中取


String类型也实现了常量池技术,但是稍微有点不同。String型是先检测常量池中有没有对应字符串,如果有,则取出来;如果没有,则把当前的添加进去。
凡是涉及内存原理,一般都是博大精深的领域,切勿听信一家之言,多读些文章。




--------   --------   --------   --------   --------   --------   --------   --------   --------
A a=new A(); //那class对象呢?this在堆空间分配
A.java经过Java编译器编译成A.class,jvm(通过类加载器什么的)把A.class加载进内存,提取A.class的类型信息到方法区中,再根据方法区中的类型信息在堆中分配空间,新建对象,把对象的地址(引用)放入栈中,就是a;
//Class对象的作用是方法区和堆间的桥梁,起到连接作用;Class对象有A类在方法区的地址,可以找到
--------   --------   --------   --------   --------   --------   --------   --------   -------- 
方法域存放着每个类的信息,就像:


1.类加载器引用


2.运行时常量池


      .数值常量


      .区域引用


      .方法引用


      .属性


3.域(Field)数据


  .每个区域:


    .名称


    .类型


    .修改器


    .属性值


4.方法数据


      .每个方法


        .名称


        .返回值


        .参数类型(按顺序)


        .修改器


        .属性值


5.方法代码


   .每个方法:


     .Bytecodes


     .操作符栈大小


     .局部变量大小


     .局部变量表


     .异常表:


        . 每个异常句柄:


            .开始指针


            .结束指针


            .句柄代码的PC偏移量


            .常量池索引
--------   --------   --------   --------   --------   --------   --------   --------   --------
Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的,因此不能显式地声明一个Class对象。
  一般某个类的Class对象被载入内存,它就用来创建这个类的所有对象。
******************************************************************************************************* 
 
Class.forName("");的作用是要求JVM查找并加载指定的类
Class对象的生成方式如下:


  1.Class.forName("类名字符串")


  2.类名.class


  3.实例对象.getClass()
//AA aa=(AA)Class.forName("dfs.AA").newInstance();
生成Class对象的过程其实是如此的:


当我们编写一个新的java类时,JVM就会帮我们编译成class对象,存放在同名的.class文件中。在运行时,当需要生成这个类的对象,JVM就会检查此类是否已经装载内存中。若是没有装载,则把.class文件装入到内存中。若是装载,则根据class文件生成实例对象。
--------   --------   --------   --------   --------   --------   --------   --------   -------- 
异常对象都是派生于Throwable类的一个实例,Throwable类下面2个分支:Error和Exception
Error类层次结构描述了系统内部错误和资源耗尽错误。
程序不该抛出这种类型的对象,如果出现了这样的内部错误,除了通告给用户,并尽使程序安全地终止外,无他法


Exception分为RuntimeException和其他Exception
Error和RuntimeException统称为未检查(unchecked)异常
所有其他异常属于已检查异常




--------   --------   --------   --------   --------   --------   --------   --------   -------- 
  public Object pop() { 
             if (size == 0) 
                 throw new RuntimeException("空栈异常"); 
             Object ele = elementData[--size];// 这里为局部变量,当方法结束,局部变量会被回收 
             elementData[size] = null; // 消去强引用关系,避免产生内存泄漏。 
             return ele;               // 返回栈顶元素 size自减1个长度 
        }  
代码中pop() 函数实现出栈,其中 elementData[size] = null;切断了元素和其引用的引用关系,这样可以使元素进入不可达状态,从能被系统回收,如果不切断引用,该元素将一直可以可达状态,就会常驻内存。
而针对上一句Object ele = elementData[--size];  就是为了暂存这个元素,用于作为return的返回值,有人会问这个为什么不会造成内存泄露,他们之间不是已经有了引用和被引用的关系,
     原因是这里的Object对象是局部变量,局部变量的生命周期跟方法生命周期一样,该方法结束了,搞局部变量会被垃圾回收机制收回,所以这个担心是没必要的。
--------   --------   --------   --------   --------   --------   --------   --------   --------
泛型是1.5中引入的一个新的概念,由于不用进行强制转换类型了,所以具有较高的安全性和易用性。因为泛型其实只是在编译器中实现的而虚拟机并不认识泛型类项,所以要在虚拟机中将泛型类型进行擦除。也就是说,在编译阶段使用泛型,运行阶段取消泛型,即擦除。 


擦除是将泛型类型以其父类代替,如String 变成了Object等。其实在使用的时候还是进行带强制类型的转化,只不过这是比较安全的转换,因为在编译阶段已经确保了数据的一致性。 
--------   --------   --------   --------   --------   --------   --------   --------   --------
comparable& Comparator 都是用来实现集合中的排序的,只是Comparable(直接用Person实现Comparable<T>接口)是在集合内部定义的方法实现的排序,Comparator是在集合外部实现的排序,(另外定义一个类Personcompare,作为比较器)所以,如想实现排序,就需要在集合外定义Comparator接口的方法compare()或在集合内实现Comparable接口的方法compareTo()。 
comparator<T>接口与Comparable<T>接口的区别
1. Comparator 和 Comparable 相同的地方


他们都是java的一个接口, 并且是用来对自定义的class比较大小的,


什么是自定义class: 如 public class Person{ String name; int age }.


当我们有这么一个personList,里面包含了person1, person2, persion3....., 我们用Collections.sort( personList ), 是得不到预期的结果的. 这时肯定有人要问, 那为什么可以排序一个字符串list呢:


如 StringList{"hello1" , "hello3" , "hello2"}, Collections.sort( stringList ) 能够得到正确的排序, 那是因为 String 这个对象已经帮我们实现了 Comparable接口 , 所以我们的 Person 如果想排序, 也要实现一个比较器。


2. Comparator 和 Comparable 的区别


Comparable


Comparable 定义在 Person类的内部:


public class Persion implements Comparable {..比较Person的大小..},


因为已经实现了比较器,那么我们的Person现在是一个可以比较大小的对象了,它的比较功能和String完全一样,可以随时随地的拿来比较大小,因为Person现在自身就是有大小之分的。Collections.sort(personList)可以得到正确的结果。


Comparator


Comparator 是定义在Person的外部的, 此时我们的Person类的结构不需要有任何变化,如


public class Person{ String name; int age },


然后我们另外定义一个比较器:


public PersonComparator implements Comparator() {..比较Person的大小..},


在PersonComparator里面实现了怎么比较两个Person的大小. 所以,用这种方法,当我们要对一个 personList进行排序的时候, 我们除了了要传递personList过去, 还需要把PersonComparator传递过去,因为怎么比较Person的大小是在PersonComparator里面实现的, 如:


Collections.sort( personList , new PersonComparator() ).


3. Comparator 和 Comparable 的实例


Comparable:


实现Comparable接口要覆盖compareTo方法, 在compareTo方法里面实现比较:
public class Person implements Comparable {
String name;
int age
public int compareTo(Person another) {
int i = 0;
i = name.compareTo(another.name); // 使用字符串的比较
if(i == 0) { // 如果名字一样,比较年龄, 返回比较年龄结果
return age - another.age;
} else {
return i; // 名字不一样, 返回比较名字的结果.
}
}
}
这时我们可以直接用 Collections.sort( personList ) 对其排序了.


Comparator:


实现Comparator需要覆盖 compare 方法:
public class Person{
String name;
int age
}


class PersonComparator implements Comparator { 
public int compare(Person one, Person another) {
int i = 0;
i = one.name.compareTo(another.name); // 使用字符串的比较
if(i == 0) { // 如果名字一样,比较年龄,返回比较年龄结果
return one.age - another.age;
} else {
return i; // 名字不一样, 返回比较名字的结果.
}
}
}
Collections.sort( personList , new PersonComparator()) 可以对其排序


4:总结


两种方法各有优劣, 用Comparable 简单, 只要实现Comparable 接口的对象直接就成为一个可以比较的对象,但是需要修改源代码, 用Comparator 的好处是不需要修改源代码, 而是另外实现一个比较器, 当某个自定义的对象需要作比较的时候,把比较器和对象一起传递过去就可以比大小了, 并且在Comparator 里面用户可以自己实现复杂的可以通用的逻辑,使其可以匹配一些比较简单的对象,那样就可以节省很多重复劳动了。 
--------   --------   --------   --------   --------   --------   --------   --------   -------- 
Java 8允许我们给接口添加一个非抽象的方法实现
看看在老版本的Java中是如何排列字符串的:
复制代码 代码如下:


List<String> names = Arrays.asList("peter", "anna", "mike", "xenia");
Collections.sort(names, new Comparator<String>() {
    @Override
    public int compare(String a, String b) {
        return b.compareTo(a);
//return s.length()-b.length();
//String a = "2345";
//String b = "2322";
//则a.compareTo(b)返回2
//b.compareTo(a)返回-2
    }
});
--------   --------   --------   --------   --------   --------   --------   --------   -------- 
为什么说 Java 比 C++ 安全?
"C++ 比 java 灵活" == "Java 比 C++ 安全"
Java不支持指针,舍弃了C++的指针对存储器的直接操作,程序运行时,内存由操作系统分配,这样可以避免病毒通过指针侵入系统,同时也避免了指针操作中容易产生的错误 。
重要是去掉了指针,以及代码安全性检测和垃圾回收机制,别小看这个代码检测,相当严格的,c中会出现的错误但是能编译通过的在java里不行,如果用eclipse编程直接就会提示哪里有误,个人觉得那个异常处理机制不错 
--参考方法--
Java中有一个ArrayIndexOutOfBoundsException,可以检查数组下标越界,在C语言中不做此检查
所以Java比C安全一点。
--------   --------   --------   --------   --------   --------   --------   --------   -------- 
面试基础问答:抽象类和接口的区别?
抽象类(abstract class)可以包含功能定义和实现,接口(interface)只能包含功能定义
抽象类是从一系列相关对象中抽象出来的概念, 因此反映的是事物的内部共性;接口是为了满足外部调用而定义的一个功能约定, 因此反映的是事物的外部特性
分析对象,提炼内部共性形成抽象类,用以表示对象本质,即“是什么”
为外部提供调用或功能需要扩充时优先使用接口




一:接口支持多继承,而抽象不支持;
二:接口只定义抽象方法,而抽象可以提供有实现的方法;
三:接口中的方法在继承类中必须全部实现,而抽象类可以不但这时该继承在也要定义为抽象类。
四:接口是Can-do,而抽象是Is-a关系。
--------   --------   --------   --------   --------   --------   --------   --------   -------- 
基本类型使用fianl不能改变的是他的数值。而对于对象引用,不能改变的是他的引用,而对象本身是可以修改的。
--------   --------   --------   --------   --------   --------   --------   --------   -------- 
1 class类的特殊性:  
  
(1)无构造函数。class对象在加载类的时候由java虚拟机通过类加载器中的defineClass方法自动调用。  
  
(2)可以描述基本类型。虽然8个基本类型在java中并不是对象,但是class类仍然可以描述它们。  
  
(3)class对象都是单例,一个class对象描述一个类,并且只描述一个类,反过来也成立,一个类只有一个class对象。  
  
2 区别getDeclaredXXX和getXXX方法  
  
getDeclaredXXX和getXXX方法总是成对出现的,两者区别是:  
  
getDeclaredXXX获得自身所有的方法,包括公有,私有,不受访问权限的限制;  
  
getXXX方法获得所有public级别的方法,包括从父类中继承的方法。  
  
3 动态加载类  
  
使用import关键字的包,jvm在启动的时候会自动加载所依赖的包下的类文件,要想程序在运行的时候动态加载所需要的类库文件,可以使用forName方法。  
  
需要注意的是:forName只是将类加载到内存中,不会产生类的对象,也不会执行任何方法。动态加载的限制:  
  
(1)动态加载的类不包括8个基本类型。  
  
(2)数组不适用于forName方法的动态加载,应该使用:array类的方法:  
  
String [] strs= (String [])Array.newInstance(String.class,8)  


--------   --------   --------   --------   --------   --------   --------   --------   -------- 
在java的集合中,判断两个对象是否相等的规则是:




首先,判断两个对象的hashCode是否相等


如果不相等,认为两个对象也不相等
如果相等,则判断两个对象用equals运算是否相等
如果不相等,认为两个对象也不相等
如果相等,认为两个对象相等


我们在equals方法中需要向下转型,效率很低,所以先判断hashCode方法可以提高效率
--------   --------   --------   --------   --------   --------   --------   --------   -------- 
java跳出多层循环:在最外面的for前面加ok:
                 在for内部用 break ok;
(也可以用一个标记变量flag=false)for循环条件判断!flag
--------   --------   --------   --------   --------   --------   --------   --------   -------- 
xml和json的区别:::
数据体积方面
JSON相对于XML来讲,数据的体积小,传递的速度更快些。
数据交互方面。
JSON与JavaScript的交互更加方便,更容易解析处理,更好的数据交互。
.传输速度方面。
JSON的速度要远远快于XML。
--------   --------   --------   --------   --------   --------   --------   --------   -------- 
面向对象编程强调抽象、封装、继承、多态
抽象:就是把一类事物共有的属性和行为提取出来,形成一个物理模型(模版),这种研究问题的方法称为抽象。
封装:就是将类的属性包装起来,不让外界轻易的知道他的内部实现。只提供给你对外的接口让你来调用。如设置属性或方法的访问权限(private、protected、public、默认)。
继承:就是从父类把它的有用的东西拿过来自己用,不用在自己去实现了,像母亲会把双眼皮传给女儿,不用她自己去割了 
多态:一个对象变量可以指向多种实际类型的现象。通过不同类的实现来表示相似的逻辑。子类对象赋给父类类型变量


顺便说一下重载和重写(覆盖)的区别:
重载:相同的方法名,不同的实现机制(参数的个数或类型)。
重写:从父类继承的方法不能满足需要,可将此方法的逻辑在子类中重新实现。我们最常用的就是重写toString()方法了。
--------   --------   --------   --------   --------   --------   --------   --------   -------- 
ArrayList底层原理:
数组进行扩容时,会将老数组中的元素重新拷贝一份到新的数组中,每次数组容量的增长大约是其原容量的1.5倍。这种操作的代价是很 高的,因此在实际使用时,我们应该尽量避免数组容量的扩张。当我们可预知要保存的元素的多少时,要在构造ArrayList实例时,就指定其容量,以避免 数组扩容的发生。


当我们往HashMap中put元素的时候,先根据key的hashCode重新计算hash值,根据hash值得到这个元素在数组中的位置(即下标),如果数组该位置上已经存放有其他元素了,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放在链尾。如果数组该位置上没有元素,就直接将该元素放到此数组中的该位置上。
   如果这两个 Entry 的 key 通过 equals 比较返回 false,新添加的 Entry 将与集合中原有 Entry 形成 Entry 链,而且新添加的 Entry 位于 Entry 链的头部
 归纳起来简单地说,HashMap 在底层将 key-value 当成一个整体进行处理,这个整体就是一个 Entry 对象。


在HashMap数组扩容之后,最消耗性能的点就出现了:原数组中的数据必须重新计算其在新数组中的位置,并放进去,这就是resize。    
  默认情况下,数组大小为16,那么当HashMap中元素个数超过16*0.75=12的时候,就把数组的大小扩展为 2*16=32,即扩大一倍,然后重新计算每个元素在数组中的位置,而这是一个非常消耗性能的操作,所以如果我们已经预知HashMap中元素的个数


 底层使用HashMap来保存HashSet中所有元素。
.HashMap对元素的遍历顺序跟Entry插入的顺序无关,而LinkedHashMap对元素的遍历顺序可以跟Entry<K,V>插入的顺序保持一致


Collections则是集合类的一个工具类/帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。服务于Java的Collection框架。


--------   --------   --------   --------   --------   --------   --------   --------   -------- 
Lock能完成synchronized所实现的所有功能
  
不同: 
1.ReentrantLock功能性方面更全面,比如时间锁等候,可中断锁等候,锁投票等,因此更有扩展性。在多个条件变量和高度竞争锁的地方,用ReentrantLock更合适,ReentrantLock还提供了Condition,对线程的等待和唤醒等操作更加灵活,一个ReentrantLock可以有多个Condition实例,所以更有扩展性。 
2.ReentrantLock必须在finally中释放锁,否则后果很严重,编码角度来说使用synchronized更加简单,不容易遗漏或者出错。 
3.ReentrantLock 的性能比synchronized会好点。 
4.ReentrantLock提供了可轮询的锁请求,他可以尝试的去取得锁,如果取得成功则继续处理,取得不成功,可以等下次运行的时候处理,所以不容易产生死锁,而synchronized则一旦进入锁请求要么成功,要么一直阻塞,所以更容易产生死锁。 
--------   --------   --------   --------   --------   --------   --------   --------   --------
get请求和post请求的区别:
get请求提交得数据放置在HTTP请求协议头中,而post请求提交的数据放在实体数据中;
get提交的数据的长度有限制,而post没有限制,
get通过URL的方式来传递用户的请求,请求数据会附加在URL后面,可能会密码泄露




HTTP:
请求行:说明请求类型,要访问的资源,HTTP版本等
请求头:
空行:
请求主体:添加任意数据
<!-- 配置事务管理器 -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>


<!-- 事务的传播特性    tx:advice用来配置事务增强处理-->


<tx:advice id="txadvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- PROPAGATION_REQUIRED:如果存在一个事务,则支持当前事务。如果没有事务则开启 -->
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="delete*" propagation="REQUIRED" />
<tx:method name="modify*" propagation="REQUIRED" />


<!--hibernate4必须配置为开启事务 否则 getCurrentSession()获取不到 
     采用getCurrentSession()创建的session会绑定到当前线程中 -->
<!-- 采用getCurrentSession()创建的session在commit或rollback时会自动关闭 -->
<tx:method name="*" propagation="REQUIRED" read-only="true" />
</tx:attributes>
</tx:advice>


<!-- 那些类那些方法使用事务 -->
<aop:config>
<!-- 只对业务逻辑层实施事务 -->
<aop:pointcut id="allManagerMethod"
expression="execution(* com.jialin.service.*.*(..))" />
<aop:advisor pointcut-ref="allManagerMethod" advice-ref="txadvice" />
<!-- 使用<aop:advisor .../>元素启用 自动代理?-->
</aop:config>




 --------   --------   --------   --------   --------   --------   --------   --------   --------
public ListNode sortList(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }


        ListNode mid = findMiddle(head);


        ListNode right = sortList(mid.next);
        mid.next = null;
        ListNode left = sortList(head);


        return merge(left, right);
    } 
--------   --------   --------   --------   --------   --------   --------   --------   -------- 
贪心策略:
--------   --------   --------   --------   --------   --------   --------   --------   -------- 
普通java类(排序)实现Comparable接口重写CompareTo方法:
class NumbersComparator implements Comparator<String> {
@Override
public int compare(String s1, String s2) {
return (s2 + s1).compareTo(s1 + s2);
}
}
//重写String;
 String[] strs = new String[nums.length];
        for (int i = 0; i < nums.length; i++) {
            strs[i] = Integer.toString(nums[i]);
        }
        Arrays.sort(strs, new NumbersComparator());
--------   --------   --------   --------   --------   --------   --------   --------   -------- 


while(s!=0){
res++;s=s&(s-1);}     
求25!0的个数 5 10 15 20 25 可以分解出6个5
while(N){
  res+=N/5;
  N/=5;
}
--------   --------   --------   --------   --------   --------   --------   --------   -------- 
JAVA的JVM的内存可分为3个区:堆(heap)、栈(stack)和方法区(method) 
jvm只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身 
每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象),对象都存放在堆区中 


方法区: 
1.又叫静态区,跟堆一样,被所有的线程共享。方法区包含所有的class和static变量。 
2.方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量。 
3. 类中方法的字节码(也就是说具体的实现的代码)也是放在方法区的
4. 方法区主要是记录类型信息的


--------   --------   --------   --------   --------   --------   --------   --------   -------- 
A[A[i]-1]!=A[i]    1 2  3  4 要位于数组 0 1 2 3 位置上
--------   --------   --------   --------   --------   --------   --------   --------   -------- 
自动装箱拆箱:
当我们创建一个Integer对象时,却可以这样:
Integer i = 100; (注意:不是 int i = 100; 
实际上,执行上面那句代码的时候,系统为我们执行了:Integer i = Integer.valueOf(100); 


此即基本数据类型的自动装箱功能。
 自动拆箱(unboxing),也就是将对象中的基本数据从对象中自动取出。如下可实现自动拆箱:


1 Integer i = 10; //装箱 
2  int t = i; //拆箱,实际上执行了 int t =i.intValue();
  在进行运算时,也可以进行拆箱。 
//装箱是Integer.valueOf(int i),拆箱是:i.intValue()
1 Integer i = 10; 
2 System.out.println(i++);


equals() 比较的是两个对象的值(内容)是否相同。


"==" 比较的是两个对象的引用(内存地址)是否相同,也用来比较两个基本数据类型的变量值是否相等。
--------   --------   --------   --------   --------   --------   --------   --------   -------- 
AOP 为系统中的业务组件添加某种通用的功能,如Log日志
Habernate通过Session来操作事务
JDBC使用Connection来操作事务,但程序代码必然会和事务操作代码耦合,
--------   --------   --------   --------   --------   --------   --------   --------   --------
虚拟内存:
--------   --------   --------   --------   --------   --------   --------   --------   --------
RMI(Remote Method Invocation)远程方法调用是一种计算机之间利用远程对象互相调用实现双方通讯的一种通讯机制。使用这种机制,某一台计算机上的对象可以调用另外 一台计算机上的对象(代理对象)来获取远程数据。
--------   --------   --------   --------   --------   --------   --------   --------   --------
//HashMap重写 实现hashCode()    
        public final int hashCode() {    
            return (key==null   ? 0 : key.hashCode()) ^    
                   (value==null ? 0 : value.hashCode());    
        } 
HashMap中key和value都允许为null
,int hash = key.hashCode();
再把hash通过一下运算得到一个int h. 
hash ^= (hash >>> 20) ^ (hash >>> 12); 
int h = hash ^ (hash >>> 7) ^ (hash >>> 4); 
它的目的是让“1”变的均匀一点,散列的本意就是要尽量均匀分布。
逻辑与运算,即 h & (length-1),这样得到的结果就是一个比length小的正数,我们把这个值叫做index。其实这个index就是索引将要插入的值在数组中的 位置
key->hashcode->h->index->遍历链表->插入


为什么覆盖了equals方法之后一定要覆盖hashCode方法,很简单,比如,
String a = new String(“abc”);
String b = new String(“abc”);
如果不覆盖hashCode的话,那么a和b的hashCode就会不同,把这两个类当做key存到HashMap中的话就 会出现问题,就会和key的唯一性相矛盾。
--------   --------   --------   --------   --------   --------   --------   --------   --------
java.util.BitSet可以存true/false
bs.set(i, false);  
 bm.set(1); //设为true;
bm.size();//64 128
申请的位都是以64为倍数的,就是说你申请不超过一个64的就按64算,超过一个不超过2个的就按128算。
--------   --------   --------   --------   --------   --------   --------   --------   --------
内存泄露?
--------   --------   --------   --------   --------   --------   --------   --------   --------
鸽巢原理
无序数组a:a(1),a(2),...a(n)
求数组下标k,t;使得连续子数组a(k+1),a(k+2),...a(t)的元素和能被n整除,找不到则返回-1,-1
要求时间复杂度O(n)
解法:
求a1,a1+a2,。。。a(1)+a(2)+...+a(m);
每次sum%m都能得到一个数,记录下,碰到等于之前记录过的就得到k,l了
鸽巢原理的应用,复杂度时空O(n) 空O(n) 
--------   --------   --------   --------   --------   --------   --------   --------   --------
hashcode()和equals()
--------   --------   --------   --------   --------   --------   --------   --------   -------- 
C++语言的一个类库,用来方便地管理一系列的bit位而不用程序员自己来写代码。
bitset除了可以访问指定下标的bit位以外,还可以把它们作为一个整数来进行某些统计。
--------   --------   --------   --------   --------   --------   --------   --------   -------- 
在计算机中,所有的数据在存储和运算时都要使用二进制数表示 大家如果要想互相通信而不造成混乱,那么大家就必须使用相同的编码规则 ASCII编码,统一规定了上述常用符号用哪些二进制数来表示。
--------   --------   --------   --------   --------   --------   --------   --------   -------- 
碰到过的算法题应该问题不太,但是碰到从来没见过的题就比较捉急了。
无头绪的算法题,最先考虑几个特例,相当于运行下,
先考虑暴力破解的方法,再考虑其他的。dp?分治?
--------   --------   --------   --------   --------   --------   --------   --------   -------- 
在执行session.load时,Hibernate首先从当前session的一级缓存中获取id对应的值,在获取不到的情况下,将根据该对象是否配置了二级缓存来做相应的处理,如配置了二级缓存,则从二级缓存中获取id对应的值,(执行Session.get没有这一步)如仍然获取不到则还需要根据是否配置了延迟加载来决定如何执行,如未配置延迟加载则从数据库中直接获取,在从数据库获取到数据的情况下,Hibernate会相应的填充一级缓存和二级缓存,如配置了延迟加载则直接返回一个代理类,只有在触发代理类的调用时才进行数据库查询的操作。 


备注 load方法过程:一级缓存 ---> 二级缓存 ----> DB访问 ---> 填充一级缓存[、二级缓存] / 返回一个代理类
 


备注:load和get方法的另外一个区别就是:当对象在DB中找不到时,load会抛出异常,而get仅仅返回null
load方法抛出异常不是在创建对象时,而是在程序要使用load获取的对象时,才开始工作,要是这时发现数据库中不存在该数据则抛出异常。
--------   --------   --------   --------   --------   --------   --------   --------   -------- 
request.getParameter  
  是用来接受来自get方法或post方法的参数  
getAttribute()在request和session中都有,只是作用域不同,在取之前肯定是要在某个地方存一下,这种
东东可以存取对象
Parameter是html裡傳來的像 checkbox textfield password radio ...的value
getAttribute是取得jsp中用setAttribute()設定的attribute
還有....
parameter得到的是string
attribute得到的是object
--------   --------   --------   --------   --------   --------   --------   --------   --------


java.lang.long 
中有个方法; 
Long a; 
int b=a.intValue(); 
--------   --------   --------   --------   --------   --------   --------   --------   -------- 
save是返回插入数据的主键的,而saveOrUpdate是void
save方法更适用于确定了是要插入,而且需要得到插入数据的主键
而saveOrUpdate更倾向于不缺定是插入还是更新,而且你不需要得到他的主键
另一方面,如果你无法确定你要插入或更新的对象是不是持久态或游离态时。如果你save一个持久态或更新一个游离态,这都是有问题的,此时你就要用到saveOrUpdate
总体来说,如果你能确定你即将操作对象的状态,则不需要用saveOrUpdate
--------   --------   --------   --------   --------   --------   --------   --------   --------
char str[]="1234 xyz";


char* str1=strstr(str,"34");
结果是 34 xyz
//不用库函数实现strstr
char *mystrstr(char *str1, char*str2)
{
    char *p = NULL;
    if (strlen(str1) < strlen(str2))return p;
    for (char* pstr1 = str1; *pstr1 !='\0'; pstr1++)
    {
        int find = 1;
        for (char* pstr2 = str2; *pstr2 !='\0'; pstr2++)
        {
            //防止越界
            if (*(pstr1 + (pstr2 - str2)) == '\0')
            {
                find = 0;
                break;
            }
            if (*(pstr1 + (pstr2 - str2)) != *pstr2)
            {
                find = 0;
                break;
            }
        }
        if (find==1)
        {
            p = pstr1;
            break;
        }
    }
    return p;


}
//用库函数
char *strtsr(const char* s1,const char* s2){
 int l1,l2;
l2=strlen(s2);
if(!l2)return (char*)s1;
l1=strlen(s1);
while(l1>=l2)
{
  l1--;
  if(!memcmp(s1,s2,l2))
     return (char *)s1;
  s1++;
}
return NULL;
}


memcmp(s1,s2,l2)
当buf1<buf2时,返回值<0
当buf1=buf2时,返回值=0
当buf1>buf2时,返回值>0
--------   --------   --------   --------   --------   --------   --------   --------   -------- 
void quickSort2(double* a, int left, int right)
{//快排非递归
stack<int> t;
if(left<right)
{
int p = partition(a, left, right);


if (p-1>left)
{
t.push(left);
t.push(p-1);
}
if (p+1<right)
{
t.push(p+1);
t.push(right);
}


while(!t.empty())
{
int r = t.top();
t.pop();
int l = t.top();
t.pop();


p = partition(a, l, r);


if (p-1>l)
{
t.push(l);
t.push(p-1);
}
if (p+1<r)
{
t.push(p+1);
t.push(r);
}


}
}
}
--------   --------   --------   --------   --------   --------   --------   --------   --------
搜索引擎(search engine)是指根据一定的策略、运用特定的计算机程序搜集互联网上的信息,在对信息进行组织和处理后,并将处理后的信息显示给用户,是为用户提供检索服务的系统。搜索引擎包括全文索引、目录索引、元搜索引擎、垂直搜索引擎、集合式搜索引擎、门户搜索引擎与免费链接列表等。百度和谷歌等是搜索引擎的代表。


数据库引擎是用于存储、处理和保护数据的核心服务。利用数据库引擎可控制访问权限并快速处理事务,从而满足企业内大多数需要处理大量数据的应用程序的要求。
MyISAM的读性能是比Innodb强不少
InnoDB和MyISAM是许多人在使用MySQL时最常用的两个表类型,这两个表类型各有优劣,视具体应用而定。
基本的差别为:
MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持。
MyISAM类型的表强调的是性能,其执行数度比InnoDB类型更快,但是不提供事务支持,而InnoDB提供事务支持已经外部键等高级数据库功能。
--------   --------   --------   --------   --------   --------   --------   --------   -------- 
HashSet 中是不可以放入重复对象的,那么在 HashSet 中又是怎样判定元素是否重复的呢?
(首先要知道 HashSet 内部实际是通过 HashMap 封装的):
    public boolean add ( Object o ) { //HashSet 的 add 方法
           return map.put ( o, PRESENT ) == null ;
    }
所以在 java 的集合中,判断两个对象是否相等的规则是:
(hashCode是jdk根据对象的地址或者字符串或者数字算出来的int类型的数值)
1 ,判断两个对象的 hashCode 是否相等
      如果不相等,认为两个对象也不相等,完毕
      如果相等,转入 2
2 ,判断两个对象用 equals 运算是否相等
      如果不相等,认为两个对象也不相等
      如果相等,认为两个对象相等


为什么是两条准则,难道用第一条不行吗?不行,因为 hashCode() 相等时, equals() 方法也可能不等 ,所以必须用第 2 条准则进行限制,才能保证加入的为非重复元素。
--------   --------   --------   --------   --------   --------   --------   --------   --------
ConcurrentHashMap中主要实体类就是三个:ConcurrentHashMap(整个Hash表),Segment(桶),HashEntry(节点)
 put操作一上来就锁定了整个segment,这当然是为了并发的安全,修改数据是不能并发进行的
--------   --------   --------   --------   --------   --------   --------   --------   -------- 
二进制串在Java里面所指的是byte[]     字节流
序列化: 将数据结构或对象转换成二进制串的过程
反序列化:将在序列化过程中所生成的二进制串转换成数据结构或者对象的过程
JSON 可以将JavaScript 对象中表示的一组数据转换为字符串,然后就可以在函数之间轻松地传递这个字符串
JSON(JavaScript Object Notation)是一种轻量级的数据交换语言
--------   --------   --------   --------   --------   --------   --------   --------   --------
Java 字节流和字符流的相互转换
1、从字节流到字符流:InputStreamReader、OutputStreamWriter类可以实现。
(从字节流转化为字符流时,实际上就是byte[]转化为String时)
 
2、从字符流到字节流:可以从字符流中获取char[]数组,转换为String,然后调用String的API函数getBytes() 获取到byte[],然后就可以通过ByteArrayInputStream、ByteArrayOutputStream来实现到字节流的转换。
(字符流转化为字节流时,实际上是String转化为byte[])byte[]    String.getBytes(String charsetName)


--------   --------   --------   --------   --------   --------   --------   --------   -------- 
TCP在发送新的数据之前,以特定的顺序将数据包的标号,并需要得到这些包传送给目标机之后的确认消息,没收到
确认就重发。


第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。


第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态;


第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED状态,完成三次握手。
--------   --------   --------   --------   --------   --------   --------   --------   --------
Group By语句从英文的字面意义上理解就是“根据(by)一定的规则进行分组(Group)”。
--它的作用是通过一定的规则将一个数据集划分成若干个小的区域,然后针对若干个小区域进行数据处理。
--注意:group by 是先排序后分组;
在集合函数中加上了HAVING来起到测试查询结果是否符合条件的作用。
select COUNT(*)as '>20岁人数',classid  from Table1 
where sex='男' 
group by classid,age 
having AVG(age)>20 
--------   --------   --------   --------   --------   --------   --------   --------   --------
左连接显示左边表的所有行,公共部分记录集+左表记录
右连接显示右边表的所有行
外连接显示所有表的所有行
内连接:利用内连接可获取两表的公共部分的记录 
交叉连接不带WHERE 子句,它返回被连接的两个表所有数据行的笛卡尔积
--------   --------   --------   --------   --------   --------   --------   --------   --------
给定一个单链表,只给出头指针head:
1、如何判断是否存在环?
2、如何知道环的长度?
3、如何找出环的连接点在哪里?
4、带环链表的长度是多少?
1、对于问题1,使用追赶的方法,设定两个指针slow、fast,从头指针开始,每次分别前进1步、2步。如存在环,则两者相遇;如不存在环,fast遇到NULL退出。
2、对于问题2,记录下问题1的碰撞点p,slow、fast从该点开始,再次碰撞所走过的操作数就是环的长度s。
3、问题3:有定理:碰撞点p到连接点的距离=头指针到连接点的距离,因此,分别从碰撞点、头指针开始走,相遇的那个点就是连接点。(证明在后面附注)
4、问题3中已经求出连接点距离头指针的长度,加上问题2中求出的环的长度,二者之和就是带环单链表的长度
--------   --------   --------   --------   --------   --------   --------   --------   --------
云计算的核心思想是将大量用网格连接的计算资源统一管理和调度,构成一个计算资源池向用户提供按需服务 
--------   --------   --------   --------   --------   --------   --------   --------   -------- 
Java 有三种创建类实例的方法:
* 用 new 操作符
* 用 Class.forName(classname).newInstance() method
* 用 clone() 方法
--------   --------   --------   --------   --------   --------   --------   --------   --------
类:类是一个封装了数据和在数据上的操作的程序结构。在面向对象的编程中,类可以看成对象的蓝图。
对象:一个对象是属于某个类的程序结构,具有状态和行为。
--------   --------   --------   --------   --------   --------   --------   --------   -------- 
资源清理(Finalization)的作用?   Finalization通过调用finalized()实现。Finalization的目的是为了对象得到清理之前执行某些操作。此方法在GC之前执行必要的清理工作,也就是消除’orphan objects’。孤儿对象
--------   --------   --------   --------   --------   --------   --------   --------   --------
垃圾回收机制有什么缺点?尽管垃圾收集器在它自己的线程中运行,但仍然对性能有影响。它增加了开销,因为JVM必须跟踪所有未被引用的对象,然后释放这些未引用的对象。垃圾收集器可使用“的System.gc”或“Runtime.gc”来强制执行。 
--------   --------   --------   --------   --------   --------   --------   --------   --------
instanceof关键字的作用:“instanceof” 用于检查一个对象是什么类型。
--------   --------   --------   --------   --------   --------   --------   --------   -------- 
ResultSetMetaData的是一个对象,用于获取ResultSet对象的类型和列的属性的信息。
如下:


ResultSet resultSet1 = statement1.executeQuery(“SELECT a, b, c FROM TABLE2″);
ResultSetMetaData rsmd = rs.getMetaData();
--------   --------   --------   --------   --------   --------   --------   --------   --------
一个任务的优先级是一个整数值。这个值用于各个任务之间执行的相对顺序。调度是任务执行的顺序。它被任务调度器控制。任务调度器会尝试让具有较高优先级的任务在优先级较低的任务之前执行。任务调度器会根据这个值来确定何时执行这个任务。 
--------   --------   --------   --------   --------   --------   --------   --------   -------- 
什么是静态初始化块?
静态初始化块可以被看做一个,没有名字,没有参数,没有返回值的成员。没有必要从类定义之外引用它。语法:


static
{
//CODE
}
静态初始化块中的代码是由JVM进行类加载时执行。
因为它是在类加载时自动执行,参数对它来说没有任何意义,所以静态初始化块没有一个参数列表。


静态初始化块是一个名为’static’的代码块。一块在类中的顺序执行。当类被加载的时候,静态初始化中的代码会被执行。先于构造器中的代码。
--------   --------   --------   --------   --------   --------   --------   --------   --------
有4种类型的内部类 – 成员内部类,局部内部类,静态内部类和匿名内部类。
1.成员内部类-类(外部类)的成员。
2.局部内部类-这是一个块中定义的内部类。
3.静态内部类-类似于静态成员,这个类本身是静态的。
4.匿名内部类-类没有名称,只能实现一个接口或继承自一个抽象类。


外部类不能任意访问内部类的成员。要做到这一点,外部类必须创建其内部类的对象(静态内部类除外)。
内部类可以访问所有的外部类的成员,因为内部类就像是一个类的成员。
匿名内部类是使用的场景如下:一个对象创建后,调用单一的方法,调用完成后立即回收对象。多用于事件驱动编程
--------   --------   --------   --------   --------   --------   --------   --------   -------- 
java中关键字volatile的作用:Volatile是轻量级的synchronized
    在当前的Java内存模型下,线程可以把变量保存在本地内存(比如机器的寄存器)中,而不是直接在主存中进行读写。这就可能造成一个线程在主存中修改了一个变量的值,而另外一个线程还继续使用它在寄存器中的变量值的拷贝,造成数据的不一致。要解决这个问题,只有把该变量声明为volatile,这就指示JVM,这个变量是不稳定的,每次使用它都到主存中进行读取。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。Java语言规范中指出:为了获得最佳速度,允许线程保存共享成员变量的私有拷贝,而且只当线程进入或者离开同步代码块时才与共享成员变量的原始值对比。这样当多个线程同时与某个对象交互时,就必须要注意到要让线程及时的得到共享成员变量的变化。而volatile关键字就是提示JVM:对于这个成员变量不能保存它的私有拷贝,而应直接与共享成员变量交互。
   此处注意:volatile关键字只能保证线程的可见性,但不能保证原子性,试图用volatile保证原子性会很复杂!


    用在多线程,同步变量。 线程为了提高效率,将某成员变量(如A)拷贝了一份(如B),线程中对A的访问其实访问的是B。只在某些动作时才进行A和B的同步。因此存在A和B不一致的情况。volatile就是用来避免这种情况的。       
    volatile告诉jvm, 它所修饰的变量不保留拷贝,直接访问主内存中的(也就是上面说的A) 、
--------   --------   --------   --------   --------   --------   --------   --------   --------
目前在Java中存在两种锁机制:synchronized和Lock,
数据同步需要依赖锁,那锁的同步又依赖谁?synchronized给出的答案是在软件层面依赖JVM,而Lock给出的方案是在硬件层面依赖特殊的CPU指令
--------   --------   --------   --------   --------   --------   --------   --------   --------
 synchronized机制对锁的释放是隐式的, 只要线程运行的代码超出了synchronized语句块范围, 锁就会被释放. 而Lock机制必须显式的调用Lock对象的unlock()方法才能释放锁, 这为获取锁和释放锁不出现在同一个块结构中, 以及以更自由的顺序释放锁提供了可能. 在大多数情况下,应该使用以下语句: 


     Lock l = ...; 
     l.lock();
     try {
         // access the resource protected by this lock
     } finally {
         l.unlock();
     }
//lock()和unlock()之间就是传说中操作系统中的critical section(临界区域),一次只能有一个线程访能够访问
//所有已知实现类: 
//ReentrantLock(可重入的互斥锁定) ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock 


public class LockTest {  
    public static void main(String[] args) {  
        final Outputter1 output = new Outputter1();  
        new Thread() {  
            public void run() {  
                output.output("zhangsan");  
            };  
        }.start();        
        new Thread() {  
            public void run() {  
                output.output("lisi");  
            };  
        }.start();  
    }  
}  
class Outputter1 {  
    private Lock lock = new ReentrantLock();// 锁对象  
    public void output(String name) {  
        // TODO 线程输出方法  
        lock.lock();// 得到锁  
        try {  
            for(int i = 0; i < name.length(); i++) {  
                System.out.print(name.charAt(i));  
            }  
        } finally {  
            lock.unlock();// 释放锁  
        }  
    }  

--------   --------   --------   --------   --------   --------   --------   --------   --------
 try {  
            Thread.sleep(10000);// 睡10秒  
        } catch (InterruptedException e) {  
            return;  
        }  
--------   --------   --------   --------   --------   --------   --------   --------   --------
C语言中的malloc和JVM中的new的对象存储空间的:


malloc和new产生的对象存储都是发生在堆中的,而非栈。


而C++和Java的引用(包括引用COPY)都是在栈中的。 
--------   --------   --------   --------   --------   --------   --------   --------   --------    
索引(index)是除表之外另一重要的、用户定义的存储在物理介质上的数据结构。
我们的汉语字典的正文本身 就是一个聚集索引,
把这种正文内容本身就是一种按照一定规则排列的目录称为“聚集索引”。
--------   --------   --------   --------   --------   --------   --------   --------   -------
    当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法?


  不能,一个对象的一个synchronized方法只能由一个线程访问。
----------------------------------------------------------------------------
在多个线程之间共享了Count类的一个对象,这个对象是被创建在主内存(堆内存)中,每个线程都有自己的工作内存(线程栈),工作内存存储了主内存Count对象的一个副本,当线程操作Count对象时,首先从主内存复制Count对象到工作内存中,然后执行代码count.count(),改变了num值,最后用工作内存Count刷新主内存Count。


 Object lock = new Object(); //对象说 
    synchronized (lock) {  
        for(int i = 0; i < name.length(); i++) {  
            System.out.print(name.charAt(i));  
        }  
    }  
//这个锁显然每个线程都会创建,没有意义。
----------------------------------------------------------------------------
实例方法中加入sychronized关键字封锁的是this对象本身,而在静态方法中加入sychronized关键字封锁的就是类本身。静态方法是所有类实例对象所共享的,因此线程对象在访问此静态方法时是互斥访问的,从而可以实现线程的同步.
class MyThread implements java.lang.Runnable{
  ...
  public synchronized void run() 
    {
        for (int i = 0; i < 100; ++i)
        {
            System.out.println("Thread ID: " + this.threadId + " : " + i);
        }
    }
}
这里我们在run()方法中加入了synchronized关键字,希望能对run方法进行互斥访问,但结果并不如我们希望那样,这是因为这里synchronized锁住的是this对象,即当前运行线程对象本身。


//代码中创建了10个线程,而每个线程都持有this对象的对象锁,这不能实现线程的同步。
----------------------------------------------------------------------------
//n皇后关键代码:
for (int col = 0; col < n; col++) {// 这个for遍历的是column
if(checkPosotion(queenList, row,col)){
queenList[row]=col; //能pass这个插位置 就说明 可以在这个row的i位置可以放
placeQueen(queenList, row+1, n,result);
}
}
----------------------------------------------------------------------------


算法要求在五行之内写出二分查找,我用了6行,不知道有高手可以用五行写出来不:
[cpp] view plaincopy
#include<stdio.h>  
#include<stdlib.h>  
int a[]={10,22,42,51,56,63,78,99,102,118};  
int binary_search(int low, int high, int key) {  
    if(low > high)  
        return -1;  
    int mid = low + (high - low) / 2;  
    if(a[mid] == key)  
        return mid;  
    return (a[mid] > key ? binary_search(low, mid-1, key) : binary_search(mid+1, high, key));  
}  
void main() {  
    int result = binary_search(0, sizeof(a)/sizeof(int), 102);  
    printf("%d\n",a[result]);  
}  


注意 int  mid = low + (high - low) / 2;这句,很多面试题目都有这个问题,这个主要是编程的细节问题,开始可能想到这样写:int mid = (low + high) / 2;但是 low,和high的值加起来之后有可能超出int的表示范围,从而使其成为负数。


一个JVM运行在一个进程里,
方法区 
在一个jvm实例的内部,类型信息被存储在一个称为方法区的内存逻辑区中。类型信息是由类加载器在类加载时从类文件中提取出来的。类(静态)变量也存储在方法区中。 
jvm在运行应用时要大量使用存储在方法区中的类型信息。
因为方法区是被所有线程共享的,所以必须考虑数据的线程安全




Spring Web MVC 处理Http请求的大致过程:


一旦Http请求到来,DispatcherSevlet将负责将请求分发。DispatcherServlet可以认为是Spring提供的前端控制器,所有的请求都有经过它来统一分发。
在DispatcherServlet将请求分发给Spring Controller之前,需要借助于Spring提供的HandlerMapping定位到具体的Controller。HandlerMapping是这样一种对象,它能够完成客户请求到Controller之间的映射。在Struts中,这种映射是通过struts-config.xml文件完成的。其中,Spring为Controller接口提供了若干实现,例如Spring默认使用的BeanNameUrlHandlerMapping。还有,SimpleUrlHandlerMapping,CommonsPathMapHandlerMapping


HandlerMapping接口的实现类:
SimpleUrlHandlerMapping  通过配置文件,把一个URL映射到Controller
DefaultAnnotationHandlerMapping  通过注解,把一个URL映射到Controller类上


HandlerAdapter接口 -- 处理请求的映射
AnnotationMethodHandlerAdapter类,通过注解,把一个URL映射到Controller类的方法上




Spring Controller将处理来自DispatcherServlet的请求。Spring的Controller类似于struts的Action,能够接受HttpServletRequest和HttpServletResponse。Spring为Controller接口提供了若干实现类,位于org.springframework.web.servlet.mvc包中。由于Controller需要为并发用户处理上述请求,因此实现Controller接口时,必须保证线程安全并且可重用。Controller将处理客户请求,这和Struts Action 扮演的角色是一致的。
Controller接口 -- 控制器
由于我们使用了@Controller注解,添加了@Controller注解注解的类就可以担任控制器(Action)的职责,
所以我们并没有用到这个接口。


一旦Controller处理完客户请求,则返回ModelAndView对象给DispatcherServlet前端控制器。ModelAndView中包含了模型(Model)和视图(View)。从宏观角度考虑,DispatcherServlet是整个Web应用的控制器;从微观角度考虑,Controller是单个Http请求处理过程中的控制器,而ModelAndView是Http请求过程中返回的模型和视图。前端控制器返回的视图可以是视图的逻辑名,或者实现了View接口的对象。View对象能够渲染客户响应结果。其中,ModelAndView中的模型能够供渲染View时使用。借助于Map对象能够存储模型。如果ModelAndView返回的视图只是逻辑名,则需要借助Spring提供的视图解析器(ViewResoler)在Web应用中查找View对象,从而将响应结果渲染给客户。DispatcherServlet将View对象渲染出的结果返回个客户。




HandlerInterceptor 接口--拦截器
我们自己实现这个接口,来完成拦截的器的工作。


 asList方法:将数组转换成list集合。 
String[] arr = {"abc","kk","qq"}
List<String> list = Arrays.asList(arr);//将arr数组转成list集合。


 集合变数组:用的是Collection接口中的方法:toArray(); 
如果给toArray传递的指定类型的数据长度小于了集合的size,那么toArray方法,会自定再创建一个该类型的数据,长度为集合的size。


格式:// 增强for循环括号里写两个参数,第一个是声明一个变量,第二个就是需要迭代的容器 
for( 元素类型 变量名 : Collection集合 & 数组 ) { 
....
 } 


for(Object obj : map.entrySet()) { 
Map.Entry entry = (Entry) obj;  // obj 依次表示Entry 
System.out.println(entry.getKey() + "=" + entry.getValue()); 

//在使用增强for循环时,不能对元素进行赋值;


泛型限定: 
上限:?extends E:可以接收E类型或者E的子类型对象。 
下限:?super E:可以接收E类型或者E的父类型对象。 
泛型的细节:
 1)、泛型到底代表什么类型取决于调用者传入的类型,如果没传,默认是Object类型; 
2)、使用带泛型的类创建对象时,等式两边指定的泛型必须一致; 原因:编译器检查对象调用方法时只看变量,然而程序运行期间调用方法时就要考虑对象具体类型了;




字符流: 
Reader:用于读取字符流的抽象类。
Writer:写入字符流的抽象类
字节流: 
InputStream:是表示字节输入流的所有类的超类。 
OutputStream:


File类:将文件系统中的文件和文件夹封装成了对象。


LinkedHashMap是HashMap的一个子类,它保留插入的顺序,如果需要输出的顺序和输入时的相同,那么就选用LinkedHashMap。
IdentityHashMap允许key值重复,但是——key必须是两个不同的对象,即对于k1和k2,当k1==k2时,IdentityHashMap认为两个key相等,而HashMap只有在k1.equals(k2) == true 时才会认为两个key相等。




比较方法equals()和==的区别,一句话:equals()比较的是对象的内容,也就是JVM堆内存中的内容,==比较的是地址,也就是栈内存中的内容
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值