面试例题1:对象与实例有什么区别?
解析:在Java的内存分配中,对象和实例是不同的,前者分配在内存堆里,后者分配在堆栈里,至于为什么要这样分,参考一下其他的资料。对象是不变的东西,它是对客观事物的抽象,实例是对操作对象的引用,你不能直接操作对象。
答案:对象和实例从宏观的角度看,区别是:对象是同类事物的一种抽象表现形式,而实例是对象的具体化,一个对象可以实例化很多实例,对象就是一个模型,实例是照着这个模型生产的最终产品。实际上就是这样,一个对象可以实例化N个实例。就像根据一个模型可以制造多个实际的产品一样。
从内存分配的角度来看,对象是保存在堆中的,而实例是存储在栈中的,实例其实只是对象的一个引用,也就是指向对象的指针。
面试例题2:Java中所有的类都继承了java.lang.Object类,而在C++中没有像java.lang.Object这样的类,这是为什么呢?都是面向对象,Java这样做有什么好处呢?
解析:Java采用的是单根结构,所有的类都继承了java.lang.Object类。对于Java这种纯 面向对象的语言来说,这种设计具有很好的灵活性,比如对垃圾收集来说很有利,所有的类都具有java.lang.Object类具有的方法等。C++没有 更多这样的方法,大概是为了向后兼容。向C兼容,满足它设计上最大的灵活性。
答案:C++的特点是指针,一个指针可以指向任何的对象、结构、基本类型、函数。
Java没有指针类型,所以Java用Object基础类的共同特征来实现所有对象类型之间的转换。
面试例题3:声明与定义之间的区别是什么?在Java里声明和定义能否分开?
解析:
声明:一种把一个名称引入或者重新引入到某个作用域的构造。
定义:它也是一种声明,但该声明必须给出被声明实体的细节。
对于变量而言,这里的细节是指:为被声明实体保留存储空间。
对于class类型和函数定义而言,指的是包含有一对花括号内容的声明。
对于外部变量而言,指的是前面没有关键字extern或者在声明时就进行初始化。
变量的声明有以下两种情况。
一种是需要建立存储空间的。例如,int a 在声明的时候就已经建立了存储空间。
另一种是不需要建立存储空间的,例如,extern int a。其中,变量a是在别的文件中定义的。前者是“定义性声明(defining declaration)”,或者称为“定义(definition)”,而后者是“引用性声明(referencing declaration)”。从广义的角度来讲,声明中包含着定义,但是并非所有的声明都是定义,例如int a,它既是声明,同时又是定义。然而对于 extern a来讲,它只是声明不是定义。在一般的情况下我们常常这样叙述,把建立空间的声明称为“定义”,而把不需要建立存储空间的声明称为“声明”。很明显在这里 指的声明的范围是比较窄的,也就是说非定义性质的声明。
答案:
变量的定义和声明的区别在于是否分配内存,如果分配内存就是定义,否则就是声明。
类中的变量只是声明而不是定义,因为它只是类声明的一部分。不同于变量的定义,类的定义是一种新的类型的定义,只有实例化后才会分配内存。所以类成员变量只是声明而不是定义。
在Java中,利用Interface,也可以将声明和实现分开。如下所示。
//MyInterface.java
public interface MyInterface
{
void method();
}
//MyImpl.java
public class implements MyInterface
{
public void method()
{
//……
}
}
面试例题4:Which is incorrect about the class?(关于类的描述下面哪个是错误的?)[金山公司2005年面试题]
A.A class is a blueprint to objects.
B.We use the keyword class to create a class construct.
C.Once a class is declared, the class name becomes a type name and
can be used to declare variables.
D.The class is same as the struct, and there are no different between
class and struct.
解析:这道题的考点是类的概念。
答案:D
面试例题5:Which is incorrect about the OOP?(下面关于面向对象技术的叙述哪个是错误的?)[金山公司2005年面试题]
A.The central idea of OOP is to build programs using software objects.
B.The OOP focuses mainly on the step-by-step procedure as procedure-
oriented programing.
C.The OOP offers many advantages: simplicity,modularity,modifiability,
extensibility, and so on.
D.The key concept of object orientation is the attachment of procedure
to data.
解析:OOP的概念面试例题。面向对象和面向过程不能混为一谈。
答案:B,D
类和对象
面试例题1:以下代码编译时会产生错误的是______。[Trend公司2005年面试题]
class reverseIt4
{
public static void main(String[] args)
{
EnclosingClass jb2; //-----1
System.out.println(jb2.m); //-----2
}
}
class EnclosingClass //--------3
{
public int m = 6;
class InnerClass //-------4
{
int msquare;
InnerClass()
{
msquare = m*m;
}
}
}
A.语句1 B.语句2 C.语句3 D.语句4
解析:语句3和语句4显然是正确的,尽管它们的描述不是那么规范(存在一个类中的类)。语句1声明了一个类,但是没有做定 义,于是问题就出现了。声明好比只是告诉编译器有一个人,但是如果不定义,这个人就是个抽象的人,没有身高、体重、年龄、职业的“空”人。所以定义对象必 须在声明的同时给它定义。正确的程序如下。
class reverseIt4
{
public static void main(String[] args)
{
EnclosingClass jb = new EnclosingClass();
System.out.println(jb.m);
}
}
class EnclosingClass
{
public int m = 6;
class InnerClass
{
int msquare;
InnerClass()
{
msquare = m*m;
}
}
}
答案:该题是问编译在哪儿出现问题,尽管问题出在1处,但编译器不会发现,编译器只有在2处才会发现问题。所以答案选B。
面试例题2:Object是所有类的父类,任何类都默认继承Object。Object类到底实现了哪些方法?
答案:
1.clone方法
保护方法,实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常。
2.getClass方法
final方法,获得运行时类型。
3.toString方法
该方法用得比较多,一般子类都有覆盖。
4.finalize方法
该方法用于释放资源。因为无法确定该方法什么时候被调用,很少使用。
5.equals方法
该方法是非常重要的一个方法。一般equals和==是不一样的,但是在Object中两者是一样的。子类一般都要重写这个方法。
6.hashCode方法
该方法用于哈希查找,重写了equals方法一般都要重写hashCode方法。这个方法在一些具有哈希功能的Collection中用到。
一般必须满足obj1.equals(obj2)==true。可以推出obj1.hash- Code()==obj2.hashCode(),但是hashCode相等不一定就满足equals。不过为了提高效率,应该尽量使上面两个条件接近等价。
7.wait方法
wait方法就是使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。wait()方法一直等待,直到获得锁或者被中断。wait(long timeout)设定一个超时间隔,如果在规定时间内没有获得锁就返回。
调用该方法后当前线程进入睡眠状态,直到以下事件发生。
(1)其他线程调用了该对象的notify方法。
(2)其他线程调用了该对象的notifyAll方法。
(3)其他线程调用了interrupt中断该线程。
(4)时间间隔到了。
此时该线程就可以被调度了,如果是被中断的话就抛出一个InterruptedException异常。
8.notify方法
该方法唤醒在该对象上等待的某个线程。
9.notifyAll方法
该方法唤醒在该对象上等待的所有线程。
嵌套类
面试例题1:请说明static nested class和inner class的不同。
答案:
1.nested(嵌套)class(一般是C++的说法)
nested class是合成型聚集关系(Composite Aggregation)的另一种表达方式,也就是说nested class也可以用Aggregation表达出来。但是,nested class更加精确地表达了一种专用的、紧耦合的关系,尤其在代码生成时,nested class在Java中映射成inline class。比如,计算机专用开关电源类可以作为计算机类的nested class,但是,电池组类就不一定适合作为计算机类的nested class,因为,电池组类表述的是一个过于通用的对象,可能还被包含(Aggregation)于模型中的其他设备对象。class A nested in class B,则说明A是一个nested class,一般A是用来完成B中的某种重要功能的。
2.inner class(一般是Java的说法)
Java内部类与C++嵌套类最大的不同就在于是否有指向外部的引用上。
静态内部类(inner class)意味着:创建一个static内部类的对象,不需要一个外部类对象;不能从一个static内部类的一个对象访问一个外部类对象。
面试例题2:关于下面类的定义,以下哪种说法是正确的?[研华科技2005年11月面试题]
public class Droitwich{
class one{
private class two{
public void main(){
System.out.println("two");
}
}
}
}
A.此代码不能编译成功,因为该类嵌套了不止一层
B.此代码不能编译通过,因为class two是私有的
C.此代码可以编译通过,并且在运行的时候输出字符串two
D.此代码编译没有错误
解析:
内部类或嵌套类在类层级上没有限制,所以选项A是错误的。
内部类可以是私有类,所以选项B也是错误的。
选项C的main方法不是public static void main的,并且假设命令行是java Droitwich,它不能在任何地方被调用。
答案:D
接口在实际语言,如Delphi、Java、C++等中,都有广义和狭义之分,这很重要,以前就是因为没明白接口的广义和狭义之分,始终没能真正理解接口的真正意义。
广义接口从一般意义上说,凡是一个类提供给外部使用的部分都可以被称为接口。但是在引入继承和抽象类之前,这个广义接口并没有太大意义。广义接口的真正意义是在类的继承中体现多态的功能,这种接口又被称为抽象类接口。
狭义接口是指特定的函数集合,一般是用interface(Delphi)声明的,它表示一个方法集合,这个 集合被称为一个命名接口。一个命名接口中的方法必须在一个类中实现后才能被使用,一个类继承实现一个接口,称为这个类实现了该接口,一个接口可以被多个类 实现,一个类也可以继承多个接口,这样就形成了一种灵活的接口调用方式,从而实现更加灵活和节省资源的多态。
从上述认识来看,接口实际上是结合着多态而来的,它的最大的任务就是实现多态。而多态又是面向对象最精华的理论,掌握了多态,也就掌握了面向对象的精髓。但掌握多态必须先理解和掌握接口,只有充分理解接口的意义,才能更好地应用多态。
在面试过程中,各大企业会考量你对虚函数、纯虚函数、私有继承、多重继承等知识点的掌握程度。因此,这是本书比较难掌握的一章。
基础知识
面试例题1:下面哪一项说法是正确的?
A.在一个子类中一个方法不是public的就不能被重载
B.覆盖一个方法只需要满足相同的方法名和参数类型就可以了
C.覆盖一个方法必须需要相同的方法名参数和返回类型
D.一个覆盖的方法必须有相同的方法名、参数名和参数类型
解析:
对于在同一可访问区内被声明的几个具有不同参数列(参数的类型、个数、顺序不同)的同名函数,程序会根据不同 的参数列来确定具体调用哪个函数,这种机制叫重载,重载不关心函数的返回值类型。覆盖是指派生类中存在重新定义的函数,其函数名、参数列、返回值类型必须 同父类中的相对应被覆盖的函数严格一致,覆盖函数和被覆盖函数只有函数体(花括号中的部分)不同,当派生类对象调用子类中该同名函数时会自动调用子类中的 覆盖版本,而不是父类中的被覆盖函数版本,这种机制就叫做覆盖。
成员函数被重载的特征如下。
(1)相同的范围(在同一个类中);
(2)函数名字相同;
(3)参数不同;
(4)virtual关键字可有可无。
覆盖的特征如下。
(1)不同的范围(分别位于派生类与基类);
(2)函数名字相同;
(3)参数相同;
(4)基类函数必须有virtual关键字。
答案:C
面试例题2:下面的说法中哪项是正确的?
A.静态方法不能被覆盖成非静态的方法
B.静态方法不能被声明成私有的
C.私有的方法不能被重载
D.一个重载的方法在基类中不通过检查不能抛异常
解析:JDK 1.1版本会发布这样一个提示信息:静态的方法不能被覆盖。选项 B和C的说法并不合理,没有合理的理由来说静态的方法不能被声明成私有的,或私有的方法不能被重载。选项D是对于一个覆盖方法异常限制的混杂版本来说的。
答案:A
面试例题3:给定下面的代码。
class Base {}
class Agg extends Base{
public String getFields(){
String name = "Agg";
return name;
}
}
public class Avf{
public static void main(String argv[]){
Base a = new Agg();
//Here
}
}
What code placed after the comment //Here will result in calling the getFields method resulting in the output of the string "Agg"?(下面哪个选项的代码替换到//Here,会调用getFields方法使输出结果输出字符串“Agg”?)
A.System.out.println(a.getFields());
B.System.out.println(a.name);
C.System.out.println((Base) a.getFields());
D.System.out.println( ((Agg) a).getFields());
解析:Base类型要引用Agg类的实例需要把Base类显示转换为Agg类,然后调用Agg类中的 getFields()方法。如果a是Base类的一个实例的话,它要调用getFields()方法,那此方法在Base类中是不存在的,必须把a转换 为Agg类的一个实例,这样才可以调用它里面的方法。
答案:D
面试例题4:如果在下列代码中的Here处添加一段代码,问哪一个选项不能通过编译[Trend公司2005年10月面试题]
public class Upton{
public static void main(String argv[]){
}
public void amethod(int i){}
//Here
}
A.public int amethod(int z){}
B.public int amethod(int i,int j){return 99;}
C.protected void amethod(long l){}
D.private void anothermethod(){}
解析:选项A不能通过编译。一个方法是显式地返回一个int值的方法,另一个是在同一个类中上述方法的一个重定义。方法中参数从i换做z对一个方法并没有任何影响。一个方法不能在同一个类中被覆盖。
答案:A
面试例题5:下面代码的输出结果是多少?[Trend公司2005年10月面试题]
class A {
public static void prt() {
System.out.println("1");
}
public A() {
System.out.println("A");
}
}
public class B extends A {
public static void prt() {
System.out.println("2");
}
public B() {
System.out.println("B");
}
public static void main(String[] args) {
A a = new B();
a = new A();
}
}
解析:每新建一个对象,都会产生一个构造函数,因为产生构造函数的顺序是A,B,A,所以结果是A,B,A。
答案:A,B,A
面试例题6:下面代码的输出结果是多少?[Trend公司2005年10月面试题]
class Parent {
protected String value = "123";
public String getValue() {
return value;
}
}
public class Child extends Parent {
protected String value = "456";
}
解 析:父类里的东西也可以理解成你自己的东西。也就是说在程序里面有两个value,一个是123,另一个是456。而现在要输出的是父类里面的那个 value,所以就是123。原因是在输出语句中使用的是getValue()方法,而这个方法就是父类里面的方法。它的返回值是父类里面定义的 value,从父类继承来的没有被子类覆盖的方法操作的是继承于父类的被隐藏的变量,也就是123。
答案:123