Java语言程序设计复习提纲
这是我在准备Java考试时整理的提纲,如果是通过搜索引擎搜索到这篇博客的师弟师妹,建议还是先参照PPT和课本,这个大纲也不是很准确,自己总结会更有收获,多去理解含义,不要死记硬背,否则遇到概念辨析题会特别吃亏,如果觉得有收获点赞关注,祝考试顺利。
1.Java语言具有可移植性、可跨平台运行特点的原因是什么?
可移植性:因为 Java 是结构中立的,所以Java 的程序是可移植的。 他们可以不经过重新编译而在任何一个机器上运行。
可跨平台:Java语言是高级语言,而Java字节码是低级语言,字节码类似于机器指令,但它是体系结构中立的,是可以在任何带Java虚拟机(JVM)的平台上运行的。虚拟机不是物理机器,而是一个解释Java字节码的程序。这样Java字节码可以在不同的硬件平台和操作系统上运行。Java源代码编译成Java字节码,然后Java字节码被JVM解释执行。
2.为什么说Java语言具有健壮、安全的特性?
健壮性:
Java 编译器检测出许多别的语言只有在首次执行的时候才会指出的问题。
Java 已经清除了几种在其它语言中被发现易于出错的编程结构。
Java具有运行时异常处理特性,它为健壮性提供了编程支持。
安全性:
Java 实现了几种安全机制以保护系统免受危险程序的破坏 。
当加载某类后,JVM使用一个字节码验证器(bytecode verifier)的程序来检验字节码的合法性,确保字节码不会违反Java的安全规范。Java强制执行严格的安全规范,以确保来自网络的Java程序不会篡改和危害你的计算机。
3.简述Java虚拟机(JVM)的作用是什么?
Java虚拟机:是一个解释执行Java字节码的软件。
4.简述JVM的垃圾回收机制。
在C++中,使用new实现动态内存分配,分配后需要负责这块内存的整个生命周期,最后由delete来释放,但如果忘记释放内容,会导致内存泄露。同时错误的使用delete可能会清除尚未引用的对象或空间中的公共资源。
在Java中,使用new来创建对象并在堆中为对象分配空间(基本数据类型除外),而对象的释放则是由GC(Garbage Collection垃圾回收器)决定和执行。Java中对内存对象的访问采用的是引用方式,当CG跟踪到某个对象没有被任何线程访问时,该对象就要被删除,就将其加入垃圾回收队列,但是进行垃圾回收的线程是一种低优先级的系统线程,为此系统不会马上进行对象的消除,因而何时消除并释放内存是无法预知的。
一般是在CPU空闲或空间不足时自动进行垃圾回收,程序员无法精准掌握控制垃圾回收的时机和回收的顺序。
5.简述软件开发的过程。(书,PPT)
需求规范、系统分析、系统设计、实现、测试、部署、维护。
6.什么是短路运算符“(short-circuit operator)?试举例说明。
短路运算符:顾名思义,短路运算符具有短路功能.
如果 "&&" 运算符的第一个表达式为false,则第二个表达式就不会执行
如果 "||" 运算符的第一个表达式为true,则第二个表达式就不会执行
If x is 1, what is x after this expression?
(x > 1)&& (x++ < 10)
If x is 1, what is x after this expression?
(1 > x) && ( 1 > x++)
7.简述使用JDK中的调试工具jdb时,可以使用的调试方法。
JDK包含了一个命令行调试器jdb,结合一个类名来调用该命令。Jdb本身也是一个Java程序,运行自身的一个Java解释器的拷贝。
Debugger is a program that facilitates debugging. You can use a debugger to
- 一次执行一条语句
- 跟踪进入或者一步运行一个方法
- 设置断点
- 显示变量
- 显示调用堆栈
- 修改变量
8.什么是Unicode编码?(书,PPT)
Unicode编码是Unicode协会建立的一种编码方案,它支持使用世界各种语言所书写的文本交换、处理和显示。Unicode编码一开始被设计为16位的字符编码,但一个16位的编码所能产生的字符只用65535个,它不足以表示全世界所有字符的,因此Unicode标准被扩展为1112064个字符。这些字符都远超原来16位的限制被称为补充字符(supplementary character)。Java支持这些补充字符。
一个16位的Unicode编码占两个字节,用以\u开头的4位十六进制数表示,范围从'\u0000'到'\uFFFF'。
9.什么是方法签名(Method signature)?试举例说明。(书,PPT)
方法签名( Method signature ):包括方法名和参数列表。
注意方法名不包括方法的返回类型、返回值和访问修饰符。
Max(int num1, int mum2)
10.Java语言中,方法的参数传递有哪几种?不同类型参数传传递的区别是什么。试举例说明。
值传递
引用传递
值传递:方法调用时,实际参数把它的值传递给对应的形式参数,方法执行中形式参数,形式值的改变不影响实际参数的值。
引用传递:也称为传地址。方法调用时,实际参数的引用(地址,而不是参数的值)传递给方法中相对应的形式参数,在方法执行中,对形式参数的操作实际上就是对实际参数的操作,方法执行中形式参数值的改变将会影响实际参数的值。
值传递例子:
引用传递例子:
Java使用值传递的方法传递实参给方法。传递基本数据类型的值和传递数组值会有很大不同。
对于基本数据类型参数,传递的是实参的值。在方法中改变局部参数的值并不影响方法之外变量的值。
对于数组类型参数,参数值是数组的引用,传递给方法的是这个引用。方法体中数组发生的改变,将会影响到作为参数传给方法的原始数组。
11.什么是局部变量?什么是局部变量的作用域?可不可以在一个方法声明名字相同的变量多次?局部变量的初始化与实例变量的初始化有什么异同?
局部变量:在方法中定义的变量是局部变量(local variable)。
局部变量的作用域:从声明的地方开始,知道包含该变量的块结束为止。局部变量都必须在使用之前进行声明和赋值。
你可以在一个方法的不同块里声明相同的变量多次, 但是不能在嵌套块或同一块中两次声明同一变量。
局部变量的初始化与实例变量的初始化的异同:
实例变量是声明在类里面而不是在方法中。局部变量是声明在方法中的。
实例变量永远都有默认值;如果你没有明确的赋值给实例变量,实例变量还是会有值。
局部变量没有默认值;如果在局部变量被初始化前就要使用的话,编译器会显示错误。局部变量都必须在使用之前进行声明。
12.如何声明一个数组引用变量,如何创建一个数组?什么时候为数组分配内存?什么是数组的越界访问?怎样避免下标越界?
声明数组变量datatype[] arrayRefVar;
double[] myList; double myList[];// 这种风格是允许的,但不推荐使用
创建数组arrayRefVar = new datatype[arraySize];
myList = new double[10];
// 创建数组并将它的引用赋值给变量
refVar = new dataType[10][10];
//声明和创建数组合放在一条语句中
dataType[][] refVar = new dataType[10][10];
//还可选择的语法
dataType refVar[][] = new dataType[10][10];
你也可以使用数组初始化语法来声明、创建和初始化一个二维数组。例如:
Java中的数组可以看到一个特殊的对象,声明时是放在栈中的,分配的空间存储在堆中
当数组被初始化时给数组分配空间
数组的越界访问:数组(指针)越界访问,是指使用了超过有效范围的偏移量。
如只分配了10个元素的空间,但是访问了第11个元素,就属于越界。
避免下标越界的方法:
为了避免错误的发生,在使用时应确保所使用的下标不超过arrayRefVar.length-1,且不小于0
在Java中,数组被看做对象。数组是用new操作符创建的,一个数组变量实际上是包含一个数组引用的变量。
13.什么是不规则数组(ragged array,锯齿数组),试举例说明。
二维数组中的每一行本身就是一个数组。因此,各行的长度可以不同。这样的数组被称为锯齿数组。例如:
int[][] matrix = { {1, 2, 3, 4, 5}, {2, 3, 4, 5}, {3, 4, 5}, {4, 5}, {5} };
matrix.length 是 5
matrix[0].length 是 5
matrix[1].length 是 4
matrix[2].length 是 3
matrix[3].length 是 2
matrix[4].length 是 1
一定要注意二维数组的最后一行后面没有逗号
14.什么是构造方法?构造方法有返回值吗?构造方法如何命名?构造方法可以重载吗?什么是缺省构造方法(default constructor,默认构造方法)?什么情况下,系统才会自动给一个类提供缺省构造方法?
构造方法是一种特殊的方法,调用它来初始化对象。
构造方法没有返回值,没有void。
构造方法必须具备和它所属类相同的名字。
构造方法以重载。也就是说可以有同名的构造方法, 但他们必须有不同的函数签名。
默认构造方法:如果一个类中没有构造方法,类中隐式地定义的一个方法体为空的无参构造方法。
当且仅当类中没有明确定义任何构造方法时系统才会自动提供它。
15.操作符new的作用是什么?构造方法的作用是什么?什么时候会被调用?构方法的执行顺序是什么(父类与子类的构造方法)?
new运算符实例化一个类对象,通过给这个对象分配内存并返回一个指向该内存的引用。new运算符也调用了对象的构造函数。
构造方法是一种特殊的方法,主要用来在创建对象时初始化对象,即为对象成员变量赋初始值。
构造方法是在使用new操作符创建一个对象(仅此一种情况)时被自动调用的。
先调用父类的构造方法,再调用子类的构造方法。
16.什么是引用类型?试举例画图说明基本类型变量和引用类型变量的区别。试举例说明基本类型变量的复制操作(=)和对象类型变量的复制操作(=)有何不同。
类是一种引用类型,这意味着该类类型的变量可以引用该类的一个实例。
Circle mycircle = new Circle();
mycircle 中存放的是对Circle对象的引用。
基本类型变量和引用类型变量的区别:
对基本类型变量来说,对应内存所存储的值是基本数据类型的值;对应引用类型变量来说,对应内存所存储的值是一个引用,是对象的存储地址。
如图所示,int类型变量i的值就是int值1,而Circle对象c的值保存的是一个引用,它只用Circle对象的内容存储在内存中的位置。
将一个变量赋值给另一个变量时,另外一个变量就被赋值给相同的值,对于基本数据类型而言,就是将一个变量的值赋给另一个变量。对于引用数据类型而言,就是将一个变量的引用赋给另一个变量。
注意在执行完赋值语句c1=c2后,c1指向c2所指的同一个对象,c1以前引用的对象就不再有用,会变成垃圾进行回收。
17.什么是实例变量、实例方法、静态变量、静态方法。调用实例方法与静态方法有何异同。静态变量的作用域是什么?
实例变量依赖于类的某个具体的实例,它是不能被同一个类的不同对象所共享的。存储在互不相关的内存中。
实例方法被类的实例调用的方法。
静态变量(static variable)被类中的所有对象所共享。也成为类(class variable)变量。作用域是整个类。
静态方法(static method)。无须创建类的实例就可以调用的方法。
使用静态修饰符static声明静态变量、常量和方法。
实例方法与静态方法异同:实例方法可以调用实例方法和静态方法,以及访问实例数据域或者静态数据域。静态方法只能调用静态方法以及访问静态数据域,不能调用实例方法或者访问实例数据域,因为静态方法和静态数据域不属于某个特定的对象。实例方法必须创建实例才能调用,静态方法无需创建实例就可以调用。
静态变量的作用域:整个类的所有对象。作用域为类级。
18.java中,当类的成员前用private、protected、public、默认(成员前无任何修饰符)修饰时,成员的可访问性分别是什么?
Private:私有的,只能在它自己的类中被访问。数据或方法可以被声明它的类访问。
Public:公有的,都可以访问。类、数据或方法对在任何包中的任何类都是可见的。
Protected:受保护的,包内都可见,其他包内的子类也可见。允许子类访问定义在父类中的数据域或方法,但不允许不同包的非子类访问这些数据域和方法;
默认:仅包内可见,类、变量或者方法能被同一个包(package)内的任何一个访问。
19.什么是不可变类(Immutable Classes)、不可变对象(Immutable Objects)?以String为例,说明不可变类的优点?
不可变对象:一旦创建其内容就不能再改变
不可变类:不可变对象的类称为不可变类
成为不可变类需要满足的条件:
a、所有数据域都是私有的
b、没有修改器方法
c、没有返回一个指向可变数据域的引用的访问器方法
以String为例,说明不可变类的优点:
a、便于实现字符串常量池
b、使多线程安全
c、避免安全问题。网络连接和数据库连接使用字符串做参数,字符串不可变
d、加快字符串处理速度
20.简述类的下述设计原则:内聚性、分担责任、重用、一致性、清晰性、封装性。
(1)(内聚性)类应该描述一个单一实体,而所有的类操作应该在逻辑上互相配合,支持一个一致的目的。例如:可以设计一个类用于学生,但不应该将学生与教职工组合在同一个类中,因为学生和教职工是不同的实体。
(2)(分担责任) 如果一个实体担负太多的职责,就应该按各自的职责将它分为几个类。例如:String类、StringBuffer类和StringBuilder类都用于处理字符串,但是它们的职责各有不同。String类处理不可变字符串,StringBuilder类创建可变字符串,StringBuffer和StringBuilder类似,只是StringBuffer类还包括更新字符串的同步方法。
(3)类是为了重用而设计的。用户可以以不同的组合和顺序,在许多不同环境中合并多个类。因此,应该设计一个类,这个类应该没有对用户使用它的目的及使用时间的限制,设计属性以确保用户可以按值的任何顺序和任何组合来设置属性,所设计的方法实现的功能应该与它们出现的顺序无关。
(4)一致性:遵循标准Java程序设计风格和命名习惯。为类、数据域和方法选取具有信息的名字。通常的风格是将数据声明置于构造方法之前,并且将构造方法置于方法之前。
(5)清晰性:类应该有一个很清晰的合约,从而易于解释和理解。用户可以以各种不同组合、顺序,以及在各种环境中结合使用多个类。因此再设计一个类时,这个类不应该限制用户如何以及何时使用该类;以一种方式设计属性,以容许用户按值的任何顺序和任何组合来设置;设计方法应该使得实现的功能与他们出现的顺序无关。
方法应在不产生混淆的情况下进行直观定义。不应该声明一个来自其他数据域的数据域。
(6)封装性:一个类应该使用private修饰符隐藏其数据,以免用户直接访问它。这使得类更易于维护。只在希望数据域可读的情况下,才提供get方法;也只在希望数据域可更新的情况下,才提供set方法。
21.什么是关联?什么是聚集?什么是组合?聚集和组合的UML图标识是什么?
关联:关联是一种常见的二元关系,描述两个类之间的活动。
聚集:聚合关系强调的是整体和部分的关系,其中部分可以脱离整体而存在。比如雁群和一只大雁的关系,就是聚合关系,大雁离开雁群还是可以独立存在的。
组合:组合关系也是一种特殊的关联关系,它与聚合关系很像,也是强调整体与部分的关系,不同的是部分无法脱离整体存在。比如学生用手捡钱,其中手就是学生的一部分,但是手不能脱离学生而单独存在。
22.简述生成子类对象时,如何调用父类的构造方法?
父类的构造方法不能被继承。
它们被显式(explicitly)或隐式(implicitly)地调用。
使用super关键字显式调用。
public Circle(double radius, String color, boolean filled) { super(color, filled); this.radius = radius; }
23.什么是构造方法链?关键字super的作用是什么?使用super时应注意什么?
当构造一个子类的对象时,子类构造方法会在完成自己的任务之前,首先调用它的父类的构造方法。如果父类继承自其他类,那么父类构造方法又会在完成自己的任务之前,调用它自己的父类的构造方法。这个过程持续到沿着这个继承体系结构的最后一个构造方法被调用为止。这就是构造方法链。构造一个类的实例时,将会调用沿着继承链的所有父类的构造方法。这就被称为构造方法链(constructor chaining)。
super的作用:1)调用父类的构造方法 2)调用父类的普通方法
语句super()调用父类的无参构造方法,而语句super(arguments)调用与参数匹配的父类的构造方法。语句super()和super(arguments)必须出现在子类构造方法的第一行,这是显示调用父类构造方法的唯一方式。
调用父类的普通方法
public void printCircle() { System.out.println("The circle is created " + super.getDateCreated() + " and the radius is " + radius); }
在这种情况下其实没必要加super,因为该方法已经被circle继承,但在某些情况下必不可少。
使用super时应注意:
调用父类构造方法必须使用关键字super,而这个调用必须是构造方法的第一条语句!在子类中调用父类构造方法的名字会引起一个语法错误。
24.java中,什么是方法覆盖?什么是方法重载?试比较覆盖与重载?java中的重载与C++的重载有何不同。试举例说明。
方法覆盖:子类从父类中继承方法,有时,子类需要修改父类中定义的方法的实现,这个操作被称作方法覆盖(重写)。
方法重载:如果有两个方法的方法名相同,但参数不一致,那么可以说一个方法是另一个方法的重载。
比较:方法重载意味着使用同样的名字但是不同的签名来定义多个方法。方法重写发生在具有继承关系的不同类中,意味着在子类中提供一个对方法的新的实现。
Java与c++中的不同:Java中方法重载可以发生在同一个类中,也可以发生 在具有继承关系的不同类中;而C++类中的函数重载只能发生在本类中,这是他们一个非常重要的区别。
25.简述多态的概念和多态的意义。
一种物质有多种形态。在专业术语中,多态是一种运行时绑定机制(run-time binding) ,也就是使用父类对象的地方都可以使用子类的对象。这就是通常所说的多态。
多态意味着父类型的变量可以引用子类型的对象。
26.什么是引用变量的声明类型?什么是引用变量的实际类型?什么是动态绑定?
一个变量必须被声明为某种类型。变量的这个类型称为它的声明类型。
变量的实际类型是被该变量引用的对象的实际类型。
动态绑定:在运行时根据具体对象的实际类型进行绑定。
27.父类与子类的引用变量之间,在互相转换时,转换规则是什么?instanceof运算符的作用是什么?试举例说明。
总是可以将一个子类的实例转换为一个父类的变量,称为向上转换,因为子类的实例永远是它的父类的实例。当把一个父类的实例转换为它的子类变量(称为向下转换)时,必须使用转换记号“(子类名)”进行显示转换,向编译器表明你的意图。为使转换成功,必须确保要转换的对象是子类的一个实例。如果父类对象不是子类的一个实例,就会出现一个运行异常ClassCastException。
使用instanceof运算符来检测一个对象是否属于一个类,例:
Object myObject = new Circle(); ... // Some lines of code /** Perform casting if myObject is an instance of Circle */ if (myObject instanceof Circle) { System.out.println("The circle diameter is " + ((Circle)myObject).getDiameter()); ...}
28.试比较equals方法和比较操作符“==”。
equals方法
1. 是一个方法,而非运算符
2. 只能适用于引用数据类型
3. Object类中equals()的定义:
public boolean equals(Object obj) { return (this == obj); }
说明:Object类中定义的equals()和==的作用是相同的:比较两个对象的地址值是否相同.即两个引用是否指向同一个对象实体
4. 像String、Date、File、包装类等都重写了Object类中的equals()方法。重写以后,比较的不是两个引用的地址是否相同,而是比较两个对象的"实体内容"是否相同。
5. 通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的"实体内容"是否相同。那么,我们 就需要对Object类中的equals()进行重写.
重写的原则:比较两个对象的实体内容是否相同.
比较运算符==
- 如果比较的是基本数据类型变量:比较两个变量保存的数据是否相等。(不一定类型要相同)
- 如果比较的是引用数据类型变量:比较两个对象的地址值是否相同.即两个引用是否指向同一个对象实体
29.什么是this引用变量,其作用是什么?通过this调用同一个类的构造主法时,此语句是否可以出现在构造方法的任意位置上?
关键字this是指向调用对象本身的引用名。可以用this关键字访问对象的实例成员。
this作用:
this可以访问隐藏数据域
this可以调用同一个类的另外一个构造方法
不可以出现在构造方法的任意位置。Java要求在构造方法中,语句this(参数列表)应在其他可执行语句之前出现。
30.简述final修饰类、变量、方法时,其作用是什么。
final类不能被继承,例如:final class Math {...}
final变量是一个常量:final static double PI = 3.14159;
父类中的final方法不能被子类所覆盖(重写)。
31.定义一个子类时,使用哪一个关键字表示继承?什么是单一继承?什么是多重继承?Java支持多重继承吗?为了实现类似多重继承的功能,在java中应该如何做?
关键字:extends
一个Java类只可能直接继承自一个父类。这种限制成为单一继承。
从几个类派生出一个子类,这个能力称为多重继承。
Java是不允许多重继承的。
在Java中多重继承是可以通过接口来实现的。
32.简述与使用if语句处理异常相比,使用throw-try-catch-finally语句处理异常有什么优点。
if用于逻辑判断,try运行可能会存在异常的代码块,throw抛出异常,catch捕获异常,finally是一定会执行的代码,在异常处理中if用于控制程序,不适合错误提示及跟踪错误,throw-try-catch-finally语句将检测错误和处理错误分离,可以显示错误提示,跟踪并处理错误,正确代码与错误代码分离,更清晰
33.异常处理的优点和缺点分别是什么?
它能使方法抛出一个异常给它的调用者,并由这个调用者可以处理该异常。如果没有这个能力,那么被调用的方法就必须自己处理异常或终止该程序。
异常处理最根本的优势就是将检测错误(由被调用的方法完成)从处理错误(由调用方法完成)中分离出来。
缺点:异常处理通常需要更多的时间和资源。
34.简述异常处理的过程。如何定义一个自定义异常类?关键字throw和throws的作用分别是什么?
声明一个异常、抛出一个异常、捕获一个异常
异常处理过程:当异常被抛出,正常的执行流程就被中断了。异常被catch块捕获,catch块中的代码处理异常。之后,执行catch 块之后的语句。
可以通过派生java.lang.Exception类来定义一个自定义异常类。
自定义异常类:尽量使用API 中的异常类,如果遇到不能用预定义异常类恰当描述的问题,就可以通过派生exception 类或其子类,来创建自己的异常类。
声明异常的关键字是throws,抛出异常的关键字是throw。
关键字throw是抛出异常,语句类似于方法的调用,但不同于调用方法的是,它调用catch块。
关键字throws 是声明异常,表明MethodName 方法可能会抛出异常ExName,如果方法可能会抛出多个异常,就可以用throws后面一个用逗号分隔的异常列表。
35.简述try{…} catch(…){…}catch(…){…}结构的工作过程。
try用来检测可能存在异常的代码块,如果在执行try块的过程中没有异常,则跳过catch子句;如果在执行try块中某条语句抛出一条异常,正常的执行流程就被中断了,跳过try块剩余的语句,异常被对应的catch块捕获,catch块中的代码处理异常。之后,执行catch 块之后的语句。
36.什么是是必检异常(checked exceptions)?什么是非检查型异常(unchecked exceptions)?
RuntimeException、Error以及它们的子类都被称为免检异常(unchecked exceptions)。
剩下所有其它异常都被称为必检异常(checked exceptions),意思是编译器会强制程序员检查并通过try-catch块处理它们,或在方法头进行声明。
在大多数情况下,免检异常都会反映出程序设计上不可恢复的逻辑错误,这些都是程序中必须纠正的逻辑错误。免检异常可能在程序的任何一个地方出现。为了避免过多地使用try-catch块,Java语言不强制要求编写代码捕获或声明免检异常。
注:unchecked exceptions,译为“非检查型异常”更准确些。
37.什么是抽象类型?抽象类的作用是什么?抽象类是否可实例化?
一个父类设计的非常抽象,以至于它都没有任何具体的实例,这样的类称为抽象类。
作用:抽象类可以包含抽象方法,这些方法将在具体的子类中实现。在继承的层次结构中,每个新子类都使类变得越来越明确和具体。
抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。
由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。
抽象类不能用new操作符来创建它的实例。
38.接口是什么?接口的作用是什么?如何定义一个接口?如何使用一个接口?接口可不可以实例化?
接口(interface)是一种与类相似的结构,它只包含常量和抽象方法。
接口在许多方面都与抽象类很相似,但是它的目的是指明相关或者不相关类的多个对象的共同行为。
为了区分接口和类,Java采用下面的语法来定义接口:
使用关键字implements继承一个接口。可以使用接口作为引用变量的数据类型或转换类型的结果等。
不能实例化。
39.什么是浅复制(Shallow Copy)和深复制(Deep Copy)?如何实现深复制?
浅拷贝:只复制当前的对象,对该对象内部的引用(其他类对象作为自己的元素也叫对其他对象的引用)不能复制(在堆内存中从新创建空间,内容相同,但地址不同)。
深拷贝:对对象内部的引用均复制,是创建一个新的实例,并复制实例。不仅要复制对象的所有基本数据类型的成员变量值,还要为所有引用数据类型的成员变量申请存储空间,并复制每个引用数据类型成员变量所引用的对象,直到该对象可达的所有对象。也就是说,对象进行深拷贝要对整个对象图进行拷贝!
(1) 通过重写clone方法来实现深拷贝。每一层的每个对象都进行浅拷贝。为对象图的每一层的每一个对象都实现Cloneable接口并重写clone方法,最后在最顶层的类的重写的clone方法中调用所有的clone方法即可实现深拷贝。
(2) 通过对象序列化实现深拷贝。将对象序列化为字节序列后,默认会将该对象的整个对象图进行序列化,再通过反序列即可完美地实现深拷贝。
重写前只能实现浅拷贝的clone方法
重写后可以实现深拷贝的clone方法
40.从数据成员、构造方法、成员方法三方面对比一下接口与抽象类。
|
数据成员 |
构造方法 |
成员方法 |
抽象类 |
无限制 |
子类通过构造方法链调用构造方法,抽象类不能用new操作符实例化 |
无限制 |
接口 |
所有的变量必须是public static final |
没有构造方法。接口不能用new操作符实例化 |
所有方法必须是公共的抽象public abstract实例方法 |
41.JavaFX中,什么是舞台(Stage), 场景 (Scene), 节点(Nodes)?三者之间的关系是什么?面板(pane)作用是什么?
一个 JavaFX 应用包含三个主要的控件:Stage、Scene 和 Nodes
Stage舞台:一个Stage对象是一个窗体,用于显示包含了节点的场景。当应用程序启动的时候,一个称为主舞台的Stage对象由JVM自动创建。
Scene场景:表示 JavaFX 应用的物理内容。它包含 scene 图像所有的内容。scene 对象由 javafx.scene 包中的 Scene 类表示。在一个实例中,场景对象只能添加到一个 stage 中。
可以通过 Scene 类来实例化场景。将尺寸(宽和高)和根节点传入 stage 的构造方法可以控制它的大小。
Nodes节点:节点是可视化组件,比如一个形状、一个图像视图、一个UI组件或者一个面板。
关系:可以认为舞台是一个支持场景的平台,节点如同在场景中演出的演员。
面板的作用:用于容纳节点,自动地将节点布局在一个希望的位置和大小。
42.JavaFX中,什么是属性绑定?有哪两种属性绑定?
属性绑定:可以将一个目标对象和一个源对象绑定。如果源对象中的值改变了,目标对象也将自动改变。
目标对象称为绑定对象或者绑定属性,源对象称为可绑定对象或者可观察对象。
一个属性的改变将反映到另一个对象上,反过来也一样,这称为双向绑定。
如果目标和源同时都是绑定属性和可观察属性,它们就可以使用bindBidirectional方法进行双向绑定。
单向绑定、双向绑定。
43.描述面板StackPane、FlowPane、GridPane、Borderpane、HBox、VBox的布局特点是什么。
类 |
描述(布局特点) |
Pane |
布局面板的基类,它有getChildren()方法来返回面板的节点列表 |
StackPane |
节点放置在面板中央,并且叠加在其他节点之上 |
FlowPane |
节点以水平方式一行一行放置,或者垂直方式一列一列放置 |
GridPane |
节点放置在一个二维网格的单元格中 |
Borderpane |
将节点放置在顶部、右边、底部、左边以及中间区域 |
HBox |
节点放在单行中 |
VBox |
节点放在单列中 |
44.简述JavaFX中一个事件从触发到被处理的过程。
Java采用一个基于委托的模型来进行事件处理:一个源对象触发一个事件,然后一个对该事件感兴趣的对象处理它。后者称为一个对象处理器或者一个事件监听器。一个对象如果要成为一个源对象上面的事件处理器,需要满足两个条件:
45.什么是事件源对象?什么是事件对象?描述两者之间的关系。
事件源对象:产生一个事件并且触发它的组件称为事件源对象,比如一个按钮是按钮单击动作事件的源对象。
事件对象:由事件源产生的对象,是一个事件类的实例,一个事件对象包含与事件相关的任何属性。
关系:事件是从一个事件源上产生的对象。
46.文本IO与二进制IO有何区别?
文本I/O建立在二进制I/O之上,为字符编码和解码提供了一个抽象级别。文本I/O需要进行编码和解码。写入字符时,JVM将Unicode转化为特定文件编码,而读取时,反之。
二进制I/O不需要转换,所以二进制I/O比文本I/O更有效。如果向文件写入字节,就是将原始的字节复制到文件中。当从文件读取字节时,就会返回文件中的确切字节。
二进制文件与主机的编码方案无关,因此是可移植的。任何机器上的Java程序都可以读取Java程序所创建的二进制文件。
Java类文件存储为二进制文件,可以在任何具有Java虚拟机的机器上运行。
47.什么是内部类?什么是匿名内部类?
内部类(Inner class),或者称为嵌套类,是一个定义在另外一个类范围中的类。内部类对于定义处理器类特别有效。
public class line { Point p1,p2; class Point{//内部类 int x,y; Point(int x,int y) { this.x=x; this.y=y; } }; }
内部类可以使得程序 更加精简。
内部类支持包含它的类的工作,可被编译成一个名为OuterClassName$InnerClassName的类。
例如:Test类的内部类A,被编译成Test$A.class。
一个匿名内部类是一个没有名字的内部类。它将定义一个内部类以及创建一个内部类的实例结合在一步实现。
匿名类不具有类名,不具有抽象性,不能派生出子类。通常用在图形用户界面(GUI)设计中进行各种事件处理,如鼠标事件、按钮事件和键盘事件等。
48.什么是UTF-8?为什么使用UTF-8?
UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码,又称万国码。
由于许多应用程序只需要ASCII码字符集,所以将8位ASCII表示为16位的Unicode码是很浪费的,为解决这个问题出现了一些中间格式字符集,它允许系统可以同时操作Unicode码及ASCII码,UTF-8就是其中一种。
49.什么可序列化的(serializable)对象?一个对象如何实现可序列化。
并不是每一个对象都可以写到输出流。可以写入输出流中的对象称为可序列化的。
可序列化的对象的类必须实现Serializable接口。Serializable接口是一种标记性接口。因为它没有方法,所以,不需要在类中为实现Serializable接口增加额外的代码。
实现这个接口,可启动Java序列化机制,自动完成存储对象和数组的过程。
50.JVM(java虚拟机)中有几个比较重要的内存区域:方法区、常量池、堆区、栈区,这几个区域在java类的生命周期中扮演着比较重要的角色,他们的作用分别是什么?
堆:存放所有new出来的对象实例
栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)
常量池:存放字符串常量(string)和基本类型常量(public static final)
方法区:用于存储虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码数据。
分析程序写结果
1、
import java.io.*; public class Test{ public static void main(String args [ ]){ AB s = new AB("Hello!","I love JAVA."); System.out.println(s.toString( )); } } class AB { String s1; String s2; public AB(String str1, String str2) { s1 = str1; s2 = str2; } public String toString( ){ return s1+s2; } }
Hello!I love JAVA.
2、
class Animal { Animal() { System.out.print("Animal"); } } public class Test extends Animal { Test() { System.out.print("Dog "); } public static void main(String[] args) { Test snoppy = new Test(); } }
AnimalDog
3、
public class Father { String name, address, tel; int age; public Father(String name, int age) { this.name = name; this.age = age; } void out() { System.out.print("姓名:" + name); System.out.print(" 年龄:" + age); } void outOther() { System.out.print(" 家庭住址:" + address); System.out.print(" 电话:" + tel); } }
class Son extends Father { String school; public Son(String name, int age) { super(name, age); } void out() { super.out(); super.outOther(); System.out.println("学校:" + school); } public static void main(String args[]) { Son son = new Son("Tom", 15); son.address = "金水区"; son.school = "九中"; son.tel = "66123456"; son.out(); } }
姓名:Tom 年龄:15 家庭住址:金水区 电话:66123456学校:九中
4、
abstract class Shape { abstract void display(); } class Circle extends Shape { void display() { System.out.println("Circle"); } } class Rectangle extends Shape { void display() { System.out.println("Rectangle"); } } class Triangle extends Shape { void display() { System.out.println("Triangle"); } } public class AbstractClassDemo { public static void main(String args[]) { Shape p; p = null; int which; for (which = 0; which < 3; which++) { switch (which) { case 0: p = new Circle(); break; case 1: p = new Rectangle(); break; case 2: p = new Triangle(); break; } p.display(); } return; } }
Circle
Rectangle
Triangle
5、
public class Father{ int a=100; public void miner(){ a--; } public static void main(String[] args){ Father x = new Father(); Son y = new Son(); System.out.println(y.a); System.out.println( y.getA()); y.miner(); System.out.println(y.a); System.out.println(y.getA()); } } class Son extends Father{ int a = 0; public void plus(){ a++; } public int getA() { return super.a; } }
0 100 0 99
要注意这里的基础关系,子类本身就有一个变量a了,但父类也有一个a,这样子类就有两个a变量
6、
public class StringExample { String str = new String("good"); char[] cArray = { 'a', 'b', 'c' }; public static void main(String args[]) { StringExample se = new StringExample (); se.change(se.str, se. cArray); System.out.println(se.str + " and " ); System.out.print(se.cArray); } public void change(String str, char ch[]) { str = "test ok"; ch[0] = 'g'; } }
good and
gbc
change函数中传递的都是引用,但String是不可变类, str = "test ok"创建了一个新的字符串常量。
7、
public class StringTest{ public static void main(String args[]) { String str1 = "Application"; String str2 = new String("Application"); String str3 = "Application"; if (str1 == str2){ System.out.println("str1 == str2 is true"); } if (str1 == str3){ System.out.println("str1 == str3 is " + (str1 == str3)); } } }
str1 == str3 is true
注意这里str1和str2是存放在常量池中的,它们有着相同的引用地址
而str3是new出来的,虽然常量池中已经有"Application"了,但还会在内存(不是字符串常量池中,而是在堆里面)上创建一个新的String对象,二者的引用不同。
编程题
1.采用面向对象的方式编写一个通迅录管理程序,通迅录中的信息包括:姓名,公司,联系电话,邮编。要求的操作有:添加一个联系人,列表显示所有联系人。先给出类定义,然后给出类实现。(提示:可以设计二个类,一个通迅录条目类CommEntry,一个通讯录类Commus)
CommEntry.java
public class CommEntry { private String name; private String company; private String tels; private String address; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getCompany() { return company; } public void setCompany(String company) { this.company = company; } public String getTels() { return tels; } public void setTels(String tels) { this.tels = tels; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } @Override public String toString() { return "CommEntry [name=" + name + ", company=" + company + ", tels=" + tels + ", address=" + address + "]"; } }
Commus.java
import java.util.ArrayList; import java.util.Scanner; public class Commus { private ArrayList<CommEntry> ace = new ArrayList<CommEntry>(); public void add() { CommEntry ce = new CommEntry(); Scanner input = new Scanner(System.in); String name= input.nextLine(); String company= input.nextLine(); String tels= input.nextLine(); String address= input.nextLine(); ce.setName(name); ce.setCompany(company); ce.setTels(tels); ce.setAddress(address); ace.add(ce); }; public void display() { for(int i=0;i<ace.size();i++) { System.out.println(ace.get(i).toString()); } } public static void main(String []args) { Commus c = new Commus(); c.add(); c.add(); c.display(); } }
2.设计实现一个类模拟整数栈操作。
import java.util.ArrayList; public class MyStack { private ArrayList<Object> list = new ArrayList<>(); public boolean isEmpty() { return list.isEmpty(); } public int getSize() { return list.size(); } public Object peek() { return list.get(getSize() - 1); } public Object pop() { Object o = list.get(getSize() - 1); list.remove(getSize() - 1); return o; } public void push(Object o) { list.add(o); } @Override public String toString() { return "stack: " + list.toString(); } }
2. 定义一个表示学生信息的类Student,要求如下:
(1)类Student的成员变量:
sNO 表示学号;sName表示姓名;sGender表示性别;sAge表示年龄;sJava:表示Java课程成绩。
(2)类Student带参数的构造函数:
在构造函数中通过形参完成对成员变量的赋值操作。
(3)类Student的函数成员:getNo():获得学号;getName():获得姓名;getGender():获得性别; getAge()获得年龄;getJava():获得Java 课程成绩
(4)根据类Student的定义,创建五个该类的对象,输出每个学生的信息,计算并输出这五个学生Java语言成绩的平均值,以及计算并输出他们Java语言成绩的最大值和最小值。
public class Student { private String sNo; private String sName; private String sGender; private String sAge; private String sJava; public Student(String sNo,String sName,String sGender,String sAge,String sJave) { this.sNo=sNo; this.sName= sName; this.sGender=sGender; this.sAge=sAge; this.sJava=sJave; } public Student() { } public String getsNo() { return sNo; } public String getsName() { return sName; } public String getsGender() { return sGender; } public String getsAge() { return sAge; } public String getsJava() { return sJava; } @Override public String toString() { return "Student [sNo=" + sNo + ", sName=" + sName + ", sGender=" + sGender + ", sAge=" + sAge + ", sJava=" + sJava + "]"; } }
import java.util.Scanner; public class StudentDom { public static void main() { Student[] st = new Student[3]; System.out.println("请录入学生学号、姓名、性别、年龄、成绩:"); Scanner in = new Scanner(System.in); for (int i = 0; i < st.length; i++) { st[i] = new Student(in.nextLine(), in.nextLine(), in.nextLine(), in.nextLine(), in.nextDouble()); } Student s1=null;//创建一个为空的对象进行数据交换 for(int i=0;i<st.length;i++) { for (int j =0; j < st.length; j++) { if(j!=4)//这里必须加上这个条件,不然数字会报出越界的问题 if(st[j].getsJava()<st[j+1].getsJava()) { s1=st[j+1]; st[j+1]=st[j]; st[j]=s1; } } } System.out.println("学生的成绩排名如下\n姓名\t学号\t成绩"); for (int i = 0; i < st.length; i++) { System.out.println(st[i].toString()); } } }