好像出现了一个误区,现在看java面试越来越难,要求越来越高了

标签(空格分隔): Java面向对象


1. 面向对象的特征有哪些方面?

    • 抽象就是找出一些事物的相似和共性之处,然后将这些事物归为一个类,这个类只考虑这些事物的相似和共性之处,并且会忽略与当前主题和目标无关的那些方面,将注意力集中在与当前目标有关的方面。
    • 例如,看到一只蚂蚁和大象,你能够想象出它们的相同之处,那就是 抽象。抽象包括行为抽象和状态抽象两个方面。例如,定义一个 Person 类,如下:
      classPerson{ String name; int age; }人本来是很复杂的事物,有很多方面,但因为当前系统只需要了解人的姓名和年龄,所以上面定义的类中只包含姓名和年龄这两个属性,这就是一种抽像,使用抽象可以避免考虑一些与目标无关的细节。我对抽象的理解就是不要用显微镜去看一个事物的所有方面,这样涉及 的内容就太多了,而是要善于划分问题的边界,当前系统需要什么,就只考虑什么。
  • 继承:在定义和实现一个类的时候,可以在一个已经存在的类的基础之上来进行,把这个已经存在的类所定义的内容作为自己的内容,并可以加入若干新的内容,或修改原来的方法使之更适合特殊的需要,这就是继承。继承是子类自动共享父类数据和方法的机制,这是类之间的一种关系,提高了软件的可重用性和可扩展性。

    • 封装是保证软件部件具有优良的模块性的基础,封装的目标就是要实现软件部件的“高内聚、低耦合”,防止程序相互依赖性而带来的变动影响。在面向对象的编程语言中,对象是封装 的最基本单位,面向对象的封装比传统语言的封装更为清晰、更为有力。面向对象的封装就是把描述一个对象的属性和行为的代码封装在一个“模块”中,也就是一个类中,属性用变量定义,行为用方法进行定义,方法可以直接访问同一个对象中的属性。通常情况下,只要记 住让变量和访问这个变量的方法放在一起,将一个类中的成员变量全部定义成私有的,只有这个类自己的方法才可以访问到这些成员变量,这就基本上实现对象的封装,就很容易找出要分配到这个类上的方法了,就基本上算是会面向对象的编程了。把握一个原则:把 对同一事物进行操作的方法和相关的方法放在同一个类中,把方法和它操作的数据放在同 一个类中。

    • 例如,人要在黑板上画圆,这一共涉及三个对象:人、黑板、圆,画圆的方法要分配给哪个对象呢?由于画圆需要使用到圆心和半径,圆心和半径显然是圆的属性,如果将它们在类中定义成了私有的成员变量,那么,画圆的方法必须分配给圆,它才能访问到圆心和半径这两 个属性,人以后只是调用圆的画圆方法、表示给圆发给消息而已,画圆这个方法不应该分配在人这个对象上,这就是面向对象的封装性,即将对象封装成一个高度自治和相对封闭的 个体,对象状态(属性)由这个对象自己的行为(方法)来读取和改变。

    • 一个更便于理解的例子就是,司机将火车刹住了,刹车的动作是分配给司机,还是分配给火车,显然,应该分配给火车,因为司机自身是不可能有那么大的力气将一个火车给停下来的,只有火车自己 才能完成这一动作,火车需要调用内部的离合器和刹车片等多个器件协作才能完成刹车这个动作,司机刹车的过程只是给火车发了一个消息,通知火车要执行刹车动作而已。

  • 多态:多态是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编 程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象, 该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。 因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到 各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以 改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。多态性 增强了软件的灵活性和扩展性。例如,下面代码中的 UserDao 是一个接口,它定义引用变 量 userDao 指向的实例对象由 daofactory.getDao()在执行的时候返回,有时候指向的是

2. 面向对象的一道继承题目

    • 重载 Overload 表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同(即参数个数或类 型不同)。
    • 至于 Overloaded的方法是否可以改变返回值的类型这个问题,要看你倒底想问什么呢?这个题目很模糊。如果 几个Overloaded 的方法的参数列表不一样,它们的返回者类型当然也可以不一样。但我估计你想问的问题是:如果两个方法的参数列表完全一样,是否可以让它们的返回值不同来实现重载 Overload。这是不行的,我们可以用反证法来说明这个问题,因为我们有时候调用一个方法时也可以不定义返回结果变量,即不要关心其返 回结果,例如,我们调用 map.remove(key) 方法时,虽然 remove 方法有返回值,但是我们通常都不会定义接收返回结果的变量,这时候假设该类中有两个名称和参数列表完全相同的方法,仅仅是返回类型不同,Java 就无法确定编程者倒底是想调用哪个方法了,因为它无法通过返回结果类型来判断。
    • Overload 对我们来说可能比较熟悉,可以翻译为重载,它是指我们可以定义一些名称相同的方法,通过定义不 同的输入参数来区分这些方法,然后再调用时,VM 就会根据不同的参数样式,来选择合适的方法执行。在使用 重载要注意以下的几点:
      • 在使用重载时只能通过不同的参数样式。例如,不同的参数类型,不同的参数个数,不同的参数顺序(当然,同一方法内的几个参数类型必须不一样,例如可以是 fun(int,float) ,但是不能 fun(int,int)) ;
      • 不能通 过访问权限、返回类型、抛出的异常进行重载;
      • 方法的异常类型和数目不会对重载造成影响;
      • 对于继承来说,如果某一方法在父类中是访问权限是 priavte,那么就不能在子类对其进行重载,如果定义的 话,也只是定义了一个新方法,而不会达到重载的效果。
    • 重写 Override表示子类中的方法可以与父类中的某个方法的名称和参数完全相同,通过子类创建的实例对象调 用这个方法时,将调用子类中的定义方法,这相当于把父类中定义的那个完全相同的方法给覆盖了,这也是面向 对象编程的多态性的一种表现。子类覆盖父类的方法时,只能比父类抛出更少的异常,或者是抛出父类抛出的异 常的子异常,因为子类可以解决父类的一些问题,不能比父类有更多的问题。子类方法的访问权限只能比父类的 更大,不能更小。如果父类的方法是 private 类型,那么,子类则不存在覆盖的限制,相当于子类中增加了一个 全新的方法。
    • Override 可以翻译为覆盖,从字面就可以知道,它是覆盖了一个方法并且对其重写,以求达到不同的作用。对我 们来说最熟悉的覆盖就是对接口方法的实现,在接口中一般只是对方法进行了声明,而我们在实现时,就需要实 现接口声明的所有方法。除了这个典型的用法以外,我们在继承中也可能会在子类覆盖父类中的方法。
    • 在覆盖要 注意以下的几点:
      • 覆盖的方法的标志必须要和被覆盖的方法的标志完全匹配,才能达到覆盖的效果;
      • 覆盖的方法的返回值必须和被覆盖的方法的返回一致;
      • 覆盖的方法所抛出的异常必须和被覆盖方法的所抛出的异常一致,或者是其子类;
      • 被覆盖的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。

4. Java 中,什么是构造函数?什么是构造函数重载?什么是复制构造函数?

当新对象被创建的时候,构造函数会被调用。每一个类都有构造函数。在程序员没有给类提供构造函数的情况 下,Java 编译器会为这个类创建一个默认的构造函数。

Java 中构造函数重载和方法重载很相似。可以为一个类创建多个构造函数。每一个构造函数必须有它自己唯一的 参数列表。

Java 不支持像 C++ 中那样的复制构造函数,这个不同点是因为如果你不自己写构造函数的情况下,Java不会创 建默认的复制构造函数。

不支持,Java 不支持多继承。每个类都只能继承一个类,但是可以实现多个接口。

7. 接口和抽象类的区别是什么?

Java 提供和支持创建抽象类和接口。它们的实现有共同点,不同点在于:

接口中所有的方法隐含的都是抽象的。而抽象类则可以同时包含抽象和非抽象的方法。

类可以实现很多个接口,但是只能继承一个抽象类

类如果要实现一个接口,它必须要实现接口声明的所有方法。但是,类可以不实现抽象类声明的所有方法,当然,在这种情况下,类也必须得声明成是抽象的。

抽象类可以在不提供接口方法实现的情况下实现接口。

Java 接口中声明的变量默认都是 final 的。抽象类可以包含非 final 的变量。

接口是绝对抽象的,不可以被实例化。抽象类也不可以被实例化,但是,如果它包含 main 方法的话是可以被调用的。

8. 下列说法正确的有()?

解析:这里可能会有误区,其实普通的类方法是可以和类名同名的,和构造方法唯一的区分就是,构造方法没有

答案:CD 解析:接口很重要,为了说明情况,这里稍微啰嗦点:

(1)接口用于描述系统对外提供的所有服务,因此接口中的成员常量和方法都必须是公开(public)类型的,确保外部 使用者能访问它们;

(2)接口仅仅描述系统能做什么,但不指明如何去做,所以接口中的方法都是抽象(abstract)方法;

(3)接口不涉及和任何具体实例相关的细节,因此接口没有构造方法,不能被实例化,没有实例变量,只有静态(static)变量;

(4)接口中的变量是所有实现类共有的,既然共有,肯定是不变的东西,因为变化的东西也不能够算共有。所以变量是不可变(final)类型,也就是常量了。

(5) 接口中不可以定义变量。如果接口可以定义变量,但是接口中的方法又都是抽象的,在接口中无法通过行为来修改属性。有的人会说了,没有关系,可以通过实现接口的对象的行为来修改接口中的属性。这当然没有问题,但是考虑这样的情况。如果接口 A中有一个public 访问权限的静态变量 a。按照 Java 的语义,我们可以不 通过实现接口的对象来访问变量 a,通过 A.a = xxx; 就可以改变接口中的变量 a的值了。正如抽象类中是可以这 样做的,那么实现接口 A 的所有对象也都会自动拥有这一改变后的 a的值了,也就是说一个地方改变了 a,所有这些对象中 a的值也都跟着变了。这和抽象类有什么区别呢,怎么体现接口更高的抽象级别呢,怎么体现接口提供的统一的协议呢,那还要接口这种抽象来做什么呢?所以接口中不能出现变量,如果有变量,就和接口提供的统一的抽象这种思想是抵触的。所以接口中的属性必然是常量,只能读不能改,这样才能为实现接口的对象提供 一个统一的属性。

通俗的讲,你认为是要变化的东西,就放在你自己的实现中,不能放在接口中去,接口只是对一类事物的属性和行为更高层次的抽象。对修改关闭,对扩展(不同的实现implements)开放,接口是对开闭原则的一种体现。
接口中不可以定义变量即只能定义常量(加上final修饰就会变成常量)。所以接口的属性默认是 public static final 常量,且必须赋初值。

10. 下面是 People 和 Child 类的定义和构造方法,每个构造方法都输出编号。在 执行 new Child("mike") 的时候都有哪些构造方法被顺序调用?请选择输出结果

考察的又是父类与子类的构造函数调用次序。在 Java中,子类的构造过程中必须调用其父类的构造函数,是因为有继承关系存在时,子类要把父类的内容继承下来。但如果父类有多个构造函数时,该如何选择调用呢?

第一个规则:子类的构造过程中,必须调用其父类的构造方法。一个类,如果我们不写构造方法,那么编译器会帮我们加上一个默认的构造方法(就是没有参数的构造方法),但是如果你自己写了构造方法,那么编译器就不会给你添加了,所以有时候当你 new一个子类对象的时候,肯定调用了子类的构造方法,但是如果在子类构造方法中我们并没有显示的调用基类的构造方法,如:super(); 这样就会调用父类没有参数的构造方法。

第二个规则:如果子类的构造方法中既没有显示的调用基类构造方法,而基类中又没有无参的构造方法,则编译出错,所以,通常我们需要显示的:super(参数列表),来调用父类有参数的构造函数,此时无参的构造函数就不会被调用。

子类没有显示调用父类构造函数,不管子类构造函数是否带参数都默认调用父类无参的构造函数,若父类没有则编译出错。

(2)如果两个对象的 hashCode相同,它们并不一定相同。当然,你未必要按照要求 去做,但是如果你违背了上述原则就会发现在使用容器时,相同的对象可以出现在 Set 集合中,同时增加新元素 的效率会大大下降(对于使用哈希存储的系统,如果哈希码频繁的冲突将会造成存取性能急剧下降)。

补充:关于 equals 和 hashCode 方法,很多 Java 程序都知道,但很多人也就是仅仅知道而已,在 Joshua Bl och 的大作《Effective Java》(很多软件公司,《Effective Java》、《Java 编程思想》以及《重构:改善既 有代码质量》是 Java 程序员必看书籍,如果你还没看过,那就赶紧去亚马逊买一本吧)中是这样介绍 equals 方

实现高质量的 equals 方法的诀窍包括:

  1. 使用 == 操作符检查“参数是否为这个对象的引用”;
  2. 使用 instanceof 操作符检查“参数是否为正确的类型”;
  3. 对于类中的关键属性,检查参数传入对象的属性是否与之相匹配;
  4. 编写完 equals 方法后,问自己它是否满足对称性、传递性、一致性;
  5. 不要将 equals 方法参数中的 Object 对象替换为其他的类型,在重写时不要忘掉 @Override 注解。

答:接口可以继承接口。抽象类可以实现(implements)接口,抽象类可继承具体类,但前提是具体类必须有明确 的构造函数。

14. 指出下面程序的运行结果:

答:执行结果:1a2b2b。创建对象时构造器的调用顺序是:先初始化静态成员,然后调用父类构造器,再初始化非静态成员,最后调用自身构造器。

答:通过类的全名获得该类的类对象

1)面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)是一种计算机编程架构。AO P 是 OOP 的延续,是 Aspect Oriented Programming 的缩写,意思是面向切面编程。 将通用需求功能从不 相关类之中分离出来;同时,能够使得很多类共享一个行为,一旦行为发生变化,不必修改很多类,只要修改这 个行为就可以。AOP 就是这种实现分散关注的编程方法,它将“关注”封装在“方面”中

2)控制反转 IOC(Inversion of Control) 控制指的就是程序相关类之间的依赖关系.传统观念设计中,通常由调用者来创建被调用者的实例, 在 Spring里,创建被调用者的工作不再由调用者来完成,而是由 Spring 容器 完成,依赖关系被反转了,称为控制反转,目的是为了获得更好的扩展性和良好的可维护性。依赖注入(Depend ency injection)创建被调用者的工作由 Spring 容器完成,然后注入调用者,因此也称依赖注入。控制反转和依 赖注入是同一个概念。

16. 判断下列语句是否正确,如果有错误,请指出错误所在?

答:返回值不是 long 类型

17. 静态变量和实例变量的区别?

  • 在语法定义上的区别:静态变量前要加static关键字,而实例变量前则不加。

  • 在程序运行时的区别:实例变量属于某个对象的属性, 必须创建了实例对象(比如 new 一个), 其中的实例变量才会被分配空间,才能使用这个实例变量. 静态变量不属于某个实例对象,而是属于类,所以也称为类变量, 只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间, 静态变量就可以被使用了.

  • 总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用.

例如, 对于下面的程序, 无论创建多少个实例对象, 永远都只分配了一个staticVar变量, 并且每创建一个实例对象, 这个staticVar就会加; 但是, 每创建一个实例对象, 就会分配一个instanceVar, 即可能分配多个instanceVar, 并且每个instanceVar的值都只自加了1次.

18. 一个类是由哪些变量构成的?

在方法体, 构造体内部定义的变量 在方法结束的时候就被摧毁

在类里但是不在方法里 在类被载入的时候被实例化

19. java 中实现多态的机制是什么?

靠的是父类或接口定义的引用变量可以指向子类或具体实现类的实例对象,而程序调用的方法在运行期才动态绑定,就是引用变量所指向的具体实例对象的方法,也就是内存里正在运行的那个对象的方法,而不是引用变量的类型中定义的方法。

我要回帖

更多关于 java面试不会怎么办 的文章

 

随机推荐