Java基础知识汇总

一、Java语言的特点:

1、 面向对象:此方法是基于信息隐藏和数据抽象类型的概念;通过类的继承机制实现代码重用。Java支持单继承、多接口。Java是一个完全面向对象的语言。

2、 简单性:C++语言中结构、联合、类混用,Java中只保留了类。Java取消了goto语句,支持带标号的break和continue语句。Java取消了运算符重载。Java不支持多继承(单继承多接口)。Java中没有指针。Java取消了c++中的预处理功能和内存空间动态申请释放功能,增添了内存空间自动回收功能。

3、 可移植性:Java虚拟机

4、 稳定安全性:取消了指针;内存自动管理;

Java编译器 -> 字节码 -> (字节码校验器检查) -> Java解释器,Java解释器决定了程序中类的内存布局。

5、 高性能:平台无关;Java语言先编译后解释;支持多线程。

6、 分布性:Java语言的应用程序接口具有支持超文本传输协议HTTP和文件传输协议FTP等TCP/IP的类库。

二、Java Application程序:

Java Application程序的结构特点是:该程序是由一个或多个文件组成的,每个文件又是由一个或多个类组成的,每个类是由若干个方法和变量组成的。简单说Java程序就是类串。

在一个Java程序中,仅有一个主方法main()。Java程序就是从主方法开始执行的(程序的入口)。Java程序有若干个文件,仅有一个主文件(含main()方法的文件)。在主文件中有若干个类,只有一个是含主方法的类。

Java Application程序:编辑源程序 -> 编译生成字节码 -> 解释运行字节码

三、Java Application命令行参数:

Java Application是使用命令行来执行的,命令行参数将被保存在main()方法的参数arg[ ]中。参数arg[ ]是一个String类的对象数组。通常使用对象数组的首元素arg[0]存放第一个参数,以此类推。

public static
void main ( String arg[ ] ) {

}

四、Java中的数据类型:

基本数据类型:

整型:字节型(byte\8)、整型(int\32)、短整型(short\16)、长整型(long\64)

   浮点型:单精度浮点型(float)、双精度浮点型(double)

   字符型:char

   布尔型:boolean

复合数据类型:数组、类、接口

五、类型转换:

隐含转换:数据类型低的转换为数据类型高的,由系统自动进行。

强制转换:数据类型高的转换为数据类型低的(<类型>)<表达式>

Eg:b = 3.1415 ;   a = ( int) b ;

六、符号常量:

为了修改方便,程序中常把不允许修改的量用一个标识符表示,该标识符成为符号常量/常量符号。Java语言中只能将类的成员定义为常量,称为类常量;不允许在方法中定义常量。定义符号常量的同时必须赋初值。

<访问控制符> final <数据类型><符号常量名> = <初值>

Eg:private final double PI = 3.1415 ;

七、不常用运算符:

1、运算符:算数运算符、关系运算符、逻辑运算符、位运算符

2、表达式:算数表达式、关系表达式、逻辑表达式、赋值表达式、条件表达式

3、三目运算符(?:) -> ( d1? d2 : d3),其中d1,d2,d3为三个操作数先计算d1的值,若d1的值为true则该表达式的值为d2的值;否则为d3的值

4、对象运算符instanceof:用于测试一个指定的对象是否属于某个指定类的对象;返回true/false。使用格式:<对象名> instanceof <类名>

5、内存分配运算符:new

6、域选择运算符:.

八、字符串:

Java中提供了定义字符串的两个类:String类和StringBuffer类。因此,在Java中字符串是一个对象,而其他语言中字符串是存放在字符数组中的若干个字符。

Java语言的标准包java.lang中定义了用于创建字符串的两个类:String类和StringBuffer类。这两个类不仅可以创建字符串还可以使用类中的方法对字符串进行操作。

使用String类创建的是常量字符串,又称字符串常量;使用StringBuffer类创建的是可变字符串,又称字符串变量。

九、方法调用:

Java语言中,方法的参数可以是基本类型或复合类型

基本类型作方法参数时,参数传递的是变量值,而不是变量地址值。因此不可改变调用方法中的参数值。

复合类型(如对象)作方法参数时,参数传递的是对象的地址值。因此,对参数的改变会影响到原来的参数值。

Java语言中,符合类型变量实际上是引用,并采用动态联编。

十、方法重载:功能相同的多个方法使用同一个方法名。

同名的多个方法的参数要有所不同,即在参数类型、参数个数和参数顺序上有所区别。

重载方法的选择通常在编译时进行。系统根据不同的参数类型、个数或顺序,寻找最佳匹配方法。方法类型不参与匹配。若无法完全匹配则选择类型转换代价最小的一种方案进行匹配(高类型向低类型的转换)。

十一、构造方法和析构方法:

1、构造方法:方法名同类名;无返回值;在创建对象时系统自动调用,不被显式调用;可有参数可无参数;可重载。

<类名>(对象名)= new <类名>(<参数表>);

该语句完成如下两个任务:

① 用new通知系统为所创建的对象在内存开辟一个单元;

② 自动调用相应的构造方法使用给定的<参数表>为创建的对象进行初始化。

默认构造方法:定义类时若不定义任何构造方法,系统为该类自动生成一个默认构造方法。

2、析构方法:目的在于让程序有机会主动地释放掉不用的对象

格式如下:protected void finalize ( ) ;

当一个析构方法的对象不再被引用时,系统会自动调用析构方法,释放它所占用的资源。

十二、抽象类和抽象方法:

抽象类(概念类)是使用abstract说明的类,该类没有具体的对象,但可以有构造方法。具体应用中抽象类一定有它的子类,与其子类直接是继承关系。

抽象方法:使用abstract修饰的方法。抽象方法仅有方法头而无方法体。该方法不实现任何操作,仅作为所有子类中重载该方法的一个统一接口。

类的继承和多态:所有的类都是object类的子类

1、 子类对象的初始化:

在创建子类对象时要对自身成员变量和继承的父类中成员变量通过调用构造方法进行初始化。

构造方法不可被继承,但是可以在子类的构造方法中调用父类的构造方法。系统用this表示当前类的构造方法,用super表示直接父类的构造方法。

2、 成员的继承和覆盖

类的成员包含有成员变量和成员方法,子类中继承了父类中所有的成员。

① 成员变量的继承和覆盖:

在子类对象初始化时,要调用父类的构造方法对其成员变量初始化。若在子类中对从父类继承过来的成员变量又重新定义,即变量名相同,类型不同,则成为成员变量的覆盖/成员变量的隐藏。若在子类中要引用父类中继承的变量则可使用super标识。

② 成员方法的重载和覆盖—Java语言的多态性

子类继承了父类的所有方法,当子类对父类中相同方法头的方法进行重新定义时便产生了方法覆盖。在子类中通过方法名仅能访问本身的成员方法,访问父类用super。方法重载:略

十三、接口:

Interface是定义接口的关键字。在接口体内由两部分组成:一部分是对接口变量的说明;另一部分是对接口方法的说明。前一部分是用final修饰的常量,后一部分是用abstract说明的抽象方法。因此接口是若干个常量和抽象方法的集合。

若实现接口的类是抽象类,则可以不实现接口中的所有方法,但是在抽象类的非抽象子类中对其父类所实现的接口中的所有抽象方法都必须实现。如果实现接口的类是非抽象类,则该类体内必须实现接口中所有的抽象方法,并且方法头与接口中定义的完全一致。

----接口与一般抽象类的区别:---------------------------------------------------

① 一个子类只能是一个抽象类,不可能是多个抽象类的子类;但是一个类可以同时实现多个接口。

② 接口是在编译时处理的;抽象类是在运行时处理的。接口比抽象类节省开销。

十四、包:

包是一种若干个松散的类的集合;默认情况下,同一个包中的类可以相互访问。

Java语言的类库:

Java.lang包:Java语言的核心类库,包含Java程序中必不可少的系统类。

   Java.io包:Java语言的输入/输出类库

   Java.util包:包含一些低级实用工具(Date类、Vector类、Stack类等)

   Java.awt包:Java语言用于构建图形用户界面的类库

   Java.applet包:在Internet浏览器中的Java Applet程序运行

   Java.net包:用于实现网络功能的类库。

Java语言基础类库:

1、Object类:该类是Java程序中所有类的父类,也是库中所有类的父类。Object类中包含了Java类的公共属性,其中较主要的方法如下所述:

(1)protected Object clone ( )用来生成当前对象的一个备份,并返回这个复制对象;
(2)public boolean equals ( Object obj )用于比较两个对象是否相同;
(3)public final class getClass ( )用于获取当前对象所属的类信息,返回class对象;
(4)protected void finalize ( )用于回收当前对象所需要完成的清理工作;
(5)public String toString ( )用于返回当前对象本身的有关信息,按字符串对象返回;
(6)public final void notify ( )用于唤醒线程;

2、Math类:提供了一些常用的数学运算的标准数学函数的方法。

3、System类:系统提供的一种特殊类,所有变量和方法都是static的,引用时以System为前缀即可。

(1)该类提供了以下3种标准设备的属性:

① 系统标准输入设备为:public static InputStream in ;

② 系统标准输出设备为:public static PrintStream out ;

③ 系统标准输错误输出为:public static PrintStream err ;

(2)该类提供了一些常用方法:

public static long currentTimeMillis ( ) 获取当前时刻的微秒数

public static void exit ( int status ) 在用户线程执行完之前强行推出运行状态,并将状态信息status返回给OS

Public static void gc ( ) 强制调用Java虚拟机垃圾回收功能

4、字符串类:Java语言中字符串分为两大类:一类是字符串常量类String,该类创建的对象是不允许改变的;另一类是字符串变量类StringBuffer,该类创建的对象是允许改变的。“(不)允许改变”的含义是指字符串长度固定,内容不变。

十五、字符串类:

1、 String类的常用方法:

① 求字符串长度:public int length ( ) ;

② 判断字符串的前后缀:

public boolean startsWith ( String prefix ) ;

public boolean endsWith ( String suffix ) ;

③ 查找字符串中指定字符:

public int indexOf ( char ch ) ; //从前向后查

public int indexOf ( char ch ,int fromIndex) ; //从指定位置由前向后查

public int lastIndexOf ( char ch ) ; //从后向前查

public int lastIndexOf ( char ch ,int fromIndex) ; //从指定位置由后向前查

④ 查找字符串中的指定子串:

------四种------

⑤ 比较两个字符串:

------三种------

2、 StringBuffer类

① 获取和修改串长度的方法

② 字符串变量中获取字符和修改字符的方法

③ 字符串变量中获附加和插入各种类型数据的方法

④ String类和StringBuffer类对象相互转换的方法

StringBuffer sb = new StringBuffer ( String s ) ;
String s = sb.toString ( ) ;

⑤ 字符串的加法和赋值运算

String s = “mn”+ “pg” + Integer.toString( 123 ) ;

十六、数组(Arrays)类:

Arrays类是集合框架的一个成员类,其功能主要是对数组对象进行排序、搜索和填充等操作。Arrays类所提供的方法都是静态方法,可直接通过类名加以引用。

java没有联合和结构 java取消了联合概念_Java


基本的集合接口:

Collection接口是一组允许重复的对象;

Set接口继承Collection,但不允许集合中有重复元素;

List接口继承Collection,允许集合中有重复元素,并引入为之索引;

Map接口与Collection接口无关,所包含的是键-值对。

集合Set:

在集合框架中,HashSet和TreeSet实现了Set接口。

一般用HashSet类创建一个无序的集合对象,当需要从集合中有序地获取元素时,可采用TreeSet来建立集合对象。注意:添加到TreeSet中的元素必须是可排序的(这也是TreeSet实现有序输出的代价)。

列表(List):

列表指一个有序的对象集合,也称为一个对象序列。通过列表接口,可利用整数索引对列表中的每个元素有准确的控制。与集合最大不同是,列表中容许出现重复元素。

在集合框架中,实现上述列表接口的是ArrayList类和LinkedList类。

ArrayList类通过数组来实现;LinkedList类通过链表来实现。因实现方式不同,操作代价也不同。一般,对一个列表的开始结尾处有频繁的增删操作时LinkedList较为合适,通常用LinkedList表示一个堆栈(stack)或队列(queue)。LinkedList类中实现了一些ArrayList中没有的方法,用于在列表起始处增删元素。

映射(Map):

映射接口是与Collection接口并列的一个接口,该接口描述了不重复的键到值的映射,键与值一一对应。

HashMap类与TreeMap类是集合框架提供的Map接口实现类。在Map中插入、删除和定位元素,HashMap是最好的选择。但如果需要按顺序遍历键,需要选择TreeMap。

为了优化HashMap空间的使用,可以调整初始容量和负载因子以优化效率。

而TreeMap没有调优选项,其对象的插入和删除是通过红-黑树算法的实现,并将整个映射图维持一个平衡树结构。

历史集合类:

常用的历史集合类:Vector类、Dictionary类和HashTable类。

Vector类表示一个可自动扩缩容量的数组集合,可存储不同类型的对象元素。目前Vector类被LinkList类取代。不同的是Vector类有同步控制,即是线程安全的。Vector类还拥有一个子类,即Stack类,其表示的是一个标准的后进先出堆栈,主要通过push( )和pop( )方法来实现。

Dictionary类所包含的都是些抽象的方法,它构成“键-值”对集合的基础,其拥有的一个子类为Hashtable类。已被Map取代。

HashTable类实现了Dictionary类所定义的抽象方法,允许存储任何对象作为它的键或值。与实现Map接口的HashMap类和TreeMap比较,HashTable类有同步控制,即是线程安全的。

集合框架的使用原则:

1、 Set接口的两个实现类HashSet类和TreeSet类:

HashSet类所提供的操作要更快速,但包含的元素是无序排列的;

而TreeSet类则可以提供有序保证。对HashSet类可以通过调整初始容量和负载因子而获得更好的操作效率。一般情况下HashSet用到的场合更多。

2、 List接口实现的两个类ArrayList类和LinkedList类:

多数情况下ArrayList类使用更多,因为它提供了常数时间的位置访问,且利用java.lang.System类里的arraycopy( )方法可快速一次移到多个元素。

当需要频繁地向一个列表的头位置添加元素,或是频繁地自列表的迭代中删除元素时可考虑使用LinkedList类。因为这些操作所需要的时间对于LinkedList类是常数时间,而对于ArrayList类则是线性时间,所以一般用LinkedList类来实现一个队列。

3、 Map接口实现的HashMap类和TreeMap类:

两者的使用取决于是否需要有序的元素排列。TreeMap类中元素排列有序,而HashMap类中无序

4、在需要实现外同步的场合中历史集合类所有的同步控制更有优势。

十七、枚举和迭代:

枚举和迭代的功能是将一个集合对象中所有元素顺序列举出来,分别由Enumeration接口和Iterator接口所定义。

Enumeration接口仅包含两个方法声明:

(1)`public boolean hasMoreElements()`

(2)public Object nextElement()

从功能上看,Iterator接口包含了Enumeration接口所提供的上述功能。除此之外,Iterator接口还提供了删除操作,且其方法名定义更为简洁。Iterator接口所定义的方法申明:

(1)public boolean hasNext ( )

(2)public Object next ( )

(3)public void remove ( )

十八、Java垃圾回收机制:

1、垃圾回收:jvm觉得这个对象没有存在的必要,将其清理出去

2、如何确定某个对象是需要被回收的:

在java中是通过引用来和对象进行关联的,也就是说如果要操作对象,必须通过引用来进行。那么很显然一个简单的办法就是通过引用计数来判断一个对象是否可以被回收。不失一般性,如果一个对象没有任何引用与之关联,则说明该对象基本不太可能在其他地方被使用到,那么这个对象就成为可被回收的对象了。这种方式成为引用计数法。

这样的方法简单且效率高。但如果某些对象被循环引用,即使把对象赋值为null,这种算法照样不能回收。为了解决这个问题,在Java中采取了可达性分析法:该方法的基本思想是通过一系列的“GC
Roots”对象作为起点进行搜索,如果在“GC Roots”和一个对象之间没有可达路径,则称该对象是不可达的,不过要注意的是被判定为不可达的对象不一定就会成为可回收对象。被判定为不可达的对象要成为可回收对象必须至少经历两次标记过程,如果在这两次标记过程中仍然没有逃脱成为可回收对象的可能性,则基本上就成为可回收对象。3、垃圾回收算法:

① Mark-Sweep(标记-清除)算法:

标记-清除算法分为两个阶段:标记阶段和清除阶段。标记阶段的任务是标记出所有需要被回收的对象,清除阶段就是回收被标记的对象所占用的空间。

② Copying(复制)算法:

为了解决Mark-Sweep算法的缺陷,Copying算法就被提了出来。它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把已使用的内存空间一次清理掉,这样一来就不容易出现内存碎片的问题。

③ Mark-Compact(标记-整理)算法:

为了解决Copying算法的缺陷,充分利用内存空间,提出了Mark-Compact算法。

该算法标记阶段和Mark-Sweep一样,但是在完成标记之后,它不是直接清理可回收对象,而是将存活对象都向一端移动,然后清理掉端边界以外的内存。

④ Generational Collection(分代收集)算法:

分代收集算法是目前大部分JVM的垃圾收集器采用的算法。它的核心思想是根据对象存活的生命周期将内存划分为若干个不同的区域。一般情况下将堆区划分为老年代(Tenured Generation)和新生代(Young Generation),老年代的特点是每次垃圾收集时只有少量对象需要被回收,并不是回收所有,而新生代的特点是每次垃圾回收时都有大量的对象需要被回收,那么就可以根据不同代的特点采取最适合的收集算法。可以调用System.gc()方法查看回收情况。

目前大部分垃圾收集器对于新生代都采取Copying算法,因为新生代中每次垃圾回收都要回收大部分对象,也就是说需要复制的操作次数较少,但是实际中并不是按照1:1的比例来划分新生代的空间的,一般来说是将新生代划分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden空间和其中的一块Survivor空间,当进行回收时,将Eden和Survivor中还存活的对象复制到另一块Survivor空间中,然后清理掉Eden和刚才使用过的Survivor空间。

而由于老年代的特点是每次回收都只回收少量对象,一般使用的是Mark-Compact算法

注意,在堆区之外还有一个代就是永久代(Permanet Generation),它用来存储class类、常量、方法描述等。对永久代的回收主要回收两部分内容:废弃常量和无用的类。

十九、关键字static:

“static方法就是没有this的方法。在static方法内部不能调用非静态方法,反过来是可以的。而且可以在没有创建任何对象的前提下,仅仅通过类本身来调用static方法。这实际上正是static方法的主要用途。”

这段话虽然只是说明了static方法的特殊之处,但是可以看出static关键字的基本作用,简而言之,一句话来描述就是:

方便在没有创建对象的情况下来进行调用(方法/变量)。

Java中static存在的误区:

①与C/C++中的static不同,Java中的static关键字不会影响到变量或者方法的作用域。在Java中能够影响到访问权限的只有private、public、protected(包括包访问权限)这几个关键字;

②静态成员变量虽然独立于对象,但是不代表不可以通过对象去访问,所有的静态方法和静态变量都可以通过对象访问(只要访问权限足够)。

③Java语法的规定:static是不允许用来修饰局部变量。

1、static方法

static方法一般称作静态方法,由于静态方法不依赖于任何对象就可以进行访问,因此对于静态方法来说,是没有this的。并且由于这个特性,在静态方法中不能访问类的非静态成员变量和非静态成员方法,因为非静态成员方法/变量都是必须依赖具体的对象才能够被调用。

但是要注意的是,虽然在静态方法中不能访问非静态成员方法和非静态成员变量,但是在非静态成员方法中是可以访问静态成员方法/变量的

2、static变量

static变量也称作静态变量,静态变量和非静态变量的区别是:静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。而非静态变量是对象所拥有的,在创建对象的时候被初始化,存在多个副本,各个对象拥有的副本互不影响。

static成员变量的初始化顺序按照定义的顺序进行初始化。

3、static代码块

static关键字还有一个比较关键的作用就是:用来形成静态代码块以优化程序性能。static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。

static块可以用来优化程序性能,是因为它的特性:只会在类加载的时候执行一次。因此,很多时候会将一些只需要进行一次的初始化操作都放在static代码块中进行。

二十(一)、Java中HashMap的工作原理:

Java中HashMap是以键值对(key-value)的形式存储元素的,它的基本数据结构是数组+链表。HashMap需要一个hash函数,它使用hashCode( )方法和equals( )方法来向集合/从集合添加和检索元素。当调用put( )方法时,HashMap会计算key的hash值,然后把键值对存储在集合中合适的索引上。如果key已存在,value会被更新成新值。

HashMap的重要特性是它的容量、负载因子和扩容极限。


二十(二)、HashCode( ) 方法、equals( )方法解析:

集合类中不允许元素重复,当集合元素很多时,向其中加入元素要进行一一比较效率极低。于是,Java采用了哈希表的原理。哈希算法也称为散列算法,是将数据依特定算法直接指定到一个地址上。

这样一来,当集合要添加新的元素时,先调用这个元素的hashCode方法,就一下子能定位到它应该放置的物理位置上。 如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了, 就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址。

所以这里存在一个冲突解决的问题。这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次。

hashMap是怎样实现key-value这样键值对的保存?

HashMap中有一个内部类Entry,主要有4个属性,key ,hash,value,指向下一个节点的引用next ,看到这个实体类就明白了,在HashMap中存放的key-value实质是通过实体类Entry来保存的。

static class Entry<k,v> implements Map.Entry<k,v>{
		final K key;
		V value;
		Entry<k,v> next;
		int hash;
		//......
}</k,v></k,v></k,v>

hashMap的实现原理?

HashMap使用到的数据类型主要就是数组和链表,首先看原理图。

在hashMap的原理图中,左边是通过数组来存放链表的第一个节点。

java没有联合和结构 java取消了联合概念_总结_02


hashMap的put过程?

我们提到过Entry类里面有一个next属性,作用是指向下一个Entry。比如说: 第一个键值对A进来,通过计算其key的hash得到的index=0,记做:Entry[0] = A。一会后又进来一个键值对B,通过计算其index也等于0,现在怎么办?HashMap会这样做:B.next = A,Entry[0] = B,如果又进来C,index也等于0,那么C.next = B,Entry[0] = C;这样我们发现index=0的地方其实存取了A,B,C三个键值对,他们通过next这个属性链接在一起。也就是说数组中存储的是最后插入的元素。

hashMap的get过程?

public V get(Object key){
		if(key == null)
				return getForNullKey();
		int hash = hash(key.hashCode());
		//先定位到数组元素,再遍历该元素处的链表
		for(Entry<k,v> e = table[indexFor(hash,table.length)];
			e != null;
			e = e.next){
			Object k;
			if(e.hash == hash && ((k = e.key) == key || key.equals(k)))
					return e.value;
			}
			return null;
}

hashMap存取的时候是如何定位数组下标的?

通过key的hash值和数组长度求&,这意味着数组下标相同,并不表示hashCode相同。所以在Entry中存有一个hash值,在比较Entry的时候都是想比较hash值。

static int indexerFor(int h,int length){
		return h & (length-1);
}

hashMap什么时候开始rehash?

在hashMap中有一个加载因子loadFactor,默认值是0.75,当数组的实际存入值的大小 > 数组的长度×loadFactor 时候就会rehash,重新创建一个新的表,将原表的映射到新表中,这个过程很费时。

HashMap的遍历

第一种:

//效率高,推荐使用

Map map = new HashMap();
Iterator iter = map.entrySet().iterator();
while(iter.hashNext()){
		Map.Entry entry = (Map.Entry)iter.next();
		Object key = entry.getKey();
		Object val= entry.getValue();
}

第二种:

//效率低,尽量少使用

Map map = new HashMap();
Iterator iter = map.keySet().iterator();
while(iter.hashNext()){
		Object key = iter.next();
		Object val= map.get(key);
}

HashMap这两种遍历方法是分别对keyset及entryset来进行遍历,但是对于keySet其实是遍历了2次,一次是转为iterator,一次就从hashmap中取出key所对于的value。而entryset只是遍历了第一次,它把key和value都放到了entry中,即键值对,所以就快了。

HashMap与Hashtable的区别:

1、HashMap可以接受null键值和值,而Hashtable则不能。
2、Hashtable是线程安全的,通过synchronized实现线程同步。而HashMap是非线程安全的,但是速度比Hashtable快。



二十一、Comparable和Comparator接口:

1、Java提供了一个只包含compareTo( )的Comparable接口。此方法可以对两个对象进行排序。返回负数、0、正数来表明已经存在的对象小于,等于,大于输入对象。

2、Java提供了包含compare( )和equals( )两个方法的Comparator接口。

Compare( )方法用来给两个输入参数排序。返回负数、0、正数来表明第一个参数是小于,等于,大于第二个参数。

equals( )方法需要一个对象作为参数,用于决定输入参数是否和comparator相等;只有当输入参数也是一个comparator并且输入参数和当前comparator的排序结果相同时,此方法返回true。

二十二、Java中Exception和Error:

Exception和Error都是Throwable的子类

Exception用于用户程序可以捕获的异常情况;表示一个由程序员导致的错误;应在程序级被处理

如:
数组下标越界异常:ArrayIndexOutOfBoundsException
文件未找到异常:FileNotFoundException
操作数据库异常:SQLException

Error定义了不期望被用户程序捕获的异常。

二十三、throw和throws:

throw关键字用于在程序中明确的抛出异常;而throws语句用于表明方法不能处理的异常。每一个方法都要指定那些异常不能处理,方法点用这才能确保处理可能发送的异常。

1、 throw用于方法内部,throws用于方法声明上;

2、 throw后跟异常对象,throws后跟异常类型;

3、 throw后只能跟一个异常对象;throws后可以一次声明多种异常类型。



二十四、JDBC( Java DataBase Connectivity ):

Java数据库互联。JDBC是允许用户在不同数据库之间做选择的一个抽象层。JDBC允许开发者使用Java写数据应用程序,而无需关心底层特定数据库细节。

JDBC是一套面向对象的应用程序接口(API),制定了统一的访问各类数据库的标准接口。开发人员可用纯Java语言和标准SQL语句编写完整的数据库应用程序。

JSP请求如何被处理:

浏览器首先请求一个以.jsp结尾的页面,发起JSP请求。Web服务器读取这个请求,使用JSP编译器把JSP页面转化成一个Servlet类。注意:只有当第一次请求页面或是JSP文件发生改变时JSP文件才会被编译,然后服务器调用servlet类,处理浏览器请求。一旦请求执行结束,servlet会把响应发送给客户端。

二十五、修饰符:

类的修饰符:用于说明类的作用域和其他性质

1、 public。说明该类为公共类,可被其他类所使用。程序中主类必须是公共类

2、 默认说明。规定该类只能被同一个包中的类使用,不可被其他包中的类所使用。

3、 abstract。抽象类,是一种没有具体对象的概念类。通常抽象类是它所有子类的公共属性集合。

4、 final。该类不肯可能有子类,故成为最终类。这种类常用来完成某种标准功能。Final和abstract不可同时修饰一个类。

变量的修饰符:

访问控制修饰符:

1、 公有访问控制符public。公共变量,若它属于一个公共类,则可被所有类访问。

2、 默认访问控制符。类中变量若无访问控制符,则具有包访问性,可被同一个包中的其他类访问。

3、 私有访问控制符private。该变量仅可被该类自身访问,任何其他类(包括它的子类)都没有访问权限。

4、 保护访问控制符protected。改变量可被该类自身、同包的其他类和其他包中该类的子类访问。

5、 私有保护访问控制符private protected。该变量可被该类自身和该类的所有子类(包括其他包里的子类)访问。

非访问控制修饰符:

1、 静态变量static。静态变量的特点是属于类的,而不是属于某个对象。静态变量被系统存放在一个公共存储单元中,任何对象都可以访问它,也可以修改它。静态变量的引用可以使用类名或对象名。

2、 最终变量final。最终变量就是Java语言中的常量符号。它的值在程序执行过程中不会改变。

3、 易失变量volatile。被volatile修饰的变量可能同时被多个线程所控制和修改。

方法的修饰符:

访问控制修饰符:

1、 公有访问控制符public。使用该修饰符修饰的方法可作为该类对外的接口,程序可以通过它与类体内的成员进行信息交换。

2、 默认访问控制符。此方法具有包方法性,可被同一包内的其他类访问。

3、 私有访问控制符Private。此方法只能被该类自身访问,不可被其他类(包含其子类)访问。

4、 保护访问控制符protected。此方法的访问权限:该类自身;与其在同一个包内的其他类;在其他包中的该类的子类。

6、 私有保护访问控制符private protected。该方法可被该类自身和该类的所有子类访问。

非访问控制符:

1、 抽象方法abstract。抽象方法是只有方法说明没有具体实现的一种方法。该方法的具体实现都出现在该类的子类中。使用抽象方法的目的是使所有该类的子类都有一个同名的方法作为统一接口。

2、 静态方法static。静态方法是属于整个类的方法。对其调用应该使用类名,也可用对象名。静态方法在内存中的代码不被任何对象所专有。通常静态方法只能处理静态变量。

3、 最终方法final。此方法不可被当前类的子类重新定义。保证系统安全。

4、 本地方法native。该方法用于说明用其他语言书写方法体,并实现方法功能的特殊方法。

5、 同步方法synchronized。该方法主要用于多线程共存的程序中的协调和同步。

二十六、Java内存模型:

1、 程序计数器:是一个数据结构,用于保存当前执行的程序的内存地址。Java虚拟机的多线程就是通过线程轮流切换并分配处理器时间来实现的,为了线程切换后能恢复到正确的位置,每条线程都需要一个独立的程序计数器。

2、 Java虚拟机栈:线程私有的,与线程生命周期相同,用于局部变量表,操作栈,方法返回值。局部变量表放着基本数据类型、还有对象的引用。

3、 本地方法栈:和虚拟机栈很像,不过它是为虚拟机使用到的native方法提供服务。

4、 Java堆:所有线程共享的一块内存区域,对象实例几乎都在此分配。

5、 方法区:各个线程共享的区域,存储虚拟机加载的类信息,常量,静态变量,编译后的代码。

6、 运行时常量池:代表运行时每个class文件中的常量表。包括几种常量:编译时的数字常量、方法或者域的引用。

二十七、Java自动拆装箱:

在Java中,所有要处理的东西几乎都是对象 (Object),例如之前所使用的Scanner是对象,字符串(String)也是对象,之后还会看到更多的对象。然而基本(Primitive)数据类型不是对象,也就是您使用int、double、boolean等定义的变量,以及您在中直接写下的字面常量。

而使用Java有一段时间的人都知道,有时需要将基本数据类型转换为对象。例如使用Map对象要put()方法时,需要传入的参数是对象而不是基本数据类型。

要使用打包类型(Wrapper Types)才能将基本数据类型包装为对象,在J2SE 5.0之前,要使用以下语句才能将int包装为一个Integer对象:Integer integer = new Integer(10);

在 J2SE 5.0之后提供了自动装箱的功能,可以直接使用以下语句来打包基本数据类型:

Integer integer = 10;

在进行编译时,编译器再自动根据写下的语句,判断是否进行自动装箱动作。在上例中integer参考的会是Integer类的实例。同样的动作可以适用于 boolean、byte、short、char、long、float、double等基本数据类型,分别会使用对应的打包类型(Wrapper Types)Boolean、Byte、Short、Character、Long、Float或Double。

二十八、wait()和sleep()的区别:

sleep来自Thread类,和wait来自Object类

调用sleep()方法的过程中,线程不会释放对象锁;而调用 wait 方法线程会释放对象锁。

sleep睡眠后不出让系统资源,wait让出系统资源其他线程可以占用CPU。
sleep(milliseconds)需要指定一个睡眠时间,时间一到会自动唤醒。

二十九、Java8相关知识点:(部分)

1、 HashMap 的底层实现有变化:HashMap 是数组 + 链表 + 红黑树(JDK1.8 增加了红黑树部分)实现。

2、 JVM 内存管理方面,由元空间代替了永久代。
② 元空间并不在虚拟机中,而是使用本地内存;
② 默认情况下,元空间的大小仅受本地内存限制;

3、 新的包 java.time 包
① 包含了所有关于日期、时间、时区、持续时间和时钟操作的类;
② 这些类都是不可变的、线程安全的。

三十、数据库知识点:

1、 事务作为单个逻辑工作单元执行一系列操作,满足四大特性:

原子性(Atomicity):事务作为一个整体被执行 ,要么全部执行,要么全部不执行;

一致性(Consistency):保证数据库状态从一个一致状态转变为另一个一致状态;

隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行;

持久性(Durability):一个事务一旦提交,对数据库的修改应该永久保存。

2、 事务的并发问题有哪几种?

丢失更新、脏读、不可重复读以及幻读。

3、 独占锁(或排他锁)和共享锁

(1)排他锁(X锁或WLOCK)
某数据对事物加上排他锁,该事物可读写数据,其他事务不可再对数据加任何类型的锁,也就无法读写该数据,只有等待开锁。

(2)共享锁(S所或RLOCK)
允许其他事务对同一数据进行检索,但不得对同一数据进行修改操作。

4、数据库中where、group by、having关键字:

(1)where 子句用来筛选 from 子句中指定的操作所产生的的行;

(2)group by 子句用来分组 where 子句的输出;

(3)having 子句用来从分组的结果中筛选行;

having 和 where 的区别:
(1)语法类似,where 搜索条件在进行分组操作之前应用;having 搜索条件在进行分组操作之后应用;

(2)having 可以包含聚合函数 sum、avg、max 等;

(3)having 子句限制的是组,而不是行。

5、 数据库索引有什么用?底层数据结构是什么?为何使用这种数据结构?

(1)索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息;(作用:快速检索数据信息)

(2)底层数据结构是 B+ 树;

(3)使用 B+ 树的原因:查找速度快、效率高,在查找的过程中,每次都能抛弃掉一部分节点,减少遍历个数。

<深入理解数据库索引采用B树和B+树的原因

简要介绍B+树:

B+树是为磁盘或其他直接存取辅助设备而设计的一种平衡查找树,在B+树中,所有记录节点都是按键值的大小顺序存放在同一层的叶节点中,各叶节点指针进行连接。

B+树的特征:

1.有k个子树的中间节点包含有k个元素(B树中是k-1个元素),每个元素不保存数据,只用来索引,所有数据都保存在叶子节点。

2.所有的叶子结点中包含了全部元素的信息,及指向含这些元素记录的指针,且叶子结点本身依关键字的大小自小而大顺序链接。(链表)

3.所有的中间节点元素都同时存在于子节点,在子节点元素中是最大(或最小)元素。

4.B+树查找时是从上到下查找;B-树则是从下往上查找(中序遍历)

B+树的优势:

1.单一节点存储更多的元素(这样该节点下分支变多了,树变矮胖了),使得查询的IO次数更少。

2.所有查询都要查找到叶子节点,查询性能稳定。

3.所有叶子节点形成有序链表,便于范围查询。

三十一、Java中的多态:

所谓多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。

Eg:比如你是一个酒神,对酒情有独钟。某日回家发现桌上有几个杯子里面都装了白酒,从外面看我们是不可能知道这是些什么酒,只有喝了之后才能够猜出来是何种酒。你一喝,这是剑南春、再喝这是五粮液、再喝这是酒鬼酒….在这里我们可以描述成如下:
酒 a = 剑南春
酒 b = 五粮液
酒 c = 酒鬼酒

这里所表现的的就是多态。剑南春、五粮液、酒鬼酒都是酒的子类,我们只是通过酒这一个父类就能够引用不同的子类,这就是多态——我们只有在运行的时候才会知道引用变量所指向的具体实例对象。
诚然,要理解多态我们就必须要明白什么是“向上转型”。在继承中我们简单介绍了向上转型,这里就在啰嗦下:在上面的喝酒例子中,酒(Win)是父类,剑南春(JNC)、五粮液(WLY)、酒鬼酒(JGJ)是子类。我们定义如下代码:

JNC a = new  JNC();

对于这个代码我们非常容易理解无非就是实例化了一个剑南春的对象嘛!但是这样呢?

Wine a = new JNC();

在这里我们这样理解,这里定义了一个Wine 类型的a,它指向JNC对象实例。由于JNC是继承与Wine,所以JNC可以自动向上转型为Wine,所以a是可以指向JNC实例对象的。

这样做存在一个非常大的好处,在继承中我们知道子类是父类的扩展,它可以提供比父类更加强大的功能,如果我们定义了一个指向子类的父类引用类型,那么它除了能够引用父类的共性外,还可以使用子类强大的功能。

但是向上转型存在一些缺憾,那就是它必定会导致一些方法和属性的丢失,而导致我们不能够获取它们。所以父类类型的引用可以调用父类中定义的所有属性和方法,对于只存在与子类中的方法和属性它就望尘莫及了。

所以对于多态我们可以总结如下:
指向子类的父类引用由于向上转型了,它只能访问父类中拥有的方法和属性,而对于子类中存在而父类中不存在的方法,该引用是不能使用的,尽管是重载该方法。

若子类重写了父类中的某些方法,在调用该些方法的时候,必定是使用子类中定义的这些方法(动态连接、动态调用)。

对于面向对象而言,多态分为编译时多态和运行时多态。其中编辑时多态是静态的,主要是指方法的重载,它是根据参数列表的不同来区分不同的函数,通过编辑之后会变成两个不同的函数,在运行时谈不上多态。而运行时多态是动态的,它是通过动态绑定来实现的,也就是我们所说的多态性。

Java实现多态有三个必要条件:继承、重写、向上转型。

在Java中有两种形式可以实现多态,继承和接口:

1、 基于继承实现的多态
基于继承的实现机制主要表现在父类和继承该父类的一个或多个子类对某些方法的重写,多个子类对同一方法的重写可以表现出不同的行为。

在上面的代码中JNC、JGJ继承Wine,并且重写了drink()、toString()方法,程序运行结果是调用子类中方法,输出JNC、JGJ的名称,这就是多态的表现。不同的对象可以执行相同的行为,但是他们都需要通过自己的实现方式来执行,这就要得益于向上转型了。

我们都知道所有的类都继承自超类Object,toString()方法也是Object中方法,当我们这样写时:

Object o = new JGJ();

		System.out.println(o.toString());

输出的结果是Wine : JGJ。
Object、Wine、JGJ三者继承链关系是:JGJ—>Wine—>Object。所以我们可以这样说:当子类重写父类的方法被调用时,只有对象继承链中的最末端的方法才会被调用。但是注意如果这样写:

Object o = new Wine();

		System.out.println(o.toString());

输出的结果应该是Null,因为JGJ并不存在于该对象继承链中。
所以基于继承实现的多态可以总结如下:对于引用子类的父类类型,在处理该引用时,它适用于继承该父类的所有子类,子类对象的不同,对方法的实现也就不同,执行相同动作产生的行为也就不同。

如果父类是抽象类,那么子类必须要实现父类中所有的抽象方法,这样该父类所有的子类一定存在统一的对外接口,但其内部的具体实现可以各异。这样我们就可以使用顶层类提供的统一接口来处理该层次的方法。

2、 基于接口实现的多态:
继承是通过重写父类的同一方法的几个不同子类来体现的,那么就可就是通过实现接口并覆盖接口中同一方法的几不同的类体现的。

在接口的多态中,指向接口的引用必须是指定这实现了该接口的一个类的实例程序,在运行时,根据对象引用的实际类型来执行对应的方法。

继承都是单继承,只能为一组相关的类提供一致的服务接口。但是接口可以是多继承多实现,它能够利用一组相关或者不相关的接口进行组合与扩充,能够对外提供一致的服务接口。所以它相对于继承来说有更好的灵活性。