Day03
1. 介绍一下包装类的自动拆装箱与自动装箱
- 自动装箱是指把一个基本类型的数据直接赋值给对应的包装类型;自动拆箱是指把一个包装类型的对象直接赋值给对应的基本类型;
- 通过自动装箱、自动拆箱功能,可以大大简化基本类型变量和包装类对象之间的转换过程。比如,某个方法的参数类型为包装类型,调用时我们所持有的数据却是基本类型的值,则可以不做任何特殊的处理,直接将这个基本类型的值传入给方法。
- Java是一门非常纯粹的面向对象的编程语言,其设计理念是“一切皆对象”。但8种基本数据类型的确带来了一定的方便性,但在某些时候也会受到一些制约。
- 不同的包装类不能直接进行比较,这包括:不能用==进行直接比较,因为他们是不同的数据类型;不能转为字符串进行比较,因为转为字符串后,浮点值带小数点,整数值不带,这样他们永远都不相等;不能使用compareTo方法进行比较,虽然他们都有compareTo方法,但该方法只能对相同类型进行比较。整数、浮点类型的包装类都继承于Number类型,而Number类型分别定义了将数字转换为byte、short、int、long、float、double的方法。所以,可以将Integer、Double先转为转换为相同的基本数据类型(如double),然后使用==进行比较
2. 请你说说Java的异常处理机制
- 异常处理机制可以让程序具有极好的容错性和健壮性,当程序运行出现了意料之外的状况时,系统会生成一个Exception对象来通知程序,从而实现“业务功能实现部分代码”与“错误处理部分代码”分离,使程序获得更好的可读性。Java异常机制可以分成异常处理、抛出异常、异常跟踪栈三个部分。处理异常的语句由try、catch、finally但部分组成。try块用于包裹业务代码,catch块用于捕获并处理某个类型异常,finally块则用于回收资源。
- 如果业务代码发生异常,系统就会创建一个异常对象,并将这个异常对象提交给JVM,然后由JVM寻找可以处理这个异常的catch块,并将这个异常对象交给catch块处理。如果JVM没有找到可以处理异常的catch块,那么运行环境会终止,JAVA程序也会退出
- 若业务代码打开了某项资源,则可以在finally块中关闭这项资源,因为无论是否发生异常,finally块一定会执行(一般情况下)
- 当程序出现错误时,系统会自动抛出异常。除此之外,Java也允许程序主动抛出异常。当业务代码中判断某项错误的条件成立时,可以使用throw关键字向外抛出异常。在这种情况下,如果当前方法不知道该如何处理这个异常,可以在方法签名上通过throws关键字声明抛出异常,则将该异常交给JVM处理。
- 程序运行时,经常会发生一系列方法调用,从而形成方法调用栈。异常机制会导致异常在这些方法之间传播,而异常的传播顺序和方法调用相反。异常从发生异常的方法向外传播,首先传给该方法的调用者,再传给上层调用者,以此类推。最终会传给main方法,若依然没有得到处理,则JVM会终止程序,并打印异常跟踪栈信息
- throw和throws的区别:
- throws只能在方法签名中使用,可以声明抛出多个异常,多个异常之间用逗号隔开,表示当前方法不知道如何处理这个异常,这个异常由该方法的调用者处理。throws表示出现异常的一种可能性,并不一定会发生这些异常
- throw表示方法内抛出某种异常对象,throw语句可单独使用。throw语句抛出的是一个异常实例,而不是一个异常类,而且每次只能抛出一个异常实例。执行throw语句一定抛出了某种异常
- 关于finally的问题。当Java程序执行try块、catch块时遇到了return或throw语句,这两个语句都会导致该方法立即结束,但是系统执行这两个语句并不会结束该方法,而是去寻找该异常处理流程中是否包含finally块,如果没有finally块,程序立即执行return或throw语句,方法终止;如果有finally块,系统立即开始执行finally块。只有当finally块执行完成后,系统才会再次跳回来执行try块、catch块里的return或throw语句;如果finally块里也使用了return或throw等语句,finally块会终止方法,系统将不会跳回去执行try块、catch块里的任何代码。这将会导致try块、catch块中的return、throw语句失效,所以,我们应该尽量避免在finally中使用return或者throw。
- finally块不执行的几种情况:如果当一个线程在执行try语句块或者catch语句块时被打断interrupted或者被终止killed,与其相对应的finally语句块可能不会执行。如果在try块或者catch块中使用
System.exit(1);
来退出虚拟机,则finally块将失去执行机会
3. 说说你对面向对象的理解
- 面向对象的三大基本特征:封装、继承、多态。其中,封装是指将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,让外部程序通过该类提供的方法来实现对内部信息的操作和访问,这种做法有助于规范使用者的行为,让使用者只能通过事先预定的方法访问数据,提高了代码的可维护性;
- 继承是面向对象实现代码复用的重要手段,Java通过extends关键字来实现类的继承,实现继承的类被称为子类,被继承的类称为父类(有的也被称为基类和超类),父类和子类的关系是一种一般和特殊的关系;多态的实现离不开继承,在设计程序时,我们可以将参数的类型定义为父类型。在调用程序时,则可以根据实际情况,传入该父类型的某个子类型的实例,这样就实现了多态。
- 对于父类型,可以有三种形式,即普通的类、抽象类、接口。对于子类型,则要根据它自身的特征,重写父类的某些方法,或实现抽象类/接口的某些抽象方法。
- 封装的优点:隐藏类的成员变量和实现细节,不允许外部直接访问;规范使用者的行为,让使用者只能通过事先预定的方法访问数据,通过在这个方法中加入逻辑控制,限制使用者对成员变量的不合理访问;可进行数据检查,从而有利于保证对象信息的完整性;便于修改,提高代码的可维护性
- 继承的优点:代码共享,减少创建类的工作量,每个子类都拥有父类的方法和属性,提高了代码复用;提高代码的可扩展性,很多开源框架的扩展接口都是通过继承父类接口(即接口可继承接口)来完成的
- 继承的缺点:继承是侵入性的。只要继承,就必须拥有父类的所有属性和方法;降低了代码的灵活性,子类必须拥有父类的属性和方法。增强了耦合性;当父类的常量、变量和方法被修改时,需要考虑子类的修改,而且在缺乏规范的环境下,这种修改可能会导致大量代码重构。
- 多态的优点:提高了代码的维护性,提高了代码的扩展性;java中实现多态需要三个条件,一是有继承关系的存在,二是需要有方法重写,三是需要有父类的引用指向子类对象
4. 请你说说重载和重写的区别,构造方法能不能重写
- 重载要求发生在同一个类中,多个方法之间方法名相同且参数列表不同。注意重载与方法的返回值和访问修饰符无关。
- 重写发生在父类子类中,若子类方法想要和父类方法构成重写关系,则它的方法名,参数列表必须和父类方法相同。另外,返回值要小于等于父类方法,抛出的异常要小于等于父类方法,访问修饰符则要大于等于父类方法,也就是说,若父类方法用private修饰,则子类不能对其重写。
- 同一个类中有多个构造器,多个构造器的形参列表不同就被称为构造器重载,构造器重载让Java类包含了多个初始化逻辑,从而允许使用不同的构造器来初始化对象。
- 构造方法不能重写,因为构造方法需要和类保持同名,而重写的要求是子类方法要和父类方法保持同名
- 父类方法和子类方法之间也有可能发生重载,因为子类会获得父类的方法,如果子类中定义了一个与父类方法名字相同但参数列表不同的方法,就会形成子类方法和父类方法重载
5. 请介绍一下访问修饰符
- Java提供的访问级别控制从小到大为:private->default->protected->public
- private:类中被private修饰的成员只能在当前类的内部被访问。根据这点,我们可以使用它来修饰成员变量,从而将成员变量隐藏在这个类的内部。
- default:如果类中的成员或者一个外部类不使用任何访问修饰符来进行修饰,那么它就是default级别的,default访问控制的类成员或者外部类可以被相同包下的其他类访问。
- protected:如果一个类成员被protected访问修饰符修饰,那么和这个成员不但可以被同一个包下的其他类访问,还可以被定义它的类的子类访问,无论子类是否在同一包内。一般来讲,如果一个方法别protected修饰,那么通常是希望它的子类来重写它。
- 对于局部变量而言,它的作用域就是他所在的方法,不可能被其他类所访问,所以不能使用访问修饰符来修饰。对于外部类而言,只能使用pubic和默认修饰