Java笔试知识点总结(基础)

 

异常

异常分类

Java的异常分为两种,一种是运行时异常(RuntimeException),一种是非运行异常也叫检查式异常(CheckedException)。

对异常的处理只有两种try  catch捕获或throws 声明(抛出)异常

1、运行时异常不需要程序员去显式处理,当异常出现时,JVM会帮助处理。常见的运行时异常有:

NullPointerException    

(

对null进行操作时产生,但是注意有个特例,

Test test=null;

test.hello();

假如hello是个静态方法时,是可以正常编译运行的,空指针异常必须是去引用堆对象了,才会有空指针。

)

ArrayStoreException(数组存储异常,即数组存储类型不一致)

ArithmeticException(所有和算数有关的都是这个异常,比如除数为0)

NumberFormatException(调用parseInt()方法时,如果输入的字符串不是int型或超过int范围则会抛出该异常)

2、非运行异常需要程序员手动去捕获或者抛出异常进行显示的处理,因为Java认为Checked异常都是可以被修复的异常。常见的异常有:

IOException  (输入输出流编程中,读和写时都要手动抛出)

 

try—catch—finally执行顺序

1、try中没有抛出异常,则catch语句不执行,如果有finally语句,则接着执行finally语句,继而接着执行finally之后的语句;

2、try中抛出异常,有匹配的catch语句,则catch语句捕获,如果catch中有return语句,则要在finally执行后再执行;

注意:throw意味着抛出之后,方法就到此为止了,相当于return。

注意:catch块和finally块不能同时省略

 

正则表达式

坑点:replaceAll方法的第一个参数是一个正则表达式。

元字符

描述

\

将下一个字符标记符、或一个向后引用、或一个八进制转义符。例如,“\\n”匹配\n。“\n”匹配换行符。序列“\\”匹配“\”而“\(”则匹配“(”。即相当于多种编程语言中都有的“转义字符”的概念。

^

匹配输入字符串的开始位置。如果设置了RegExp对象的Multiline属性,^也匹配“\n”或“\r”之后的位置。

$

匹配输入字符串的结束位置。如果设置了RegExp对象的Multiline属性,$也匹配“\n”或“\r”之前的位置。

*

匹配前面的子表达式任意次。例如,zo*能匹配“z”,也能匹配“zo”以及“zoo”。*等价于o{0,}

+

匹配前面的子表达式一次或多次(大于等于1次)。例如,“zo+”能匹配“zo”以及“zoo”,但不能匹配“z”。+等价于{1,}。

?

匹配前面的子表达式零次或一次。例如,“do(es)?”可以匹配“do”或“does”中的“do”。?等价于{0,1}。

{n}

n是一个非负整数。匹配确定的n次。例如,“o{2}”不能匹配“Bob”中的“o”,但是能匹配“food”中的两个o。

{n,}

n是一个非负整数。至少匹配n次。例如,“o{2,}”不能匹配“Bob”中的“o”,但能匹配“foooood”中的所有o。“o{1,}”等价于“o+”。“o{0,}”则等价于“o*”。

{n,m}

m和n均为非负整数,其中n<=m。最少匹配n次且最多匹配m次。例如,“o{1,3}”将匹配“fooooood”中的前三个o为一组,后三个o为一组。“o{0,1}”等价于“o?”。请注意在逗号和两个数之间不能有空格。

?

当该字符紧跟在任何一个其他限制符(*,+,?,{n},{n,},{n,m})后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串“oooo”,“o+”将尽可能多的匹配“o”,得到结果[“oooo”],而“o+?”将尽可能少的匹配“o”,得到结果 ['o', 'o', 'o', 'o']

.点

匹配除“\r\n”之外的任何单个字符。要匹配包括“\r\n”在内的任何字符,请使用像“[\s\S]”的模式。

(pattern)

匹配pattern并获取这一匹配。所获取的匹配可以从产生的Matches集合得到,在VBScript中使用SubMatches集合,在JScript中则使用$0…$9属性。要匹配圆括号字符,请使用“\(”或“\)”。

(?:pattern)

非获取匹配,匹配pattern但不获取匹配结果,不进行存储供以后使用。这在使用或字符“(|)”来组合一个模式的各个部分时很有用。例如“industr(?:y|ies)”就是一个比“industry|industries”更简略的表达式。

(?=pattern)

非获取匹配,正向肯定预查,在任何匹配pattern的字符串开始处匹配查找字符串,该匹配不需要获取供以后使用。例如,“Windows(?=95|98|NT|2000)”能匹配“Windows2000”中的“Windows”,但不能匹配“Windows3.1”中的“Windows”。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。

(?!pattern)

非获取匹配,正向否定预查,在任何不匹配pattern的字符串开始处匹配查找字符串,该匹配不需要获取供以后使用。例如“Windows(?!95|98|NT|2000)”能匹配“Windows3.1”中的“Windows”,但不能匹配“Windows2000”中的“Windows”。

(?<=pattern)

非获取匹配,反向肯定预查,与正向肯定预查类似,只是方向相反。例如,“(?<=95|98|NT|2000)Windows”能匹配“2000Windows”中的“Windows”,但不能匹配“3.1Windows”中的“Windows”。

(?<!pattern)

非获取匹配,反向否定预查,与正向否定预查类似,只是方向相反。例如“(?<!95|98|NT|2000)Windows”能匹配“3.1Windows”中的“Windows”,但不能匹配“2000Windows”中的“Windows”。这个地方不正确,有问题

此处用或任意一项都不能超过2位,如“(?<!95|98|NT|20)Windows正确,“(?<!95|980|NT|20)Windows 报错,若是单独使用则无限制,如(?<!2000)Windows 正确匹配

x|y

匹配x或y。例如,“z|food”能匹配“z”或“food”(此处请谨慎)。“[zf]ood”则匹配“zood”或“food”。

[xyz]

字符集合。匹配所包含的任意一个字符。例如,“[abc]”可以匹配“plain”中的“a”。

[^xyz]

负值字符集合。匹配未包含的任意字符。例如,“[^abc]”可以匹配“plain”中的“plin”。

[a-z]

字符范围。匹配指定范围内的任意字符。例如,“[a-z]”可以匹配“a”到“z”范围内的任意小写字母字符。

注意:只有连字符在字符组内部时,并且出现在两个字符之间时,才能表示字符的范围; 如果出字符组的开头,则只能表示连字符本身.

[^a-z]

负值字符范围。匹配任何不在指定范围内的任意字符。例如,“[^a-z]”可以匹配任何不在“a”到“z”范围内的任意字符。

\b

匹配一个单词边界,也就是指单词和空格间的位置(即正则表达式的“匹配”有两种概念,一种是匹配字符,一种是匹配位置,这里的\b就是匹配位置的)。例如,“er\b”可以匹配“never”中的“er”,但不能匹配“verb”中的“er”。

\B

匹配非单词边界。“er\B”能匹配“verb”中的“er”,但不能匹配“never”中的“er”。

\cx

匹配由x指明的控制字符。例如,\cM匹配一个Control-M或回车符。x的值必须为A-Z或a-z之一。否则,将c视为一个原义的“c”字符。

\d

匹配一个数字字符。等价于[0-9]。grep 要加上-P,perl正则支持

\D

匹配一个非数字字符。等价于[^0-9]。grep要加上-P,perl正则支持

\f

匹配一个换页符。等价于\x0c和\cL。

\n

匹配一个换行符。等价于\x0a和\cJ。

\r

匹配一个回车符。等价于\x0d和\cM。

\s

匹配任何不可见字符,包括空格、制表符、换页符等等。等价于[ \f\n\r\t\v]。

\S

匹配任何可见字符。等价于[^ \f\n\r\t\v]。

\t

匹配一个制表符。等价于\x09和\cI。

\v

匹配一个垂直制表符。等价于\x0b和\cK。

\w

匹配包括下划线的任何单词字符。类似但不等价于“[A-Za-z0-9_]”,这里的"单词"字符使用Unicode字符集。

\W

匹配任何非单词字符。等价于“[^A-Za-z0-9_]”。

 

继承

子类能继承父类的所有成员,所以子类对象是绝对大于父类对象的,可以继承,只是无法访问到而已,想访问用反射!!

多态的三要素,继承,重写,父类引用指向子类对象(至于要不要把重载加进去,有争议!!)

多态的最常见应用,向上转型,但父类的引用无法访问子类独有的方法,

重写

 

方法重写应遵循“两同两小一大”原则:

  1. “两同”:即方法名相同,形参列表相同;
  2. “两小”:子类方法声明抛出的异常比父类的更小或者相等;子类返回值类型比父类的更小或者相等
  3. “一大”:子类方法的访问修饰符应比父类方法更大或相等。(private和static方法不能被重写)

重点在于要时刻记得若子类重写了父类方法,父类调用时会调用子类重写之后的方法
当然,这一切的前提都是 实例化子类对象

重载

方法重写应遵循“一同一不同”原则:

  1. “一同”:即方法名相同;
  2. “一不同”:参数列表必须不同(参数类型,参数个数)

 

super()和this()

1)调用super()必须写在子类构造方法的第一行,否则编译不通过。每个子类构造方法的第一条语句,都是隐含地调用super(),而且如果父类没有这种形式的构造函数,那么在编译的时候就会报错。

2)super()从子类中调用父类的构造方法,this()在同一类内调用其它重载的构造方法。

3)super()和this()均需放在构造方法内第一行。

4)this()或super()在一个构造器内只能出现一次,而且this()和super()不能同时出现在一个构造函数里面,否则编译器不通过。

6)this()和super()都指的是对象,所以,均不可以在static环境中使用。包括:static变量,static方法,static语句块。

7)从本质上讲,this是一个指向本对象的指针而不是类的引用, 然而super是一个Java关键字。

8)this.xxx和super.xxx可以引用本类或父类的成员变量(如果访问权限允许的话)。

9)可以使用super.fun()访问父类被子类隐藏的变量或覆盖的方法

构造器

初始化过程: 

1. 初始化父类中的静态成员变量和静态代码块 ; 

2. 初始化子类中的静态成员变量和静态代码块 ; 

3.初始化父类的普通成员变量和代码块,再执行父类的构造方法;

4.初始化子类的普通成员变量和代码块,再执行子类的构造方法; 

子类构造器的默认第一行就是super(),默认调用直接父类的无参构造。这也就是一旦一个子类的直接父类没有无参的构造的情况下,必须在自己构造器的第一行显式的指明调用父类或者自己的哪一个构造器。

其实 普通的类方法是可以和类名同名的,和构造方法唯一的区分就是,构造方法没有返回值。

执行顺序:

父类静态域——》子类静态域——》父类成员初始化——》父类构造块——》父类构造方法——》子类成员初始化——》子类构造块——》子类构造方法;

注:静态初始化块(静态块仅在类加载时执行一次),静态变量这两个是属于同一级别的,是按代码写得顺序执行的

注2:只有执行完构造函数,对象才能完成初始化,属性才能有值,不然都是null或0。

注3:并不是静态块最先初始化,而是静态域.(BM:是静态域!!!!!!!)

而静态域中包含静态变量、静态块和静态方法,其中需要初始化的是静态变量和静态块.而他们两个的初始化顺序是靠他们俩的位置决定的!

注4:

静态块:用static申明,JVM加载类时执行,仅执行一次

构造块:类中直接用{}定义,每一次创建对象时执行

执行顺序优先级:静态块>main()>构造块>构造方法

举个例子,假如先执行public static B t1 = newB();该语句创建对象,其后会根据优先级,紧跟着调用构造块,输出构造块

匿名内部类

匿名内部类的创建格式为: new 父类构造器(参数列表)|实现接口(){

                                             //匿名内部类的类体实现

                                        }

  1. 使用匿名内部类时,必须继承一个类或实现一个接口
  2. 匿名内部类由于没有名字,因此不能定义构造函数
  3. 匿名内部类中不能含有静态成员变量和静态方法

 

 

线程

创建线程

创建线程的方法有很多种,下面是最常见三种:

注意:线程类光创建实例没用,线程是不能自动运行的,必须通过start()启动
(1)继承Thread类,重写run方法,main方法中用start()启动;
(2)实现Runnable接口,重写run方法,并将对象实例作为参数传递给Thread类的构造方法,Thread对象通过start使用;
(3)实现callable接口,重写call方法,通过线程池的submit方法启动,并且线程执行完毕后会有返回值。

线程状态

Java笔试知识点总结(基础)

线程调用start后并不保证线程启动的顺序,run则保证线程间顺序执行。

 

 

修饰符和运算符

外部类修饰符

public(访问控制符),将一个类声明为公共类,他可以被任何对象访问,一个程序的主类必须是公共类。

abstract,将一个类声明为抽象类,没有实现的方法,需要子类提供方法实现。

final,将一个类生命为最终(即非继承类),表示他不能被其他类继承。

friendly,默认的修饰符,只有在相同包中的对象才能使用这样的类。

  

成员变量修饰符(包括内部类)

内部类,可理解为外部类的成员,所以修饰类成员的关键字都能使用

public(公共访问控制符),指定该变量为公共的,他可以被任何对象的方法访问。

private(私有访问控制符)指定该变量只允许自己的类的方法访问,其他任何类(包括子类)中的方法均不能访问。

protected(保护访问控制符)指定该变量可以别被自己的类和子类访问。在子类中可以覆盖此变量。

friendly ,在同一个包中的类可以访问,其他包中的类不能访问。

final,最终修饰符,指定此变量的值不能变。

static(静态修饰符)指定变量被所有对象共享,即所有实例都可以使用该变量。变量属于这个类。

transient(过度修饰符)指定该变量是系统保留,暂无特别作用的临时性变量。

volatile(易失修饰符)指定该变量可以同时被几个线程控制和修改。

  Java笔试知识点总结(基础)

方法修饰符

public(公共控制符)

private(私有控制符)指定此方法只能有自己类等方法访问,其他的类不能访问(包括子类)

protected(保护访问控制符)指定该方法可以被它的类和子类进行访问。

final,指定该方法不能被重载。

static,指定不需要实例化就可以**的一个方法。

synchronize,同步修饰符,在多个线程中,该修饰符用于在运行前,对他所属的方法加锁,以防止其他线程的访问,运行结束后解锁。

native,本地修饰符。指定此方法的方法体是用其他语言在程序外部编写的。

 

接口修饰符

接口中字段的修饰符:public static final(默认不写),即必须是常量,且赋值。

接口中方法的修饰符:public abstract(默认不写),可以是friendly  abstract,1.8中可以有静态方法了

接口的修饰符:public或什么 都不写(默认权限,而且默认是什么都不写)

 

抽象类

特点:
1-抽象类和抽象方法必须用abstract关键字修饰。
2-抽象类中不一定都是抽象方法(没有方法体,即必须没有大括号{}),但是有抽象方法的类一定是抽象类。
3-抽象类不能直接实例化(可通过多态实现),因为它不是具体的类。
4-抽象类是有构造方法的,只是不能实例化,用于子类访问父类数据的初始化。
抽象类的子类:
      1- 不重写抽象方法,抽象类的子类是一个抽象子类。
      2-重写父类所有抽象方法,子类才能不是抽象类。

成员变量:
       既可以是变量(private等)也可以是常量(public static final)。

abstract关键字不可以与哪些关键字一起使用:
private 冲突;private修饰的成员不能被继承,从而不可以被子类重写,而abstract修饰的是要求被重写的。
final  冲突;final修饰的成员是最终成员,不能被重写,所以冲突,
static 无意义;static修饰成员用类名可以直接访问,但是abstract修饰成员没有方法体,所以访问没有方法体的成员无意义。

抽象类中注意的问题:
一个类如果没有抽象方法,可以是抽象类,即抽象类中可以完全没有抽象方法。
这样类的主要目的就是不让创建该类对象。

 

访问权限修饰符

Java笔试知识点总结(基础)

( 1 )对于外部类而言,它也可以使用访问控制符修饰,但外部类只能有两种访问控制级别: public 和默认。因为外部类没有处于任何类的内部,也就没有其所在类的内部、所在类的子类两个范围,因此 private 和 protected 访问控制符对外部类没有意义。

( 2 )内部类的上一级程序单元是外部类,它具有 4 个作用域:同一个类( private )、同一个包( protected )和任何位置( public),即有4种访问权限。所以,“一个文件中只能有一个public class。”是错的,还可以多个内部类

( 3 ) 因为局部成员的作用域是所在方法,其他程序单元永远不可能访问另一个方法中的局部变量,所以所有的局部成员都不能使用访问控制修饰符修饰。

Java笔试知识点总结(基础)

运算符优先级

小知识:<<=左移赋值 ,>>>= 右移赋值,>>带符号右移(相当于除以2的n次方),>>>(无符号右移,左边空缺补充为0)

小知识:-n=~n+1(按位取反公式)

口诀:淡云一笔安洛三福 单目>算数运算符>移位>比较>按位>逻辑>三目>赋值

有个很有意思的例子i=i++;

这里Java使用了中间缓存变量机制:
i=i++;等同于:
temp=i; (等号右边的i)
i=i+1;      (等号右边的i)
i=temp;   (等号左边的i)
而i=++i;则等同于:
i=i+1;
temp=i;
i=temp;

“==”和equals方法

equal :是用来比较两个对象内部的内容是否相等的(因为String类重写了equals()方法,Object类定义中,和==是相同效果的)。
==:是用来判断两个对象的地址是否相同,即是否是指相同一个对象。而基本数据类型是只能用==比较数值是否相等。

Java笔试知识点总结(基础)

Byte,Short,Integer,Long,Character这5种整型的包装类也只是在对应值小于等于127并且大于等于-128时才可使用常量池,因为他们只占用一个字节(-128~127)。

例如Integer.valueOf源码方法中也有判断,如果传递的整型变量>= -128并且小于127时会返回IntegerCache类中一个静态数组中的某一个对象, 否则会返回一个新的Integer对象

包装类的“==”运算在不遇到算术运算的情况下不会自动拆箱

包装类的equals()方法不处理数据转型

JDK

编程

1.

javac.exe是编译.java文件

java.exe是执行编译好的.class文件

javadoc.exe是生成Java说明文档

jdb.exe是Java调试器

javaprof.exe是剖析工具

2.

写好的java文件后缀名为text.java

编译java文件:输入javac text.java回车,编译会生成.class文件

运行java文件:java text;

一次编译多个java文件用javac *.java. 即可编译当前目录下的所有java文件

3.

-s指定存放生成的源文件的位置

-d即可设置系统属性

4.

可以使用逗号的是变量初始化的语句,比如 int i=1,b=2;

如果是赋值语句,不能用逗号分隔,只能用分号。

举例:只能是x=a; y=b;而不能是x=a, y=b;

命名规则

标识符是不以数字开头的字母数字序列:

数字是指0~9,字母指大小写英文字母、下划线(_)和美元符号($)

关键字

instanceof 用来在运行时指出对象是否是特定类的一个实例,instanceof通过返回一个布尔值来指出,这个对象是否是这个特定类或者是它的子类的一个实例

在Java7之前,switch只能支持 byte、short、char、int或者其对应的封装类以及Enum类型。在Java7中,呼吁很久的String支持也终于被加上了。

在根类Object中包含一下方法:  

  1. clone();
  2. equals();
  3. finalize();
  4. getClass();
  5. notify(),notifyAll();
  6. hashCode();
  7. toString();
  8. wait();

五个基本原则


单一职责原则(Single-Resposibility Principle):一个类,最好只做一件事,只有一个引起它的变化。单一职责原则可以看做是低耦合、高内聚在面向对象原则上的引申,将职责定义为引起变化的原因,以提高内聚性来减少引起变化的原因。 
开放封闭原则(Open-Closed principle):软件实体应该是可扩展的,而不可修改的。也就是,对扩展开放,对修改封闭的。 
Liskov替换原则(Liskov-Substituion Principle):子类必须能够替换其基类。这一思想体现为对继承机制的约束规范,只有子类能够替换基类时,才能保证系统在运行期内识别子类,这是保证继承复用的基础。 
依赖倒置原则(Dependecy-Inversion Principle):依赖于抽象。具体而言就是高层模块不依赖于底层模块,二者都同依赖于抽象;抽象不依赖于具体,具体依赖于抽象。 
接口隔离原则(Interface-Segregation Principle):使用多个小的专门的接口,而不要使用一个大的总接口

常识

1、Java一律采用Unicode编码方式,每个字符无论中文还是英文字符都占用2个字节。

Java虚拟机中通常使用UTF-16的方式保存一个字符

2、const和goto是保留关键字。true和false看起来像关键字,但严格来说,它们是boolean常量;null看起来也像关键字,但严格来说,它是null常量。

3、Java程序的种类有:

(a)内嵌于Web文件中,由浏览器来观看的_Applet

(b)可独立运行的 Application

(c)服务器端的 Servlets

4、想用转义字符请用单引号!!!!!!!!!

5、

"c:\\my\\1.txt" "c:/my/1.txt" 都是正确的答案。 但"\"这个符号在中英文环境下是不一样的显示;而"/"在中英文环境下是相同的显示。所以前者需要转义。

./表示当前项目的路径
../表示当前目录的父目录路径

6、关于字符串有个编译器的优化问题,hotspot中 编译时String a ="tao"+"bao"将直接变成"taobao";String b="tao";String c="bao";(b+c)==MESSAGE则不会优化,因为不知道在之前的步骤中bc会不会发生改变,而针对b+c则是用语法糖,新建一个StringBuilder来处理

再举个例子:String str1 = "hello";这里的str1指的是方法区的字符串常量池中的“hello”,编译时期就知道的; String str2 = "he" + new String("llo");这里的str2必须在运行时才知道str2是什么,所以它是指向的是堆里定义的字符串“hello”,所以这两个引用是不一样的。

7、object的getClass()方法:返回当前运行时的类。然后再调用getName()方法返回:包名+类名(不加.class)

8、类似 java.io.OutputStreamWrite这样已经是完整的类,无需在导入,而单独printWrite这个类,并不是调用完整的类名。则需要import导入

8、记住:Math.round()是先加0.5,然后再向下取整。所以Math.round(-11.5) 的结果 就是-11

泛型

1、创建泛型对象的时候,一定要指出类型变量T的具体类型。争取让编译器检查出错误,而不是留给JVM运行的时候抛出类不匹配的异常。

2、JVM如何理解泛型概念 —— 类型擦除。事实上,JVM并不知道泛型,所有的泛型在编译阶段就已经被处理成了普通类和方法。 处理方法很简单,我们叫做类型变量T的擦除(erased) 。 总结:泛型代码与JVM ① 虚拟机中没有泛型,只有普通类和方法。 ② 在编译阶段,所有泛型类的类型参数都会被Object或者它们的限定边界来替换。(类型擦除) ③ 在继承泛型类型的时候,桥方法的合成是为了避免类型变量擦除所带来的多态灾难。 无论我们如何定义一个泛型类型,相应的都会有一个原始类型被自动提供。原始类型的名字就是擦除类型参数的泛型类型的名字。

3、“泛型的类型擦除机制意味着不能在运行时动态获取List<T>中T的实际类型”是错的,可以通过反射获取

 

 

 

JVM

Java内存模型(JMM)

JMM通过控制主内存与每个线程的本地内存之间的交互,来保证可见性,原子性,有序性。

“volatile”关键字有如下两个作用

  • 保证被volatile修饰的共享变量对所有线程是可见的,也就是当一个线程修改了一个被volatile修饰共享变量的值,新值可以被其他线程立即得知。

  • 禁止指令重排序优化。

简单点说:保证对修饰的变量,线程读写前都会从主内存同步更新,保证了可见性。

“synchronized”关键字有如下两个作用

  • 关键字 synchronized可以保证在同一个时刻,只有一个线程可以执行某个方法或者某个代码块(主要是对方法或者代码块中存在共享数据的操作)

  • synchronized可保证一个线程的变化(主要是共享数据的变化)被其他正确的线程所看到(保证可见性,完全可以替代Volatile功能)

简单点说:保证在块开始时同步主内存的值到工作内存,而块结束时将变量同步回主内存

“final”关键字的注意事项:

创建一个不可变对象    final Main x=new Main();

final修饰的只是引用,也就是说x只能指向这个对象的地址,但是对象本身可以改变。

所以在多线程中,这个对象依旧不是线程安全的,想要这个对象被其他线程正确的查看,必须要用“synchronized”关键字修饰。

GC

年老代溢出原因有  循环上万次的字符串处理、创建上千万个对象、在一段代码内申请上百M甚至上G的内存

持久代溢出原因  动态加载了大量Java类而导致溢出。

1,新生代:(1)所有对象创建在新生代的Eden区,当Eden区满后触发新生代的Minor GC,将Eden区和非空闲Survivor区存活的对象复制到另外一个空闲的Survivor区中。(2)保证一个Survivor区是空的,新生代Minor GC就是在两个Survivor区之间相互复制存活对象,直到Survivor区满为止。
2,老年代:当Survivor区也满了之后就通过Minor GC将对象复制到老年代。老年代也满了的话,就将触发Full GC,针对整个堆(包括新生代、老年代、持久代)进行垃圾回收。
3,持久代:持久代如果满了,将触发Full GC。

ClassLoader

一个jvm中默认的classloader有Bootstrap ClassLoader、Extension ClassLoader、App ClassLoader,分别各司其职:

  • Bootstrap ClassLoader     负责加载java基础类,主要是 %JRE_HOME/lib/ 目录下的rt.jar、resources.jar、charsets.jar和class等
  • Extension ClassLoader      负责加载java扩展类,主要是 %JRE_HOME/lib/ext 目录下的jar和class
  • App ClassLoader           负责加载当前java应用的classpath中的所有类。

classloader 加载类用的是全盘负责委托机制。 所谓全盘负责,即是当一个classloader加载一个Class的时候,这个Class所依赖的和引用的所有 Class也由这个classloader负责载入,除非是显式的使用另外一个classloader载入。 
所以,当我们自定义的classlo ader加载成功了 com.company.MyClass以后,MyClass里所有依赖的class都由这个classLoader来加载完成。

JVM加载类的实现方式,我们称为 双亲委托模型

如果一个类加载器收到了类加载的请求,他首先不会自己去尝试加载这个类,而是把这个请求委托给自己的父加载器,每一层的类加载器都是如此,因此所有的类加载请求最终都应该传送到顶层的Bootstrap ClassLoader中,只有当父加载器反馈自己无法完成加载请求时,子加载器才会尝试自己加载。

双亲委托模型的重要用途是为了解决类载入过程中的安全性问题。

假设有一个开发者自己编写了一个名为Java.lang.Object的类,想借此欺骗JVM。现在他要使用自定义ClassLoader来加载自己编写的java.lang.Object类。然而幸运的是,双亲委托模型不会让他成功。因为JVM会优先在Bootstrap ClassLoader的路径下找到java.lang.Object类,并载入它

JDBC

ResultSet

  • 表示数据库结果集的数据表,通常通过执行查询数据库的语句生成。 
  • 当前行的第一列的索引是1,而不是0.

桥接模式

Java数据库连接库JDBC用了桥接模式,桥接模式的定义是将抽象部分与它的实现部分分离,使它们都可以独立地变化。意图是将抽象与实现解耦,JDBC连接 数据库 的时候,在各个数据库之间进行切换,基本不需要动太多的代码,甚至丝毫不动,原因就是JDBC提供了统一接口,每个数据库提供各自的实现,用一个叫做数据库驱动的程序来桥接就行了

加载驱动方法

1.Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");

2. DriverManager.registerDriver(new com.mysql.jdbc.Driver());

3.System.setProperty("jdbc.drivers", "com.mysql.jdbc.Driver");

 

数据类型

基本数据类型(原生类)

 

 

默认值

存储需求(8位=1字节)

  取值范围 

 示例 

byte 

0

1

 -2^7—2^7-1 

byte b=10;

char 

 ‘ \u0000′ 

2

 0—2^16-1 

char c=’c’ ; 

short 

0

2

-2^15—2^15-1 

short s=10; 

int  

0

4

-2^31—2^31-1 

int i=10; 

long 

0

8

-2^63—2^63-1  

long o=10L; 

float  

 0.0f  

4

-2^31—2^31-1 

float f=10.0F 

double  

0.0d 

8

-2^63—2^63-1 

double d=10.0; 

boolean 

false  

1

true\false 

boolean flag=true;

1)两个数值进行二元操作时,会有如下的转换操作:(byte-short-int-long-float-double)

如果两个操作数其中有一个是double类型,另一个操作就会转换为double类型。

否则,如果其中一个操作数是float类型,另一个将会转换为float类型。

否则,如果其中一个操作数是long类型,另一个会转换为long类型。

否则,两个操作数都转换为int类型。

多种混合计算时,自动将所有数据类型转换为容量最大的一种数据类型,即自动向上转型。向下转型只能强转,而强转可能会出现丢失精度的问题。

被final修饰的变量是常量,参与计算时类型不会发生改变,但如果是无final修饰的byte类型变量,java中进行计算时候将他们提升为int类型,再进行计算,相加计算后结果已经是int类型,若再赋值给byte类型,那么类型肯定不匹配,编译不会通过,需要进行强制转换。

Java中的byte,short,char进行计算时都会提升为int类型。

要注意:

float占4个字节比long占8个字节大,因为底层的实现方式不同。

浮点数的32位并不是简单直接表示大小,而是按照一定标准分配的

第1位,符号位,即S

接下来8位,指数域,即E。

剩下23位,小数域,即M,取值范围为[1 ,2 ) 或[0 , 1)

然后按照公式: V=(-1)^s * M * 2^E

也就是说浮点数在内存中的32位不是简单地转换为十进制,而是通过公式来计算而来,通过这个公式虽然,只有4个字节,但浮点数最大值要比长整型的范围要大

2)整型默认为int,如果需要long,须加l或L。小数默认double,d或D可省略,但如果需要float,须加f或F,例如float = 0.1f

八进制,以8为基数的算法,逢8进1.所以8在八进制就是010,前面那个0是为了和十进制区分用的,也叫转译符。

3 )实现GBK编码字节流到UTF-8编码字节流的转换

byte[] src,dst;

dst=new String(src,"GBK").getBytes("UTF-8")

引用类型

1.((TestClass)null).testMethod();这种写法看似很奇葩,其实是可以的,

null可以被强制类型转换成任意类型(不是任意类型对象),于是可以通过它来执行静态方法。

2.枚举

 

Java笔试知识点总结(基础)

 

变量与常量与方法

实例变量: 定义在类中的变量是类的成员变量,可以不进行初始化, java 会自动进行初始化。(如果是引用类默认初始化为 null, 如果是基本类型,默认初始化为 0或 false )

局部变量 :定义在方法中的变量,必须进行初始化,否则不通过编译。

类变量 :(也叫作静态变量)是类中独立于方法之外的变量,用 static 修饰,不用初始化,有默认初始值false。静态变量只能在类主体中定义,不能在方法中定义。 静态变量属于类所有而不属于方法。静态变量被所有的对象所共享,在内存中只有一个副本,它当且仅当在类初次加载时会被初始化。

静态变量的使用:1、如果是本类使用,可以直接就用静态变量名。2、如果是其他类使用,可以使用类名来调用,也可以创建一个实例对象来调用。3、如果静态变量所在的类是静态类,那么不管在本类里或者在其他外部类,都可以直接使用静态变量名。

类方法:    有如下限制 (1) 类方法中不能引用对象变量; (2) 类方法中不能调用类的对象方法; (3) 在类方法中不能使用super、this关键字。 (4)类方法不能被覆盖。    (5)类方法中调用本类的类方法可直接调用

final 修饰的变量: 也称为常量,只用final修饰可以在其定义时就初始化,也可以到类的构造方法里面再对它进行初始化,但用static和final关键字同时修饰的常量就必须在定义时初始化。

 

JavaWeb

中间件

中间件是一种独立的系统软件,位于客户机/服务器的操作系统之上,中间件位于操作系统之上,应用软件之下,而不是位于操作系统内核之中,管理计算机资源和网络通讯。是连接两个独立应用程序或独立系统的软件。相连接的系统,即使它们具有不同的接口,但通过中间件相互之间仍能交换信息。执行中间件的一个关键途径是信息传递。通过中间件,应用程序可以工作于多平台或OS环境。

(简单来说,中间件并不能提高内核的效率,一般只是负责网络信息的分发处理)

而Java常用中间件有jetty,apache,JBOSS,webloigc,tomcat

JSP

Servlet与JSP九大内置对象的关系


JSP对象         怎样获得
out->response.getWriter
request ->Service方法中的req参数
response ->Service方法中的resp参数
session ->request.getSession
application ->getServletContext


exception ->Throwable          当jsp标签中isErrorPage ="false"时,只能用errorPage="error.jsp"(isErrorPage默认是false)
                                                 当isErrorPage ="true"时,页面才会直接使用exception
page  ->this
pageContext  ->PageContext
Config ->getServletConfig

重定向

1.从地址栏显示来说

forward是服务器请求资源,然后服务器直接内部访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器.浏览器根本不知道服务器发送的内容从哪里来的,所以它的地址栏还是原来的地址.

注意:“forward是服务器将控制权转交给另外一个内部服务器对象,由新的对象来全权负责响应用户的请求”这句话是错的,服务器会直接访问目标地址的URL,不会把控制权转交!!

redirect是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址.所以地址栏显示的是新的URL.

2.从数据共享来说

forward:转发页面和转发到的页面可以共享request里面的数据.

redirect:不能共享数据.

3.从运用地方来说

forward:一般用于用户登陆的时候,根据角色转发到相应的模块.

redirect:一般用于用户注销登陆时返回主页面和跳转到其它的网站等.

4.从效率来说

forward:高.

redirect:低.

INCLUDE

动态 INCLUDE 用 jsp:include 动作实现 <jsp:include page="included.jsp" flush="true" /> 它总是会检查所含文件中的变化 , 适合用于包含动态页面 , 并且可以带参数。各个文件分别先编译,然后组合成一个文件。

静态 INCLUDE 用 include 伪码实现 , 定不会检查所含文件的变化 , 适用于包含静态页面 <%@ include file="included.htm" %> 。先将文件的代码被原封不动地加入到了主页面从而合成一个文件,然后再进行翻译,此时不允许有相同的变量。 

以下是对 include 两种用法的区别 , 主要有两个方面的不同 ;
    一 : 执行时间上 :
    <%@ include file="relativeURI"%> 是在翻译阶段执行
    <jsp:include page="relativeURI" flush="true" /> 在请求处理阶段执行 .
    二 : 引入内容的不同 :
    <%@ include file="relativeURI"%>
    引入静态文本 (html,jsp), 在 JSP 页面被转化成 servlet 之前和它融和到一起 .
    <jsp:include page="relativeURI" flush="true" /> 引入执行页面或 servlet 所生成的应答文本 .

分页步骤

1、count(*)得到总记录数

2、计算总页数

3、获取所有记录

4、过滤显示本页数据

 

 

集合框架

Map

hashMap在单线程中使用大大提高效率,在多线程的情况下使用hashTable来确保安全。hashTable中使用synchronized关键字来实现安全机制,但是synchronized是对整张hash表进行锁定即让线程独享整张hash表,在安全同时造成了浪费。concurrentHashMap采用分段加锁的机制(使用segment来分段和管理锁)来确保安全

List

Arraylist的内存结构是数组,当超出数组大小时创建一个新的数组,将原数组中元素拷贝过去。其本质是顺序存储的线性表,插入和删除操作会引发后续元素移动,效率低,但是随机访问效率高

LinkedList的内存结构是用双向链表存储的,链式存储结构插入和删除效率高,不需要移动。但是随机访问效率低,需要从头开始向后依次访问

List的remove方法在删除元素时总会保持下标连续,因此删除第一个元素的时候后面的元素会依次向前覆盖,举个例子,你删除了下标为0的元素后,下标为1的元素就会向前覆盖,结果就是下标为0的元素成了开始时下标为1的元素,其他依次向前同理覆盖,但是你现在遍历的下标加1了啊!不就成了访问之前的第三个元素了,那第二个元素不就被跳过了嘛

Set

hashset类的hashCode()值相等,equals()也相等,就确定为相等,即重复元素。因为默认hasncode根据内存地址计算,所以要重写,保证equals时hashcode相等就是元素相等。