Java面试准备 --自用

1.java 的八大类型     byte shot int  float double long char boolean  

2.string 不能被继承 因为有 final 修饰符

3. string  是一个常量 ; stringBuffer  和stringBuild 是可变的,buffer是线程安全的。build非线程安全的  多一个 synchronized 进行修饰

4.arrayList 和 linkedList的区别在于 arrayList是基于数组实现的。所以访问速度是很快的 复杂度 0(1)

  而linkedList是链表的形式,即每个节点会有引用指向他的上一个节点和下一个节点 这样插入,删除 速度很快

  所以linkedList 比ArrayList  相比要占内存较多

5. Java 类 实例化执行顺序 。首先是 父级的静态代码块 --自己的静态代码块 --父级的成员变量赋值 --自己的成员变量赋值 --父级的构造方法-自己的构造方法

6. Java虚拟机自带的加载  根类加载器(Bootstrap)   扩展类加载器(Extension)   系统类加载器(System)

   用户自定义的类加载器     java.lang.ClassLoader的子类   用户可以定制类的加载方式

7. java 虚拟机类加载机制  1.类的加载指的是将类的.class文件中的二进 制数据读入到内存中,将其放在运行时数 据区的方法区内

   2. 然后进行验证 包括类文件的结构检查 语义检查    3,类的解析 把符号引用转为直接引用,即在一个类里面调用另一个的方法,会用一个指针指向另一个方法在方法区的内存位置 4. 类进行初始化;类的加载器机制是父委托机制 除了根类加载器,其他两个都是java.lang.classLoad的子类。

8. map  相关的  hashmap 是线程不安全的。concurretHashMap是线程安全的,或者是 hashtable 但现在不建议使用了;linkedHashMap 保持了 插入顺序。

9. 抽象类和接口相关

  1、抽象类和接口都不能直接实例化,如果要实例化,抽象类变量必须指向实现所有抽象方法的子类对象,接口变量必须指向实现所有接口方法的类对象。 
2、抽象类要被子类继承,接口要被类实现。 
3、接口只能做方法申明,抽象类中可以做方法申明,也可以做方法实现 
4、接口里定义的变量只能是公共的静态的常量,抽象类中的变量是普通变量。 
5、抽象类里的抽象方法必须全部被子类所实现,如果子类不能全部实现父类抽象方法,那么该子类只能是抽象类。同样,一个实现接口的时候,如不能全部实现接口方法,那么该类也只能为抽象类。 
6、抽象方法只能申明,不能实现。abstract void abc();不能写成abstract void abc(){}。 
7、抽象类里可以没有抽象方法 
8、如果一个类里有抽象方法,那么这个类只能是抽象类 
9、抽象方法要被实现,所以不能是静态的,也不能是私有的。 
10、接口可继承接口,并可多继承接口,但类只能单根继承。

关于final的重要知识点

  1. final关键字可以用于成员变量、本地变量、方法以及类。
  2. final成员变量必须在声明的时候初始化或者在构造器中初始化,否则就会报编译错误。
  3. 你不能够对final变量再次赋值。
  4. 本地变量必须在声明时赋值。
  5. 在匿名类中所有变量都必须是final变量。
  6. final方法不能被重写。
  7. final类不能被继承。
  8. final关键字不同于finally关键字,后者用于异常处理。
  9. final关键字容易与finalize()方法搞混,后者是在Object类中定义的方法,是在垃圾回收之前被JVM调用的方法。
  10. 接口中声明的所有变量本身是final的。
  11. final和abstract这两个关键字是反相关的,final类就不可能是abstract的。
  12. final方法在编译阶段绑定,称为静态绑定(static binding)。
  13. 没有在声明时初始化final变量的称为空白final变量(blank final variable),它们必须在构造器中初始化,或者调用this()初始化。不这么做的话,编译器会报错“final变量(变量名)需要进行初始化”。
  14. 将类、方法、变量声明为final能够提高性能,这样JVM就有机会进行估计,然后优化。
  15. 按照Java代码惯例,final变量就是常量,而且通常常量名要大写:
10 单例模式比较好的实现

 publicclassSingleton{privatevolatilestatic Singleton singleton;privateSingleton(){}publicstatic SingletongetSingleton(){if (singleton == null) {synchronized (Singleton.class) {if (singleton ==null) { singleton =new Singleton();} }}return singleton; }

11  equals相等两个对象,则hashcode一定要相等。但是hashcode相等的两个对象不一定equals相等。

12  java  多线程  sleep()  线程等待但是不会释放锁,wait 等待会释放锁需要notify进行唤醒。join 会等待子线程执行完之后再执行主线程。   

新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread();

就绪状态(Runnable):当调用线程对象的start()方法(t.start();),线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;

运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。注:就     绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;

阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才 有机会再次被CPU调用以进入到运行状态。根据阻塞产生的原因不同,阻塞状态又可以分为三种:

1.等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;

2.同步阻塞 -- 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;

3.其他阻塞 -- 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。

死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期。


关于jvm的


jvm  java 虚拟机 主要分为  堆 ,栈,方法区 ,程序计数器  ;  线程是在栈里面运行的。 堆 分为 新生代和老年代;以及永久代

堆里面放的主要是 类的实例,而栈里面放的是一个类的引用

永久代放的是 加载需要的class文件和相关的静态资源       

新生代有分为  一个eden 和两个 survivor 新生的类先放到eden ,如果eden满了存放到 其中一个survivor,然后这个满了,再放另外一个中。

通过新生代的多次垃圾回收后,没有回收掉的,会放入老年代中

方法区只是逻辑上存在,并不真正的存在

方法区存储每一个java类的结构信息:比如运行时常量池,字段和方法数据,构造函数和普通方法的字节码内容以及类、实例、接口初始化时需要使用到的特殊方法等数据。 



SpringMVC运行原理

1. 客户端请求提交到DispatcherServlet

2. 由DispatcherServlet控制器查询HandlerMapping,找到并分发到指定的Controller中。

4. Controller调用业务逻辑处理后,返回ModelAndView

5. DispatcherServlet查询一个或多个ViewResoler视图解析器,找到ModelAndView指定的视图

6. 视图负责将结果显示到客户端

SpringMVC运行原理

1. 客户端请求提交到DispatcherServlet

2. 由DispatcherServlet控制器查询HandlerMapping,找到并分发到指定的Controller中。

4. Controller调用业务逻辑处理后,返回ModelAndView

5. DispatcherServlet查询一个或多个ViewResoler视图解析器,找到ModelAndView指定的视图

6. 视图负责将结果显示到客户端


HashMap的实现机制:

1. 维护一个每个元素是一个链表的数组,而且链表中的每个节点是一个Entry[]键值对的数据结构。

2. 实现了数组+链表的特性,查找快,插入删除也快。

3. 对于每个key,他对应的数组索引下标是 int i = hash(key.hashcode)&(len-1);

4. 每个新加入的节点放在链表首,然后该新加入的节点指向原链表首

        

所谓spring事务的传播属性,就是定义在存在多个事务同时存在的时候,spring应该如何处理这些事务的行为。这些属性在TransactionDefinition中定义,具体常量的解释见下表:
常量名称     常量解释
PROPAGATION_REQUIRED     支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择,也是 Spring 默认的事务的传播。
PROPAGATION_REQUIRES_NEW     新建事务,如果当前存在事务,把当前事务挂起。新建的事务将和被挂起的事务没有任何关系,是两个独立的事务,外层事务失败回滚之后,不能回滚内层事务执行的结果,内层事务失败抛出异常,外层事务捕获,也可以不处理回滚操作
PROPAGATION_SUPPORTS     支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY     支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_NOT_SUPPORTED     以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER     以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED     
如果一个活动的事务存在,则运行在一个嵌套的事务中。如果没有活动事务,则按REQUIRED属性执行。它使用了一个单独的事务,这个事务拥有多个可以回滚的保存点。内部事务的回滚不会对外部事务造成影响。它只对DataSourceTransactionManager事务管理器起效。
三、数据库隔离级别
隔离级别     隔离级别的值     导致的问题
Read-Uncommitted     0     导致脏读
Read-Committed     1     避免脏读,允许不可重复读和幻读
Repeatable-Read     2     避免脏读,不可重复读,允许幻读
Serializable     3     串行化读,事务只能一个一个执行,避免了脏读、不可重复读、幻读。执行效率慢,使用时慎重
脏读:一事务对数据进行了增删改,但未提交,另一事务可以读取到未提交的数据。如果第一个事务这时候回滚了,那么第二个事务就读到了脏数据。
不可重复读:一个事务中发生了两次读操作,第一次读操作和第二次操作之间,另外一个事务对数据进行了修改,这时候两次读取的数据是不一致的。
幻读:第一个事务对一定范围的数据进行批量修改,第二个事务在这个范围增加一条数据,这时候第一个事务就会丢失对新增数据的修改。
总结:
隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大。
大多数的数据库默认隔离级别为 Read Commited,比如 SqlServer、Oracle
少数数据库默认隔离级别为:Repeatable Read 比如: MySQL InnoDB
四、Spring中的隔离级别
常量     解释
ISOLATION_DEFAULT     这是个 PlatfromTransactionManager 默认的隔离级别,使用数据库默认的事务隔离级别。另外四个与 JDBC 的隔离级别相对应。
ISOLATION_READ_UNCOMMITTED     这是事务最低的隔离级别,它充许另外一个事务可以看到这个事务未提交的数据。这种隔离级别会产生脏读,不可重复读和幻像读。
ISOLATION_READ_COMMITTED     保证一个事务修改的数据提交后才能被另外一个事务读取。另外一个事务不能读取该事务未提交的数据。
ISOLATION_REPEATABLE_READ     这种事务隔离级别可以防止脏读,不可重复读。但是可能出现幻像读。
ISOLATION_SERIALIZABLE     这是花费最高代价但是最可靠的事务隔离级别。事务被处理为顺序执行。
五、事务的嵌套
通过上面的理论知识的铺垫,我们大致知道了数据库事务和spring事务的一些属性和特点,接下来我们通过分析一些嵌套事务的场景,来深入理解spring事务传播的机制。
假设外层事务 Service A 的 Method A() 调用 内层Service B 的 Method B()
PROPAGATION_REQUIRED(spring 默认)
如果ServiceB.methodB() 的事务级别定义为 PROPAGATION_REQUIRED,那么执行 ServiceA.methodA() 的时候spring已经起了事务,这时调用 ServiceB.methodB(),ServiceB.methodB() 看到自己已经运行在 ServiceA.methodA() 的事务内部,就不再起新的事务。
假如 ServiceB.methodB() 运行的时候发现自己没有在事务中,他就会为自己分配一个事务。
这样,在 ServiceA.methodA() 或者在 ServiceB.methodB() 内的任何地方出现异常,事务都会被回滚。
PROPAGATION_REQUIRES_NEW
比如我们设计 ServiceA.methodA() 的事务级别为 PROPAGATION_REQUIRED,ServiceB.methodB() 的事务级别为 PROPAGATION_REQUIRES_NEW。
那么当执行到 ServiceB.methodB() 的时候,ServiceA.methodA() 所在的事务就会挂起,ServiceB.methodB() 会起一个新的事务,等待 ServiceB.methodB() 的事务完成以后,它才继续执行。
他与 PROPAGATION_REQUIRED 的事务区别在于事务的回滚程度了。因为 ServiceB.methodB() 是新起一个事务,那么就是存在两个不同的事务。如果 ServiceB.methodB() 已经提交,那么 ServiceA.methodA() 失败回滚,ServiceB.methodB() 是不会回滚的。如果 ServiceB.methodB() 失败回滚,如果他抛出的异常被 ServiceA.methodA() 捕获,ServiceA.methodA() 事务仍然可能提交(主要看B抛出的异常是不是A会回滚的异常)。
PROPAGATION_SUPPORTS
假设ServiceB.methodB() 的事务级别为 PROPAGATION_SUPPORTS,那么当执行到ServiceB.methodB()时,如果发现ServiceA.methodA()已经开启了一个事务,则加入当前的事务,如果发现ServiceA.methodA()没有开启事务,则自己也不开启事务。这种时候,内部方法的事务性完全依赖于最外层的事务。
PROPAGATION_NESTED
现在的情况就变得比较复杂了, ServiceB.methodB() 的事务属性被配置为 PROPAGATION_NESTED, 此时两者之间又将如何协作呢?  ServiceB#methodB 如果 rollback, 那么内部事务(即 ServiceB#methodB) 将回滚到它执行前的 SavePoint 而外部事务(即 ServiceA#methodA) 可以有以下两种处理方式:
a、捕获异常,执行异常分支逻辑
void methodA() { 
        try { 
            ServiceB.methodB(); 
        } catch (SomeException) { 
            // 执行其他业务, 如 ServiceC.methodC(); 
        } 
    }
这种方式也是嵌套事务最有价值的地方, 它起到了分支执行的效果, 如果 ServiceB.methodB 失败, 那么执行 ServiceC.methodC(), 而 ServiceB.methodB 已经回滚到它执行之前的 SavePoint, 所以不会产生脏数据(相当于此方法从未执行过), 这种特性可以用在某些特殊的业务中, 而 PROPAGATION_REQUIRED 和 PROPAGATION_REQUIRES_NEW 都没有办法做到这一点。
b、 外部事务回滚/提交 代码不做任何修改, 那么如果内部事务(ServiceB#methodB) rollback, 那么首先 ServiceB.methodB 回滚到它执行之前的 SavePoint(在任何情况下都会如此), 外部事务(即 ServiceA#methodA) 将根据具体的配置决定自己是 commit 还是 rollback
另外三种事务传播属性基本用不到,在此不做分析。


Spring工作原理 
 
一、 IoC(Inversion of control): 控制反转 
  1、IoC: 
  概念:控制权由对象本身转向容器;由容器根据配置文件去创建实例并创建各个实例之间的依赖关系 
  核心:bean工厂;在Spring中,bean工厂创建的各个实例称作bean 
二、AOP(Aspect-Oriented Programming): 面向方面编程 
  1、 代理的两种方式: 
    静态代理: 
     针对每个具体类分别编写代理类; 
     针对一个接口编写一个代理类; 
    动态代理: 
    针对一个方面编写一个InvocationHandler,然后借用JDK反射包中的Proxy类为各种接口动态生成相应的代理类 
  2、 AOP的主要原理:动态代理 


        Spring 已经用过一段时间了,感觉Spring是个很不错的框架。内部最核心的就是IOC了, 
动态注入,让一个对象的创建不用new了,可以自动的生产,这其实就是利用java里的反射 
反射其实就是在运行时动态的去创建、调用对象,Spring就是在运行时,跟xml  Spring的配置 
文件来动态的创建对象,和调用对象里的方法的 。 
     Spring还有一个核心就是AOP这个就是面向切面编程,可以为某一类对象 进行监督和控制(也就是 
在调用这类对象的具体方法的前后去调用你指定的 模块)从而达到对一个模块扩充的功能。这些都是通过 
配置类达到的。 
   Spring目的:就是让对象与对象(模块与模块)之间的关系没有通过代码来关联,都是通过配置类说明 
管理的(Spring根据这些配置 内部通过反射去动态的组装对象) 
   要记住:Spring是一个容器,凡是在容器里的对象才会有Spring所提供的这些服务和功能。 
Spring里用的最经典的一个设计模式就是:模板方法模式。(这里我都不介绍了,是一个很常用的设计模式) 
  Spring里的配置是很多的,很难都记住,但是Spring里的精华也无非就是以上的两点,把以上两点跟理解了 
也就基本上掌握了Spring. 
 
各个部分的作用:
  1.springmvc请所有的请求都提交给DispatcherServlet,它会委托应用系统的其他模块负责负责对请求进行真正的处理工作。 

  2.DispatcherServlet查询一个或多个HandlerMapping,找到处理请求的Controller. 

  3.DispatcherServlet请请求提交到目标Controller 

  4.Controller进行业务逻辑处理后,会返回一个ModelAndView 

  5.Dispathcher查询一个或多个ViewResolver视图解析器,找到ModelAndView对象指定的视图对象 

  6.视图对象负责渲染返回给客户端。






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值