第一章 Java基础 50 道面试题


文章目录


前言

匿名内部类访问的局部变量为什么必须要用final修饰?

用final修饰实际上就是为了保护数据的一致性,这里所说的数据一致性,对引用变量来说是引用地址的一致性,对基本类型来说就是值的一致性。

final修饰符对变量来说,深层次的理解就是保障变量值的一致性。因为引用类型变量其本质是存入的是一个引用地址,说白了还是一个值(可以理解为内存中的地址值)。用final修饰后,这个这个引用变量的地址值不能改变,所以这个引用变量就无法再指向其它对象了。

为什么需要用final保护数据的一致性呢?因为将数据拷贝完成后,如果不用final修饰,则原先的局部变量可以发生变化。这里到了问题的核心了,如果局部变量发生变化后,匿名内部类是不知道的(因为他只是拷贝了局不变量的值,并不是直接使用的局部变量)。这里举个栗子:原先局部变量指向的是对象A,在创建匿名内部类后,匿名内部类中的成员变量也指向A对象。但过了一段时间局部变量的值指向另外一个B对象,但此时匿名内部类中还是指向原先的A对象。那么程序再接着运行下去,可能就会导致程序运行的结果与预期不同。

Java基础

1、jdk和jre有什么区别?

JDK(Java Development Kit),Java开发工具包

JRE(Java Runtime Environment),Java运行环境

JVM (java Virtual Machinejava),Java 虚拟机

JDK中包含JRE,JDK中有一个名为jre的目录,里面包含两个文件夹bin和lib,bin就是JVM,lib就是JVM工作所需要的类库

对于Java的开发人员是必须要安装JDK的,因为里面放的是Java的开发工具。

但是对于Java程序的运行只需要安装JRE就够了。

由此我们梳理出一个非常简单的结构,JDK中包含JRE和JavaC等Java开发工具,而JRE又包含着JVM虚拟机。

Java程序的基本处理流程:

. java文件通过 javac 进行编译成 .class文件,class文件又抛给到不同的虚拟机(Windows ,Linux),虚拟机调用类库将 .class文件解释成机械码,映射到系统调用。这样就使得Java程序的一次编译,到处运行。

在这里插入图片描述

2、final在Java中有什么作用?

简述final关键字的作用
表示为最终的,可以修饰类,修饰方法,修饰变量

修饰类:表示类不可以被继承,把父类变成了太监类

修饰方法:表示方法不能被子类覆盖(形参列表和返回值不变,方法中业务进行改变),但可以进行重载(也就是可以设置不同的形参和返回值,但方法业务不能更改)

修饰变量:表示变量一旦被赋值就不能更改它的值

如果修饰的是静态变量 需要在声明变量时赋值或在静态代码块中进行赋值,

例如 : public static final int i = 10;或 static{静态代码块进行赋值}

如果修饰的是成员变量 可以在声明变量时赋值,调用时赋值,和在 普通代码块中进行赋值

{ 我是普通代码块 } static{ 我是静态代码块 }

如果修饰的是局部变量 可以声明时不进行赋值,但使用时一定要赋值,但不能进行第二次赋值。

在这里插入图片描述

在这里插入图片描述

3、有常量类了为什么还要使用枚举类?

为了限制参数的范围
当我们需要一些固定不变的数据时,就可以将其声明为静态常量,以方便复用,然后通过类名点方法名的方式调用获取到常量,虽然我们定义常量时,指定了一些不变的数据,例如 public static final int SPRING = 1; 当我们的某个方法需要传入这个常量时,通过传入的常量执行不同的逻辑,此时就会发现没有办法限制调用者传什么值进来,调用者不仅可以传入 常量 1 ,还能传入其他 int 类型的变量,当然可以在方法上面添加注释提醒调用者,或者在方法中对传入的非法参数进行特殊的处理。

这时就需要使用 枚举类 来解决这个问题,让方法接收一个枚举类,在枚举类中定义需要的数据类型,这样调用者如果不传一个我们定义好的枚举类进来,最多也只能传一个null,如果传一个我们定义好的枚举类,就可以通过枚举类的get方法获取对应的常量。这样就限制了调用者能够传递的数据类型。

总结:
枚举能够很好的帮我们限定语义,能够在编译阶段就检查每个值的合理性,并且可以用于 switch 判断,以及自带了多个方法提供使用,比普通常量更加方便,当然也不是说必须使用枚举,常量很多场景下也是非常合适的。

4、为什么使用包装类?

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

5、==和equals的区别是什么?

1.equals和== 最大的区别是一个是方法一个是运算符。

2.==: 如果比较的对象是基本数据类型,则比较的是数值是否相等;如果比较的是引用数据类型,则比较的是对象的地址值是否相等。

3.equals(): 用来比较方法两个对象的内容是否相等。

注意:equals 方法不能用于基本数据类型的变量,如果没有对 equals 方法进行重写,则比较的是引用类型的变量所指向的对象的地址。
在这里插入图片描述

6、hashcode是什么有什么作用?

hashcode是一个对象的唯一标识符,它是根据对象的内容通过特殊算法计算出来的一个整数。hashcode主要用于在哈希表、集合、映射等数据结构中快速查找和定位对象,提高程序的效率。同时,它也是一些类库和框架在进行对象比较、对象去重等操作时的重要依据。

7、重写hashcode为什么要重写equals?

重写hashCode后再比较两个对象时,可以判断两个对象是否是同一个对象,而equals会比较两个对象的内容是否相同,只有当这两个条件都成立时,我们才能判定它们为同一个对象,我们在往HashMap,put元素时,就会先使用hashCode判断两个对象的code是否相同,如果相同再使用 equals 进行内容的比对,如果也相同,就能判定为同一个对象,然后进行返回,不进行元素的插入,但如果equals 的条件不成立,就表名这两个对象只是hashCode相同,但内容不同,可能发生了Hash碰撞,就会将需要擦插入的元素挂载到对应的链表。而这种业务操作是很常见的,大家就不约而同的在重写 hashCode后都去重写 equals 。

8、怎么解决Hash碰撞 ?

1、链地址法
对于相同的哈希值,使用链表进行连接。(HashMap使用此法)

优点

处理冲突简单,无堆积现象。即非同义词决不会发生冲突,因此平均查找长度较短;
适合总数经常变化的情况。(因为拉链法中各链表上的结点空间是动态申请的)
占空间小。装填因子可取α≥1,且结点较大时,拉链法中增加的指针域可忽略不计
删除结点的操作易于实现。只要简单地删去链表上相应的结点即可。

缺点

查询时效率较低。(存储是动态的,查询时跳转需要更多的时间)
在key-value可以预知,以及没有后续增改操作时候,开放定址法性能优于链地址法。
不容易序列化

2、再哈希法
提供多个哈希函数,如果第一个哈希函数计算出来的key的哈希值冲突了,则使用第二个哈希函数计算key的哈希值。

优点

不易产生聚集
缺点

增加了计算时间

9、Java有哪些引用数据类型?

8种基本数据类型的包装类都是引用数据类型,所有类的父类 Object 也是引用数据类型,和常用的容器集合 ArrayList,LinkedList,HashSet,LinkedHashSet、HashMap,LinkedHashMap都是引用数据类型。

10、什么是Java序列化?什么情况下会使用到序列化?

依靠网络进行数据传输,必须是二进制数据,而在java中都是以对象的形式存在,这时就需要先将对象进行序列化,通过网络传输后再进行反序列化。序列化也可以使用 IO 对象流到本地磁盘进行存储,在原型模式中,可以将对象序列化到磁盘,再反序列化后进行强制类型转换,就可以达到深拷贝对象的效果。

11、在Java中为什么不允许从静态方法中访问非静态变量?

1、静态变量属于类本身,在类加载的时候就会分配内存,可以通过类名直接访问;

2、非静态变量属于类的对象,只有在类的对象产生时,才会分配内存,通过类的实例去访问;

3、静态方法也属于类本身,但是此时没有类的实例,内存中没有非静态变量,所以无法调用。

12、在Java中什么时候使用重载什么时候使用重写?

重载发生在本类,根据形参列表的不同进行匹配对应的方法,返回值可以不同,方法的重写发生在父子类,子类可以通过重写父类的方法进行自身业务的需求,但返回值要相同。如果无意间重写了父类的方法,可能会导致继承体系的一些不可预知的侵入性,根据里氏替换原则,在父子关系中如果行为不同,可再抽出一个共同的父类,两个类都去继承抽象类,这样就具有了相同的行为,而一些特有的行为也不会影响到对方,类与类之间也尽量做组合、聚合,而不是继承。

13、实例化对象有哪几种方式?

1、直接new一个对象,最常用的一种。

2、通过反射获取一个对象实例

3、序列化,通过java.io.ObjectInputStream对象流的方式。

4、工厂模式实例化、克隆实例化两种比较少用。

14、Java容器都有哪些?

在这里插入图片描述

在这里插入图片描述

15、为什么要使用克隆?如何实现对对象的克隆?深拷贝和浅拷贝的区别是什么?

使用 克隆可以帮助我们创建大量相同的对象,避免了重复去new对象的繁琐,可以使用原型模式进行对对象的克隆,常用的有两种方式,一个是实现 克隆接口,通过重写 clon 克隆方法进行对象的克隆,但是只能达到浅拷贝的效果,一个是实现序列化接口 ,先使用 对象流存储对象,再反序列化回来,就能实现对象的克隆,而且是深拷贝。

浅拷贝只会对基本数据类型和String进行拷贝,而深拷贝可以对引用数据类型进行拷贝,浅拷贝克隆对象,对象中的引用数据类型都指向同一块内存地址,而深拷贝的内存地址是不同的。

string

16、string属于基本数据类型吗?

Java中的String是一种引用数据类型,不属于基本数据类型。Java中的基本数据类型包括:byte、short、int、long、float、double、char、boolean。

在Java中除了8种基本数据类型外,其他数据类型全部都是引用(reference)数据类型

17、string为什么设计为flian ?

当我们的项目中存在大量的“abc”对象,会很浪费内存,Java的设计者们 将其他字符串变量都指向字符串池的同一个字符串,解决这个问题,但如果String 不是final的,是可变的,会生成巨大的安全问题,线程T1在用着这个"abc",T2给变成了“cba”,就会有问题了。所以String 需要被设计为final 且不可变,来保证其安全性。

首先 声明String类是Final的,那么就不会存在其他类继承String, String 如果不是final的, 那么我写一个A类继承String, String s1 = new A(“abc”); A类覆盖其方法toUpperCase(),使原字符串变为大写,s1.toUpercase(); 现在s1 输出结果是什么“ABC”,所以如果String可以被继承,那么将是不安全的,因为子类随时可以覆盖你的方法,也就无法实现不可变, 所以首先String类是final的。

18、string,stringbuff,stringbiudre的区别?

性能 string—stringbuilder—stringbuffer

string 是 final 修饰的,每次变更都会创建一个新的string对象,所以它的性能是最差的。
stringbuilder是线程不安全的,发生变更是在原来的对象上面进行操作,性能最强。
stringbuffer是线程安全的,它的每个方法上面都加了 synchronized 关键字。 多线程共享变量时要使用stringbuffer。

总结:如果经常改变字符串变量,不考虑使用string,优先使用stringbuilder,多线程共享变量时使用stringbuffer。

19、string i = " a " 和 new string(" a ") 一样吗?

不一样,string i = " a " 会在字符串常量池中创建一个String 对象, new string(" a ") 会在堆内存中创建对象。

20、string类的常用方法有哪些 ?

1.length()方法 获取字符串长度,

String str = "abcdef";
System.out.println(str.length());//输出结果:6

2.charAt(int index)方法 传递一个下标参数,返回字符串对应位置的字符

String str = "abc";
System.out.println(str.charAt(1));//输出结果:b

3.indexOf()方法 传递某个字符,返回在字符串中的第一个位置

String str = "abcabc";
System.out.println(str.indexOf('a'));//输出结果:0

4.subString(int start)方法 默认是取到字符串末尾

String str = "abcdef";
System.out.println(str.subString(2));//输出结果:cdef

5、equals()方法 判断字符串内容是否相同,区分大小写。

String str1 = "abc";
String str2 = "ABC";
System.out.println(str1.equals(str2));//输出结果:false

21、如何将字符串反转?

1.StringBuilder的reverse()方法,最简单

public static String reverse4(String s) {

  return new StringBuffer(s).reverse().toString();
}

2.使用字符串数组,实现从尾部开始逐个逆序放入字符串

public static String reverse3(String s) {

  char[] array = s.toCharArray();

  String reverse = "";

  for(int i = array.length - 1; i >= 0; i--)

  reverse += array[i];

  return reverse;

}

22、String str =new String(“ab”) 会创建几个对象 ?

public class StringNewTest {
    public static void main(String[] args) {
        String str = new String("ab");
    }
}

javap -v StringNewTest.class 反编译后, 部分片段如下:

在这里插入图片描述
根据反编译后字节码分析:

1、一个对象是:new关键字在堆空间创建的;
2、另一个对象是:字符串常量池中的对象"ab"。 (如果前后文中还有代码,并且已经有 ab 常量在常量池存在时,ab 将不再创建,因为在常量池只能存在一份相同的对象)
结论是至少是2个对象。

23、String str =“a”+ “b” 会创建几个对象 ?

public class StringNewTest {
    public static void main(String[] args) {
        String str = "a" + "b";
    }
}

javap -v StringNewTest.class 反编译后, 部分片段如下:
在这里插入图片描述
“a” + “b” 在编译时,就已经编译为 ab, 被放到常量池中。
所以只有一个对象 :ab

注意:
如果前后文中还有代码,并且已经有 ab 常量在常量池存在时,ab 将不再创建,因为在常量池只能存在一份相同的对象。

24、new string a ➕new string b会创建几个对象?

对象1:new StringBuilder()

对象2:new String(“a”)

对象3:常量池中的"a"

对象4:new String(“b”)

对象5:常量池中的"b"

深入剖析:StringBuilder中的toString():

对象6:new String(“ab”)

强调一下,toString()的调用,在字符串常量池中,没有生成"ab"

附加题
String s1 = new String(“1”) + new String(“1”);//s1变量记录的地址为:new String
s1.intern();//在字符串常量池中生成"11"。如何理解:jdk6:创建了一个新的对象"11",也就有新的地址;jdk7:此时常量池中并没有创建"11",而是创建了一个指向堆空间中new String(“11”)的地址;
String s2 = “11”;
System.out.println(s1 == s2);//jdk6:false;jdk7:true

字符串拼接操作的总结
常量 与 常量 的拼接结果在 常量池,原理是 编译期 优化;
常量池 中不会存在相同内容的常量;
只要其中一个是变量,结果在堆中。 如: String s2 = s1+“DEF” ;
变量拼接的原理 是StringBuilder 。
如果拼接的结果是调用 intern() 方法,则主动将常量池中 还没有的字符串 对象放入池中,并返回地址。

面向对象

25、说说你所了解的面向对象的三大特征?

封装:核心思想就是“隐藏细节”、“数据安全”,将对象不需要让外界访问的成员变量和方法私有化,只提供符合开发者意愿的公有方法来访问这些数据和逻辑,保证了数据的安全和程序的稳定。所有的内容对外部不可见。

继承:Java中只支持单继承,对于继承最大的优处就是提高代码的复用性,子类继承父类的成员变量和方法,私有属性可以继承,但不能直接访问,继承父类后还可在自身的业务需求进行扩展。如果子类不是通过重写父类的方法,而是自己特有的方法行为,通过父类型引用是不能够调用到子类特有的方法行为的。

多态:基于对象所属类不同,外部对同一个方法的调用,实际方法的执行逻辑不同。多态的三个条件 继承,重写,父类型引用指向子类型对象。

26、面向对象和面向过程有什么区别 ?

面相过程可以说是按照一定的顺序去解决问题,这样的方法干脆明了,我想做什么可以立即去做。
而面向对象不同,面向对象需要考虑需求的扩展性和维护性,可以把面向过程中的同一属性抽取出来,抽取出的对象只做自己分内的事,而不用担心其余对象的行为方法。

27、说一下你对面向对象的理解 ?

对于Java对象,就比如在银行出纳员问题中,有出纳、客户、账户、交易、货币等许多对象,在这些类的成员或元素都具有某种共性,例如每个账户都有余额,每个出纳都可以处理存款请求等,因此,每个成员都有其自身的状态:每个账户都有不同的结余金额,每个出纳都有不同的姓名。因此,出纳、客户、交易、货币、账户等都可以在计算机的程序中别表示为唯一的实体,这些实体就是对象,每一个对象都属于定义了特性和行为的某个特定的类。

28、组合和继承的区别 ?

​ 组合和继承是面向对象中两种代码复用的方式。

组合是指在新类里面创建原有类的对象,重复利用已有类的功能。被称为 has-a 关系。
继承是面向对象的主要特性之一,它允许设计人员根据其他类的实现来定义一个类的实现。被称为 is-a 关系

使用注意事项:
除非两个类之间是 is-a 关系,否则不要轻易使用继承,不要单纯地为了实现代码的重用而使用继承,因为过多地使用继承会破坏代码的可维护性。
不要仅仅为了实现多态而继承,如果类之间没有 is-a 的关系,可以通过实现接口与组合方式来达到相同的目的。
由于 Java 语言只支持间继承,如果 想同时继承两个类或多个类,在 Java 中是无法实现的。在 Java 语言中,能使用组合就尽量不要使用继承

接口

29、为什么不直接在类里面写对应的方法, 而要多写一个接口(或抽象类)?

1、重要性:在Java语言中, abstract class 和interface 是支持抽象类定义的两种机制。正是由于这两种机制的存在,才赋予了Java强大的 面向对象能力。

2、简单、规范性:如果一个项目比较庞大,实现类比较多时很难进行管理,加一层接口上去,可以让我们很简单直观的看出接口的实现类的业务需求与行为,在平常的开发中也可以通过注入接口,调用到对应的实现类,而不需要关心实现类的具体实现。

3、维护、拓展性:通过使用接口可以让我们的程序的耦合度降低,可以方便后期业无需求的添加。添加新的业务也只需要让一个新的类去实现接口,而对于接口的引用则不需要改变。

4、安全、严密性:接口是实现软件松耦合的重要手段,它描叙了系统对外的所有服务,而不涉及任何具体的实现细节。这样就比较安全、严密一些。

30、既然接口跟抽象类差不多, 什么情况下要用接口而不是抽象类?

抽象类用来定义类与类之间的共同特征,将这些共有的属性进行抽象,子类继承,子类可以拥有自己特有的特征,而接口是对行为的约束,实现了接口的类都要去实现接口定义的方法,一旦实现了这些方法,该类就拥有了这些“功能”。

当我们需要对类的行为进行定义或者扩展时就可以使用到接口,比如我们现在有一个 鸟儿对象,它可以通过实现一个定义了 飞翔和唱歌的 接口,实现这两个方法,就可以拥有这两个功能,如果我们想要将这个 鸟儿对象 存储到磁盘,可以通过实现序列化接口进行存储,想要很多只鸟儿,可以实现 克隆接口重写克隆方法进行对象的克隆。

31、说一下接口的特点?

1、接口中的抽象方法不需要使用abstract关键字声明,接口使用interface声明

2、接口中变量都是默认由public static final修饰的,而抽象类中可以有变量

3.接口中没有构造方法,构造方法用于创建对象,所以接口不能new对象来创建,但是可以多态,接口与实现类的关系与父类与子类的关系相同

4、类不支持多继承,但类支持多实现;接口直接支持相互继承而且支持多继承(A,B也是接口),接口是对行为的抽象化,而抽象类是对事物的抽象化

5、实现接口中的类中必须实现接口中的所有方法,如果不实现接口中的所有方法,那么该类是抽象类

32、接口如果被default关键字修饰会怎么样?

如果接口定义的方法被 default 修饰,接口中的方法可以定义方法体,实现接口后不需要进行重写。

这主要是为了解决如果我们往接口中添加新的方法,由于已经实现了接口的实现类都会受到影响,都要去重写这个新添加的方法,牵一发而动全身。

33、接口和抽象类有哪些区别?

1、抽象类中可以定义构造器,接口不能定义构造器
2、抽象类可以有抽象方法和具体方法,接口只能有抽象方法
3、抽象类中的成员可以是private、默认、protected、public,接口只能是 public
4、抽象类中可以定义成员变量,接口的成员变量实际都是常量
5、抽象类可以包含静态方法,接口不能有静态方法
6、一个类只能继承一个抽象类,可以实现多个接口

34、接口和类的区别?

接口并不是类,编写接口的方式和类很相似,但是它们属于不同的概念。类描述对象的属性和方法。接口则包含类要实现的方法。除非实现接口的类是抽象类,否则该类要定义接口中的所有方法。

抽象类

35、什么是抽象类?什么情况下会使用抽象类?

无法完整描述一个事物的类,抽象类是对类与类之间共同特征的抽象,抽象类的抽象方法子类必须进行重写,否则子类仍然是抽象类。

当两个类之间大致的特征相同,却有着极少部分的行为不同时,可以使用抽象类,将他们共同的特征抽取出来,然后两个类都去继承抽象类,两个子类再去各自实现自己特有的行为特征。

36、抽象类可以被实例化吗?抽象方法呢?抽象方法可以被private关键字修饰吗?为什么?

抽象类不能被实例化,只能被子类化!在抽象类中,子类实例化会先初始化父类,但父类初始化并不是创建一个父类对象,而是把父类中定义的对象相关属性都初始化,因为这些属性子类对象也是拥有的。所以,为了保证子类对象的完整性,要从最底层的父类开始,逐级初始化,所有初始化都完成后才会产生一个完整的子类对象。
注意:接口与抽象类非常类似,但是它不可以被实例化,因为接口压根没有构造函数。

抽象方法可以被private关键字修饰吗?为什么?
抽象方法不能被 private关键字修饰,因为抽象方法必须由子类进行实现,而如果被 private 修饰,子类就无法访问父类的私有属性,子类就不能够重写父类的抽象方法,与抽象方法的定义相违背。

37、普通类和抽象类有哪些区别?

1.普通类中不可含有抽象方法,可以被实例化
2.抽象类:则抽象类中所有的方法自动被认为是抽象方法,没有实现过程,不可被实例化 ,当然抽象类中也可包含具体的已实现方法。
抽象类的子类,除非也是抽象类,否则必须实现该抽象类声明的抽象方法

38、抽象类中有构造方法吗 ?

在抽象类中可以有构造方法,只是不能直接创建抽象类的实例对象,但实例化子类的时候,就会初始化父类,不管父类是不是抽象类都会调用父类的构造方法,初始化一个类,先初始化父类。

39、抽象类可以用final声明么?

不能,抽象类是被用于继承的,final修饰代表不可修改、不可继承的。

40、抽象类能否使用static声明 ?

Java中抽象类的抽象方法不可以使用static构成静态的抽象方法。
因为抽象类是不能被实例化的,即不能分配内存。而static修饰的方法,在实例化之前就已经分配了内存,所以抽象类中不能有静态的抽象方法。
另一方面,定义抽象方法的目的就是为了让子类继承并重写此方法,但是如果定义成静态方法,该方法就无法被重写。

static修饰的类,不可以被继承。
static修饰的方法,可以被继承,但是不可以被重写。

41、抽象类的应用——模板方法设计模式

模板方法设计模式,是将抽象类一系列固定需要执行的方法聚合在抽象类的某一个方法中,这样子类去继承抽象类,就可以暴露给外界一个模板方法,通过这一个模板方法达到调用一系列固定方法的效果。模板方法也可以设计成fianl 不让子类去重写。

42、举例说明什么情况下会更倾向于使用抽象类而不是接口

就比如我们上面提到的,模板方法模式,就需要使用抽象类定义一个模板方法,对其他方法进行固定顺序的调用,这时是不能使用接口的,因为接口中定义的方法不能有方法体,但是也可以通过 default 关键字进行修饰,达到可以具有方法体的效果,但如果我们需要在模板方法上面添加 钩子方法,就会变得相对繁琐,所有这时就更倾向使用抽象类,而不是接口。

继承

43、Java为什么不允许多继承?

(1)如果在一个子类继承的多个父类中拥有相同名字的实例变量,子类在引用该变量时将产生歧义,无法判断应该使用哪个父类的变量。
(2)如果在一个子类继承的多个父类中拥有相同方法,子类中有没有覆盖该方法,那么调用该方法时将产生歧义,无法判断应该调用哪个父类的方法。
在接口中不能有实例变量,只能有静态的常量,不能有具体的方法(包含方法体),只能有抽象方法,因此也就摒弃了多继承的缺点。

44、组合大于继承,什么时候组合?什么时候用继承?

当类与类之间的特征与行为大致一致时,可以使用继承简化类的编写,但如果父子类之间存在歧义,可以使用组合或者聚合对类与类之间进行整合,这样即使B类 没有继承 A类 ,在 A 类中 也可以使用到 B类的方法,也不需要担心因为破坏继承而导致程序的侵入性。

①不破坏封装,整体类与局部类松耦合,彼此相对独立。若是继承,子类必须继承父类方法,限制较大;父类的改动会影响子类;
​ ②具有较好的扩展性。继承制在成员较多时可能形成多代层次,复杂且易出错,组合则没有这个缺点;
③支持动态组合,整体对象可以选择不同的局部对象。因为类与类之间相对独立,组合也会比继承更加灵活,修改更加容易;
④整体类可以对局部类包装形成新的接口;调用新方法不再受到继承中命名等诸多限制;

45、继承的优缺点 ?

1、优点

提高了代码的再利用性。
提高了代码的维护性。
让类与类有关,是多态的前提。

2、缺点

提高类的耦合性。这样一个类的变化会影响其他与此类相关的类别。父类的改变会直接影响到子类。
打破了封装性。

46、什么时候需要重写父类的方法?重写后怎么调用父类的方法?

继承性的基础之上的,没有继承性也就不能谈方法的重写。方法的重写是当程序中父类的某一个方法并不能满足子类的需求时,子类可以重新定义该方法的内容与功能来满足子类的需求的一种操作。

当父类的业务逻辑满足不了子类的需求时,就需要重写父类的方法,就算对父类的方法进行了重写,仍可以通过 super 关键字调用到父类的方法。

46、子类继承父类后会有哪些行为限制?

子类重写父类或接口中的方法名、参数列表一致。

不可以降低方法的访问权限。 (子类继承父类的访问修饰符要比父类的更大,也就是更加开放,假如我父类是protected修饰的,其子类只能是protected或者public,绝对不能是friendly(默认的访问范围)或者private,当然使用private就不是继承了。)

返回值类型只能是父类中返回值类型或者是其子类。

抛出异常也不能超出父类方法的异常范围(若父类方法没有抛出异常,则子类也不能抛出异常,若父类抛出异常,子类抛出的异常只能是父类异常类型或者是其子类型)

异常体系

47、throw和throws的区别 ?

throw是在代码中抛出异常
throws是在方法签名中声明抛出异常,指明这个方法可能会抛出的异常类型

在Java中,throw 用于抛出一个已知的异常,使用 throw 时,必须指定异常对象,而 throws 用于声明可能会抛出的异常。

48、try catch fianlly中如果catch中return了,Fianlly还会执行吗?

不管有没有出现异常,finally块中代码都会执行;

当try和catch中有return时,finally仍然会执行, 执行顺序 catch —finally ----catch中的return;

finally是在return后面的表达式运算后执行的(此时并没有返回运算后的值,而是先把要返回的值保存起来,管finally中的代码怎么样,返回的值都不会改变,任然是之前保存的值),所以方法返回值是在finally执行前确定的;

finally中最好不要包含return,否则程序会提前退出,返回值不再是try或catch块中的返回值。

唯一能使 finally 不执行的方法是,在try 或者 catch 中 调用 System. exit(0)退出虚拟机。

49、final finally finalize有什么区别 ?

final:
final是一个修饰符,可以修饰变量、方法和类。如果final修饰变量,意味着被修饰的变量一旦被初始化之后就不能再被改变。

finally:
finally是一个关键字,常与 try catch 一起联用于异常处理,finally方法块一定会被执行,无论try方法块是否有异常发生,所以常用于流的关闭。

finalize:
finalize 方法是在对象被回收之前调用的方法,是给对象最后一次复活的机会,什么时候需要使用finalize方法没有保证,需要根据具体的业务逻辑进行选择。

使用finalize方法没有保证:这是因为该方法的执行优先级很低,需要进行等待让主线程等待这个方法执行完后再去进行垃圾回收,不然垃圾回收的执行优先级高于finalize方法,没等到finalize方法执行就一级把对象当成垃圾回收了。但是即使救活了这个对象,再次进行垃圾回收的话就再也救不活了。

50、平常在开发中都遇到过哪些异常 ?

1、空指针异常(NullPointException),2、数组越界异常(ArrayIndexOutOfBoundsException),3、强制类型转换异常(ClassCastException)4、数字格式化异常(NumberFormatException),5、输入类型不匹配异常(InputMismatchException),6、算数运算符异常(ArithmeticException),8、SQL异常(SQLException),9、内存溢出异常(OutOfMemoryError),10、IO异常(IOException),11、找不到文件异常(FileNotFoundException)

统一异常处理怎么实现?

枚举类

包装类

IO流

封装:核心思想就是“隐藏细节”、“数据安全”,将对象不需要让外界访问的成员变量和方法私有化,只提供符合开发者意愿的公有方法来访问这些数据和逻辑,保证了数据的安全和程序的稳定。所有的内容对外部不可见。\n继承:子类可以继承父类的属性和方法,并对其进行拓展。将其他的功能继承下来继续发展 。\n多态:同一种类型的对象执行同一个方法时可以表现出不同的行为特征。通过继承的上下转型、接口的回调以及方法的重写和重载可以实现多态。方法的重载本身就是一个多态性的体现。%

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值