2019年最新50道java基础部分面试题(三)

2二、面向对象的特征有哪些方面
计算机软件系统是现实生活中的业务在计算机中的映射,而现实生活中的业务其实就是一个个对象协做的过程。面向对象编程就是按现实业务同样的方式将程序代码按一个个对象进行组织和编写,让计算机系统可以识别和理解用对象方式组织和编写的程序代码,这样就能够把现实生活中的业务对象映射到计算机系统中。
面向对象的编程语言有封装、继承 、抽象、多态等4个主要的特征。
1封装:
封装是保证软件部件具备优良的模块性的基础,封装的目标就是要实现软件部件的“高内聚、低耦合”,防止程序相互依赖性而带来的变更影响。在面向对象的编程语言中,对象是封装的最基本单位,面向对象的封装比传统语言的封装更为清晰、更为有力。面向对象的封装就是把描述一个对象的属性和行为的代码封装在一个“模块”中,也就是一个类中,属性用变量定义,行为用方法进行定义,方法能够直接访问同一个对象中的属性。一般状况下,只要记住让变量和访问这个变量的方法放在一块儿,将一个类中的成员变量所有定义成私有的,只有这个类本身的方法才能够访问到这些成员变量,这就基本上实现对象的封装,就很容易找出要分配到这个类上的方法了,就基本上算是会面向对象的编程了。把握一个原则:把对同一事物进行操做的方法和相关的方法放在同一个类中,把方法和它操做的数据放在同一个类中。
例如,人要在黑板上画圆,这一共涉及三个对象:人、黑板、圆,画圆的方法要分配给哪一个对象呢?因为画圆须要使用到圆心和半径,圆心和半径显然是圆的属性,若是将它们在类中定义成了私有的成员变量,那么,画圆的方法必须分配给圆,它才能访问到圆心和半径这两个属性,人之后只是调用圆的画圆方法、表示给圆发给消息而已,画圆这个方法不该该分配在人这个对象上,这就是面向对象的封装性,即将对象封装成一个高度自治和相对封闭的个体,对象状态(属性)由这个对象本身的行为(方法)来读取和改变。一个更便于理解的例子就是,司机将火车刹住了,刹车的动做是分配给司机,仍是分配给火车,显然,应该分配给火车,由于司机自身是不可能有那么大的力气将一个火车给停下来的,只有火车本身才能完成这一动做,火车须要调用内部的离合器和刹车片等多个器件协做才能完成刹车这个动做,司机刹车的过程只是给火车发了一个消息,通知火车要执行刹车动做而已。java

抽象:
抽象就是找出一些事物的类似和共性之处,而后将这些事物归为一个类,这个类只考虑这些事物的类似和共性之处,而且会忽略与当前主题和目标无关的那些方面,将注意力集中在与当前目标有关的方面。例如,看到一只蚂蚁和大象,你可以想象出它们的相同之处,那就是抽象。抽象包括行为抽象和状态抽象两个方面。例如,定义一个Person类,以下:
class Person{
String name;
int age;
}
人原本是很复杂的事物,有不少方面,但由于当前系统只须要了解人的姓名和年龄,因此上面定义的类中只包含姓名和年龄这两个属性,这就是一种抽像,使用抽象能够避免考虑一些与目标无关的细节。我对抽象的理解就是不要用显微镜去看一个事物的全部方面,这样涉及的内容就太多了,而是要善于划分问题的边界,当前系统须要什么,就只考虑什么。正则表达式

继承:
在定义和实现一个类的时候,能够在一个已经存在的类的基础之上来进行,把这个已经存在的类所定义的内容做为本身的内容,并能够加入若干新的内容,或修改原来的方法使之更适合特殊的须要,这就是继承。继承是子类自动共享父类数据和方法的机制,这是类之间的一种关系,提升了软件的可重用性和可扩展性。编程

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

比喻:人吃饭,你看到的是左手,仍是右手?
2三、java中实现多态的机制是什么?
靠的是父类或接口定义的引用变量能够指向子类或具体实现类的实例对象,而程序调用的方法在运行期才动态绑定,就是引用变量所指向的具体实例对象的方法,也就是内存里正在运行的那个对象的方法,而不是引用变量的类型中定义的方法。
2四、abstract class和interface有什么区别?
含有abstract修饰符的class即为抽象类,abstract 类不能建立的实例对象。含有abstract方法的类必须定义为abstract class,abstract class类中的方法没必要是抽象的。abstract class类中定义抽象方法必须在具体(Concrete)子类中实现,因此,不能有抽象构造方法或抽象静态方法。若是的子类没有实现抽象父类中的全部抽象方法,那么子类也必须定义为abstract类型。
接口(interface)能够说成是抽象类的一种特例,接口中的全部方法都必须是抽象的。接口中的方法定义默认为public abstract类型,接口中的成员变量类型默认为public static final。
下面比较一下二者的语法区别:
1.抽象类能够有构造方法,接口中不能有构造方法。
2.抽象类中能够有普通成员变量,接口中没有普通成员变量
3.抽象类中能够包含非抽象的普通方法,接口中的全部方法必须都是抽象的,不能有非抽象的普通方法。设计模式

  1. 抽象类中的抽象方法的访问类型能够是public,protected和(默认类型,虽然
    eclipse下不报错,但应该也不行),但接口中的抽象方法只能是public类型的,而且默认即为public abstract类型。
  2. 抽象类中能够包含静态方法,接口中不能包含静态方法
  3. 抽象类和接口中均可以包含静态成员变量,抽象类中的静态成员变量的访问类型能够任意,但接口中定义的变量只能是public static final类型,而且默认即为public static final类型。
  4. 一个类能够实现多个接口,但只能继承一个抽象类。
    下面接着再说说二者在应用上的区别:
    接口更多的是在系统架构设计方法发挥做用,主要用于定义模块之间的通讯契约。而抽象类在代码实现方面发挥做用,能够实现代码的重用,例如,模板方法设计模式是抽象类的一个典型应用,假设某个项目的全部Servlet类都要用相同的方式进行权限判断、记录访问日志和处理异常,那么就能够定义一个抽象的基类,让全部的Servlet都继承这个抽象基类,在抽象基类的service方法中完成权限判断、记录访问日志和处理异常的代码,在各个子类中只是完成各自的业务逻辑代码,伪代码以下:
    public abstract class BaseServlet extends HttpServlet{
    public final void service(HttpServletRequest request, HttpServletResponse response) throws IOExcetion,ServletException {
    记录访问日志
    进行权限判断
    if(具备权限){
    try{
    doService(request,response);
    }
    catch(Excetpion e) {
    记录异常信息
    }
    }
    }
    protected abstract void doService(HttpServletRequest request, HttpServletResponse response) throws IOExcetion,ServletException;
    //注意访问权限定义成protected,显得既专业,又严谨,由于它是专门给子类用的
    }

public class MyServlet1 extends BaseServlet
{
protected void doService(HttpServletRequest request, HttpServletResponse response) throws IOExcetion,ServletException
{
本Servlet只处理的具体业务逻辑代码
} api

}
父类方法中间的某段代码不肯定,留给子类干,就用模板方法设计模式。
备注:这道题的思路是先从整体解释抽象类和接口的基本概念,而后再比较二者的语法细节,最后再说二者的应用区别。比较二者语法细节区别的条理是:先从一个类中的构造方法、普通成员变量和方法(包括抽象方法),静态变量和方法,继承性等6个方面逐一去比较回答,接着从第三者继承的角度的回答,特别是最后用了一个典型的例子来展示本身深厚的技术功底。
2五、abstract的method是否可同时是static,是否可同时是native,是否可同时是synchronized?
abstract的method 不能够是static的,由于抽象的方法是要被子类实现的,而static与子类扯不上关系!
native方法表示该方法要用另一种依赖平台的编程语言实现的,不存在着被子类实现的问题,因此,它也不能是抽象的,不能与abstract混用。例如,FileOutputSteam类要硬件打交道,底层的实现用的是操做系统相关的api实现,例如,在windows用c语言实现的,因此,查看jdk 的源代码,能够发现FileOutputStream的open方法的定义以下:
private native void open(String name) throws FileNotFoundException;
若是咱们要用java调用别人写的c语言函数,咱们是没法直接调用的,咱们须要按照java的要求写一个c语言的函数,又咱们的这个c语言函数去调用别人的c语言函数。因为咱们的c语言函数是按java的要求来写的,咱们这个c语言函数就能够与java对接上,java那边的对接方式就是定义出与咱们这个c函数相对应的方法,java中对应的方法不须要写具体的代码,但须要在前面声明native。
关于synchronized与abstract合用的问题,我以为也不行,由于在我几年的学习和开发中,历来没见到过这种状况,而且我以为synchronized应该是做用在一个具体的方法上才有意义。并且,方法上的synchronized同步所使用的同步锁对象是this,而抽象方法上没法肯定this是什么。
2六、什么是内部类?Static Nested Class 和 Inner Class的不一样。
内部类就是在一个类的内部定义的类,内部类中不能定义静态成员(静态成员不是对象的特性,只是为了找一个容身之处,因此须要放到一个类中而已,这么一点小事,你还要把它放到类内部的一个类中,过度了啊!提供内部类,不是为让你干这种事情,无聊,不让你干。我想多是既然静态成员相似c语言的全局变量,而内部类一般是用于建立内部对象用的,因此,把“全局变量”放在内部类中就是毫无心义的事情,既然是毫无心义的事情,就应该被禁止),内部类能够直接访问外部类中的成员变量,内部类能够定义在外部类的方法外面,也能够定义在外部类的方法体中,以下所示:
public class Outer
{
int out_x = 0;
public void method()
{
Inner1 inner1 = new Inner1();
public class Inner2 //在方法体内部定义的内部类
{
public method()
{
out_x = 3;
}
}
Inner2 inner2 = new Inner2();
}数组

public class Inner1   //在方法体外面定义的内部类
    {
    }

}
在方法体外面定义的内部类的访问类型能够是public,protecte,默认的,private等4种类型,这就好像类中定义的成员变量有4种访问类型同样,它们决定这个内部类的定义对其余类是否可见;对于这种状况,咱们也能够在外面建立内部类的实例对象,建立内部类的实例对象时,必定要先建立外部类的实例对象,而后用这个外部类的实例对象去建立内部类的实例对象,代码以下:
Outer outer = new Outer();
Outer.Inner1 inner1 = outer.new Innner1();多线程

在方法内部定义的内部类前面不能有访问类型修饰符,就好像方法中定义的局部变量同样,但这种内部类的前面可使用final或abstract修饰符。这种内部类对其余类是不可见的其余类没法引用这种内部类,可是这种内部类建立的实例对象能够传递给其余类访问。这种内部类必须是先定义,后使用,即内部类的定义代码必须出如今使用该类以前,这与方法中的局部变量必须先定义后使用的道理也是同样的。这种内部类能够访问方法体中的局部变量,可是,该局部变量前必须加final修饰符。
对于这些细节,只要在eclipse写代码试试,根据开发工具提示的各种错误信息就能够立刻了解到。架构

在方法体内部还能够采用以下语法来建立一种匿名内部类,即定义某一接口或类的子类的同时,还建立了该子类的实例对象,无需为该子类定义名称:
public class Outer
{
public void start()
{
new Thread(
new Runable(){
public void run(){};
}
).start();
}
}并发

最后,在方法外部定义的内部类前面能够加上static关键字,从而成为Static Nested Class,它再也不具备内部类的特性,全部,从狭义上讲,它不是内部类。Static Nested Class与普通类在运行时的行为和功能上没有什么区别,只是在编程引用时的语法上有一些差异,它能够定义成public、protected、默认的、private等多种类型,而普通类只能定义成public和默认的这两种类型。在外面引用Static Nested Class类的名称为“外部类名.内部类名”。在外面不须要建立外部类的实例对象,就能够直接建立Static Nested Class,例如,假设Inner是定义在Outer类中的Static Nested Class,那么可使用以下语句建立Inner类:
Outer.Inner inner = new Outer.Inner();
因为static Nested Class不依赖于外部类的实例对象,因此,static Nested Class能访问外部类的非static成员变量。当在外部类中访问Static Nested Class时,能够直接使用Static Nested Class的名字,而不须要加上外部类的名字了,在Static Nested Class中也能够直接引用外部类的static的成员变量,不须要加上外部类的名字。
在静态方法中定义的内部类也是Static Nested Class,这时候不能在类前面加static关键字,静态方法中的Static Nested Class与普通方法中的内部类的应用方式很类似,它除了能够直接访问外部类中的static的成员变量,还能够访问静态方法中的局部变量,可是,该局部变量前必须加final修饰符。

备注:首先根据你的印象说出你对内部类的整体方面的特色:例如,在两个地方能够定义,能够访问外部类的成员变量,不能定义静态成员,这是大的特色。而后再说一些细节方面的知识,例如,几种定义方式的语法区别,静态内部类,以及匿名内部类。
2七、内部类能够引用它的包含类的成员吗?有没有什么限制?
彻底能够。若是不是静态内部类,那没有什么限制!
若是你把静态嵌套类看成内部类的一种特例,那在这种状况下不能够访问外部类的普通成员变量,而只能访问外部类中的静态成员,例如,下面的代码:
class Outer
{
static int x;
static class Inner
{
void test()
{
syso(x);
}
}
}

答题时,也要能察言观色,揣摩提问者的心思,显然人家但愿你说的是静态内部类不能访问外部类的成员,但你一上来就顶牛,这很差,要先顺着人家,让人家满意,而后再说特殊状况,让人家吃惊。

2八、Anonymous Inner Class (匿名内部类) 是否能够extends(继承)其它类,是否能够implements(实现)interface(接口)?
能够继承其余类或实现其余接口。不只是能够,而是必须!
2九、super.getClass()方法调用
下面程序的输出结果是多少?
import java.util.Date;
public class Test extends Date{
public static void main(String[] args) {
new Test().test();
}

public void test(){
    System.out.println(super.getClass().getName());
}

}

很奇怪,结果是Test
这属于脑筋急转弯的题目,在一个qq群有个网友正好问过这个问题,我以为挺有趣,就研究了一下,没想到今天还被你面到了,哈哈。
在test方法中,直接调用getClass().getName()方法,返回的是Test类名
因为getClass()在Object类中定义成了final,子类不能覆盖该方法,因此,在
test方法中调用getClass().getName()方法,其实就是在调用从父类继承的getClass()方法,等效于调用super.getClass().getName()方法,因此,super.getClass().getName()方法返回的也应该是Test。
若是想获得父类的名称,应该用以下代码:
getClass().getSuperClass().getName();
30、String是最基本的数据类型吗?
基本数据类型包括byte、int、char、long、float、double、boolean和short。
java.lang.String类是final类型的,所以不能够继承这个类、不能修改这个类。为了提升效率节省空间,咱们应该用StringBuffer类
3一、String s = "Hello";s = s + " world!";这两行代码执行后,原始的String对象中的内容到底变了没有?
没有。由于String被设计成不可变(immutable)类,因此它的全部对象都是不可变对象。在这段代码中,s原先指向一个String对象,内容是 "Hello",而后咱们对s进行了+操做,那么s所指向的那个对象是否发生了改变呢?答案是没有。这时,s不指向原来那个对象了,而指向了另外一个 String对象,内容为"Hello world!",原来那个对象还存在于内存之中,只是s这个引用变量再也不指向它了。
经过上面的说明,咱们很容易导出另外一个结论,若是常常对字符串进行各类各样的修改,或者说,不可预见的修改,那么使用String来表明字符串的话会引发很大的内存开销。由于 String对象创建以后不能再改变,因此对于每个不一样的字符串,都须要一个String对象来表示。这时,应该考虑使用StringBuffer类,它容许修改,而不是每一个不一样的字符串都要生成一个新的对象。而且,这两种类的对象转换十分容易。
同时,咱们还能够知道,若是要使用内容相同的字符串,没必要每次都new一个String。例如咱们要在构造器中对一个名叫s的String引用变量进行初始化,把它设置为初始值,应当这样作:
public class Demo {
private String s;
...
public Demo {
s = "Initial Value";
}
...
}
而非
s = new String("Initial Value");
后者每次都会调用构造器,生成新对象,性能低下且内存开销大,而且没有意义,由于String对象不可改变,因此对于内容相同的字符串,只要一个String对象来表示就能够了。也就说,屡次调用上面的构造器建立多个对象,他们的String类型属性s都指向同一个对象。
上面的结论还基于这样一个事实:对于字符串常量,若是内容相同,Java认为它们表明同一个String对象。而用关键字new调用构造器,老是会建立一个新的对象,不管内容是否相同。
至于为何要把String类设计成不可变类,是它的用途决定的。其实不仅String,不少Java标准类库中的类都是不可变的。在开发一个系统的时候,咱们有时候也须要设计不可变类,来传递一组相关的值,这也是面向对象思想的体现。不可变类有一些优势,好比由于它的对象是只读的,因此多线程并发访问也不会有任何问题。固然也有一些缺点,好比每一个不一样的状态都要一个对象来表明,可能会形成性能上的问题。因此Java标准类库还提供了一个可变版本,即 StringBuffer。

3二、是否能够继承String类?
String类是final类故不能够继承。

3三、String s = new String("xyz");建立了几个String Object? 两者之间有什么区别?
两个或一个,”xyz”对应一个对象,这个对象放在字符串常量缓冲区,常量”xyz”无论出现多少遍,都是缓冲区中的那一个。New String每写一遍,就建立一个新的对象,它一句那个常量”xyz”对象的内容来建立出一个新String对象。若是之前就用过’xyz’,这句表明就不会建立”xyz”本身了,直接从缓冲区拿。
3四、String 和StringBuffer的区别
JAVA平台提供了两个类:String和StringBuffer,它们能够储存和操做字符串,即包含多个字符的字符数据。这个String类提供了数值不可改变的字符串。而这个StringBuffer类提供的字符串进行修改。当你知道字符数据要改变的时候你就可使用StringBuffer。典型地,你可使用StringBuffers来动态构造字符数据。另外,String实现了equals方法,new String(“abc”).equals(new String(“abc”)的结果为true,而StringBuffer没有实现equals方法,因此,new StringBuffer(“abc”).equals(new StringBuffer(“abc”)的结果为false。

接着要举一个具体的例子来讲明,咱们要把1到100的全部数字拼起来,组成一个串。
StringBuffer sbf = new StringBuffer();
for(int i=0;i<100;i++)
{
sbf.append(i);
}
上面的代码效率很高,由于只建立了一个StringBuffer对象,而下面的代码效率很低,由于建立了101个对象。
String str = new String();
for(int i=0;i<100;i++)
{
str = str + i;
}
在讲二者区别时,应把循环的次数搞成10000,而后用endTime-beginTime来比较二者执行的时间差别,最后还要讲讲StringBuilder与StringBuffer的区别。

String覆盖了equals方法和hashCode方法,而StringBuffer没有覆盖equals方法和hashCode方法,因此,将StringBuffer对象存储进Java集合类中时会出现问题。3五、如何把一段逗号分割的字符串转换成一个数组?若是不查jdk api,我很难写出来!我能够说说个人思路:1.用正则表达式,代码大概为:String [] result = orgStr.split(“,”);2.用 StingTokenizer ,代码为:StringTokenizer tokener = StringTokenizer(orgStr,”,”);String [] result = new String[tokener .countTokens()];Int i=0;while(tokener.hasNext(){result[i++]=toker.nextToken();}

相关文章
相关标签/搜索