1.java的四大特性:抽象,继承,封装,多态
抽象的概念:
这里我先补充一下对象的概念,在java中世界万物皆对象,对象就是客观存在的事物,比如一个人,一支笔。而抽象就是将对象的某些细节和特征抽取出来,用程序代码表示,抽取出来的东西一般我们称之为类或者接口,因此抽象分为两个方面,数据抽象和过程抽象。
数据抽象:就是将事物的共同的特征用程序代码表示,通过抽象成为对象的属性,比如一个人有年龄,性别,身高,这些代表人的特征通过数据抽象成人这个对象的属性
过程抽象:就是将事物的行为用程序代码表示,通过抽象成为对象的方法,比如一个人,他要吃饭,他要跑步,这类的行为通过过程抽象成为人这个对象的方法。
继承的概念:
继承的单词是extends,但我个人更趋向理解为扩展,所以我认为继承就是从已有的类派生出新的类,新的类吸收已有的类的属性和方法,并且能够扩展的新的能力(新的方法)
比如车这个类,有车轮,车灯这些属性,但是车又可以派生出小轿车和大卡车两个类,这两个类都有车轮,车灯这些属性,并且为小轿车添上一个后备箱,为大卡车添上一个大货箱,
这添加出来的就是扩展后的功能。
继承的意义就是提高代码的复用性,如果两个类存在is-a的关系(比如绵羊属于羊这一类)子类继承父类的方法和属性,并且可以扩展自己的方法,如果需要实现父类中的同名方法必须进行重写。但是继承缺点很明显,第一点它打破了封装的概念,父类向子类暴露了实现细节。并且父类改变了,子类也要进行相应的改变,耦合度太高。所以大多情况下都会选择使用接口。
多态的概念:
在说多态之前,我要说下接口。在Java中接口是一个全部由抽象方法组成的集合,接口需要用interface定义,里面只能有抽象的方法和常量。接口就是体现事物扩展的不同功能,接口的不同实现方式就是多态,打个比方,有一个插座接口,声明了充电这个方法,插座可以用来插充电宝,插手机,插电风扇进行充电,至于怎么充,就是充电宝手机电风扇内部具体的实现。这种不同的实现方式就是接口多态的体现。一个类可以实现多个接口,实现类实现接口就必须重写这个接口里所有的方法,接口只做方法的声明,具体的实现由实现类去做。
接口对比继承就是降低耦合性,就那刚才那个插座接口举例,及时你电风扇内部充电功能改变了,都不会影响到插座充电的功能。
2.String类和StringBuffer类
String类为final类型的,不可继承,存储的是字符串常量,是不可改变的。
(每次赋值都是重新创建一个对象)
而StringBuffer类存储的是字符串变量,可以对字符串进行一系列的操作。
比如String str = “abc”,str = str + “de” ,输出的虽然是abcde,但是实际情况是,我们先创建一个String对象str,并把“abc”赋值给str,然后str = str+”de”执行的是,JVM创建了一个新的对象也名为str,然后再把原来的str的值和“de”加起来再赋值给新的str,而原来的str就会被JVM的垃圾回收机制(GC)给回收掉了。
StringBuffer类是线程安全的,适合多线程在字符缓冲区进行操作的情况。
3.异常
我们知道,在java中,所有异常对象都是throwable类的一个实例,我们不仅可以使用java内置的异常类,还可以自定义自己的异常类。
在异常中分为两种,一种是error,另一种是Exception。
Error:描述了java运行时系统的内部错误和资源耗尽错误。比如我们熟知的stackoverflowError栈溢出,其实就是错误,也不需要捕获。
Exception又可以分为runtimeException 和其他异常
runtimeException指的是在java虚拟机运行正常的情况下,由于程序部分代码错误所产生的异常,而程序本身没有问题,比如我们熟知的数组下标越界异常indexofboundException和空指针nullpointException异常
其他异常就是因I/O错误导致的异常:(也称编译时异常,就是我们写代码时必须要抛出的异常,比如SQLException,IOException,ClassNotFoundException ,FileNotFoundException文件未找到异常。
对于运行时异常,java编译器不要求必须进行异常捕获处理或者抛出声明,由程序员自行决定。
非运行时异常(检查异常,编译异常,必须要处理的异常)
java编译器强制程序员必须进行捕获处理,比如常见的IOExeption和SQLException。对于非运行时异常如果不进行捕获或者抛出声明处理,编译都不会通过。
4.进程和线程
关于进程和线程的概念,不同角度有不同的方法,我目前认为,进程就是程序在计算机上的一次运行活动,是操作系统进行资源分配和调度的一个独立单位,说起这个资源分配和调度,原本都是由进程完成的,每个进程所能访问的内存都是圈好的,一人一份,互不影响,由于cpu越来越牛逼,因此在进程的基础上,再次细分,线程就是进程的一个实体,就是cpu调度和分配的基本单位,它本身基本上不拥有资源,只拥有一小部分必不可少的资源(如程序计数器),因此一个进程拥有多个线程,同一个进程中的多个线程之间可以并发执行。
就像火车和车厢,进程就是火车,车厢就是线程。
比如火车拥有多个车厢(一个进程拥有多个线程)
不同进程之间的数据很难共享,但是不同线程之间的数据很易共享(比如火车换乘很麻烦,但是从一个车厢到另一个车厢很简单)
进程间不会相互影响,一个线程挂掉将导致整个进程挂掉(一列火车不会影响到另外一列火车,但是如果一列火车上中间的一节车厢着火了,将影响到所有车厢)
5.java多线程
Java的线程有五种状态
新建状态(New):当线程对象对创建后,即进入了新建状态,如:Thread t = new MyThread();
就绪状态(Runnable):当调用线程对象的start()方法,线程即进入就绪状态。处于就绪状态的线程,只是说明此线程已经做好了准备,随时等待CPU调度执行,并不是说执行了t.start()此线程立即就会执行;
运行状态(Running):当CPU开始调度处于就绪状态的线程时,此时线程才得以真正执行,即进入到运行状态。值得一提的是,就绪状态是进入到运行状态的唯一入口,也就是说,线程要想进入运行状态执行,首先必须处于就绪状态中;
阻塞状态(Blocked):处于运行状态中的线程由于某种原因,暂时放弃对CPU的使用权,停止执行,此时进入阻塞状态,直到其进入到就绪状态,才有机会再次被CPU调用以进入到运行状态。根据阻塞产生的原因不同,阻塞状态又可以分为三种:
1.等待阻塞:运行状态中的线程执行wait()方法,使本线程进入到等待阻塞状态;
2.同步阻塞 -- 线程在获取synchronized同步锁失败(因为锁被其它线程所占用),它会进入同步阻塞状态;
3.其他阻塞 -- 通过调用线程的sleep()或join()或发出了I/O请求时,线程会进入到阻塞状态。当sleep()状态超时、join()等待线程终止或者超时、或者I/O处理完毕时,线程重新转入就绪状态。
死亡状态(Dead):线程执行完了或者因异常退出了run()方法,该线程结束生命周期
线程的创建和启动有两种方式
一种是继承Thread类,一种是实现runable接口,但是在java1.5以后提出了一个叫callable接口,他的不同之处在于有返回值和可以抛出异常,便于我们处理异常信息。
什么是线程安全?Vector是一个线程安全类吗?
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。一个线程安全的计数器类的同一个实例对象在被多个线程使用的情况下也不会出现计算失误。很显然你可以将集合类分成两组,线程安全和非线程安全的。Vector 是用同步方法来实现线程安全的, 而和它相似的ArrayList不是线程安全的。
如何停止一个线程?
目前来说并没有提供相应的api来停止线程,而是当run() 或者 call() 方法执行完的时候线程会自动结束,如果要手动结束一个线程,你可以用volatile 布尔变量来退出run()方法的循环或者是取消任务来中断线程
6.Servlet的生命周期
Servlet被服务器实例化后,容器运行其init方法,请求到达时运行其service方法ÿ