第一章 Java基础知识
Java基础概念
1.Java语言有哪些优点
- Java是纯面向对象的语言
- 平台无关性
- Java提供了很多内置的类库
2.为什么需要public static void main (String [] args) 这个方法
main方法是Java程序的入口方法,JVM在运行程序时,会首先找main()方法。而且它还只认且必须有public与static修饰,返回值是void,方法名是main,传递参数为字符串数组。
补充:
这里的static可以这样理解:static表名main()方法是一个静态变量,即方法中的代码是存储在静态存储区的,只要类被加载后,就可以使用该方法而不需要通过实例化对象来访问,可以直接通过类名.main()直接访问。
字符串数组参数args为开发人员在命令行状态下与程序交互提供了一种手段。
注:main()方法是否还有其他可用的定义格式?
1.public与static无先后顺序
2.可以将main方法定义为final(因为不会去覆盖main方法)
3.可以用synchronized来修饰main方法
注:main方法作为程序的入口方法,因此不能用abstract关键字来修饰。
注:java中为什么不允许使用final和abstract同时修饰一个方法
final方法不允许被子类重写,而abstract方法必须被子类重写
3.如何实现在main()方法执行前输出“Hello World”
由于静态块在类被加载时就会被调用,因此可以再main()方法执行前,利用静态块实现输出"Hello World"的功能。而且静态块可以放在任何位置都会先于main方法执行,不一定是放在main方法前面。
4.Java程序初始化的顺序是怎样的
在Java语言中,当实例化对象时,对象所在类的所有成员变量首先要进行初始化,只有当所有类成员完成初始化后,才会调用对象所在类的构造函数创建对象。Java程序初始化一般遵循3个原则:1.静态对象(变量)优先于非静态对象(变量)初始化,其中,静态对象(变量)只初始化一次,而非静态对象(变量)可能会初始化多次。2.父类优先于子类进行初始化。3.按照成员变量的定义顺序进行初始化。即使变量定义散布于方法定义之中,它们依然在任何方法(包括构造函数)被调用之前先初始化。
Java程序初始化工作可以在许多不同的代码块中完成(例如静态代码块、构造函数等),它们执行的顺序如下:父类静态变量、父类静态代码块、子类静态变量、子类静态代码块、父类非静态变量、父类非静态代码块、父类构造函数、子类非静态变量、子类非静态代码块、子类构造函数。
5.Java中的作用域有哪些
在Java语言中,变量的类型主要有3种:成员变量、静态变量和局部变量(类中方法体内定义的变量)。类的成员变量的作用范围与类的实例化对象的作用范围相同,当类被实例化时,成员变量就会在内存中分配空间并初始化,知道这个被实例化对象的声明周期结束时,成员变量的生命周期才结束。被sattic修饰的成员变量被称为静态变量或全局变量,与成员变量不同的是,静态变量不依赖于特定的实例,而是被所有实例所共享,也就是说,只要一个类被加载,JVM就会给类的静态变量分配存储空间。因此,就可以通过类名和变量名来访问静态变量。局部变量的作用域与可见性为它所在的花括号内。
此外,成员变量也有4中作用域:
作用域与可见性 | 当前类 | 同一package | 子类 | 其他package |
---|---|---|---|---|
public | √ | √ | √ | √ |
private | √ | × | × | × |
protected | √ | √ | √ | × |
default | √ | √ | × | × |
private表明该成员变量或方法是私有的,只有当前类对其具有访问权限,除此之外的其他类或者对象没有访问权限
protected表明成员变量或方法对该类自身,与它在同一个包中的其他类,在其他包中的该类的子类都可见。
default表明该成员变量或方法只有自己和与其位于同一包中的类可见。若父类与子类位于同一个包内,则子类对父类的default成员变量或方法都有访问权限;若父类与子类位于不同的package(包)内,则没有访问权限
需要注意的是,这些修饰符只能修饰成员变量,不能用来修饰局部变量。private与protected不能用来修饰类(只有public、abstract或final能用来修饰类)
6.一个Java文件中是否可以定义多个类
一个Java文件中可以定义多个类,但是最多只能有一个类被public修饰,并且这个类的类名与文件名必须相同,若这个文件中没有public的类,则文件名随便是一个类的名字即可。
补充:
main方法其实不一定要写在public类中,只是我们习惯这么写,还有exclipse执行时会默认在public类中找main方法,找不到就会报错。但是我们可以人为的让exclipse在我们指定的类中(不一定是public)寻找main方法
7.什么是构造函数
构造函数的主要作用是完成对象的初始化工作,即在对象初始化时初始化对象的成员变量。构造函数总是伴随着new操作一起调用,且不能由程序的编写者直接调用,必须要由系统调用(构造函数只能通过new自动调用)。构造函数在对象实例化时会自动调用,且只运行一次;而普通的方法是在程序执行到它时被调用,且可以被该对象调用多次。
注:普通方法是可以与构造函数有相同的方法名的!
8.为什么Java中有些接口没有任何方法
在Java语言中,有些接口内部没有任何方法,也就是说,实现这些接口的类不需要重写任何方法,这些没有任何方法声明的接口又被叫做标识接口,标识接口对实现它的类没有任何语义上的要求,它仅仅充当一个标识的作用,用来表明实现它的类术语一个特定的类型。这个标签类似于汽车的标志图标,每当人们看到一个汽车的标志图标时,就能知道这款汽车的品牌。Java类库中已存在的标识接口又Cloneable和Serializable等。在使用时会经常用instanceof来判断实例对象的类型是否实现了一个给定的标识接口。
9.Java中的clone方法有什么作用
在实际变成中,会遇到从某个已有的对象A创建出另外一个与A具有相同状态的对象B,并且对B的修改不会影响到A的状态。
补充:Java中的所有类默认都继承自Object类,而Object类中提供了一个clone()方法。这个方法的作用是返回一个Object对象的复制。这个复制函数返回的是一个新的对象而不是一个引用。
10.什么是反射机制
反射机制允许程序在运行根据指定的类名获得类的信息。反射机制提供的功能主要有:得到一个对象所属的类;获取一个类的所有成员变量和方法;在运行时创建对象;在运行时调用对象的方法。
在反射机制中,Class是一个非常重要的类,那么如何才能获取Class类呢?总共有如下3种方法
- Class.forName(“类的路径”)
- 类名.Class
- 实例.getClass()
常见笔试题:
Java创建对象的方式有几种(4种)
- 通过new语句实例化一个对象
- 通过反射机制创建对象
- 通过clone()方法创建一个对象
- 通过反序列化的方式创建对象(在什么是序列化时可以讲)
11.package有什么作用
包的宗旨是把.java文件(Java源文件)、.class文件(编译后的文件)以及气体resource文件(如.xml文件、avi文件、.mp3文件、.txt文件等)有条理地进行组织,以供使用。
Package主要有一下两个作用:1.提供多层命名空间,解决命名冲突,通过使用package,使得处于不同package中的类可以存在相同的名字。2.对类按功能进行分类,使项目的组织更加清晰。
面向对象技术
1.什么是继承
1.为什么需要继承(好处):提高代码的重用性;提高程序的扩展性
2.为什么不支持多继承:因为多个父类中有相同的成员,会产生调用的不确定性。
3.什么时候使用继承:当类与类之间存在所属关系时,就使用继承。
继承的主要特性:
1.java不支持多继承,即子类最多只能有一个父类,但是可以通过实现多个接口来达到多重继承的目的。
2.子类只能继承父类的非私有(public与producted)成员变量与方法。
3.当子类中定义的成员变量和父类中定义的成员变量相同时或子类中定义的方法和父类中定义方法有相同的方法名和相同的参数个数与类型时,子类将会覆盖父类的方法,而不会继承。
2.组合和继承有什么区别
组合和继承是面向对象中两种代码复用的方式。组合是指在新类里面创建原有类的对象,重复利用已有类的功能。继承是面向对象的主要特性之一,它允许设计人员根据其它类的实现来定义一个类的实现。
如果是is-a关系,就用继承;如果是has-a关系,就用组合。如Vehicle、Car和Tire。
补充:
组合和继承都允许在新的类中设置子对象,只是组合是显示的,继承是隐式的。组合和继承存在着对应关系:组合中的整体类和继承中的子类对应,组合中的局部类和继承中的父类对应。
3.多态的实现机制是什么
Java中提供了哪两种用于多态的机制?
编译时多态和运行时多态。编译时多态是通过方法的重载实现的,运行时多态是通过方法的覆盖(子类覆盖父类方法)实现的。
注:只有类中的方法才有多态的概念,类中成员变量没有多态的概念。成员变量是无法实现多态的,成员变量的值取父亲还是子类并不取决于创建对象的类型,而是取决于所定义变量的类型,这是在编译期间确定的。
如果在编译时能够确定执行多态方法中的哪一个,称为编译时多态,否则称为运行时多态。
方法重载都是编译时多态。
4.重载和覆盖有什么区别
1.重载是在同一类中方法之间的关系,是。水平关系。不同的函数使用相同的函数名,但是函数的参数个数、类型或参数顺序不同。调用时根据函数的参数来区分不同的函数。
2.重载对于访问权限、返回值类型和抛出的异常没有要求,可以相同,可以不同。
3.覆盖是子类与父类之间的关系,是垂直关系与父类同名同参,返回值类型相同。父类被覆盖的方法不能为private,否则其子类只是定义了一个方法,并没有对其覆盖。此外重写要求子类比父类抛出更少的异常。并且子类方法的权限大于等于父类的(父类不能为private)
5.抽象类(abstract class)与接口(interface)有什么异同
抽象类与接口是java语言中对抽象概念进行定义的两种机制。它们两者之间对抽象概念的支持有很大的相似,甚至可以互换,但是也有区别。
相同点:1.都不能被实例化。2.接口的实现类或抽象类的子类都只有实现了接口或抽象类中的方法后才能被实例化。
不同点:从语法上说1.一个类可以实现多个接口,但一个类只能继承一个抽象类,因此使用接口可以间接地达到多重继承的目的。
从设计层次上说2.对于抽象类而言,它是自下而上来设计的,我们需要知道子类才能抽象出父类,而接口不同,它根本不需要知道子类的存在,只是要定义一个规则即可,至于什么子类,什么时候实现它一概不知。3.接口设计理念是has-a关系,而抽象类设计理念是is-a关系。
1.“is-a”是继承的关系,比如人是动物,人和动物是继承的关系;
2.“has-a”是聚合的关系,比如人有眼睛,人和眼睛是聚合的关系;
3.如果一个类继承自另一个类,那么它们是“is-a”的关系,如果一个类的成员中引用了另一个类,那么它们是“has-a”的关系
8.内部类有哪些
内部类可以分为很多种:主要有以下四种:成员内部类、静态内部类、局部内部类和匿名内部类。
class outerClass {
static class innerClass{} //静态内部类
}
class outerClass {
class innerClass{} //静态内部类
}
class outerClass {
public void menberFunction() {
class innerClass{} //局部内部类
}
}
class
静态内部类不依赖于外部类实例而被实例化,而通常的内部类需要再外部类实例化后才能实例化。静态内部类只能访问外部类的静态成员和静态方法(包括私有类型)。
成员内部类只有在外部类实例化后,才能实例化。它可以自由地引用外部类的属性和方法,无论这些属性和方法是静态的还是非静态的。特别注意的是:由于它和一个实例绑定在了一起,不可以定义静态的属性和方法。
局部内部类是定义在一个代码块内的类,它的作用范围为其所在的代码块,是内部类中最少使用到的一种类型。局部内部类像局部变量一样,不能被public、protected、private以及static修饰。只能访问方法中定义为final类型的局部变量。(使用很少)
匿名内部类是一种没有类名的内部类,不能使用关键字class,extends、implements,没有构造函数,它必须继承其他类或实现其他接口。1:匿名内部类不能有构造函数;2:匿名内部类不能定义静态成员、方法和类;3.只能创建一个匿名内部类的一个实例;4.一个匿名内部类一定是在new的后面,这个匿名内部类必须继承一个父类或实现一个接口。
9.如何获取父类的类名
Java语言提供了获取类名的方法:getClass.getName(),我们可以以此来获取类名。
public class Test {
public void test() {
System.out.println(this.getClass.getName());
}
public static void main(String[] args) {
new Test().test(); //返回值是Test
}
}
class A{}
public class Test extends A{
public void test() {
System.out.println(super.getClass.getName());
}
public static void main(String[] args) {
new Test().test(); //返回值还是Test
}
}
为什么会这样?因为Java语言中任何类都继承自Object,getClass()方法在Object类中定义为final与native,子类不能覆盖这个方法,而这个方法的释义是:返回此Object的运行时类。由于上面运行时类是Test,而不是A,所有才这样。那么该怎么办呢?利用Java反射机制。
class A{}
public class Test extends A{
public void test() {
System.out.println(this.getClass.getSuperclass().getName());
}
public static void main(String[] args) {
new Test().test(); //返回值还是A
}
}
10.this与super有什么区别
1.在堆中的每一个java对象上都有this,this保存内存地址指向自身。this可以用于成员方法中,它的一个非常重要的作用就是用来区分对象的成员变量与方法的形参(当一个方法的形参与成员变量的名字相同时,就会覆盖成员变量)。
2.this(实参)用于通过一个构造方法去调用另一个构造方法,必须出现在构造方法的第一行。
注意:this不能用在静态方法中,因为静态方法的执行不需要java对象的存在,直接是类名.的方式访问。静态方法先于对象存在的。
3.super用来访问父类的方法或者成员变量。当子类的方法或成员变量与父类有相同名字时也会覆盖父类的方法或成员变量,要想访问父类的方法或者成员变量只能通过super关键字访问。
4.super(实参)用于通过子类的构造方法去调用父类的构造方法。而且必须放在第一行(因此this(…)与super(…))不能共存。一个构造方法第一行如果没有this(…),也没有显示的去调用super(…),系统会默认调用super(…)。
4.3 关键字
1.变量命名有哪些规则
在Java语言中,变量名、函数名、数组名统称为标识符,标识符只能由字母、数字、下划线和$组成,并且标识符第一个字符不能是数字。此外标识符区分大小写,不能使用关键字。
2. final、finally和finalize有什么区别
final用于声明属性、方法和类,分别表示属性不可变、方法不可覆盖和类不可被继承
finally作为异常处理的一部分,它只能用在try/catch语句中,并且附带一个语句块,表示这段语句最终一定被执行。经常被用在需要释放资源的情况下。
finalize是Object类的一个方法,在垃圾回收器执行时会调用被回收对象的finalize()方法,可以覆盖该方法实现对其他资源的回收,例如关闭文件等。需要注意的是,一旦垃圾回收器准备好释放对象占用的空间,将首先调用其finalize()方法,并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。
3.assert有什么作用
虽然assert的功能与if判断类似,通常在程序开发和测试时使用。为了提高程序运行的效率,在软件发布后,assert检查默认是被关闭的。但二者存在本质的区别:assert一般在调试程序时使用,但如果不小心用assert来控制了程序的业务流程,那在调试结束后去掉assert就意味着修改了程序的正常逻辑,这样的做法非常危险;而if判断本身就是用以控制程序流程的。
4.static关键字有哪些作用
static关键字是希望某个方法或属性与类而不是对象关联在一起,也就是说再没有兑现给定情况下,就可以使用这些方法或属性。
1.static 成员变量;2.static 成员方法;3.static 代码块(静态代码块,可以初始化);4.static 内部类:Static内部类不依赖于外部类实例对象而被实例化,而通常的内部类需要再外部类实例化后才能实例化。静态内部类不能与外部类的类名相同,不能访问外部类的普通成员变量,只能访问外部类的静态变量和静态方法。只有内部类才能被定义为static。
5.使用switch时有哪些注意事项
在使用switch(expr)时,expr只能是一个枚举常量(不能是变量)(只能是整形或字符类型)或一个整数表达式,其中整数表达式可以是基本类型或其对应的包装类Integer,当然也可以是不同长度的整形(short、byte、char)。但不能是long、float、double。Case语句之后可以是直接的常量数值也可以是一个常量计算式,不能是变量。
Java7后,switch开始支持String类型,其实质还是调用hashCode()函数,比较数值。因此switch和case后不能为null。
6.volatile有什么作用
在Java语言中,优势为了提高程序的运行效率,编译器会自动对其进行优化,把经常访问的变量缓存起来,程序在读取这个变量时有可能会从缓存(例如寄存器)中读取,而不会去缓存中读取。这样可以提高运行效率。但当遇到多线程编程时,变量的值可能因为别的线程而改变了,而该缓存的值不会响应改变,从而造成应用程序和实际的变量值不一致。
这时候volatile这个关键字就出现了,它是被设计用来修饰被不同线程访问和修改的变量。被volatile类型定义的变量,系统每次用到它时都是直接从对应的内存当中提取,而不会利用缓存。因此在使用了volatile修饰成员变量后,所有线程在任何时候看到变量的值都是相同的。
public calss MyThread implements Runnable {
private volatile Boolean flag;
public void stop() {
flag = false;
}
public void run() {
while (flag)
;//do something
}
}
以上代码是用来停止线程最常用的一种方法,如果boolean类型的变量flag没有被声明为volatile,那么,当这个贤臣给定run方法在判断flag值时,使用的有可能是缓存中的值,此时就不能及时获取其他线程对flag所做的操作,因此会导致线程不能及时停止。
7.instanceof有什么作用
instanceof:它的作用是判断其左边对象是否为其右边类的实例,返回的是boolean类型的数据。用它来判断某个对象是否是某个Class类(或接口、抽象类、父类)的实例。
用法:
boolean result = object instanceof class;
public static void main(Stringp[] args) {
String s = "Hello";
int[] a = {1, 2};
if(s instanceof String) { //√
System.out.println("true");
}
if(s instanceof Object) { //√
System.out.println("true");
}
if(a instanceof int[]) { //√
System.out.println("true");
}
}
8.strictfp有什么作用
关键字strictfp是strict float point的缩写,指的是精确浮点,它用来确保浮点数运算的准确性。JVM在执行浮点数运算时,如果没有指定strictfp关键字,此时计算结果可能会不精确,而且计算结果在不同平台或厂商的虚拟机上会有不同的结果,导致意想不到的错误。而一旦用了strictfp来声明的一个类、接口或者方法,那么在所声明的范围内,浮点数计算会根据一定标准来操作,保证了再不同平台上会有一致的结果。
基本类型与运算
1.Java提供了哪些基本数据类型
补充:
注:Java中的数据类型都是有符号的,它们的取值范围也是固定的,不随硬件环境或操作系统的改变而改变。
注:Java语言中,默认声明的小数是double类型的,因此在对float类型的变量进行初始化时需要进行类型转换。float类型初始化有两种方式。float f = 1.0f或float f = (float)1.0。与此类似的是,直接写的整形数字是int类型的,如果在给数据类型为long的变量直接赋值时,int类型的值无法表示一个非常大的数字,因此,要写成long l = 2601246523144L。
题2:如何如何理解赋值语句String x = null?
在Java语言中,变量被分为两大类型:原始值与引用值。
题3:赋值语句float f = 3.4是否正确?不正确
题4:原始类型与封装类型的区别?
首先,原始数据类型在传递参数时都是按值传递,而封装类型是按引用传递的。其次,它们默认值不同,封装类型是null,而基本数据类型与类型有关,如int是0。
2.什么是不可变类
不可变类是指当创建这个类的实例后,就不允许修改它的值了。它有点类似于常量,即只允许别的程序读,不允许别的程序进行修改。在Java类库中,所有基本类型的包装类都是不可变类,例如Integer、Float等。此外,String也是不可变类。
不可变类创建规则…
3.值传递与引用传递有哪些区别
方法调用时编程语言中非常重要的一个特性,在方法调用时,通常需要传递一些参数来完成特定的功能。Java语言提供了两种参数传递的方式:值传递和引用传递。
- 值传递:在方法调用中,实参会把它的值传递给形参,形参只是用实参的值初始化一个临时的存储单元,因此形参与实参虽然有着相同的值,但是却有着不同的存储单元,因此对形参的改变不会影响实参的值。
- 引用传递:在方法调用中,传递的是对象(也可以看做是对象的地址),这时形参与实参的对象指向同一块存储单元,因此对形参的修改就会影响实参的值。
注:Java中处理8种基本的数据类型用的是值传递,其他说有类型都用的是引用传递,由于这8中基本数据类型的包装类型都是不可变量,因此增加了对“按引用传递”的理解难度。
Integer a = 1;
Integer b = a;
b++;
//此时a为1,b为2
对于上面程序输出1,和2,可能我们会错误的认为Integer是按值传递的而不是按引用传递的,其实这是一个理解上的误区,上述代码还是按引用传递的,只是由于Integer是不可变类,因此没有提供改变它值的方法,在上例中,在执行b++后,由于Integer是不可变类,因此此时会创建一个新值为2的Integer赋值给b,此时b与a其实已经没有任何关系了。
4.Math类中round、ceil和floor方法的功能各是什么
round、ceil和floor方法位于Math类中,Math是一个包含了很多数学常量与计算方法的类,位于java.lang包下,能自动导入,而且Math类里边的方法全是静态方法。
1.round方法表示四舍五入。其实现原理是在原来数字的基础上线增加0.5然后再向下取证,等同于(int)Math.floor(x+0.5f)。它的返回值类型是int型。
2.ceil功能是向上取整。返回值是double型。若a是整数,则把小数“入”,若a是负数,则把小数“舍”。即把数字变大。
3.floor方法是向下取整。返回值也是double型。若a是整数,则舍弃小数部分,a是负数,则把小数“入”。即把数字变小。
Math.round(11.5)等于多少?Math.round(-11.5)等于多少?
答:12,-11。
5.如何实现无符号数的右移操作
Java提供了两种右移运算符:“>>”和“>>>”。其中前者称为有符号右移运算符,后者被称为无符号右移运算符,它们的功能是将参与运算的对象对应的二进制数右移指定的位数。二者的不同点在于“>>”在执行右移操作时,若参与运算的数字为正数,则在高位补0;若为负数,则在高位补1.而“>>>”则不同,无论参与运算的数字为正数或为负数,在执行运算时,都会在高位补0。
此外,需要特别注意的是,在对char、byte、short等类型的数进行移位操作前,编译器都会自动地将数值转化为int类型,然后才进行移位操作。由于int类型占4个Byte(32bit),因此当右移超过32bit时,是无意义的。所有Java为了保证右移的有效性,以使右移的位数不超过32bit,采用了取余的操作,即a>>n等价于a>>(n%32)。
左移操作只有有符号左移这一种,移动后补0。也会进行取余运算a<<n等价于a<<(n%32)
6.char型变量中是否可以存储一个中文汉字
Java语言中,默认使用的Unicode编码方式,即每个字符占用两个字节,因此可以用来存储中文。每个中文字符占用2Byte,每个英文字符占用1Byte。因此可以。
如何判断一个字符串中是否含有中文?并找出中文????
str.length() == str.getBytes().length ? 不含:含有中文字符
字符串与数组
1.字符串创建与存储的机制是什么
1.String s1 = “abc”; //在常量区里面存放一个”abc”字符串对象,在编译时发生
2.String s2 = “abc”; //s2引用常量区中的对象,因此不会创建新的对象,在编译时
3.String s3 = new String(“abc”); //在堆中创建新的对象,运行时发生
4.String s4 = new String(“abc”); //在堆中又创建一个新的对象,运行时发生
- 对于String类型的变量s,赋值语句s=null与s=””是否相同?
不相同:s是String类型的变量,=号把后面的东西赋给这个变量,即将字符串的引用赋给s,那么s就是一个字符串类型的引用。前一个不指向任何字符串,后一个指向空字符串。 - new String(“abc”)创建了几个对象?
答:一个或两个。如果常量池中原来有”abc”,那么只创建一个对象;如果常量池中原来没有字符串”abc”,那么久会创建两个对象。
2." == "、equals和hashCode有什么区别
1.= =
Java中的数据类型可以分为两类:基本数据类型即原始数据类型和引用数据类型。对于8种基本数据类型的比较,应该使用= =,比较的是他们的值。对于引用类型(类、接口、数组)使用= =号比较的是他们在内存中存放的地址,所以除非是同一个new出来的对象,否则为false。对象是存放在堆中的,栈中存放的是对象的引用(地址)。由此可见“==”是对栈中的值进行比较的。如果要比较堆中对象的内容是否相同,那么就要重写equals()方法了。
2.equals
默认情况下(没有覆盖equals方法)下equals方法调用的是Object类中的equals方法,而Object的equals方法主要用于判断对象的内存地址引用是不是同一个地址(此时和= =作用完全相同,只是equals是方法,得由对象引用调用)。要是覆盖了equals方法,那么就要根据具体的代码来确定equals方法的作用了。
3.hashCode
hashCode()方法是从Object类中继承过来的,它也用来鉴定两个对象是否相等。Object类中的hashCode()方法返回对象在内存中地址转换成的一个int值,所以如果没有重写hashCode()方法,任何对象的hashCode()方法都是不相等的。
hashCode()方法的返回值和equals()的关系如下:如果x.equals(y)返回true,即两个对象根据equals方法比较是相等的,那么hashCode()方法必须相等(即这两个对象调用hashCode方法产生同样的整数结果,也就是说重写equals就必须重写hashCode方法)。如果x.equals(y)返回false,即连个对象根据equals()方法比较是不相等的,那么x和y的hashCode()方法的返回值有可能相等,有可能不相等。反之如果hashCode()方法的返回值不相等,一定能推出equals()方法的返回值也不相等,而hashCode()方法的返回值相等,equals方法的返回值则可能相等,可能不相等。
下面内容作为了解:
一般覆盖equals()方法的同时也要覆盖hashCode()方法,否则,就会违反Object.hashCode的通用约定,从而导致该类无法与所有基于散列值(hash)的集合类(HashMap、HashSet和Hashtable)结合在一起正常运行。
一般讲来,equals()方法是给用户调用的,如果判断两个对象是否相等,可以重写equals()方法,然后再代码中调用,这样就可以判断它们是否相等了。对于hashCode()方法,用户一般不会去调用它,例如在hashmap中,由于key是不可以重复的,它在判断key是否重复时就判断了hashCode()这个方法,而且也用到了equals()方法。此外“不可重复”指的是equals()和hashCode()只要有一个不等就可以了。
//Object类中的equals方法
boolean equals(Object o) {
return this == o;
}
3.String、StringBuffer、StringBuilder和StringTokenizer有什么区别
1.String是不可变类,也就是说,String对象一旦被创建,其值将不能被改变,而StringBuffer是可变类,也就是对象创建后仍然可以对其值进行修改。因此,String适合在需要被共享的场合使用,而当一个字符串经常需要被修改时,使用StringBuffer。
2.另一个区别是String可以用构造函数(String s1 = new String(“world”))的方式初始化也可以用赋值(String s1 = “hello”)的方式初始化。而StringBuffer只能使用构造方法(StringBuffer s1 = new StringBuffer(“world”))的方式初始化。
StringBuilder也是可以被修改的字符串,它与StringBuffer类似,但是StringBuilder不是线程安全的。
在执行效率方面,StringBuilder最高,StringBuffer次之,String最低,鉴于此,如果操作的数据量小,优先使用String类;如果单线程下操作大量数据,优先使用StringBuilder类;如果是在多线程下操作大量数据,优先考虑StringBuffer类。
4.Java中数组是不是对象
Java中,数组不仅有其自己的属性(length属性),也有一些方法(clone方法),可以用instanceof来判断数组的类型。从这个角度说数组是对象。
5.length属性与length()方法有什么区别
数组提供了length属性可以获得数组长度。
length()方法是针对字符串而言的,String()提供了length()方法来计算字符串的长度。
除了数组的length属性和字符串的length()方法外,Java中还有一个计算大小的方法-size()方法,该方法是针对泛型集合而言的,用于查看泛型中有多少个元素。
异常处理
1.Error和exception有什么区别
Java异常结构中,实际上有两个最常用的类:Exception、Erro,这两个类全是Throwable的子类。
Exception表示表示程序需要捕捉、需要处理的异常,是由与程序设计的不完善而出现的问题,程序必须处理的问题。
Error表示系统级的错误,是java运行环境内部错误或者硬件问题,不能指望程序来处理这样的问题,除了退出运行外别无选择,它是Java虚拟机抛出的。
2.finally块中的代码什么时候被执行
正常情况下,finally语句肯定是要执行的,在try-catch之后。
问题:如果try里面有一个return语句,那么紧跟在这个try后的finally中的代码时候回执行?如果执行的话,在return之前还是return之后?
会执行,在return之前。在执行finally代码块中的内容时,会先将try里面的return语句的变量复制一份(值传递和引用传递的区别)。然后执行后面的finally语句,最后执行return语句(如果在finally语句里面对上面返回的便令进行修改,如果值传递不影响,引用传递则会影响)。
此外,如果try-finally或者catch-finally中都有return,那么finally块中的return语句将会覆盖别处的return语句,最终返回到调用者那里的是finally中的return的值。
问题:Java程序中的finally块是不是一定会被执行?
不一定会。1:如果在进入try语句块之前六出现了异常时,会直接结束,不会执行finally块中的代码;2.当程序在try块中强制退出时也不会去执行finally块中的代码。(System.exit(0))。
3.异常处理的原理是什么
异常是指程序运行时(非编译时)所发生的非正常情况或错误,当程序违反了语义规则时,JVM就会将出现的错误表示为一个异常抛出。这个异常可以再catch程序块中进行捕获,然后进行处理。
违反语义规则包括两种情况:一种是Java类库内置的语义检查,例如当数组下标越界时,会引发IndexOutOfBoundsException,当访问null的对象时,会引发NullPointerException;另外一种情况是Java允许开发人员扩展这种语义检查,开发人员可以创建自己的异常类(所有异常都是java.lang.Throwable的子类),并自由选择何时用throw关键字抛出异常。
补充:
Java语言把异常当做对象来处理,并定义了一个基类(java.lang.Throwable)作为所有异常的父类。在Java API中,已经定义了许多异常类,这些异常类分别为Error和Exception两大类。
4.运行时异常和普通异常有什么区别
Exception表示可恢复的异常,是编译器可以捕捉到的。它包含两种类型:检查异常(checked exception)和运行时异常(runtime exception)。
检查异常是在程序中最经常碰到的异常。所有继承自Exception并且不是运行时异常的异常都是检查异常,比如最常见的IO异常和SQL异常。这种异常都发生在编译阶段,Java编译器强制程序去捕获此类型的异常,即把可能会出现这些异常的代码放到try块中,把对异常的处理的代码方法哦catch块中。
运行时异常不同于检查异常,编译器没有强制对其进行捕获并处理。如果不对这种异常进行处理,当出现这种异常时,会由JVM处理,例如空指针异常,类型转换异常,数组越界异常,缓冲区溢出异常、算术异常等。
5.你平时在项目中是怎样对异常进行处理的
对于检查异常都是进行捕获处理,处理时在catch代码块中对异常信息进行记录,通常是调用异常类的相关方法获取到异常的相关信息。
对于运行时异常,应该尽量避免,比如空指针异常,在使用对象之前看看是否需要判断一下该对象是否为空。如果需要,及时作出判断。
4.7 输入输出流
1.Java中有几种类型的流
常见的流有两种,分别为字节流与字符流。字节流以字节(8bit)为单位,包括两个抽象类:InputStream(输入流)和OutputStream(输出流)。字符流以字符(16bit)为单位,根据码表映射字符,一次可以读多个字节,它包含两个抽象类:Reader(输入流)和Writer(输出流)。字节流和字符流最主要的区别为:字节流在处理输入输出时不会用到缓存,而字符流用到了缓存。
其中,字节流继承于InputStream于OutputStream,字符流继承于Reader与Writer。在java.io包中还有许多其他的流,流的作用主要是为了改善程序性能并且使用方便。
2.管理文件和目录的类是什么
对文件或目录进行管理与操作在编程中有着非常重要的作用,Java提供了一个类(File)来管理文件和文件夹,通过类不仅能够查看文件或目录的属性,而且还可以实现对文件或目录的创建、删除与重命名等操作。
方法 | 作用 |
---|---|
File(String pathname) | 根据指定的路径创建一个File对象 |
exists() | 判断对象对应的文件是否存在 |
listFiles() | 若对象代表目录,则返回目录中所有文件的File对象 |
isFile() | 判断这个对象表示的是否是文件 |
isDirectory() | 判断这个对象表示的是否是文件夹 |
createNewFile() | 若目录或文件存在,则返回false,否则创建文件或文件夹 |
mkdir() | 根据当前对象指定的路径创建目录 |
常见面试题:如何列出某个目录下的所有目录和文件?
答案:假设目录“C:\testDir1”下有两个文件夹(dir1和dir2)和一个文件file1.TXT,实现代码如下:
public static void main(String[] args) {
File file = new File("C:\\testDir1");
if (!file.exits()) {
System.out.println("dirctory is empty");
return;
}
File[] fileList = file.listFiles();
for (int i = 0; i < fileList.length; i++) {
//判断是否是目录
if (fileList[i].isDirectory()) {
System.out.println("directory is:" + fileList[i].getName());
} else {
System.out.println("file is:" + fileList[i].getName());
}
}
}
3.Java Socket是什么
网络上的两个程序通过一个双向的通信连接实现数据的交换,这个双向链路的一段成为一个Socket。在Kava语言中,Scoket可以分为两种类型:面向连接的Socket通信协议(TCP)和面向无连接的Socket通信协议(UDP)。任何一个Scoket都是由IP地址和端口号唯一确定的。
基于TCP的通信过程如下:首先,Server(服务器)端Listen(监听)指定的某个端口(建议使用大于1024的端口)是否有连接请求;其次Client(客户)端想Service端发出Connect(连接)请求;最后,Service端想Client端发回Accept(接受)请求。一个连接就简历起来了,会话随即产生。Service端和Client端都可以通过send、write等方法与对方通信。
Socket的生命周期可以分为3个阶段:打开Socket、使用Socket手法数据和关闭Socket。在Java语言中,可以使用ServiceSocket来作为服务器端,Socket作为客户端来实现网络通信。
4.Java NIO是什么
6.System.out.println()方法使用需要注意哪些问题
Java中System.out.println()方法提供了一个非常有效简单的方法来实现控制台的输出,该方法默认接收一个字符串类型的变量作为参数。当然,在使用时可以传递任意能够转换为String类型的变量作为参数(例如基本类型int,或者一个实现toString()方法的自定义类)。
Java平台与内存管理
1.为什么说Java是平台独立性语言
平台独立性是指在一个平台上编写和编译程序,而在其他平台上运行。保证Java语言具有平台独领性的机制为“中间码”和“虚拟机”。Java程序编译后不是生成可以再硬件平台上可执行的代码,而是生成了一个“中间码”。不同硬件平台上安装有不同的JVM,由JVM来负责把“中间码”翻译成硬件平台能执行的代码。
2.JVM加载class文件的原理机制是什么
这个加载过程由类加载器完成,具体而言,就是由ClassLoader和它的子类来实现的。类加载器本身也是一个类,其实质是把类文件从硬盘读取到内存中。
当程勋启动时,只把需要的类加载到JVM中,其他类只有被使用到的时候才会被加载。
在Java语言中,可以把类分为3类:系统类、扩展类和自定义类。针对这三种类提供了3种类型的加载器:系统类加载器、扩展类加载器和应用类加载器。它们是通过双亲委托的方式实现类的加载的。
类加载的主要步骤为:
- 装载:根据查找路径找到相对应的class文件,然后导入。
- 链接:分为三步。
检查:检查代价在的clas文件的正确性
准备:给类的静态变量分配存储空间
解析:将符号引用转换成直接引用(这一步是可选的) - 初始化:对静态变量和静态代码块执行初始化工作。
4.什么是GC
垃圾回收器的主要作用是回收程序中不再使用的内存。具体而言,垃圾回收器要负责完成3项任务:分配内存、确保被引用对象的内存不被错误地回收以及回收不再被引用的对象的内存空间。
对于垃圾回收器来说,它使用又想吐来记录和管理堆内存中的所有对象,通过这个又想吐就可以识别哪些对象是“可达的”(有引用变量引用它就是“可达的”),哪些对象是“不可达的”(没有引用变量引用它就是不可达的),所以“不可达”对象都是可被垃圾回收的。
垃圾回收器是依据一定的算法进行的,下面介绍其中几种常用的垃圾回收算法。
1.引用计数算法
2.追踪回收算法
3.压缩回收算法
4.复制回收算法
5.按代回收算法
5.Java是否存在内存泄漏问题
暂时不会
6.Java中堆和栈有什么区别
栈内存主要用来存放基本数据类型与引用变量。栈内存的管理是通过压栈和弹栈操作来完成的,以栈帧为基本单位来管理程序的调用关系,每当有函数调用时,都会通过压栈方式创建新的栈帧,每当函数调用结束后都会通过弹栈的方式释放栈帧。
堆内存用来存放运行时创建的对象。一般来说,通过new关键字创建出来的对象都存放在堆内存中。由于JVM是基于堆栈的虚拟机,而每个Jav程序都运行在一个单独的JVM实例上,每一个实例唯一对应一个堆,一个Java程序内的多个线程也可以运行在同一个JVM实例上,因此这些线程之间会共享堆内存,鉴于此,多线程在访问堆中的数据时需要对数据进行同步。
容器
1.Java Collections框架是什么
Java Collections框架中包含了大量集合(容器)接口以及这些接口的实现类。具体而言,主要提供了List(列表)、Queue(队列)、Set(集合)、Stack(栈)和Map(映射表,用于存放键值对)等数据结构。其中List、Queue、Set、Stack都继承自Collection接口。
下面分别介绍List、Set和Map这3个接口。
List又称为有序的Collection。它按对象进入的顺序保存对象,所以它能对列表中的每个元素的插入和删除位置进行精确的控制。同时,它可以保存重复的对象。LinkedList、ArrayList和Vector都实现了List接口。
Set表示数学意义上的集合的概念。其最主要的特点是集合中的元素不能重复,因此存入Set的每个元素都必须定义equals()方法来确保对象的唯一性。该接口又两个实现类:HashSet和TreeSet。其中TreeSet实现了SortedSet接口,因此TreeSet容器中的元素都是有序的。
Map提供了一个从键映射到值的数据结构。它用于保存键值对,其中值可以重复,但是键不可重复。Java类库中有多个实现该接口的类:HashMap、TreeMap、LinkedHashMap、WeakHashMap、IdentityHashMap。虽然它们都实现了相同的接口,但智行效率却不是完全相同的。具体而言,HashMap是基于散列表实现的,采用对象的HashCode可以进行快速查询。LinkedHashMap采用列表来维护内部的顺讯。TreeMap基于红黑树的数据结构来实现的,内部元素是按需排列的。
2.什么是迭代器
迭代器是一个对象,它的工作是遍历并选择序列中的对象。由于创建迭代器的代价小,因此迭代器通常被称为轻量级的容器。
迭代器使用说明:
1.使用容器的iterator()方法返回一个Iterator,然后通过Iterator的next()方法返回第一个元素。
2.使用Iterator的hasNext()方法判断容器中是否还有元素,如果有,可以使用next()方法获取下一个元素。
3.可以通过remove()方法删除迭代器返回的元素。
补充:
Iterator只能正想遍历集合,适用于获取移除元素。ListIterator继承自Iterator,只存在于List中,支持在迭代期间想List中添加或删除元素,并且可以在List中双向滚动。
3. ArrayList、Vector和LinkedList有什么区别
ArrayList、Vector、LinkedList类均在java.util包中,均为可伸缩数组,即可以动态改变长度的数组。
ArrayList和Vector,它们会在内存中开辟一块连续的空间来存储,由于数据存储是连续的,因此它们支持用序号(下标)来访问元素,同时索引数据的速度比较快。但是插入、删除元素比较慢。ArrayList和Vector都有一个初始化的容量的大小,当存储元素超过这个大小时会动态扩容。Vector默认扩容为原来的2倍(可改),ArrayList默认扩容是1.5倍(没有提供更改的方法)
ArrayList和Vector的最大区别是synchronization(同步)的使用,没有一个ArrayList的方法是同步的,而Vector的绝大多数方法都是直接或者间接同步的,所以Vector是线程安全的,但因此效率也略逊于ArrayList。
LinkedList是采用双向列表来实现的,因此对于随机访问效率低,但是插入和删除效率高。同时,LinkedList是非线程安全的容器。
因此:如果在实际中主要是索引或者在末端增加、删除元素时,使用ArrayList或Vector效率高。对于指定位置的插入或删除操作时,使用LinkedList效率比较高。在多线程中使用容器(即多个线程会同时访问该容器),选用Vector较为安全。
4. HashMap、Hashtable、TreeMap和WeakHashMap有哪些区别
HashMap是最常用的Map,它根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度。由于HashMap与Hashtable都采用了hash法进行索引,因此具有许多相似之处。它们主要有如下的一些区别:
1.HashMap运行null键,但是最多只能有一个,而Hashtable不允许;
2.HashMap把Hashtable的contains方法去掉了,改成了containsvalue和containsKey。
3.Hashtable是线程安全的,而HashMap如果在多线程中被多个线程访问还要考虑同步机制。
4.Hashtable使用Enumeration,HashMap使用Iterator。
5.Hashtable中,hash数组默认大小是11,增加方式是old×2+1,;HashMap中,hash数组的默认大小是16,而且一定是2的指数。
以上三种map最常用的是HashMap,HashMap里面存入的键值对在取出时是没有固定的顺序,是随机的。一般而言,在Map中插入、删除和定位元素,HashMap是最好的选择。
由于TreeMap实现了SortMap接口,会根据键排序,因此,取出来的是根据键排序的。
LinkedHashMap可以保证输入和输出顺序一致。
WeakHashMap与HashMap类似,二者的曲折的不同之处在于WeakHashMap中key采用的是“弱引用”的方式,只要WeakHashMap中的key不再被外部引用,它就可以被垃圾回收器回收。而HashMap中key采用的是“强引用的方式”,当HashMap中的key没有被外部引用时,只有这个key从HashMap中删除后。才可以被垃圾回收器回收。
常见面试题:
如何实现HashMap的同步?
HashMap可以通过Map m = Collections.synchronizedMap(new HashMap())来达到同步的效果。具体而言,这个方法发挥一个同步的map,该map封装了底层的HashMap的所有方法,使得底层的HashMap即使是在多线程的环境中也是安全的。
5.用自定义类型作为HashMap或Hashtable的key需要注意哪些问题
6.Collection和Collections有什么区别
多线程
1.什么是线程?它与进程有什么区别?
2.同步和异步有什么区别
3.如何实现Java多线程
4.run()方法与start()方法有什么区别
5.多线程同步的实现方法有哪些
6.sleep()方法与wait()方法有什么区别
7.终止线程的方法有哪些
8.synchronized与Lock有什么异同
9.什么是守护线程
10.join()方法的作用是什么
Java数据库操作
1.如何通过JDBC访问数据库
JDBC(Java DataBase Connectivity, IDBC)用于在Java程序中实现数据库操作功能。在JDBC的基本你操作中最常用的类和接口就是DriverManager、Connection、Statement、Result、PreparedStatement。
通过JDBC访问数据库一般有如下步骤:
- 注冊驱动 (仅仅做一次)
- 建立连接(Connection)
- 创建运行SQL的语句(Statement)
- 运行语句
- 处理运行结果(ResultSet)
- 释放资源
可以看下书上的代码
import java.sql.*;
public class demo1 {
public static void main(String[] args) throws Exception {
// 1.加载sql驱动
// 加载驱动,利用反射知识
Class.forName("com.mysql.jdbc.Driver");
try (
/*
* 2.使用DriverManager获取数据库连接 返回的conn代表着java程序和数据库的连接 这里要注意导入的包,
* 这里还是要注意root@localhost和root@'127.0.0.1'是两个不同用户。还有就是账户和密码的问题
* Access denied for user '123'@'localhost' (using password: YES) 就是密码出错
*/
Connection conn = DriverManager.getConnection(
"jdbc:mysql://127.0.0.1:3306/javatrain", "123", "123456");
/*
* 3.使用Connecttion来创建一个Statement对象 Statement对象用来执行SQL语句
*/
Statement stmt = conn.createStatement();
/*
* 4.执行SQL语句
* Statement有三种执行SQL语句的方式
* (1)executeQuery(sql) 执行select语句,返回查询到的结果集
* (2)execute(sql) 可执行任何的SQL语句,返回一个boolean值
* 如果执行第一个结果是ResultSet,返回true,否则返回false
* (3)executeUpdate(sql)执行DML语句,返回一个整数(代表SQL语句影响的行数)
*/
ResultSet rs=stmt.executeQuery("select * from demo1");
)
/*
* java7的特性,可以使用try语句来自动关闭数据库的各种资源
*/
{
//5.操作结果集
/*
* ResultSet就是返回的结果集,get()是获得特定列的值 next是下一行
*/
while (rs.next())
{
System.out.println("姓名为:"+rs.getInt(1)+",密码为:"+rs.getInt(2)+"。");
}
}
}
}
2.JDBC处理事务采用什么方法
采用commit和rollback方法。
一个事务由一条或多条对数据库操作的SQL语句所组成的一个不可分割的工作单元,只有当事务中的所有操作都正常执行完毕了,整个事务才会被提交给数据库。
在JDBC中,一般是通过commit()方法或rollback()方法来结束事务的操作。其中commit()表示完成对事务的提交,rollback()方法表示完成事务回滚,多用于在处理事务的过程中出现了异常的情况
一般情况下,事务默认操作是自动提交,即操作成功后,系统将自动调用commit()方法,否则将调用rollback()方法。
当然,在JDBC中,也可以通过setAutoCommit(false)方法来禁止自动提交,然后就可以把多个数据库操作的表达式作为一个事务,在操作完成后调用commit()方法实现整体提交,如果其中一个表达式操作失败,就会抛出异常,而不会调用commit()方法。在这种情况下,就可以在异常捕获的代码块中调用rollback()方法进行事务回滚。利用这种方法可以保持对数据库的多次操作后,数据仍然保持一致性。
public void updateDate()
{
try {
//设置事务自动提交为false
con.setAutoCommit(false);
stmt.execute("insert into employee values(4,'jim4',30)");
//模拟事务中出现异常情况
int b=1/0;
//若以上事务没有报错,则手动提交事务
con.commit();
} catch (SQLException e) {
try {
//事务有异常,则回滚
con.rollback();
} catch (SQLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
JDBC有哪些事务隔离级别(5种隔离级别)
为了解决于“多个线程请求相同数据”相关的问题,事务之间通常会用锁相互隔离开。JDBC API支持不同类型的事务,它们由Connection对象指派或确定。
①TRANSACTION_NONE_JDB:不支持事务
②TRANSACTION_READ_UNCOMMITTED:未提交读:脏读,不可重复读,虚读都会出现
③TRANSACTION_READ_COMMITTED:已提交读:不可重复读和虚读都会出现
④TRANSACTION_REPEATABLE_READ:可重复读:虚读会出现
⑤TRANSACTION_SERIALIZABLE:可序列化:防止脏读,不可重复读和虚读
脏读:一个事务读取了另一个事务尚未提交的数据。如事务A与事务B并发执行,事务A更新后,事务B查询读取到A尚未提交的数据,此时事务A回滚,则事务B读到的数据是无效的脏数据。
不可重复读:一个事务的操作导致另一个事务前后读取到不同的数据。例如,事务A和B并发执行,当事务B查询读取数据后,事务A更新操作更改事务B查询到的数据,此时事务B再次去读该数据,发生秋垵后两次的数据不一样。
虚读:一个事务的操作导致另一个事务前后两次查询的结果数据量不同。例如。事务A和B并发执行,当事务B查询读取数据后,事务A新增或删除了一条满足事务A的查询条件的记录,此时,事务B再次查询,发现查询到前次不存在的记录,或者前次的某个记录不见了。
事务的隔离级别越高,为避免冲突所化的经理也就越多。可以通过Connection对象的conn.setTransactionLevel()方法来设置隔离界别,通过conn.getTransactionIsolation()方法来确定当前事务的级别。
3.Class.forName的作用是什么
在Java语言中,任何类只有被加载到JVM上才能运行。Class.forName()方法的作用就是把类加载到JVM中,它会返回一个与带有给定字符串名的类或接口相关的Class对象,并且JVM会加载这个类,同时JVM会执行该类的静态代码块。
在JDBC中,这时候的静态代码块有Driver类在使用前必须向DriverManager注册自己(这是JDBC的规范)。
4.Statement、PreparedStatement和CallableStatement有什么区别
Statement用于执行不带参数的简单SQL语句。
PreparedStatement用来执行带参数的简单SQL语句。
相比Statement,PreparedStatement有以下好处
1.安全性更好,有效防止SQL注入攻击问题
2.效率更高,在使用PreparedStatement对象执行SQL命令时,命令会被数据库进行编译和解析,并放到命令缓冲区。然后,每当执行同一个PreparedStatement对象时,由于在缓冲器中可以发现预编译的命令,虽然它会被再解析一次,但不会被再次编译,是可以重复使用的,能够有效提高系统性能。
5.getString()方法与getObject()方法有什么区别
JDBC提供了getString()、getInt()和getData()等方法从ResultSet中获取数据,当查询结果集中的数据量较小时,不用考虑性能,但是当查询结果集中的数据量非常大时,就会抛出异常。
getString()或getInt()等方法在被调用时,程序会一次性地把数据都放到内存中,然后通过调用netx()和gteString()等方法来获取数据。当数据量大到内存中放不下时就会抛出异常,而使用getObject()方法就不会有这种问题,因为数据不会一次性被读到内存中,每次调用时都会直接从数据库中去获取数据,因此使用这种方法不会因为数据量过大而出错。
6.使用JDBC时需要注意哪些问题
1.保证释放不再使用的连接
2.由于与数据库连接是非常重要的资源。我们一般采用数据库连接池进行连接。
7.JDBC与Hibernate有什么区别
Hibernate是JDBC的封装,采用配置文件的形式将数据库的链接参数写到XML文件中,至于对数据库的访问还是通过JDBC来完成的。
Hiberate是一个持久层框架,它将表的信息映射到XML文件中,再从XML文件映射到响应的持久化类中。