面试官常问的 Java 基础题(三)

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

多态就是指一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。

因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。

特点:

  • 指向子类的父类引用由于向上转型了,它只能访问父类中拥有的方法和属性,而对于子类中存在而父类中不存在的方法,该引用是不能使用的,尽管是重载该方法。

  • 若子类重写了父类中的某些方法,在调用该些方法的时候,必定是使用子类中定义的这些方法(动态连接、动态调用)。

Java实现多态有三个必要条件:继承、重写、向上转型。

Java提供了编译时多态和运行时多态两种多态机制。编译时多态是通过方法重载实现的,运行时多态是通过方法的覆盖实现的。

在方法覆盖中,子类可以覆盖父类的方法,因此同类的方法会在父类与子类中有着不同的表现形式。

在Java语言中,基类的引用变量不仅可以指向基类的实例对象,也可以指向其子类中的实例对象。同样,接口中的引用变量也可以指向其实现类的实例对象。而程序调用的方法在运行时期才动态绑定(绑定是指将一个方法调用和一个方法主体联系在一起),绑定的是引用变量所指向的具体实例对象的方法,也就是内存中正在运行的那个对象的方法,而不是引用变量的类型中定义的方法。通过这种动态绑定实现了多态。由于只有在运行时才能确定调用哪个方法,因此通过方法覆盖实现的多态也可以被称为运行时多态。

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

22.抽象类 和 接口 有什么区别?

抽象类接口
单一继承多重实现
有构造方法,不可被实例化没有构造方法,不可继承,可实现
有普通成员变量没有普通成员变量
可包含非抽象的普通方法不可包含非抽象的普通方法
抽象方法的访问类型可以是 public,protected 和 默认类型抽象方法只能是 public 类型的,并且默认即为 public abstract 类型
可以包含静态方法不可以包含静态方法
抽象类在代码实现方面发挥作用,可以实现代码的重用接口更多的是在系统架构设计方法发挥作用,主要用于定义模块之间的通信契约。

抽象类: 含有 abstract 修饰符的类即为抽象类, 抽象类不能创建的实例对象。
抽象类中的方法不一定是抽象方法,但有抽象方法的类一定是抽象类。
抽象类中定义抽象方法必须在具体子类中实现,所以,不能有抽象构造方法或抽象静态方法。
如果子类没有实现抽象父类中的所有抽象方法,那么子类也必须定义为 abstract 类型。

接口: (interface)可以说成是抽象类的一种特例,接口中的所有方法都必须是抽象的。接口 中的方法定义默认为 public abstract 类型,接口中的成员变量类型默认为 public static final。

  • 语法区别:
  1. 抽象类可以有构造方法,接口中不能有构造方法。
  2. 抽象类中可以有普通成员变量,接口中没有普通成员变量
  3. 抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法。
  4. 抽象类中的抽象方法的访问类型可以是 public,protected 和 默认类型,但接口中的抽象方法只能是 public 类型的,并且默认即为 public abstract 类型。
  5. 抽象类中可以包含静态方法,接口中不能包含静态方法
  6. 抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是 public static 类型,并且默认即为 public static 类型。
  7. 一个类可以实现多个接口,但只能继承一个抽象类。
  • 在应用上的区别:
  1. 接口更多的是在系统架构设计方法发挥作用,主要用于定义模块之间的通信契约。
    而抽象类在代码实现方面发挥作用,可以实现代码的重用,

    例如:

    模板方法设计模式是抽象类的一个典型应用,假设某个项目的所有 Servlet 类都要用相同的方式进行权限判断、记录访问日志和处理异常,那么就可以定义一个抽象的基类,让所有的 Servlet 都继承这个抽象基类,在抽象基类的 service 方法中完成权限判断、记录访问日志和处理异常的代码,在各个子类中只是完成各自的业务逻辑代码,
    伪代码如下:
    在这里插入图片描述
    父类方法中间的某段代码不确定,留给子类编写,就用模板方法设计模式。

    这道题的思路是先从总体解释抽象类和接口的基本概念,然后再比较两者的语法细节,

    比较两者语法细节区别的步骤是:
    先从一个类中的构造方法、普通成员变量和方法(包括抽象方法) ,静态变量和方法,继承性等 6 个方面逐 一去比较回答,接着从第三者继承的角度的回答,特别是最后用了一个典型的例子来展现自己深厚的技术功底。

23.抽象方法是否可同时是 static,是否可同时是 native,是否可同时是 synchronized?

抽象方法不可是 static;
抽象方法不可是 native;
抽象方法不可是 synchronized。

抽象方法不可以是 static 的 ,因为抽象的方法是要被子类实现的,而 static 与子类扯不上关系!

抽象方法不可以是 native 的 ,native 方法表示该方法要用另外一种依赖平台的编程语言实现的(多语言),不存在着被子类实现的问题。(没有实践过)
例如,File Out put Steam 类要硬件打交道,底层的实现用的是操作系统相关的 api 实现,
例如,在 windows 用 c 语言 实现的。
所以,查看 jdk 的源代码,可以发现 FileOutputStream 的 open 方法的定义如下:
在这里插入图片描述
如果我们要用 java 调用别人写的 c 语言函数,我们是无法直接调用的,我们需要按照 java 的要求写一个 c 语言的函数,又我们的 这个 c 语言函数去调用别人的 c 语言函数。
由于我们的 c 语言函数是按 java 的要求来写的,我们这个 c 语言函数就可以与 java 对接上, java 那边的对接方式就是定义出与我们这个 c 函数相对应的方法,java 中对应的方法不需要写具体的代码,但需要在前面声明 native。

抽象方法不可以是 synchronized 的 ,关于 synchronized 与 abstract 合用的问题,我觉得也不行,因为在我几年的学习和开发中,从来没见到过这种情况,并且我觉得 synchronized 应该是作用在一个具体的方法上才有意义。

24.什么是内部类?

内部类:一个类的内部定义的类,内部类中不能定义静态成员。

(我想可能是既然静态成员类似 c 语言的全局变量,而内部类通常是用于创建内部对象用的,所以,把“全局变量”放在内部类中就是毫无意义的事情,既然是毫无意义的事情,就应该被禁止) ,
内部类可以直接访问外部类中的成员变量,内部类可以定义在外部类的方法外面,也可以定义在外部类的方法体中,
如下所示:
在这里插入图片描述
在方法体外面定义的内部类的访问类型可以是 public、protecte、friendly,private 等 4 种类型,这就好像类中定义的成员变量有 4 种访问类型一样,它们决定这个内部类的定义对其他类是否可见;对于这种情况,我们也可以在外面创建内部类的实例对象,创建内部类的实例对象时,一定要先创建外部类的实例对象,然后用这个外部类的实例对象去创建内部类的实例对象,
代码如下:
在这里插入图片描述
在方法内部定义的内部类前面不能有访问类型修饰符,就好像方法中定义的局部变量一样,但这种内部类的前面可以使用 final 或 abstract 修饰符。
这种内部类对其他类是不可见的其他类无法引用这种内部类,但是这种内部类创建的实例对象可以传递给其他类访问。
这种内部类必须是先定义,后使用,即内部类的定义代码必须出现在使用该类之前,这与方法中的局部变量必须先定义后使用的道理 也是一样的。
这种内部类可以访问方法体中的局部变量,但是,该局部变量前必须加 final 修饰符。

对于这些细节,只要在 eclipse 写代码试试,根据开发工具提示的各类错误信息就可以马上了解到。
在方法外部定义的内部类前面可以加上 static 关键字,从而成为静态内部类,或者叫 StaticNestedClass。StaticNestedClass 与普通类在运行时的行为和功能上没有什么区别,只是在编程引用时的语法上有一些差别,它可以定义成 public、protected、默认的、private 等多种类型,而普通类只能定义成 public 和默认的这两种类型。在外面引用 StaticNestedClass 类的名称为“外部类名.内部类名”。在 外面不需要创建外部类的实例对象,就可以直接创建 StaticNestedClass,
例如,
假设 Inner 是定义在 Outer 类中的 StaticNestedClass, 那么可以使用如下语句创建 Inner 类:
在这里插入图片描述
由于 staticNestedClass 不依赖于外部类的实例对象,所以,staticNestedClass 能访问外部类的非 static 成员变量。当在外部类中访 问 StaticNestedClass 时,可以直接使用 StaticNestedClass 的名字,而不需要加上外部类的名字了,在 StaticNestedClass 中也可以直接 引用外部类的 static 的成员变量,不需要加上外部类的名字。

最后,在方法体内部还可以采用如下语法来创建一种匿名内部类,即定义某一接口或类的子类的同时,还创建了该子类的实例对
象,无需为该子类定义名称:
在这里插入图片描述

备注:
首先根据你的印象说出你对内部类的总体方面的特点:
例如,在两个地方可以定义,可以访问外部类的成员变量,不能定义静态成员,这是大的特点。
然后再说一些细节方面的知识,例如,几种定义方式的语法区别,静态内部类,以及匿名内部类。


25.内部类可以引用他包含类的成员吗?有没有什么限制?

内部类可以引用他包含类的成员
如果不是静态内部类,那没有什么限制!
如果你把静态嵌套类当作内部类的一种特例,那在这种情况下不可以访问外部类的普通成员变量,而只能访问外部类中的静态成员。

例如,下面的代码:
在这里插入图片描述
静态内部类能否访问外部类的成员?

静态内部类里面不可以调用外部类的非静态方法,因为外部类的非静态方法是需要创建外部类对象才能调用的,而静态内部类是不需要外部类对象就可以得到的。

静态内部类通过 new 外部类().成员 的方式访问外部类的非静态成员,代码验证如下:
在这里插入图片描述

26.静态嵌套类 (Static Nested Class) 和 内部类(Inner Class) 的区别。

静态嵌套类不依赖外部类实例被实例化,内部类需要在外部类实例化后才能实例化。

什么是嵌套类及内部类?
可以在一个类的内部定义另一个类, 这种类称为嵌套类(nested classes),它有两种类型 :静态嵌套类非静态嵌套类
静态嵌套类使用很少, 最重要的是 非静态嵌套类, 也被称为内部类(inner)
嵌套类从JDK1.1开始引入.其中 inner 类又可分为三种:

  • 在一个类(外部类)中直接定义的内部类;
  • 在一个方法(外部类的方法)中定义的内部类;
  • 匿名内部类.

27.匿名内部类(Anonymous Inner Class)是否可以 extends(继承)其它类,是否可以 implements(实现)interface(接口)?

匿名内部类可以继承其他类,也可以实现其他接口。

28.String 是最基本的数据类型吗?

String 不是最基本的数据类型

基本数据类型包括 byte、short、int、long、double、float、char、boolean。

29.String s = “Hello”;s = s + " world!";这两行代码执行后,原始的String 对象中的内容到底变了没有?

没有。

String 是不可变(immutable)类,它的所有对象都是不可变对象。

在这段代码中,s 原先指向一个 String 对象,内容是 “Hello”,然后我们对 s 进行了+操作,那么 s 所指向的那个对象是否发生了改变呢?答案是没有。
这时,s 不指向原来那个对象了,而指向了另一个 String 对象,内容为"Helloworld!",原来那个对象还存在于内存之中,只是 s 这个引用变量不再指向它了。
通过上面的说明,我们很容易导出另一个结论,如果经常对字符串进行各种各样的修改,或者说,不可预见的修改,那么使用 String 来代表字符串的话会引起很大的内存开销。因为 String 对象建立之后不能再改变,所以对于每一个不同的字符串,都需要一个 String 对象来表示。这时,应该考虑使用 StringBuffer 类,它允许修改,而不是每个不同的字符串都要生成一个新的对象。 并且,这两种类的对象转换十分容易。
同时,我们还可以知道,如果要使用内容相同的字符串,不必每次都 new 一个 String。

后者每次都会调用构造器,生成新对象,性能低下且内存开销大,并且没有意义,因为 String 对象不可改变,所以对于内容相 同的字符串,只要一个 String 对象来表示就可以了。也就说,多次调用上面的构造器创建多个对象,他们的 String 类型属性 s 都指向同一个对象。

上面的结论还基于这样一个事实:
对于字符串常量,如果内容相同,Java 认为它们代表同一个 String 对象。而用关键字 new 调用构造器,总是会创建一个新的对象,无论内容是否相同。 至于为什么要把 String 类设计成不可变类,是它的用途决定的。其实不只 String,很多 Java 标准类库中的类都是不可变的。在 开发一个系统的时候,我们有时候也需要设计不可变类,来传递一组相关的值,这也是面向对象思想的体现。
不可变类有一些优点,比如因为它的对象是只读的,所以多线程并发访问也不会有任何问题。当然也有一些缺点,比如每个不同的状态都要一 个对象来代表,可能会造成性能上的问题。所以 Java 标准类库还提供了一个可变版本,即 StringBuffer。

30.是否可以继承 String 类?

String 类是 final 类故不可以继承。

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值