第一章
1、谈谈你过去学习编程语言的方法、经验和教训。
大一上学期我学习了c/c++这门课,章英老师讲的很详细,每周练习10道题,感觉大体上是掌握了的,但是部分(比如指针,数组)还是欠缺练习,理解也不是很到位,但是也算是入门了。大一下学期,我学习了python,基本语法掌握以后,老师讲的很深入,后期又缺少练习,感觉对python的掌握很片面。
2、高级语言的编译型和解释型语言的编译执行过程有什么区别?
编译型语言的特点是先编译,后执行。需要通过“编译器”完成编译过程,结果交由CPU执行,依赖于平台。
解释型语言边编译,边执行,通过 “解释器”(Interpreter)完成解释执行的过程。而呈现结果的过程并不需要依赖平台。
3、Java语言都有哪些特点?与C,C++,Python有何不同?
简单安全:语法借鉴C/C++,消除指针,接口代替了多重继承,垃圾自动回收机制,提供了丰富的类库
面向对象:纯面向对象语言,复用,可扩展,可维护
多线程:应用程序在同一时间并发执行多项任务
动态性:动态加载类库,运行时创建对象,适应环境发展
分布性:访问不同网络主机的数据,在不同主机上执行相关操作
跨平台,面向对象
1.c++、java和python都是面向对象的编程语言,但是c++和java都是强类型语言,而python是一种弱类型语言
2.垃圾回收机制:c++需要程序员收到回收,而java和python都有自己的垃圾回收机制GC。具体两者又有不同,python的垃圾收集机制主要是用的是引用计数方式。
3.c和java中变量的存储是真实值,而python总存储的是引用,所以python不用声明类型名称,它的输入均默认为字符串。
4.c++中用const来声明常量,java中使用final来声明,python中没有常量。
4、Java实现跨平台的原理是什么?
通过虚拟机
JDK、JRE、JVM分别是什么的简称,它们之间有何联系?
JVM:英文全称,Java Virtual Machine,是Java虚拟机,用来运行Java程序
JRE:英文全称,Java Runtime Environment,是Java运行时环境,里边包含了Java运行时所需要的类库。
JDK:英文全称,Java Development Kit,是Java开发工具包,里边包含了Java的开发工具。例如java,javac等。
JDK包含了Java的运行环境(即JRE)和Java工具。JRE包含了一个Java虚拟机(JVM)以及一些标准的类别函数库。总的来说,JDK、JRE、JVM三者都处在一个包含关系内,JDK包含JRE,而JRE又包含JVM。
具体地讲:
JDK = JRE + 开发工具集(例如Javac编译工具等)
JRE = JVM + Java SE标准类库
第二章
1、Java包含哪两大类数据类型?其中基本类型的每种类型的取值范围和默认值分别是多少?请编程验证。
基本数据类型和引用数据类型。
2、Java在什么情况下会发生整型溢出?请举例说明,并给出解决方案。
以下是摘自:http://calvin.javaeye.com/blog/91903,对于java内存泄漏的总结
(1)被生命周期极长的集合类不当持有,号称是Java内存泄漏的首因。
这些集合类的生命周期通常极长,而且是一个辅助管理性质的对象,在一个业务事务运行完后,如果没有将某个业务对象主动的从中清除的话,这个集合就会吃越来越多内存.
(2)Scope定义不对,这个很简单了,方法的局部变量定义成类的变量,类的静态变量等。
(3)异常时没有加finally{}来释放某些资源,JDBC时代也是很普遍的事情。
(4)另外一些我了解不深的原因,如:Swing里的Listener没有显式remove;内部类持有外部对象的隐式引用;Finalizers造成关联对象没有被及时清空等。
3、Java基本类型的包装类分别是哪些?其高频去间数缓存范围分别是什么?请选择一种包装类型编程验证其数据缓存特性。
byte → Byte
short → Short
int → Integer
long → Long
float → Float
double → Double
char → Character
boolean→ Boolean
Boolean:使用静态final,就会返回静态值
Byte:-128~127
Short:-128~127
Character:0~127
Long:-128~127
Integer:-128~127
4、什么是自动装箱,什么是自动拆箱,举例说明。
自动装箱: 当我们把一个基本类型的值( 20),赋值给引用变量时候,系统可以 自动将它“包装”为相应的包装类的实例程序需要对象时, 如果给的只是一个基本类型的值, 系统会将它自动装箱为包装类的实例达到的效果: 有了自动装箱之后, 基本类型的值可以当成对象用—— 其实是【假相】 。
自动拆箱: 当我们需要一个基本类型的值时, 但实际上传入的包装类的对象。 系 统会自动把对象“剥”开,得到它的值。 达到的效果: 有了自动拆箱之后, 包装类的对象可当成基本类型的值 用——其实是【假相】 。
//装箱的例子
//装箱允许将值类型隐式转化成引用类型还是在Main方法里面
int i = 2008;
object obj = i;
Console.WriteLine("1.i的值为{0},装箱之后的对象为{1}",i,obj);
i = 927;
Console.WriteLine("2.i的值为{0},装箱之后的对象为{1}",i,obj);
Console.ReadKey();
//程序运行结果
//1.i的值为2008,装箱之后的对象为2008.
//2.I的值为927,装箱之后的对象为2008
//拆箱例子
//拆箱允许将引用类型显示转换为值类型,下面通过一个实例演示拆箱的过程
int i = 112;
object obj = i;
Console.WriteLine("装箱操作:值为{0},装箱之后的对象为{1}",i,obj);
int j = (int)obj;
Console.WriteLine("拆箱操作,装箱的对象为{0},值为{1}", obj, j);
Console.ReadKey();
//程序运行后的结果
//装箱操作:值为112,装箱之后对象为112
//拆箱操作:装箱对象为112,值为112
5、int与Integer有什么区别,它们之间的相互转化是怎样的
请通过JDK文档自主学习Integer类,对主要方法进行测试。
转载https://blog.csdn.net/m0_48957269/article/details/108876760
int 属于普通数据类型,Integer是 int 所对应的包装类
①int转Integer
int a = 5;
Integer A = new Integer(a);或
Integer A = Integer.valueOf(a);
②Integer转int
Integer A = new Integer(5);
int a = A.intValue();
6、逻辑运算符&和&&的区别是什么?逻辑运算符&与位运算符&的区别是什么?请举例说明。
逻辑运算符 & 运算符左右两边的表达式首先被运算执行,再对两表达式的结果进行与运算
逻辑运算符 && 如果从左边的表达式中得到操作数能确定运算结果,则不再对右边的表达式进行运算。
逻辑运算符&
参与运算的都是布尔值
x&y,x,y都为true时,结果为true
位运算符&
x&y,x,y按位进行与操作
7、Java语言中可以采用什么语句跳出多重循环?请举例说明。
break lab; (跳出多重循环的外层循环),
其中:break是关键字;lab是用户定义的标号。
//lab:
for(int i =0; i<2; i++) {
for(int j=0; j<10; j++) {
if (j >1) {
break lab;
}
System.out.println(“break");
}
}
输出结果:
break
break
第四章
1、对象与对象引用的区别是什么?请举例说明什么是对象?
引自《Java编程思想》中的一段原话:“按照通俗的说法,每个对象都是某个类(class)的一个实例(instance),这里,‘类’就是‘类型’的同义词。”对象通常与类联系起来,对象是对客观事物的抽象,类是对对象的抽象。它们的关系是,对象是类的实例,类是对象的模板。
什么是对象引用?
同样引用《Java编程思想》的一段话,“每种编程语言都有自己的数据处理方式。有些时候,程序员必须注意将要处理的数据是什么类型。你是直接操纵元素,还是用某种基于特殊语法的间接表示(例如C/C++里的指针)来操作对象。所有这些在 Java 里都得到了简化,一切都被视为对象。因此,我们可采用一种统一的语法。尽管将一切都“看作”对象,但操纵的标识符实际是指向一个对象的“引用”(reference)。” 对象与对象引用有着本质上的区别。
2、对象作为参数传递的特点是什么?请举例说明
Java中对象作为参数传递,实际传递的是该对象的引用
public class test {
public static void main(String[] args) {
StringBuffer sb = new StringBuffer("Hello ");
System.out.println("before change, sb is "+sb.toString());
change(sb);
System.out.println("after change, sb is "+sb.toString());
}
public static void change(StringBuffer stringBuffer){
stringBuffer.append("world !");
}
}
运行结果:
before change, sb is Hello
after change, sb is Hello world !
3、对象初始化顺序是怎样的?
先初始化父类的静态代码—>初始化子类的静态代码–>初始化父类的非静态代码—>初始化父类构造函数—>初始化子类非静态代码—>初始化子类构造函数
4.类的static字段与非static字段的区别是什么?static修饰的属性和方法有什么特点?
整理来源:原文链接:https://blog.csdn.net/weixin_46402869/article/details/108911003
类的static字段和非static字段区别
关于static和非static变量的区别。
1、static 修饰的变量称为类变量或全局变量或成员变量,在类被加载的时候成员变量即被初始化,与类关联,只要类存在,static变量就存在。非static修饰的成员变量是在对象new出来的时候划分存储空间,是与具体的对象绑定的,该成员变量仅为当前对象所拥有的。
2、static修饰的变量在加载的时候先于main方法加载在内存中的数据共享区-------方法区,而非static的变量在加载的时候,是要创建变量才加载在堆内存中的。
3、一个static变量单独划分一块存储空间,不与具体的对象绑定在一起,该存储空间被类的各个对象所共享。static变量值在方法区加载一次,而非static在创建对象时会加载很多次。每次创建都会拷贝一份。
4、对象在引用成员变量是直接通过类名.变量名调用,对象在引用实例变量时只能通过对象名.变量名调用。
5、在类中调用成员变量时直接调用或者以类名.变量名方式调用,实例变量则用this或者直接调用。
关于static方法和非static方法的区别
1、 static修饰的方法也和static一样。先于main方法被加载到方法区,以便共享使用。
2、静态的static方法中不能使用this或者super关键字,因为static方法是先于对象创建之前就已经加载的方法,是属于类的方法,而this和super指向的是本类的对象或者父类的对象,非静态的方法是属于对象的,方法里可以用this和super。
3、static方法可以用对象.方法名来调用,也可以用类名.方法名来调用。而非静态的方法只能创建对象后时调用。
4、static方法是加载一次,被所有的对象所共享。而非静态方法是有多少个对象就拷贝多少次,每个对象只能调用自己的拷贝的方法。
5、对象调用非静态的方法时,不考虑线程安全性的问题,而调用静态方法时,要考虑安全性的问题。因为静态方法只有一份。而对象的方法是自己有自己的。
6、同一个类中,静态方法中只能访问类中的静态成员。而非静态方法可以访问非静态的方法(使用类名调用,或者创创建本类的对象调用)。
什么时候用static?
当一个变量需要初始化加载时候,或者是经常被调用的时候可以加上static。
用static 修饰的方法可以直接被调用, 不用static修饰的需要先实例化一个对象后才可以被调用 。
比如 person这个类里面有一个方法public static add(){}
那么可以直接用person类调用 person.add();
5、final修饰符都有什么作用?
解:修饰属性时,该属性为常量。修饰方法时,该方法为最终方法,在子类中不能被覆盖。
6、Java中float[10]arr;语句正确吗?为什么?
不能写成 float[10] arr; 系统无法识别该语句给arr数组分配内存空间。
7、Java数组元素类型为基本类型和引用类型时,有什么不同?请举例说明
对于基本类型数组而言,数组元素的值直接存储在对应的数组元素中,因此,初始化数组时,先为该数组分配内存空间,然后直接将数组元素的值存入对应数组元素中。
如:
int[] a1={1,2,3,4,5};
引用类型数组的数组元素是引用,因此情况变得更加复杂:每个数组元素里存储的还是引用,它指向另一块内存,这块内存里存储了有效数据。
如:
MyClass[] mc=new MyClass[10];
第五章
1、Java的访问控制修饰符有哪些?各有什么访问权限?请对照第7页ppt的表格分别写程序验证。
2、子类对于从父类继承的哪些属性与方法是可见的?请分别写程序进行验证。
子类继承了父类的所有属性和方法, 但只有public、protected的属性和方法在子类是可见的。
子类在继承父类的时候,首先应该满足父类可被访问,例如当子类和父类不在同一个包当中时,父类修饰符必为public;在父类能被访问的前提下,凡是修饰符为public或是protected的父类属性成员或是方法能被子类所访问;private的属性成员或是方法则不能被直接访问。子类不能直接访问父类的private属性和方法,可以调用父类的公共方法来间接访问私有属性
3、什么是组合?有什么作用?请举例说明。
什么是重载?有什么作用?请构造各种重载示例。
方法名称(函数名)相同,参数类型 或 参数个数 不同。
作用:可以使用相同名字(一个名字)的方法实现不同的功能。
class Parent{
public int Score(){
return 3;
}
public int Score(int i){
return i;
}
}
*5、什么是覆写?有什么作用?覆写父类方法的条件有哪些?请举例说明。
当子类定义了和父类属性名称完全形同的时候,就成为属性的覆盖。
class Person{
public String info = "Person";
}
class Student extends Person{
//属性覆盖
public String info = "Student";
}
public class Test{
public static void main(String[] args){
System.out.println(new Student().info);
}
}
第六章
实验:利用IDE的debug功能给例6.4和例6.5的new语句设置断点,使用单步调试(step into/step over)跟踪子类对象实例化(初始化)的执行顺序,并总结该过程。
class Pare {
int i = 3;
Pare() {
super();
}
};
class Construct extends Pare {
int i = 8;
Construct() {
}
Construct(int num) {
this();
}
public static void main(String args[]) {
Construct ct = new Construct(9);
System.out.println(ct.i);
System.out.println(ct.getSuper());
}
int getSuper() {
return super.i;
}
}
实例化执行顺序总结:
1.为子类对象分配内存空间,对域变量进行默认初始化。
2.绑定构造方法,将new对象中的参数传递给构造方法的形式参数。
3.调用this或super语句,二者必居其一,也只有一。
4.进行实例变量的显式初始化操作。
5.执行当前构造方法体中的程序代码。
2、如何实现两个对象之间互发消息,请举例说明。
使用引用的属性或方法其实都是调用对象的属性或方法,而消息概念的引入就是为了说明这样的过程。消息的实质就是引用向对象发出的服务请求,是对数据成员和成员方法的调用。下面列举能否发送消息的三个条件:
1.引用必须真实引用了特定的对象,否则会抛出NullPointerException异常。
2.访问对象必须定义了相应的属性或方法,否则编译不会通过。
3.被访问的属性或方法必须具有可访问的权限。
消息也就是相当于在遥控器和显示器之间架起沟通的桥梁。在面向对象语言中,消息把不同对象相互联系起来,共同完成特定功能。
实例代码:
class FighterPlane {
String name;
int missileNum;
public FighterPlane(String _name, int _missleNum) {
this.name = _name;
this.missileNum = _missleNum;
}
public void fire() {
if (this.missileNum > 0) {
System.out.println("now fire a missile !");
this.missileNum -= 1;
} else {
System.out.println("No missile left !");
}
}
}
class A {
FighterPlane fp;
public A(FighterPlane fpp) {
this.fp = fpp; //A对象中拥有了FighterPlane对象的引用
}
public void invoke() {
//A对象发送消息给FighterPlane的对象
System.out.println(fp.name);
}
}public class Run {
public Run() {
}
public static void main(String[] var0) {
FighterPlane ftp = new FighterPlane("su35", 10);
//产生A对象,并将ftp作为对象引用传入
A a= new A(ftp);
a.invoke();
}
}
3、谈谈组合与继承的区别以及两者的使用场景(即什么时候宜用组合?什么时候宜用继承?)
组合:通过对象内部的属性引用来实现。使对象之间的耦合性较为松散。
继承:从已有的类派生出新的类。在不同的类中也可能会有共同的特征和动作,可以把这些共同的特征和动作放在一个类中,让其它类共享。因此可以定义一个通用类,然后将其扩展为其它多个特定类,这些特定类继承通用类中的特征和动作。继承是 Java 中实现软件重用的重要手段,避免重复,易于维护,易于理解。
组合就像房间里面的窗户、墙壁、地板、桌子、椅子等,他们之间并不存在结构上的相似性,只是功能上组合可以发挥更大的作用,但是单独是可以独立运行的。继承就像对房间进行拓展成为一栋楼,前面的零部件它都具备,但是如果没有房间,大楼是无法构建的,具有结构和功能上的关联。
显而易见,在不具有结构和功能上的相似性时,使用继承可以减少代码重复率,易于维护;在结构实现不同、功能“可叠加”时,使用组合无疑是优于继承的。
4、Java中的运行时的多态的含义是什么?有什么作用?请举例说明。
Java提供了两种多态机制——重载和覆盖。运行时多态指的是覆盖,在运行时根据输入参数动态选择不同的 成员方法执行,体现了一个类本身的多态性,使代码具有良好的拓展性。
举例:同样的红烧鱼,厨师老师的红烧方法传给厨师徒弟后,厨师徒弟在红烧方法上做了改动,这是红烧方法的重写,就相当于 java 的方法重写。
重写:
class Ct{
void hongshao(int a){
System.out.println("这是厨师老师的红烧int的方法");
}
}
class Cs extends Ct{
void hongshao(int a) {
System.out.println("这是厨师徒弟的红烧int的方法");
}
}
class Cs extends Ct{
void hongshao(int a) {
System.out.println("这是厨师徒弟的红烧int的方法");
}
void hongshao(float b) {
System.out.println("这是厨师徒弟红烧float的方法");
}
void hongshao(int a,float b) {
System.out.println("这是厨师徒弟红烧int和float的方法");
}
}
5、使用接口改写例6.8中的程序。
package bookcode.ex6.part6_8;
public interface Shape {
double getArea();
double getPerimeter();
void show();
}
public class Circle implements Shape{
private int r;
public Circle(int _r){
r = _r;
}
@Override
public double getArea() {
return r * r * Math.PI;
}
@Override
public double getPerimeter() {
return 2 * Math.PI * r;
}
@Override
public void show() {
System.out.println("Circle Area:" + getArea());
System.out.println("Circle Perimeter:" + getPerimeter());
}
}
public class Rect implements Shape {
private int k;
private int m;
public Rect(int width, int height) {
k = width;
m = height;
}
public double getArea() {
return (k * m);
}
public double getPerimeter() {
return (2 * k + 2 * m);
}
@Override
public void show() {
System.out.println("Rect Area:" + getArea());
System.out.println("Rect Perimeter:" + getPerimeter());
}
}
import com.sun.tools.javac.file.SymbolArchive;
public class Triangle implements Shape{
private int x, y, z, m;
public Triangle(int _x, int _y, int _z){
x = _x;
y = _y;
z = _z;
m = (x + y +z) / 2;
}
@Override
public double getArea() {
return (Math.sqrt(m *(m - x) * (m - y) * (m - z)));
}
@Override
public double getPerimeter() {
return 2 * m;
}
@Override
public void show() {
System.out.println("Triangle Area:" + getArea());
System.out.println("Triangle Perimeter:" + getPerimeter());
}
}
public class RunShape{
public static void main(String args[]){
Rect rect = new Rect(5 , 6);
Triangle triangle = new Triangle(3, 4, 5);
Circle circle = new Circle(5);
rect.show();
System.out.println();
triangle.show();
System.out.println();
circle.show();
}
}
6、自定义一个类,覆写equals方法,以满足自身业务需求
class Person{
private String name;
private int age;
public Person(String name,int age){
this.name=name;
this.age=age;
}
public String toString(){
return this.name+"今年"+this.age+"岁";
}
public boolean equals(Object obj){//Object类可接受任何类
if(obj==null){//判断是否为空,若不判断则会出先空指针异常(NullPointerException)
return false;
}
if(this==obj){//判断是否在与自身比较(通过比较地址),若是则直接返回true
return true;
}
if(!(obj instanceof Person)){//instanceof作用为判断其左边对象是否为右边对象的实例,此处为判断主方法中equals()方法括号中的对象是否为Person类
return false;
}
//到达此处时必定是同类但不同地址的对象在比较
Person per=(Person)obj;//向下转型,比较属性值
return this.name.equals(per.name)&&this.age==per.age;//判定属性内容是否相等(易错点)
}
}
class Student{}
public class Test{
public static void main(String[] args) {
Person per1=new Person("张三",18);
Person per2=new Person("张三",18);
Person per3=new Person("lisi",19);
Person per4=null;
Student stu=new Student();
System.out.println(per1.equals(per1));//true
System.out.println(per1.equals(stu));//false
System.out.println(per1.equals(per3));//false
System.out.println(per1.equals(per4));//false
}
}
7、举例说明运算符instanceof的使用场景。
运算符的格式为:“a instanceofof A”,其中a为对象的引用,A为类。如果a为对象A的实例或A子类的实例,则会返回true;如果a为A父类的实例,则返回false;如果a对象的类和A没有任何关系,则编译不会通过。即instanceof比较的结果有三种:true、false、语法错误(编译不会通过)。
class Uncle{}
class Pare{}
class Pare1 extends Pare{}
class Pare2 extends Pare1{}
class Pare3{
public class void main(String args[]) {
Uncle u = new Uncle();
Pare p = new Pare();
Pare1 p1 = new Pare1();
Pare2 p2 = new Pare2();
if (p instanceof Pare) {
System.out.println("p instanceof Pare");
}
if (!(p1 instanceof Pare1)) {
System.out.println("p1 not instanceof Pare");
} else {
System.out.println("p1 instanceof Pare");
}
if (p2 instanceof Pare) {
System.out.println("p2 instanceof Pare");
}
if (p1 instanceof Pare1) {
System.out.println("p1 instanceof Pare1");
}
if (p2 instanceof Pare1) {
System.out.println("p2 instanceof Pare1");
}
if (p1 instanceof Pare2) {
System.out.println("p1 instanceof Pare2");
} else {
System.out.println("p1 not instanceof Pare2");
}
/ *if (p instanceof Uncle) {
System.out.println("p instanceof Uncle");
} else {
Ststem.out.println("p not instanceof Uncle");
} * /
if (full instanceof String) {
System.out.println("null instanceof String");
} else {
System.out.println("null not instanceof String");
}
}
}
输出结果如图所示,如果去掉注释符“/* ··· */”,编译会出问题。
注意:如果对比较结果取反,必须加()号,如本例的if(!(p1 instanceof Pare))。
8、谈谈抽象类与接口的异同以及两者的使用场景
第七章 异常
1.Throwable的子类包含哪两类?简述Java Error类与Exception类的区别。
Throwable包括Error和Exception这两类。
Error:致命异常。标识系统发生了不可控的错误。程序无法处理,只能人工介入。例如, 虚拟机产生的错误StackOverflowError、OutOfMemoryError。
Exception: 非致命异常。程序可处理。分为受编译器检测的checked异常(受检异常)和不受编译器检测的unchecked异常(非受检异常)。
区别:
- Error 属于系统级错误称之为“错误”,不可捕获;Exception属于应用程序级错误称之为“异常”可以通过捕获避免
- Error 无需在程序中以throws字句抛出;而Exception 需要抛出
- 存在Error 错误程序不能运行或运行中断,而存在Exception错误可运行并抛出
2. Exception又分为checked异常和unchecked异常,请分别举例说明。
unchecked异常:不需要在编译时处理的异常。
checked异常:在编译时需要检擦的异常,需要用try-catch或throws处理。
checked异常举例:
class A{
public static void main(String[]args){
try(Scanner sc=new Scanner(Systen,in)){
int a=sc.nextShort();
}catch(Exception e){
e.printStackTrace();
}
}
}
unchecked异常举例:
class A{
public static void main(String[]args){
int []a;
System.out.println(a[0]);
}
}
3. 请查阅资料,简述StackOverflowError和OutOfMemoryError两类错误的发生情形和原因。
StackOverflow(栈溢出)
发生的情形: 由于递归发生在一个单独的线程当中,当递归的深度增加时,递归栈的深度会增加,当应用程序递归得太深时,就会发生栈溢出。
原因:线程请求的栈深度大于虚拟机所允许的最大深度
举例:
public class StackOverFlow {
private int i;
public void plus() {
i++;
plus();
}
public static void main(String[] args) {
StackOverFlow stackOverFlow = new StackOverFlow();
try {
stackOverFlow.plus();
} catch (Error e) {
System.out.println("Error:stack length:" + stackOverFlow.i);
e.printStackTrace();
}
}
}
输出结果:
Error:stack length:997
java.lang.StackOverflowError
at com.dxz.jvm.StackOverFlow.plus(StackOverFlow.java:11)
OutOfMemoryError(内存溢出)
发生情形:当内存不足就会抛出该异常
原因:当Java虚拟机因对象内存不足而无法分配对象,垃圾收集器无法提供更多内存时抛出。
举例分析:
public class HeapOOM{
public static void main(String[] args){
List<HeapOOM> list = new ArrayList<HeapOOM>();
while(true){
list.add(new HeapOOM());//无限创建对象且使用集合保存其引用避免被回收
}
}
}
程序输出结果:
java.lang.OutOfMemoryError: Java heap space
4. 简述异常处理的两种方式,并举例说明区别。
1.throw
import java.util.Objects;
public class DemoThrow {
public static void main(String[] args) {
int[] arr = null;
// int[] arr = {};
int res = getElement(arr, 3);
System.out.println(res);
}
private static int getElement(int[] arr, int index){
//判断参数的合法性,检测是否为空,下列两种方法
if(arr == null){
throw new NullPointerException("传入的数组是空数组");
}
// Objects.requireNonNull(arr,"传入的数组是空数组"); //java.lang.NullPointerException: 传入的数组是空数组
if (index < 0 || index >= arr.length){
throw new ArrayIndexOutOfBoundsException("数组越界异常");
}
int num = arr[index];
return num;
}
}
2.try…catch
import java.io.IOException;
public class DemoTryCatch {
public static void main(String[] args) {
try {
readFile("c://b.txt");
}catch (IOException e){
System.out.println(e); //java.io.IOException: 文件格式不匹配!
}
System.out.println("执行完毕!"); //都会执行该代码
}
public static void readFile(String fileName) throws IOException {
/* FileNotFoundException entends IOException extends Exception*/
if (!fileName.endsWith(".txt")){
throw new IOException("文件格式不匹配!");
}
System.out.println("文件格式没问题!");
}
}
5. 选取RuntimeException类的五个子类,编写抛出并捕获上述子类异常的程序。(例如算术异常,空指针异常,类转换异常,数组越界异常等)
空栈异常
空指针异常
数组越界
6. 根据某业务场景自定义一个异常类,并在某场景下抛出该异常对象。
class CustomException extends Exception {
public CustomException(String msg){
super(msg);
}
}
public class Main{
public static void main(String[] args){
......
if(PassWord.IsTrue()){
} else {
throw CustomException("密码错误");
}
}
}
7. 异常中的throws声明与throw语句的区别是什么?请举例说明。
throws:
出现在方法的声明中,表示该方法可能会抛出的异常,然后交给上层调用它的方法程序处理,允许throws后面跟着多个异常类型。
throw:
一般会用于程序出现某种逻辑时程序员主动抛出某种特定类型的异常。throw只会出现在方法体中,当方法在执行过程中遇到异常情况时,将异常信息封装为异常对象,然后throw出去。throw关键字的一个非常重要的作用就是异常类型的转换。
8. finally子句的作用是什么?
当代码抛出一个异常时,就会终止方法中剩余代码的处理,并退出这个方法的执行。如果方法获得了一些本地资源,并且只有这个方法自己知道,又如果这些资源在退出方法之前必须回收,那么就会产生资源回收问题。
可以将资源回收的代码放入finally子句中。因为不管是否有异常捕获,finally子句中的代码都会执行。
参考:https://blog.csdn.net/nebois/article/details/120923944
第八章
1. 借助JDK文档, 选取String与StringBuffer 、StringBuilder的常用API,并编写实例测试API的功能。
String类以equals为例:
StringBuffer以append为例:
StingBulider以toString为例:
2. 请简述String,StringBuffer,StringBuilder三者之间的共同点与区别,应该分别在何种场景下使用?
3. 为什么不建议在for循环中使用“+”进行字符串拼接?
而“+”反编译后的代码,在for循环中,每次都是new了一个StringBuilder,然后再把String转成StringBuilder,再进行append。
而频繁的新建对象当然要耗费很多时间了,不仅仅会耗费时间,频繁的创建对象,还会造成内存资源的浪费。
第九章
1.FutureTask类有什么作用?它实现了哪些接口? Callable接口和Runnable接口有什么不同?
FutureTask类作用:A FutureTask可用于包装Callable或Runnable对象。 因为FutureTask实现Runnable ,一个FutureTask可以提交到一个Executor执行。
除了作为独立类之外,此类还提供了protected功能,在创建自定义任务类时可能很有用。
FutureTask实现了Runnable和Future接口
Callable接口和Runnable接口的不同:
1、Callable可以返回一个类型V,而Runnable不可以
2、Callable能够抛出checked exception,而Runnable不可以。
3、Runnable是自从java1.1就有了,而Callable是1.5之后才加上去的
4、Callable和Runnable都可以应用于executors。而Thread类只支持Runnable.
2.请查阅JDK自学线程池的相关类,如ThreadPoolExecutor构造器各个参数的意义, 利用线程池编写多线程程序。
class Account{
volatile private int value;
volatile private boolean isMoney=false;
synchronized void put(int i) {
if(isMoney) {
try {wait();}
catch(Exception e) {}
}
value+=i;
System.out.println("存入"+i+"账上金额为:"+value);
isMoney=true;
notify();
}
synchronized int get(int i) {
if(!isMoney) {
try {wait();}
catch(Exception e) {}
}
if(value>i) value-=i;
else {
i=value;
value=0;
}
System.out.println("取走"+i+"账上金额为:"+value);
isMoney=false;
notify();
return i;
}
}
class Save implements Runnable{
private Account a1;
public Save(Account a1) {
this.a1=a1;
}
public void run() {
while(true) {
a1.put(100);
}
}
}
class Fetch implements Runnable{
private Account a1;
public Fetch(Account a1) {
this.a1=a1;
}
public void run() {
while(true) {
a1.get(100);
}
}
}
public class test {
public static void main(String[] args) {
Account a1=new Account();
new Thread(new Save(a1)).start();
new Thread(new Fetch(a1)).start();
}
}
3.volatile关键字有什么作用?
1、保证该变量对所有线程的可见性;
2、禁止指令重排序优化。
4.Java提供了哪些同步机制来实现互斥?
1、对象监视器(monitor)与synchronized
Synchronized的三种用法:
synchronized 代码块:监视器就是指定的对象。
synchronized 方法:监视器就是this对象。
synchronized 静态方法:监视器就是相应的Class对象。
2、Java并发包中的锁类
Lock接口
ReentrantLock类
5.编写Java程序模拟烧水泡茶最优工序。
public class Test{
public static void main(String[] args) {
MyRunnable3 myRunnable3=new MyRunnable3();
MyRunnable4 myRunnable4=new MyRunnable4();
Thread t1=new Thread (myRunnable3);
Thread t2=new Thread (myRunnable4);
t1.setName("烧水");
t2.setName("洗杯子");
t1.start();
t2.start();
try {
t1.join();
} catch (InterruptedException e) {
//等待烧水完成
e.printStackTrace();
}
try {
t2.join();
} catch (InterruptedException e) {
// 等待洗杯子完成
e.printStackTrace();
}
System.out.println("泡茶....");
}
}
class MyRunnable3 implements Runnable{
public void run(){
System.out.println("烧开水去....");
try {
Thread.sleep(5000); //每运行一次,休眠一秒钟
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("烧完了.......");
}
}
class MyRunnable4 implements Runnable{
public void run(){
for(int i=1;i<10;i++){
System.out.println("洗 "+i+"杯子去....");
try {
Thread.sleep(1000); //每运行一次,休眠一秒钟
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
6.请使用Java并发包的Lock及Conditon改写例9.11。
import java.util.concurrent.locks.*;
class Accounter{
volatile private int value;
//布尔标志
volatile private boolean isMoney = false;
private final ReentrantLock lock=new ReentrantLock();
private Condition SaveCondition=lock.newCondition();
private Condition FetchCondition=lock.newCondition();
//put设为同步方法
void put(int i) {
lock.lock();
try {
while (isMoney) {
try {
SaveCondition.await();
} catch (Exception e) {}
}
value = value + i;
System.out.println("存入" + i + " 账上金额为:" + value);
isMoney = true;//设置标志
FetchCondition.signal();
}finally{
lock.unlock();
}
}
int get(int i) {
lock.lock();
try {
while (!isMoney) {
try {
FetchCondition.await();
} catch (Exception e) {
}
}
if (value > i)
value = value - i;
else {
i = value;
value = 0;
}
System.out.println("取走" + i + " 账上金额为:" + value);
isMoney = false;
SaveCondition.signal();
return i;
}finally{
lock.unlock();
}
}
}
class Products{
public static void main(String[] args) {
Accounter a1=new Accounter();
//存钱线程
new Thread(() -> {
while(true){ a1.put(100);}
}).start();
//取钱线程
new Thread(() -> {
while(true){ a1.get(100); }
}).start();
}
}
7. 编写一个多线程Java应用模拟生产者/消费者模型,各产生10个生产者和消费者线程,共享一个缓冲区队列(长度自设),生产者线程将产品放入到缓冲区,消费者线程从缓冲区取出产品。
class Account
{
volatile private int value;
synchronized void put(int i)
{
try {
Thread.sleep(300);
} catch (InterruptedException e) {
}
value = value + i;
System.out.println(Thread.currentThread().getName()+" 生产者--存入了 "+i+" 余量为:"+value);
}
synchronized int get(int i)
{
try {
Thread.sleep(300);
} catch (InterruptedException e) {
}
if (value>i)
value = value - i;
else
{ i = value;
value = 0;
}
System.out.println(Thread.currentThread().getName()+ " 消费者--消费了 "+i+" 余量为:"+value);
return i;
}
}
class Save implements Runnable
{
private Account a1;
public Save(Account a1)
{
this.a1 = a1;
}
public void run()
{
while(true){
a1.put(1);
}
}
}
class Fetch implements Runnable
{
private Account a1;
public Fetch(Account a1)
{this.a1 = a1 ;}
public void run()
{
while(true){
a1.get(1);
}
}
}
public class test{
public static void main(String[] args){
Account a1 = new Account();
new Thread(new Save(a1)).start();
new Thread(new Save(a1)).start();
new Thread(new Save(a1)).start();
new Thread(new Save(a1)).start();
new Thread(new Save(a1)).start();
new Thread(new Save(a1)).start();
new Thread(new Save(a1)).start();
new Thread(new Save(a1)).start();
new Thread(new Save(a1)).start();
new Thread(new Save(a1)).start();
//10个生产者和消费者
new Thread(new Fetch(a1)).start();
new Thread(new Fetch(a1)).start();
new Thread(new Fetch(a1)).start();
new Thread(new Fetch(a1)).start();
new Thread(new Fetch(a1)).start();
new Thread(new Fetch(a1)).start();
new Thread(new Fetch(a1)).start();
new Thread(new Fetch(a1)).start();
new Thread(new Fetch(a1)).start();
new Thread(new Fetch(a1)).start();
}
}
8.阅读公众号“码农翻身”的文章—《我是一个线程》。
详见:
https://mp.weixin.qq.com/s?__biz=MzAxOTc0NzExNg==&mid=416915373&idx=1&sn=f80a13b099237534a3ef777d511d831a&chksm=06ef67ee3198eef85a668f7197709b54bcd9508087ace8f6eaa11d34eb4e5392c5190a77d530&mpshare=1&scene=23&srcid=0321jXk1poHiYi02DX5AQLNw&sharer_sharetime=1635731489113&sharer_shareid=4c2e21a9ed8a602d8de5c525759a049a#rd
第十五章
1、仿照例15.4,编写基于TCP Socket的多客户/服务器通信程序。
import java.io.*;
import java.net.*;
public class ServerThread extends Thread{
Socket socket=null;
int clientnum;
public ServerThread(Socket socket,int num) {
this.socket=socket;
clientnum=num+1;
}
public void run() {
try{
String line;
BufferedReader is=new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter os=new PrintWriter(socket.getOutputStream());
BufferedReader sin=new BufferedReader(new InputStreamReader(System.in));
System.out.println("Client:"+ clientnum +is.readLine());
line=sin.readLine();
while(!line.equals("bye")){
os.println(line);
os.flush();
System.out.println("Server:"+line);
System.out.println("Client:"+ clientnum +is.readLine());
line=sin.readLine();
}
os.close();
is.close();
socket.close();
}catch(Exception e){
System.out.println("Error:"+e);
}
}
}
import java.io.*;
import java.net.*;
import ServerThread;
public class MultiTalkServer{
static int clientnum=0;
public static void main(String args[]) throws IOException {
ServerSocket serverSocket=null;
boolean listening=true;
try{
serverSocket=new ServerSocket(4700);
}catch(IOException e) {
System.out.println("Could not listen on port:4700.");
System.exit(-1);
}
while(listening){
new ServerThread(serverSocket.accept(),clientnum).start();
clientnum++;
}
serverSocket.close();
}
}
import java.io.*;
import java.net.*;
public class TalkClient {
public static void main(String args[]) {
try{
Socket socket=new Socket("127.0.0.1",4700);
BufferedReader sin=new BufferedReader(new InputStreamReader(System.in));
PrintWriter os=new PrintWriter(socket.getOutputStream());
BufferedReader is=new BufferedReader(new
InputStreamReader(socket.getInputStream()));
String readline;
readline=sin.readLine();
while(!readline.equals("bye")){
os.println(readline);
os.flush();
System.out.println("Client:"+readline);
System.out.println("Server:"+is.readLine());
readline=sin.readLine();
}
os.close();
is.close();
socket.close();
}catch(Exception e) {
System.out.println("Error"+e);
}
}
}
2、仿照例15.5,编写基于UDP数据报的多客户/服务器通信程序。
import java.io.*;
import java.net.*;
import java.nio.charset.StandardCharsets;
import java.util.*;
public class QuoteClient {
public static void main(String[] args) throws IOException
{
if(args.length!=1){
System.out.println("Usage:java QuoteClient <hostname>");
return;
}
DatagramSocket socket=new DatagramSocket();
byte[] buf=new byte[256];
buf="hello".getBytes();
InetAddress address=InetAddress.getByName(args[0]);
DatagramPacket packet=new DatagramPacket(buf, buf.length, address, 4445);
socket.send(packet);
packet=new DatagramPacket(buf,buf.length);
socket.receive(packet);
String received=new String(packet.getData());
System.out.println("Quote of the Moment:"+received );
socket.close();
}
}
public class QuoteServer{
public static void main(String args[]) throws java.io.IOException
{
new QuoteServerThread().start();
}
}
import java.io.*;
import java.net.*;
import java.util.*;
public class QuoteServerThread extends Thread
{ protected DatagramSocket socket=null;
protected BufferedReader in=null;
protected boolean moreQuotes=true;
public QuoteServerThread() throws IOException {
this("QuoteServerThread");
}
public QuoteServerThread(String name) throws IOException {
super(name);
socket=new DatagramSocket(4445);
in= new BufferedReader(new InputStreamReader(System.in));
}
public void run() {
while(moreQuotes) {
try{
byte[] buf=new byte[256];
DatagramPacket packet=new DatagramPacket(buf,buf.length);
socket.receive(packet);
System.out.println(new String(packet.getData()));
String dString= in.readLine();
if(dString.equals("bye")){moreQuotes=false;}
buf=dString.getBytes();
InetAddress address=packet.getAddress();
int port=packet.getPort();
packet=new DatagramPacket(buf,buf.length,address,port);
socket.send(packet);
}catch(IOException e)
e.printStackTrace();
moreQuotes=false;
}
}
socket.close();
}
}
3、基于TCP Socket的C/S通信与基于UDP数据报的C/S通信有哪些区别?Java分别提供了哪些支持?
第十四章
1.Java中流的分类有哪些?
(1)流从流动方向:
一般分为 输入流(InputStream) 和 输出流(OutputStream) 两类。程序可以用输出流向文件写数据,用输入流从文件中读数据。而针对屏幕只有输出流。
(2)从读取类型上分:
一般分为字节流和字符流。
(3)流从发生的源头:
可以分为节点流和过滤流。用于直接操作目标设备对应的流叫节点流(文件流,字节数组流,标准输入/输出流等)。程序可以通过过滤流(继承带有关键字Filter 的流),以更加灵活方便地读写各种类型的数据。
2.字节流InputStream和OutputStream的子类分别有哪些?请举例说明其使用场景。与其对应的字符流分别有哪些?
InputStream类族
FileInputStream 文件流
PipedInputStream 管道输入流,读取管道内容。多和PipedOutputStream一起用于多线程通信
ObjectInputStream用来恢复被序列化的对象
ByteArrayInputStream包含一个内存缓冲区,字节从中取出。
SequenceInputStream 是多种输入流的逻辑串联,从第一个输入流读取,直到最后一个输入流
FilterInputStream 过滤流,在读写数据的同时还可以对数据进行特殊处理
OutputStream类族
FileOutputStream 文件流
PipedOutputStream 管道流
ObjectOutputStream将对象序列化后写入指定地方
ByteArrayOutputStream在字节数组和流之间搭建桥梁
SequenceOutputStream 是多种输入流的逻辑串联
FilterInputStream 过滤流,在读写数据的同时还可以对数据进行特殊处理
与他们对应的字符流的关系是:
Reader类族
Writer类族
3.字节流与字符流的转化是怎样的?Java对此提供了哪些支持?
输入字节流转为字符流(解码)需要用到inputstreamReader的构造方法:把字节数组解码成字符串
InputStreamReader(InputStream in)
例如:
InputStreamReader ins = new InputStreamReader(System.in);
InputStreamReader ins = new InputStreamReader(new FileInputStream(“test.txt”));
输出字符流转为字节流用到OutputStreamWriter或PrintWriter的构造方法:
OutputStreamWriter(OutputStream out)
PrintWriter(OutputStream out)
例如:
OutputStreamWriter outs = new OutputStreamWriter(new FileOutputStream(“test.txt”));
4.Java中的过滤流(流的装配)有什么作用?请举例说明常用的过滤流。
过滤流:BufferedInputStream和BufferedOutputStream, 缓存作用,用于装配文件磁盘、网络设备、终端等读写开销大的节点流,提高读写性能。
DataInputStream di = new DataInputStream(new BufferedInputStream(new FileInputSTream(f))); //f 为File的实例。
之后可以利用DataOutStream 对象方法想文件中写内容。内容写完后,可调用其flush 方法,将多次写入的数据一次性输出到节点流FileOutStream 上;如果用PrintStream 取代现在DataOutputStream 的位置,则当调用其println 方法或其写入的字符中含有换行时,会自动调用BufferedOutputStream的flush 将缓冲区的内容写入到字节流中。
过滤流BufferedReader的使用
import java.io.*;
public class inDataSortMaxMinIn {
public static void main(String args[]) {
try{
BufferedReader keyin = new BufferedReader(new
InputStreamReader(System.in));
String c1;
int i=0;
int[] e = new int[10];
while(i<10){
try{
c1 = keyin.readLine();
e[i] = Integer.parseInt(c1);
i++;
}
catch(NumberFormatException ee){
System.out.println("请输入正确的数字!");
}
}
}
catch(Exception e){
System.out.println("系统有错误");
}}}
过滤流: DataInputStream和DataOutputStream
import java.io.*;
public class DataStream {
public static void main(String[] args)throws Exception{
try {
DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new
FileOutputStream("test.txt")));
dos.writeInt(3);//写入整型
dos.writeDouble(3.14);//写入浮点型
dos.writeUTF(“hello”);//写入字符串
dos.close();
DataInputStream dis = new DataInputStream(new BufferedInputStream(new
FileInputStream("test.txt")));
System.out.println(dis.readInt()); //读取整型,输出3
System.out.println(dis.readDouble()); //读取浮点型,输出3.14
System.out.println(dis.readUTF()); //读取字符串,输出hello
dis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}
5.什么是对象的序列化和反序列化?Java对此提供了哪些支持?
序列化:将实现了Seriallizable接口的对象转换成一个字节序列,并能够在以后将这个字节序列完全恢复为原来的对象,后者又称反序列化。
ObjectInputStream类和ObjectOutputStream类:分别实现了接口ObjectOutput 和 ObjectInput,将数据流功能扩展到可以读写对象,前者用writeObject()方法可以直接将对象保存到输出流中,而后者用readObject()方法可以直接从输入流中读取一个对象。
6.Java的File类表示什么?有什么作用?
file类不仅值系统中的文件,也指目录,因为目录也是特殊的文件。
7.Java对文件的读写分别提供了哪些支持?
以字节流的形式顺序读写文件 FileInputStream 和 FileOutputStream
读取文件
import java.io.*;
public class OpenFile {
public static void main(String args[]) throws IOException{
try{
FileInputStream rf = new FileInputStream("OpenFile.java");
int n=512,c=0;
byte buffer[] = new byte[n];
while ((c=rf.read(buffer,0,n))!=-1 ){
System.out.print(new String(buffer,0,c));
}
rf.close();
}
catch (FileNotFoundException ffe){
System.out.println(ffe);}
catch (IOException ioe){
System.out.println(ioe);
}
}
}
写入文件
import java.io.*;
public class Write1 {
public static void main(String args[]){
try{
System.out.print("Input: ");
int count,n=512;
byte buffer[] = new byte[n];
count = System.in.read(buffer);
FileOutputStream wf = new FileOutputStream("Write1.txt");
wf.write(buffer,0,count);
wf.close();
System.out.println("Save to Write1.txt!");
}
catch (FileNotFoundException ffe){
System.out.println(ffe);}
catch (IOException ioe){
System.out.println(ioe);} }
}
以字符流的形式顺序的读文件:FileReader 和FileWriter
读取文件
import java.io.*;
public class OpenFile
{
public static void main(String args[]) throws IOException
{
try
{ //创建文件输入流对象
FileReader rf = new FileReader("OpenFile.java");
char[] a = new char[50];
rf.read(a); // 读取数组中的内容
for (char c : a)
System.out.print(c); // 一个一个打印字符
rf.close(); //关闭输入流
}
catch (IOException ioe)
{ System.out.println(ioe);}
catch (Exception e)
{ System.out.println(e);}
}
}
写入文件
import java.io.*;
public class Write1
{
public static void main(String args[])
{
try
{
FileWriter wf = new FileWriter("Write1.txt");
//创建文件输出流对象
wf.write("This\n is\n an\n example\n");
wf.flush();
wf.close(); //关闭输出流
System.out.println("Save to Write1.txt!");
}
catch (IOException ioe)
{ System.out.println(ioe);}
catch (Exception e)
{ System.out.println(e);}
}
}
第十章
1.编写程序测试Java集合框架中各种常用类的 基本操作(包括添加元素,删除元素,遍历集合元素等)
Vector:从AbstractList派生而来,可自动增加容量来容纳所需对象,实现List接口,元素之间有序。
import java.util.*;
public class vector {
public static void main(String[] args) {
Vector<Integer> v=new Vector();
for(int i=1;i<=10;i++)//添加元素
v.addElement(new Integer(i));
for(Iterator it=v.iterator();it.hasNext();) {//遍历元素
Integer i=(Integer) it.next();
System.out.print(i+" ");
}
System.out.println();
v.remove(3);//删除元素
for(Iterator it=v.iterator();it.hasNext();) {
Integer i=(Integer) it.next();
System.out.print(i+" ");
}
System.out.println();
}
}
Stack:从Vector派生出,增加了栈的实现方法。
import java.util.*;
public class stack {
public static void main(String[] args) {
Stack<Integer> s=new Stack();
for(int i=0;i<10;i++)//入栈
s.push(new Integer(i));
s.add(new Integer(10));//添加
for(Iterator it=s.iterator();it.hasNext();) {//遍历
System.out.print((Integer)it.next()+" ");
}
System.out.println();
s.remove(3);//删除
for(Iterator it=s.iterator();it.hasNext();) {
System.out.print((Integer)it.next()+" ");
}
System.out.println();
s.pop();//出栈
for(Iterator it=s.iterator();it.hasNext();) {
System.out.print((Integer)it.next()+" ");
}
System.out.println();
while(!s.empty()) {
System.out.print(s.pop()+" ");
}
}
}
LinkedList:从AbstractList派生而来,实现了一个链表,由这个类定义的链表也可以像栈和队列一样被使用。
package chapter10;
import java.util.*;
public class linkedlist {
public static void main(String[] args) {
LinkedList<Integer> l=new LinkedList();
for(int i=0;i<5;i++)//从头添加
l.addFirst(new Integer(i));
for(int i=5;i<10;i++)//从尾添加
l.addLast(new Integer(i));
for(Iterator it=l.iterator();it.hasNext();) {//遍历
System.out.print((Integer)it.next());
}
System.out.println();
l.removeFirst();//从头删
l.removeLast();//从尾删
for(Iterator it=l.iterator();it.hasNext();) {//遍历
System.out.print((Integer)it.next());
}
System.out.println();
}
}
ArrayList:由AbstractList派生而来,规模可变,且能像链表一样被访问。
import java.util.*;
public class arraylist {
public static void main(String[] args) {
ArrayList<Integer> al=new ArrayList();
for(int i=1;i<=10;i++)//增加元素
al.add(new Integer(i));
for(Iterator it=al.iterator();it.hasNext();)//遍历元素
System.out.print((Integer)it.next()+" ");
System.out.println();
al.remove(4);//删除元素
for(Iterator it=al.iterator();it.hasNext();)
System.out.print((Integer)it.next()+" ");
}
}