针对《面试心得与总结—BAT、网易、蘑菇街》一文中出现的技术问题的收集与整理(2)

来源:互联网 发布:linux 限制访问目录 编辑:程序博客网 时间:2024/04/26 17:02

16. Java面向对象的三个特征与含义

1 . 封装性

  将对象的状态信息尽可能的隐藏在对象内部,只保留有限的接口和方法与外界进行交互,从而避免了外界对对象内部属性的破坏。

  Java中使用访问控制符来保护对类、变量、方法和构造方法的访问

2. 继承

   java通过继承创建分等级层次的类,可以理解为一个对象从另一个对象获取属性的过程。

3.多态

  多态是同一个行为具有多个不同表现形式或形态的能力。 多态性是对象多种表现形式的体现

参考链接:https://yq.aliyun.com/articles/52843

17. Override和Overload的含义和区别

方法的重写(Overriding)和重载(Overloading)是Java多态性的不同表现。   
重写(Overriding)是父类与子类之间多态性的一种表现,而重载(Overloading)是一个类中多态性的一种表现。如果在子类中定义某方法与其父类有相同的名称和参数,我们说该方法被重写 (Overriding) 。子类的对象使用这个方法时,将调用子类中的定义,对它而言,父类中的定义如同被"屏蔽"了。如果在一个类中定义了多个同名的方法,它们或有不同的参数个数或有不同的参数类型或有不同的参数次序,则称为方法的重载(Overloading)。不能通过访问权限、返回类型、抛出的异常进行重载。 

1. Override 特点   
1、覆盖的方法的标志必须要和被覆盖的方法的标志完全匹配,才能达到覆盖的效果;   
2、覆盖的方法的返回值必须和被覆盖的方法的返回一致;   
3、覆盖的方法所抛出的异常必须和被覆盖方法的所抛出的异常一致,或者是其子类; 
4、方法被定义为final不能被重写。  
5、对于继承来说,如果某一方法在父类中是访问权限是private,那么就不能在子类对其进行重写覆盖,如果定义的话,也只是定义了一个新方法,而不会达到重写覆盖的效果。(通常存在于父类和子类之间。) 

2.Overload 特点   
1、在使用重载时只能通过不同的参数样式。例如,不同的参数类型,不同的参数个数,不同的参数顺序(当然,同一方法内的几个参数类型必须不一样,例如可以是fun(int, float), 但是不能为fun(int, int));   
2、不能通过访问权限、返回类型、抛出的异常进行重载;   
3、方法的异常类型和数目不会对重载造成影响;   
4、重载事件通常发生在同一个类中,不同方法之间的现象。 
5、存在于同一类中,但是只有虚方法和抽象方法才能被覆写。 

其具体实现机制: 

overload是重载,重载是一种参数多态机制,即代码通过参数的类型或个数不同而实现的多态机制。 是一种静态的绑定机制(在编译时已经知道具体执行的是哪个代码段)。   
    
override是覆盖。覆盖是一种动态绑定的多态机制。即在父类和子类中同名元素(如成员函数)有不同 的实现代码。执行的是哪个代码是根据运行时实际情况而定的。


18. Interface与abstract类的区别

抽象类和接口都不能够实例化,但可以定义抽象类和接口类型的引用。一个类如果继承了某个抽象类或者实现了某个接口都需要对其中的抽象方法全部进行实现,否则该类仍然需要被声明为抽象类。接口比抽象类更加抽象,因为抽象类中可以定义构造器,可以有抽象方法和具体方法,而接口中不能定义构造器而且其中的方法全部都是抽象方法。抽象类中的成员可以是private、默认、protected、public的,而接口中的成员全都是public的。抽象类中可以定义成员变量,而接口中定义的成员变量实际上都是常量。有抽象方法的类必须被声明为抽象类,而抽象类未必要有抽象方法。

19. Static class 与non static class的区别

内部静态类不需要有指向外部类的引用。但非静态内部类需要持有对外部类的引用。非静态内部类能够访问外部类的静态和非静态成员。静态类不能访问外部类的非静态成员。他只能访问外部类的静态成员。一个非静态内部类不能脱离外部类实体被创建,一个非静态内部类可以访问外部类的数据和方法,因为他就在外部类里面。

1.首先是类中的数据,static的
class A {
static int a;
}
class B {
int b;
}
无论新建几个A对象,这几个对象公用一个int a,一个对象的a改变,另一个也会改变。
而B对象,不同对象之间的int b独立存在,互不影响,可以有多个值。

2.类中的方法
静态的方法,不需要建立对象就可以访问
如Math.abs()这个方法,我们没有建立Math的对象,就可以通过类名直接使用abs这个方法。
而非静态的方法,必须先建立对象,然后通过对象名,调用这个方法。
如JButton jb = new JButton();
jb.addActionListener(l);

ps:在静态方法的定义中,不能直接引用本类的其他非静态方法。例如。我们不能在main中直接引用,本类的其他方法。所以我们经常可以看见,在main方法中,先建立本类的一个对象,然后才通过对象调用本类的其他方法。

3.在初始化过程中,静态的总是先初始化

20. java多态的实现原理。

参考链接:http://www.cnblogs.com/startRuning/p/5673485.html


21. 实现多线程的两种方法:Thread与Runable

Thread 和 Runnable 的相同点:都是“多线程的实现方式”。
Thread 和 Runnable 的不同点:
Thread 是类,而Runnable是接口;Thread本身是实现了Runnable接口的类。我们知道“一个类只能有一个父类,但是却能实现多个接口”,因此Runnable具有更好的扩展性。
此外,Runnable还可以用于“资源的共享”。即,多个线程都是基于某一个Runnable对象建立的,它们会共享Runnable对象上的资源。
通常,建议通过“Runnable”实现多线程

参考链接:http://hjsj186.blog.163.com/blog/static/2465820332015218115231968/

22. 线程同步的方法:sychronized、lock、reentrantLock等

一.什么是sychronized

sychronized是Java中最基本同步互斥的手段,可以修饰代码块,方法,类.

在修饰代码块的时候需要一个reference对象作为锁的对象.

在修饰方法的时候默认是当前对象作为锁的对象.

在修饰类时候默认是当前类的Class对象作为锁的对象.

synchronized会在进入同步块的前后分别形成monitorenter和monitorexit字节码指令.在执行monitorenter指令时会尝试获取对象的锁,如果此没对象没有被锁,或者此对象已经被当前线程锁住,那么锁的计数器加一,每当monitorexit被锁的对象的计数器减一.直到为0就释放该对象的锁.由此synchronized是可重入的,不会出现自己把自己锁死.


二.什么ReentrantLock

以对象的方式来操作对象锁.相对于sychronized需要在finally中去释放锁 

三.synchronized和ReentrantLock的区别

除了synchronized的功能,多了三个高级功能.

等待可中断,公平锁,绑定多个Condition.

1.等待可中断

在持有锁的线程长时间不释放锁的时候,等待的线程可以选择放弃等待.   tryLock(long timeout, TimeUnit unit)

2.公平锁

按照申请锁的顺序来一次获得锁称为公平锁.synchronized的是非公平锁,ReentrantLock可以通过构造函数实现公平锁.    new RenentrantLock(boolean fair)

3.绑定多个Condition

通过多次newCondition可以获得多个Condition对象,可以简单的实现比较复杂的线程同步的功能.通过await(),signal();


分析理解:
在并发量比较小的情况下,使用synchronized是个不错的选择,但是在并发量比较高的情况下,其性能下降很严重,此时ReentrantLock是个不错的方案。

 

1、ReentrantLock 拥有Synchronized相同的并发性和内存语义,此外还多了 锁投票,定时锁等候和中断锁等候

     线程A和B都要获取对象O的锁定,假设A获取了对象O锁,B将等待A释放对O的锁定,

     如果使用 synchronized ,如果A不释放,B将一直等下去,不能被中断

     如果 使用ReentrantLock,如果A不释放,可以使B在等待了足够长的时间以后,中断等待,而干别的事情

 

    ReentrantLock获取锁定与三种方式:
    a)  lock(), 如果获取了锁立即返回,如果别的线程持有锁,当前线程则一直处于休眠状态,直到获取锁

    b) tryLock(), 如果获取了锁立即返回true,如果别的线程正持有锁,立即返回false;

    c)tryLock(long timeout,TimeUnit unit),   如果获取了锁定立即返回true,如果别的线程正持有锁,会等待参数给定的时间,在等待的过程中,如果获取了锁定,就返回true,如果等待超时,返回false;

    d) lockInterruptibly:如果获取了锁定立即返回,如果没有获取锁定,当前线程处于休眠状态,直到或者锁定,或者当前线程被别的线程中断

 

2、synchronized是在JVM层面上实现的,不但可以通过一些监控工具监控synchronized的锁定,而且在代码执行时出现异常,JVM会自动释放锁定,但是使用Lock则不行,lock是通过代码实现的,要保证锁定一定会被释放,就必须将unLock()放到finally{}中

 

3、在资源竞争不是很激烈的情况下,Synchronized的性能要优于ReetrantLock,但是在资源竞争很激烈的情况下,Synchronized的性能会下降几十倍,但是ReetrantLock的性能能维持常态;

JDK5.0的多线程任务包对于同步的性能方面有了很大的改进,在原有synchronized关键字的基础上,又增加了ReentrantLock,以及各种Atomic类。了解其性能的优劣程度,有助与我们在特定的情形下做出正确的选择。 

总体的结论先摆出来:  

synchronized: 
在资源竞争不是很激烈的情况下,偶尔会有同步的情形下,synchronized是很合适的。原因在于,编译程序通常会尽可能的进行优化synchronize,另外可读性非常好,不管用没用过5.0多线程包的程序员都能理解。 

ReentrantLock: 
ReentrantLock提供了多样化的同步,比如有时间限制的同步,可以被Interrupt的同步(synchronized的同步是不能Interrupt的)等。在资源竞争不激烈的情形下,性能稍微比synchronized差点点。但是当同步非常激烈的时候,synchronized的性能一下子能下降好几十倍。而ReentrantLock确还能维持常态。 

Atomic: 
和上面的类似,不激烈情况下,性能比synchronized略逊,而激烈的时候,也能维持常态。激烈的时候,Atomic的性能会优于ReentrantLock一倍左右。但是其有一个缺点,就是只能同步一个值,一段代码中只能出现一个Atomic的变量,多于一个同步无效。因为他不能在多个Atomic之间同步。 


所以,我们写同步的时候,优先考虑synchronized,如果有特殊需要,再进一步优化。ReentrantLock和Atomic如果用的不好,不仅不能提高性能,还可能带来灾难。

23. 锁的等级:方法锁、对象锁、类锁

方法锁(synchronized修饰方法时)

通过在方法声明中加入 synchronized关键字来声明 synchronized 方法。

synchronized 方法控制对类成员变量的访问:
每个类实例对应一把锁,每个 synchronized 方法都必须获得调用该方法的类实例的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。这种机制确保了同一时刻对于每一个类实例,其所有声明为 synchronized 的成员函数中至多只有一个处于可执行状态,从而有效避免了类成员变量的访问冲突。

对象锁(synchronized修饰方法或代码块)

  当一个对象中有synchronized method或synchronized block的时候调用此对象的同步方法或进入其同步区域时,就必须先获得对象锁。如果此对象的对象锁已被其他调用者占用,则需要等待此锁被释放。(方法锁也是对象锁)       

java的所有对象都含有1个互斥锁,这个锁由JVM自动获取和释放。线程进入synchronized方法的时候获取该对象的锁,当然如果已经有线程获取了这个对象的锁,那么当前线程会等待;synchronized方法正常返回或者抛异常而终止,JVM会自动释放对象锁。这里也体现了用synchronized来加锁的1个好处,方法抛异常的时候,锁仍然可以由JVM来自动释放。

类锁(synchronized 修饰静态的方法或代码块)

  由于一个class不论被实例化多少次,其中的静态方法和静态变量在内存中都只有一份。所以,一旦一个静态的方法被申明为synchronized。此类所有的实例化对象在调用此方法,共用同一把锁,我们称之为类锁。  

对象锁是用来控制实例方法之间的同步,类锁是用来控制静态方法(或静态变量互斥体)之间的同步。 

类锁只是一个概念上的东西,并不是真实存在的,它只是用来帮助我们理解锁定实例方法和静态方法的区别的。

24. 写出生产者消费者模式。

生产者-消费者(producer-consumer)问题,也称作有界缓冲区(bounded-buffer)问题,两个进程共享一个公共的固定大小的缓冲区。其中一个是生产者,用于将消息放入缓冲区;另外一个是消费者,用于从缓冲区中取出消息。问题出现在当缓冲区已经满了,而此时生产者还想向其中放入一个新的数据项的情形,其解决方法是让生产者此时进行休眠,等待消费者从缓冲区中取走了一个或者多个数据后再去唤醒它。同样地,当缓冲区已经空了,而消费者还想去取消息,此时也可以让消费者进行休眠,等待生产者放入一个或者多个数据时再唤醒它。

一,首先定义公共资源类,其中的变量number是保存的公共数据。并且定义两个方法,增加number的值和减少number的值。由于多线程的原因,必须加上synchronized关键字,注意while判断的条件。

    /**      * 公共资源类      */      public class PublicResource {          private int number = 0;                /**          * 增加公共资源          */          public synchronized void increace() {              while (number != 0) {                  try {                      wait();                  } catch (InterruptedException e) {                      e.printStackTrace();                  }              }              number++;              System.out.println(number);              notify();          }                /**          * 减少公共资源          */          public synchronized void decreace() {              while (number == 0) {                  try {                      wait();                  } catch (InterruptedException e) {                      e.printStackTrace();                  }              }              number--;              System.out.println(number);              notify();          }      }  

二,分别定义生产者线程和消费者线程,并模拟多次生产和消费,即增加和减少公共资源的number值
    /**      * 生产者线程,负责生产公共资源      */      public class ProducerThread implements Runnable {          private PublicResource resource;                public ProducerThread(PublicResource resource) {              this.resource = resource;          }                @Override          public void run() {              for (int i = 0; i < 10; i++) {                  try {                      Thread.sleep((long) (Math.random() * 1000));                  } catch (InterruptedException e) {                      e.printStackTrace();                  }                  resource.increace();              }          }      }      /**      * 消费者线程,负责消费公共资源      */      public class ConsumerThread implements Runnable {          private PublicResource resource;                public ConsumerThread(PublicResource resource) {              this.resource = resource;          }                @Override          public void run() {              for (int i = 0; i < 10; i++) {                  try {                      Thread.sleep((long) (Math.random() * 1000));                  } catch (InterruptedException e) {                      e.printStackTrace();                  }                  resource.decreace();              }          }      }  

三,模拟多个生产者和消费者操作公共资源的情形,结果须保证是在允许的范围内。
public class ProducerConsumerTest {      public static void main(String[] args) {          PublicResource resource = new PublicResource();          new Thread(new ProducerThread(resource)).start();          new Thread(new ConsumerThread(resource)).start();          new Thread(new ProducerThread(resource)).start();          new Thread(new ConsumerThread(resource)).start();          new Thread(new ProducerThread(resource)).start();          new Thread(new ConsumerThread(resource)).start();      }  }
参考链接:http://blog.csdn.net/u010339647/article/details/52013123

25. ThreadLocal的设计理念与作用

ThreadLocal类的大致结构和进行ThreadLocalMap的操作.我们可以从中得出以下的结论:1. ThreadLocalMap变量属于线程(Thread)的内部属性,不同的线程(Thread)拥有完全不同的ThreadLocalMap变量.2. 线程(Thread)中的ThreadLocalMap变量的值是在ThreadLocal对象进行set或者get操作时创建的.3. 在创建ThreadLocalMap之前,会首先检查当前线程(Thread)中的ThreadLocalMap变量是否已经存在,如果不存在则创建一个;如果已经存在,则使用当前线程(Thread)已创建的ThreadLocalMap.4. 使用当前线程(Thread)的ThreadLocalMap的关键在于使用当前的ThreadLocal的实例作为key进行存储ThreadLocal模式,至少从两个方面完成了数据访问隔离,有了横向和纵向的两种不同的隔离方式,ThreadLocal模式就能真正地做到线程安全:纵向隔离 —— 线程(Thread)与线程(Thread)之间的数据访问隔离.这一点由线程(Thread)的数据结构保证.因为每个线程(Thread)在进行对象访问时,访问的都是各自线程自己的ThreadLocalMap.横向隔离 —— 同一个线程中,不同的ThreadLocal实例操作的对象之间的相互隔离.这一点由ThreadLocalMap在存储时,采用当前ThreadLocal的实例作为key来保证.

话不多说,给大家推荐一篇原创博文,我就是在这篇博客http://blog.csdn.net/hua286306956/article/details/8660268里 学习的

26. ThreadPool用法与优势。

先定义一个线程池ThreadPoolExecutor,使用的时候用executor来调用runnable

优势:合理利用线程池能够带来三个好处。第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。第三:提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。


推荐链接:http://blog.csdn.net/scboyhj__/article/details/48805881

27. Concurrent包里的其他东西:ArrayBlockingQueue、CountDownLatch等等。

ArrayBlockingQueue

一个建立在数组之上被BlockingQueue绑定的阻塞队列。这个队列元素顺序是先进先出。队列的头部是在队列中待的时间最长的元素。队列的尾部是再队列中待的时间最短的元素。新的元素会被插入到队列尾部,并且队列从队列头部获取元素。

    这是一个典型的绑定缓冲,在这个缓冲区中,有一个固定大小的数组持有生产者插入的数据,并且消费者会提取这些数据。一旦这个类被创建,那么这个数组的容量将不能再被改变。尝试使用put操作给一个满队列插入元素将导致这个操作被阻塞;尝试从空队列中取元素也会被阻塞。

    这个类推荐了一个可选的公平策略来排序等待的生产者和消费者线程。默认的,这个顺序是不确定的。但是队列会使用公平的设置true来使线程按照先进先出顺序访问。通常公平性会减少吞吐量但是却减少了可变性以及避免了线程饥饿。

参考博文:http://blog.csdn.net/startupmount/article/details/37413275?utm_source=tuicool&utm_medium=referral

concurrent包是jdk1.5引入的重要的包,主要代码由大牛Doug Lea完成,其实是在jdk1.4时代,由于java语言内置对多线程编程的支持比较基础和有限,所以他写了这个,因为实在太过于优秀,所以被加入到jdk之中; 

通常所说的concurrent包基本有3个package组成 
java.util.concurrent:提供大部分关于并发的接口和类,如BlockingQueue,Callable,ConcurrentHashMap,ExecutorService, Semaphore等 
java.util.concurrent.atomic:提供所有原子操作的类, 如AtomicInteger, AtomicLong等; 
java.util.concurrent.locks:提供锁相关的类, 如Lock, ReentrantLock, ReadWriteLock, Condition等;


ountDownLatch, 可以用来在一个线程中等待多个线程完成任务的类; 
通常的使用场景是,某个主线程接到一个任务,起了n个子线程去完成,但是主线程需要等待这n个子线程都完成任务了以后才开始执行某个操作; 

掩饰代码:

@Test  public void demoCountDown()  {      int count = 10;        final CountDownLatch l = new CountDownLatch(count);      for(int i = 0; i < count; ++i)      {          final int index = i;          new Thread(new Runnable() {                @Override              public void run() {                    try {                      Thread.currentThread().sleep(20 * 1000);                  } catch (InterruptedException e) {                        e.printStackTrace();                  }                    System.out.println("thread " + index + " has finished...");                    l.countDown();                }          }).start();      }        try {          l.await();      } catch (InterruptedException e) {            e.printStackTrace();      }        System.out.println("now all threads have finished");    }

28. wait()和sleep()的区别

① 这两个方法来自不同的类分别是,sleep来自Thread类,和wait来自Object类。

sleep是Thread的静态类方法,谁调用的谁去睡觉,即使在a线程里调用b的sleep方法,实际上还是a去睡觉,要让b线程睡觉要在b的代码中调用sleep。

② 锁: 最主要是sleep方法没有释放锁,而wait方法释放了锁,使得其他线程可以使用同步控制块或者方法。

sleep不出让系统资源;wait是进入线程等待池等待,出让系统资源,其他线程可以占用CPU。一般wait不会加时间限制,因为如果wait线程的运行资源不够,再出来也没用,要等待其他线程调用notify/notifyAll唤醒等待池中的所有线程,才会进入就绪队列等待OS分配系统资源。sleep(milliseconds)可以用时间指定使它自动唤醒过来,如果时间不到只能调用interrupt()强行打断。

Thread.sleep(0)的作用是“触发操作系统立刻重新进行一次CPU竞争”。

③ 使用范围:wait,notify和notifyAll只能在同步控制方法或者同步控制块里面使用,而sleep可以在任何地方使用。

   synchronized(x){ 
      x.notify() 
     //或者wait() 
   }

29. foreach与正常for循环效率对比

不是绝对的,在选择for, foreach的时候,应该考虑以下几点:

1. 如果只是读数据,优先选择foreach,因为效率高,而且代码简单,方便;

2. 如果要写数据,就只能选择for了

30. Java IO与NIO

区别对比

IO                NIO面向流            面向缓冲阻塞IO            非阻塞IO无                选择器
1、面向流与面向缓冲

Java NIO和IO之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的。 Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。 Java NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。但是,还需要检查是否该缓冲区中包含所有您需要处理的数据。而且,需确保当更多的数据读入缓冲区时,不要覆盖缓冲区里尚未处理的数据。

2、阻塞与非阻塞IO

Java IO的各种流是阻塞的。这意味着,当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。 Java NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取。而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。 非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。 线程通常将非阻塞IO的空闲时间用于在其它通道上执行IO操作,所以一个单独的线程现在可以管理多个输入和输出通道(channel)。

3、选择器(Selector)

ava NIO的选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用一个选择器,然后使用一个单独的线程来“选择”通道:这些通道里已经有可以处理的输入,或者选择已准备写入的通道。这种选择机制,使得一个单独的线程很容易来管理多个通道。

31. 反射的作用与原理。

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

推荐链接:Class对象和java反射机制

java反射

32. 泛型常用特点,List<String>能否转为List<Object>。

1、类型安全。类型错误现在在编译期间就被捕获到了,而不是在运行时当作java.lang.ClassCastException展示出来,将类型检查从运行时挪到编译时有助于开发者更容易找到错误,并提高程序的可靠性

2、消除了代码中许多的强制类型转换,增强了代码的可读性

3、为较大的优化带来了可能

List<String>向上转换至List<Object>会丢失String类的身份(String类型的特有接口),这种转换是不完美的。
当需要由List向下转型时,你的程序必须明确的知道将对象转换成何种具体类型,不然这将是不不‘安全的操作!

33. 解析XML的几种方式的原理与特点:DOM、SAX、PULL
  • SAX是基于事件流的解析
    当解析器发现元素开始、元素结束、文本、文档的开始或结束等时,发送事件,程序员编写响应这些事件的代码,保存数据
  • DOM是基于XML文档树结构的解析
    解析器读入整个文档,然后构建一个驻留内存的树结构,然后代码就可以使用 DOM 接口来操作这个树结构

Sax定义

         SAX是一个解析速度快并且占用内存少的xml解析器,非常适合用于android等移动设备

         SAX全称是Simple API for Xml,既是指一种接口,也是一个软件包

         作为接口,sax是事件驱动型xml解析的一个标准接口

Sax工作原理

         Sax的工作原理简单的说,就是对文档进行顺序扫描,扫描到文档(document)开始与结束,扫描到元素(element)开始、结束等地方时调用事件处理

         处理函数做相应动作,然后继续扫描,直到文档结束。

Sax特点

        1. 解析效率高,占用内存少

        2.可以随时停止解析

        3.不能载入整个文档到内存

        4.不能写入xml

        5.SAX解析xml文件采用的是事件驱动

        ---sax并不需要解析完 整个文档,在按内容顺序解析文档的过程中,sax会判断当前读到的字符是否合法xml语法中的某部分,如果符合就会触发事件

DOM工作原理

dom全称Document Object Model ,为xml文档的已解析版本定义了一组接口。解析器读入整个文档,然后构建一个主流内存的树结构,

         然后代码就可以使用dom接口来操作这个树结构

DOM的特点

         >优点

                  1.整个文档树在内存中,便于操作;支持删除、修改、重新排列等多种功能

                  2.通过树形结构存取xml文档

                  3.可以在树的某个节点上向前或向后移动

           >缺点

                  1.将整个文档调入内存(包括无用的节点),浪费时间和空间

            >适用场合

                  一旦解析了文档还需多次访问这些数据;硬件资源充足(内存,cpu)

pull解析器简介

        1.pull解析器是android内置的解析器,解析原理与sax类似

        2.pull它提供了类似的事件。

              如:开始元素和结束元素事件,使用parse.next()可以进入下一个元素并触发相应的事件,事件将作为数值代码被发送

                      因此可以使用一个switch对感兴趣的事件进行处理。当元素开始解析时,调用parser.nextText()方法获取下一个Text类型节点的值

pull与sax的不同之处

          1.pull读取xml文件后触发相应的事件调用方法返回的是数字。

          2.pull可以在程序中控制,想解析到哪里就可以停止到哪里

          3.Android中更推荐使用pull解析

参考链接:http://blog.csdn.net/kukulongzai_123/article/details/7058008
34. Java与C++对比
  1. Java没有显式指针,而在C++中却可以用。
  2. Java是主动多态的,不用关心具有继承关系的多个类之间的同名成员函数会调用哪个,Java会主动地从祖父类、祖祖父类……,追溯至最高一级父类,然后从上至下开始寻找并调用;C++却不会主动使用多态,要使用多态,就要用虚函数。
  3. Java是隐式继承的;C++是被动多态的,C++把话说明白了,你继承谁就继承谁,继承多个都可以,你什么都不说那么就不继承。
  4. Java有接口,C++中却没有。C++中是定义了一个抽象类,把成员函数设为常量,并改成纯虚函数,在C++中这样的抽象类就是接口。
  5. Java是单根继承的,但是允许一个类实现多个接口;C++虽然支持多继承,尽管很少有人去用它。
  6. Java中所有的函数都与类相关,没有全局变量和非成员函数,而C++却支持这些。
  7. C++中使用的动态内存怎么用就怎么还,Java中由于包含一个垃圾收集系统。
  8. Java有很紧凑的异常处理机制,而C++稍微显得草率了一些。但是,这不代表C++异常处理机制不强大,因为Java只能抛出Throwable之类的异常,而C++却什么都可以。
  9. Java标准库是Java庞大的体现,涵盖了国际化、网络化、数学、声音、Web应用和服务以及数据库等。
35. Java1.7与1.8新特性。
 

JDK 1.7 新特性

1,switch中可以使用字串了

2,"<>"这个玩意儿的运用List<String> tempList = new ArrayList<>(); 即泛型实例化类型自动推断

3. 自定义自动关闭类

4. 新增一些取环境信息的工具方法

5. Boolean类型反转,空指针安全,参与位运算

6. 两个char间的equals

7,安全的加减乘除

8、对Java集合(Collections)的增强支持

9、数值可加下划线

10、支持二进制文字

11、简化了可变参数方法的调用

12、在try catch异常扑捉中,一个catch可以写多个异常类型,用"|"隔开,

13、jdk7之前,你必须用try{}finally{}在try内使用资源,在finally中关闭资源,不管try中的代码是否正常退出或者异常退出。jdk7之后,你可以不必要写finally语句来关闭资源,只要你在try()的括号内部定义要使用的资源

JDK 1.8 新特性

一、接口的默认方法

二、Lambda 表达式

三、函数式接口

四、方法与构造函数引用

五、Lambda 作用域

六、访问局部变量

八、访问接口的默认方法

九、Date API

十、Annotation 注解

强烈推荐参考链接:JDK各个版本的新特性jdk1.5-jdk8

36. 设计模式:单例、工厂、适配器、责任链、观察者等等。

Java开发中的23种设计模式详解(转)

37. JNI的使用

JNI是Java Native Interface的缩写,它提供了若干的API实现了Java和其他语言的通信(主要是C&C++)。从Java1.1开始,JNI标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,但是它并不妨碍你使用其他编程语言,只要调用约定受支持就可以了。使用java与本地已编译的代码交互,通常会丧失平台可移植性。但是,有些情况下这样做是可以接受的,甚至是必须的。例如,使用一些旧的库,与硬件、操作系统进行交互,或者为了提高程序的性能。JNI标准至少要保证本地代码能工作在任何Java虚拟机环境。

 推荐链接:JNI的简单使用


j2se的部分 可算整理完了,希望各位读者能够喜欢,不足的地方希望各位大神多多批评指正,过几天给大家整理JVM 的部分

0 0