集微笔记 / Java面试 / Java面试(一)

0 0

   

Java面试(一)

2018-03-16  集微笔记
1.面向对象的三大特性
继承、封装、多态
什么是继承?

  1.继承是面向对象程序设计能够提高软件开发效率的重要原因之一。

  2.继承是具有传递性的,就像现实中孙子不仅长得像爸爸而且还像他爷爷。

  3.继承来的属性和方法是隐式的,也就是在本类里面是看不见的。

  4.一个类只能有一个父类,也就是类只能是单继承。

  5.一个接口可以有多个父类,也就是接口可以是多继承。

实际项目开发中,一个类继承于另一个类,那么前者就是后者的子类,反则反之。

什么是封装?

对象数据和操作该对象的指令都是对象自身的一部分,能够实现尽可能对外部隐藏数据。
实际项目开发中,使用封装最多的就是实体类,常常和JavaBean(类必须是具体的和公共的,并且具有无参数的构造器)一起使用。

那么,实体类有那些东西呢?

答:私有的成员变量、无参数的构造器、有参数的构造器、setters和getters方法、重写tostring方法、重写hashCode和equals方法。

什么是多态?

  1.多态就是对象拥有多种形态:引用多态和方法多态。

  2.引用多态:父类的引用可以指向本类对象、父类的引用可以指向子类的对象。
  3.方法多态:创建本类对象时,调用的方法为本类的方法;创建子类对象时,调用的方法为子类   重写的方法或者继承的方法。
  4.存在多态的必要条件:继承、重写。
  5.多态的作用是消除类型之间的耦合关系。

在实际项目开发中,A类继承B类,如果在A类中不重写B类的方法的时候,输出的仍旧是B类方法里面的信息(B b=new A());如果在A类中重写B类的方法的时候,输出的是A类方法里面的信息(B b=new A())。

2.final、finally、finalize的区别
final是修饰符
被final修饰的类,就意味着不能再派生出新的子类,不能作为父类而被子类继承。因此一个类不能既被abstract声明,又被final声明。将变量或方法声明为final,可以保证他们在使用的过程中不被修改。被声明为final的变量必须在声明时给出变量的初始值,而在以后的引用中只能读取。被final声明的方法也同样只能使用,不能重载。
finally是在异常处理时提供finally块来执行任何清除操作
不管有没有异常被抛出、捕获,finally块都会被执行。try块中的内容是在无异常时执行到结束。catch块中的内容,是在try块内容发生catch所声明的异常时,跳转到catch块中执行。finally块则是无论异常是否发生,都会执行finally块的内容,所以在代码逻辑中有需要无论发生什么都必须执行的代码,就可以放在finally块中。
finalize是方法名
java技术允许使用finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在确定这个对象没有被引用时对这个对象调用的。它是在object类中定义的,因此所有的类都继承了它。子类覆盖finalize()方法以整理系统资源或者被执行其他清理工作。finalize()方法是在垃圾收集器删除对象之前对这个对象调用的。
3.Exception、Error、运行时异常与一般异常有何异同
Throwable是所有Java程序中错误处理的父类,有两种子类:Error和Exception。
Error表示由JVM所侦测到的无法预期的错误,由于这是属于JVM层次的严重错误,导致JVM无法继续执行,因此,这是不可捕捉到的,无法采取任何恢复的操作,顶多只能显示错误信息。
Exception表示可恢复的例外,这是可捕捉到的。
Java提供了两类主要的异常:runtime exception和checked exception
checked异常也就是我们经常遇到的IO异常,以及 SQL异常都是这种异常。对于这种异常,JAVA编译器强制要求我们必需对出现的这些异常进行catch。所以,面对这种异常不管我们是否愿意,只能自己去写一大堆catch块去处理可能的异常。
出现runtime异常后,系统会把异常一直往上层抛,一直遇到处理代码。如果没有处理块,到最上层,如果是多线程就由Thread.run()抛出,如果是单线程就被main()抛出。抛出之后,如果是线程,这个线程也就退出了。如果是主程序抛出的异常,那么这整个程序也就退出了。运行时异常是Exception的子类,也有一般异常的特点,是可以被catch块处理的。只不过往往我们不对他处理罢了。也就是说,你如果不对runtime异常进行处理,那么出现运行时异常之后,要么是线程中止,要么是主程序终止。

如果不想终止,则必须捕捉所有的运行时异常,决不让这个处理线程退出。队列里面出现异常数据了,正常的处理应该是把异常数据舍弃,然后记录日志。不应该由于异常数据而影响下面对正常数据的处理。在这个场景这样处理可能是一个比较好的应用,但并不代表在所有的场景你都应该如此。如果在其它场景,遇到了一些错误,如果退出程序比较好,这时你就可以不太理会运行时异常,或者是通过对异常的处理显式的控制程序退出。异常处理的目标之一就是为了把程序从异常中恢复出来

几种常见的运行时异常

1.Object x = new Integer(0);System.out.println((String)x);当试图将对象强制转换为不是实例的子类时,抛出改异常(ClassCastException)。
2.int a = 5/0;一个整数“除以零”时,抛出ArithmeticException异常。
3.String s = null;int size =s.size();当应用程序试图在需要对象的地方使用null时,抛出NullPointerException异常。
4."hello".indexOf(-1);指示索引或者为负,或者超出字符串的大小,抛出StringIndexOutOfBoundsException异常。
5.String[] ss = new String[-1];如果应用程序试图创建大小为负的数组,则抛出NegativeArraySizeException异常。
6.IllegalArgumentException抛出的异常表明向方法传递了一个不合法或不正确的参数。
7.NumberFormatException当应用程序试图将字符串转换成一种数值类型,但该字符串不能转换为适当格式时,抛出该异常。
4.int和Integer有什么区别,Integer的值缓存范围,包装(封装)类,装箱和拆箱
int是基本类型,直接存数值,进行初始化时int类的变量初始为0。
Integer是对象,用一个引用指向这个对象,Integer的变量则初始化为null。
java两种数据类型分类
原始数据类型,分为boolean,byte,int,char,long,short,double,float 
引用数据类型,分为数组,类,接口
java为每个原始类型提供了封装类:Boolean,Character,Byte,Short,Integer,Long,Float,Double
自动装箱:将基本数据类型重新转化为对象
Integer num = 9;9是基本数据类型,原则上是不能赋值给对象的,JDK5之后就可以这样声明了,自动将基本数据类型转化为对应的封装类。
自动拆箱:将对象重新转化为基本数据类型
Integer num = 9;system.out.println(a--);因为对象是不能直接进行运算的,而要转化为基本数据类型才能够运算。
深入分析
Integer a = 128;Integer b = 128;system.out.println(a==b);//false
Integer a = 4;Integer b = 5;system.out.println(a==b);//true
分析原因:归结于Java对于Integer与int的自动装箱和拆箱的设计,是一种模式:叫享元模式(flyweight)。加大对简单数字的重利用,Java定义在自动装箱时对于值在-128~127之间的值,他们被装箱为Integer对象后,会存在内存中被重用,始终只有一个对象。
5.重载和重写的区别
重载(Overload)
方法重载是指同一个类中的多个方法具有相同的名字,但这些方法具有不同的参数列表,即参数的数量或参数类型不能完全相同,返回类型可以相同也可以不同,无法以返回类型作为重载函数的区分标准。重载是一个类中多态性的一种表现。
重载规则
  1. 必须具有不同的参数列表;
  2. 可以有不同的返回类型,只要参数列表不同就可以了;
  3. 可以有不同的访问修饰符;
  4. 可以抛出不同的异常。
重载的特点
  1. 在使用重载时只能通过不同的参数样式。例如,不同的参数类型,不同的参数个数,不同的参数顺序(当然,同一方法内的几个参数类型必须不一样,例如可以是fun(int,float),但是不能为fun(int,int));
  2. 不能通过访问权限、返回类型、抛出的异常进行重载;
  3. 方法的异常类型和数目不会对重载造成影响;
  4. 对于继承来说,如果某一方法在父类中是访问权限是priavte,那么就不能在子类对其进行重载,如果定义的话,也只是定义了一个新方法,而不会达到重载的效果。
重写(Override)
方法重写是存在子父类之间的,子类定义的方法与父类中的方法具有相同的方法名字,相同的参数表和相同的返回类型。子类中不能重写父类中的final方法,必须重写父类中的abstract方法。
重写规则

  1. 参数列表必须完全与被重写的方法相同;
  2. 返回的类型必须与被重写的方法的返回类型相同;
  3. 访问修饰符的限制一定要大于被重写方法的访问修饰符(public>protected>default>private);
  4. 重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常。例如:父类的一个方法申明了一个检查异常IOException,在重写这个方法是就不能抛出Exception,只能抛出IOException的子类异常,可以抛出非检查异常。
重写的特点
  1. 覆盖的方法的标志必须要和被覆盖的方法的标志完全匹配,才能达到覆盖的效果;
  2. 覆盖的方法的返回值必须和被覆盖的方法的返回一致;
  3. 覆盖的方法所抛出的异常必须和被覆盖方法的所抛出的异常一致,或者是其子类;
  4. 被覆盖的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。
6.继承和实现
继承
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
继承的特性
  1. 子类拥有父类非private的属性,方法;
  2. 子类可以拥有自己的属性和方法,即子类可以对父类进行扩展;
  3. 子类可以用自己的方式实现父类的方法;
  4. Java的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如A类继承B类,B类继承C类,所以按照关系就是C类是B类的父类,B类是A类的父类,这是java继承区别于C++继承的一个特性;
  5. 提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系)。

继承关键字
继承可以使用extends和implements这两个关键字来实现继承,而且所有的类都是继承于java.lang.Object,当一个类没有继承的两个关键字,则默认继承object(这个类在java.lang包中,所以不需要import)祖先类。

extends关键字
在Java中,类的继承是单一继承,一个子类只能拥有一个父类,所以extends只能继承一个类。

implements关键字
使用implements关键字可以变相的使java具有多继承的特性,使用范围为类继承接口的情况,可以同时继承多个接口(接口跟接口之间采用逗号分隔)。
7.接口和抽象类
接口

接口(英文:Interface),在JAVA编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。一个类通过继承接口的方式,从而来继承接口的抽象方法。

接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法。

除非实现接口的类是抽象类,否则该类要定义接口中的所有方法。

接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须声明为抽象类。另外,在Java中,接口类型可用来声明一个变量,他们可以成为一个空指针,或是被绑定在一个以此接口实现的对象。

接口特性
  1. 接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为public abstract(其他修饰符都会报错);
  2. 接口中可以含有变量,但是接口中的变量会被隐式的指定为public static final变量(用private修饰会报编译错误);
  3. 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法。
抽象类(abstract)

在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。

抽象类除了不能实例化对象之外,类的其它功能依然存在,成员变量、成员方法和构造方法的访问方式和普通类一样。

由于抽象类不能实例化对象,所以抽象类必须被继承,才能被使用。也是因为这个原因,通常在设计阶段决定要不要设计抽象类。

父类包含了子类集合的常见的方法,但是由于父类本身是抽象的,所以不能使用这些方法。

在Java中抽象类表示的是一种继承关系,一个类只能继承一个抽象类,而一个类却可以实现多个接口。

抽象类特性
  1. 抽象类不能被实例化(初学者很容易犯的错),如果被实例化,就会报错,编译无法通过。只有抽象类的非抽象子类可以创建对象;
  2. 抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类;
  3. 抽象类中的抽象方法只是声明,不包含方法体,就是不给出方法的具体实现也就是方法的具体功能;
  4. 构造方法,类方法(用static修饰的方法)不能声明为抽象方法;
  5. 抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类。
抽象类和接口的区别
  1. 抽象类中的方法可以有方法体,就是能实现方法的具体功能,但是接口中的方法不行;
  2. 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是 public static final 类型的;
  3. 接口中不能含有静态代码块以及静态方法(用static修饰的方法),而抽象类是可以有静态代码块和静态方法;
  4. 一个类只能继承一个抽象类,而一个类却可以实现多个接口;
  5. 接口中所有的方法默认都是抽象的,而抽象类可以同时包含抽象和非抽象的方法;
  6. 一个类要实现某个接口,必须实现这个接口声明的所有方法。而一个类不需要实现抽象父类中声明的所有方法,不过,这时候这个类也必须声明为抽象类;
  7. 抽象类可以实现接口,而且不需要实现接口中的方法;
  8. 接口中的成员默认是public的,而抽象类的成员可以是private,protected或public的;
  9. 接口是绝对抽象的,不可实例化,抽象类也不可以实例化,但可以在main方法中触发实例化(注:通过匿名类实现)。
8.传引用和传值
当对象通过传值调用时,传递的是这个对象的一个拷贝。因此,即使函数修改这个对象,也不会影响原对象的值。
当对象通过传引用调用时,对象本身没有被传递,而传递的是对象的一个引用。因此,外部函数对这个对象的修改,也会反映到任何出现这个对象的地方。
传值
传值就是指将一个值传递到方法的内部。例如int a = 5,那么也就是给int型变量a赋值,值为5.如果一个方法,将这个变量传进方法的内部,则进行的就是传值。在java中,有8种基本数据类型,它们分别为:int、long、float、double、char、boolean、short、byte.这8种基本的数据类型作为参数进行传递是,都是进行的传值。除此之外,还有一种特殊的情况,String。本身String是一个引用类型,很多人认为在向方法中传递String类型参数时,是进行传引用。其实在这里,String可以看做为一个包装类,因为String其本身就是通过字符数组实现的,那么它在实现参数传递的时候,也就是以char型数据的方式进行的,也就是进行传值。
传引用
java中的引用可以初步的理解为地址。也是在new了一个对象后,该对象是存在JVM的Heap区,也就是堆。那么必然有一个地址要指向这个对象的在JVM中的位置,那么,指向这个对象的这个地址就可以简单的理解为“引用”。
9.String、StringBuilder和StringBuffer
String
  1. String类是final类,也即意味着String类不能被继承,并且它的成员方法都默认为final方法;
  2. String类的实现是通过char数组来保存字符串的;
  3. 对String对象的任何改变都不影响到原对象,相关的任何改变操作都会生成新的对象。
StringBuilder、StringBuffer
StringBuffer和StringBuilder类的对象能够被多次的修改,并且不产生新的未使用对象。
这三个类之间的区别主要是在两个方面,即运行速度和线程安全这两方面。
运行速度
首先说运行速度(执行速度),在这方面运行速度快慢为:StringBuilder>StringBuffer>String,String为字符串常量,而StringBuilder和StringBuffer均为字符串变量,即String对象一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的。
线程安全
在线程安全上,StringBuilder是线程不安全的,而StringBuffer是线程安全的。如果一个StringBuffer对象在字符串缓冲区被多个线程使用时,StringBuffer中很多方法可以带有synchronized关键字,所以可以保证线程是安全的,但StringBuilder的方法则没有该关键字,所以不能保证线程安全,有可能会出现一些错误的操作。所以如果要进行的操作是多线程的,那么就要使用StringBuffer,但是在单线程的情况下,还是建议使用速度比较快的StringBuilder。
总结

  1. String:适用于少量的字符串操作的情况;
  2. StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况;
  3. StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况。

10.构造函数、构造函数重载和复制构造函数​

构造函数

处理对象的初始化,是一种特殊的成员函数,与其他函数不同,不需要用户来调用它,在建立对象时自动执行。

  1. 每建立一个对象,就调用一次构造函数;
  2. 构造函数没有返回值,因此也没有类型,作用只是对对象进行初始化;
  3. 构造函数不需要被用户调用,也不能被用户调用。

构造函数重载
与构造函数具有相同的名字,而参数的个数或参数类型不相同。
复制构造函数
Java不支持像C++中那样的复制构造函数,这个不同点是因为如果你不自己写构造函数的情况下,Java不会创建默认的复制构造函数。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。如发现有害或侵权内容,请点击这里 或 拨打24小时举报电话:4000070609 与我们联系。

    猜你喜欢

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多
    喜欢该文的人也喜欢 更多