Java基础部分
JDK和JRE、 JVM
JDK(Java Development Kit)是 Java 开发工具包,包括了 Java 运行环境 JRE、Java 工具和
Java 基础类库。
JRE(Java Runtime Environment)是运行 Java 程序所必须的环境的集合,包含 JVM 标准实现及
Java 核心类库
JVM(Java Virtual Machine)是 Java 虚拟机的缩写,是整个 Java 实现跨平台的最核心的部分,能
够运行以Java 语言写作的软件程序。
类和对象的区别
类是一类物体的共同特性的抽象.对象是类的一个实例.
通俗的说:把某一类物品共有的特征,或者属性组装起来就是一个类. 能够具体到物品或者个体就是对象.
构造方法和普通方法的区别
构造函数的方法名和类型相同、没有返回值类型、不能写 return,是给对象初始化用的,创建对象的时
候就会初始化,执行唯一的一次构造方法,系统会默认添加一个无参的构造方法
普通方法是对象调用才能执行,可被多次调用。
构造器Constructor是否可被override
构造器Constructor不能被继承,因此不能重写Override,但可以被重载Overload。
作用域public,private,protected,以及不写时的区别
这四个作用域的可见范围如下表所示。
说明:如果在修饰的元素上面没有写任何访问修饰符,则表示 default 。
Integer与 int 的区别
int 是 Java 提供的 8 种原始数据类型之一。Java 为每个原始类型提供了封装类,Integer 是 Java 为 int
提供的封装类。int的默认值为0,而Integer的默认值为null,即Integer可以区分出未赋值和值为0的区
别,int则无法表达出未赋值的情况,例如,要想表达出没有参加考试和考试成绩为0的区别,则只能使
用Integer。在JSP开发中,Integer的默认为null,所以用el表达式在文本框中显示时,值为空白字符串,
而int默认的默认值为0,所以用el表达式在文本框中显示时,结果为0,所以,int不适合作为web层的
表单数据的类型。
&和&&的区别
&和&&都可以用作逻辑与的运算符,表示逻辑与(and),当运算符两边的表达式的结果都为 true 时,
整个运算结果才为 true,否则,只要有一方为 false,则结果为 false。
&& 还具有短路的功能,即如果第一个表达式为 false,则不再计算第二个表达式
&还可以用作位运算符,当&操作符两边的表达式不是boolean类型时,&表示按位与操作,我们通常使
用0x0f来与一个整数进行&运算,来获取该整数的最低4个bit位,例如,0x31 & 0x0f的结果为0x01。
类变量与实例变量的区别
在语法定义上的区别:静态变量前要加static关键字,而实例变量前则不加。
在程序运行时的区别:实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分
配空间,才能使用这个实例变量。静态变量不属于某个实例对象,而是属于类,所以也称为类变量,只
要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用
了。总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引
用。
类变量是所有该类的实例化对象所共有的资源,其中一个对象将它值改变,其他对象得到的就是改变后
的结果;而实例变量则属对象私有,某一个对象将其所包含的实例变量的值改变,不影响其他对象中实
例变量的值;
局部变量,由声明在某方法,或某代码段里(比如for循环)。执行到它的时候直接在栈中开辟内存并使
用的。当局部变量脱离作用域,存放该作用域的栈指针,栈顶与栈底重合即为释放内存,速度是非常快
的。
"=="和equals区别
== 操作符专门用来比较两个变量的值是否相等,也就是用于比较变量所对应的内存中所存储的数值是否
相同,要比较两个基本类型的数据或两个引用变量是否相等,只能用 ==操作符。
equals 方法是用于比较两个独立对象的内容是否相同,就好比去比较两个人的长相是否相同,它比较的
两个对象是独立的。
如果一个类没有自己定义equals方法,那么它将继承Object类的equals方法,Object类的equals方法的
实现代码如下:
这说明,如果一个类没有自己定义equals方法,它默认的equals方法(从Object 类继承的)就是使用==
操作符,也是在比较两个变量指向的对象是否是同一对象,这时候使用equals和使用 ==会得到同样的结
果,如果比较的是两个独立的对象则总返回false。如果你编写的类希望能够比较该类创建的两个实例对
象的内容是否相同,那么你必须覆盖equals方法,由你自己写代码来决定在什么情况即可认为两个对象
的内容是相同的。
String s = new String("xyz");创建了几个String Object? 二者之间
有什么区别?
两个或一个,”xyz”对应一个对象,这个对象放在字符串常量缓冲区,常量”xyz”不管出现多少遍,都是缓
冲区中的那一个。New String每写一遍,就创建一个新的对象,它一句那个常量”xyz”对象的内容来创建
出一个新String对象。如果以前就用过’xyz’,这句代表就不会创建”xyz”自己了,直接从缓冲区拿。
boolean equals(Object o){
return this==o;
}
1
2
3
构造方法 描述
StringBuilder() 创建一个容量为16的StringBuilder对象(16个空元素)
StringBuilder(CharSequence cs) 创建一个包含cs的StringBuilder对象,末尾附加16个空元素
StringBuilder(int initCapacity) 创建一个容量为initCapacity的StringBuilder对象
StringBuilder(String s) 创建一个包含s的StringBuilder对象,末尾附加16个空元素
String 、StringBuffer和StringBuilder 的区别
String
String:字符串常量,字符串长度不可变。Java 中 String 是 immutable(不可变)的。
String 类的包含如下定义:
用于存放字符的数组被声明为 final 的,因此只能赋值一次,不可再更改。
StringBuffer(JDK1.0)
StringBuffer:字符串变量(Synchronized,即线程安全)。如果要频繁对字符串内容进行修改,出于
效率考虑最好使用 StringBuffer,如果想转成 String 类型,可以调用 StringBuffer 的 toString() 方法。
Java.lang.StringBuffer 线程安全的可变字符序列。在任意时间点上它都包含某种特定的字符序列,但
通过某些方法调用可以改变该序列的长度和内容。可将字符串缓冲区安全地用于多个线程。
StringBuffer 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每
个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。
append 方法始终将这些字符添加到缓冲区的末端;
insert 方法则在指定的点添加字符。
例如,如果 z 引用一个当前内容是 start 的字符串缓冲区对象,则此方法调用 z.append("le") 会使字符
串缓冲区包含 startle ,而 z.insert(4, "le") 将更改字符串缓冲区,使之包含 starlet 。
StringBuilder(JDK5.0)
StringBuilder:字符串变量(非线程安全)。在内部,StringBuilder 对象被当作是一个包含字符序列
的变长数组。
java.lang.StringBuilder 是一个可变的字符序列,是 JDK5.0 新增的。此类提供一个与 StringBuffer 兼容
的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程
使用的时候(这种情况很普遍)。
其构造方法如下:
在大部分情况下,StringBuilder > StringBuffer。这主要是由于前者不需要考虑线程安全。
/** The value is used for character storage. */
private final char value[];
/** The offset is the first index of the storage that is used. */
private final int offset;
/** The count is the number of characters in the String. */
private final int count;
1
2
3
4
5
6
7
8
三者区别
String 类型和 StringBuffer 的主要性能区别:String 是不可变的对象, 因此在每次对 String 类型进行改
变的时候,都会生成一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符
串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以
后, JVM 的 GC 就会开始工作,性能就会降低。
使用 StringBuffer 类时,每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象
引用。所以多数情况下推荐使用 StringBuffer ,特别是字符串对象经常改变的情况下。
在某些特别情况下, String 对象的字符串拼接其实是被 Java Compiler 编译成了 StringBuffer 对象的拼
接,所以这些时候 String 对象的速度并不会比 StringBuffer 对象慢,例如:
生成 String s1 对象的速度并不比 StringBuffer 慢。其实在 Java Compiler 里,自动做了如下转换:
Java Compiler直接把上述第一条语句编译为:
所以速度很快。但要注意的是,如果拼接的字符串来自另外的 String 对象的话,Java Compiler 就不会
自动转换了,速度也就没那么快了,例如:
这时候,Java Compiler 会规规矩矩的按照原来的方式去做,String 的 concatenation(即+)操作利用
了 StringBuilder(或StringBuffer)的append 方法实现,此时,对于上述情况,若 s2,s3,s4 采用
String 定义,拼接时需要额外创建一个 StringBuffer(或StringBuilder),之后将StringBuffer 转换为
String,若采用 StringBuffer(或StringBuilder),则不需额外创建 StringBuffer。
使用策略
(1)基本原则:如果要操作少量的数据,用String ;单线程操作大量数据,用StringBuilder ;多
线程操作大量数据,用StringBuffer。
(2)不要使用String类的"+"来进行频繁的拼接,因为那样的性能极差的,应该使用StringBuffer或
StringBuilder类,这在Java的优化上是一条比较重要的原则。例如:
String s1 = “This is only a” + “ simple” + “ test”;
StringBuffer Sb = new StringBuilder(“This is only a”).append(“
simple”).append(“ test”);
1
2
String s1 = “This is only a simple test”; 1
String s2 = “This is only a”;
String s3 = “ simple”;
String s4 = “ test”;
String s1 = s2 + s3 + s4;
1
2
3
4
String result = "";
for (String s : hugeArray) {
result = result + s;
}
// 使用StringBuilder
StringBuilder sb = new StringBuilder();
for (String s : hugeArray) {
sb.append(s);
}
String result = sb.toString();
1
2
3
4
5
6
7
8
9
10
11
当出现上面的情况时,显然我们要采用第二种方法,因为第一种方法,每次循环都会创建一个
String result用于保存结果,除此之外二者基本相同(对于jdk1.5及之后版本)。
(3)为了获得更好的性能,在构造 StringBuffer 或 StringBuilder 时应尽可能指定它们的容量。
当然,如果你操作的字符串长度(length)不超过 16 个字符就不用了,当不指定容量
(capacity)时默认构造一个容量为16的对象。不指定容量会显著降低性能。
(4)StringBuilder 一般使用在方法内部来完成类似 + 功能,因为是线程不安全的,所以用完以后
可以丢弃。StringBuffer 主要用在全局变量中。
(5)相同情况下使用 StringBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提
升,但却要冒多线程不安全的风险。而在现实的模块化编程中,负责某一模块的程序员不一定能清
晰地判断该模块是否会放入多线程的环境中运行,因此:除非确定系统的瓶颈是在 StringBuffer
上,并且确定你的模块不会运行在多线程模式下,才可以采用 StringBuilder;否则还是用
StringBuffer。
final, finally, finalize的区别
final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。
内部类要访问局部变量,局部变量必须定义成final类型。
finally是异常处理语句结构的一部分,表示总是执行。
finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法
提供垃圾收集时的其他资源回收,例如关闭文件等。JVM不保证此方法总被调用。finalize()方法中一般
用于释放非 Java 资源(如打开的文件资源、数据库连接等),或是调用非Java方法(native方法)时分
配的内存(比如 C 语言的 malloc()系列函数)。
避免使用的原因:
首先,由于 finalize()方法的调用时机具有不确定性,从一个对象变得不可到达开始,到 finalize()方法
被执行,所花费的时间这段时间是任意长的。我们并不能依赖 finalize()方法能 及时的回收占用的资源,
可能出现的情况是在我们耗尽资源之前,gc 却仍未触发,因而通常的做法是提供显示的 close()方法供客
户端手动调用。另外,重写 finalize()方法意味着延长了回收对象时需要进行更多的操作,从而延长了对
象回收的时间。
Java中finally语句块的深度解析(try catch finally的执行顺序)
1、除了以下2种情况外,不管有木有出现异常,finally块中代码都会执行;
①程序未进入try{}块的执行,如在try之前出现运行时异常,程序终止。
②程序进入到try{}和catch{}块的执行,但是在try{}或者catch{}块碰到了System.exit(0)语句,jvm直接
退出。 finally{}块不会执行
2、当try和catch中有return时,finally仍然会执行;
3、finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值
的引用地址保存起来,而不管finally中的代码怎么样,最后返回的都是这个引用地址(或者说这个引用
地址指向的对象),而这个返回值在finally中会不会被改变要分以下2种情况)。
①若这个返回值是基本数据类型(int,double)或者不可变类对象(如String,Integer),则不管
finally中的代码怎么样,返回的值都不会改变,仍然是之前保存的值,
②若这个值是可变类对象,返回值会被改变。
所以函数返回值是在finally执行前确定的;
4、finally中最好不要包含return,否则程序会提前退出,返回值不是try或catch中保存的返回值,而
是finally中的return值。