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

11.静态变量和实例变量的区别?

  1. 静态标量前面有static,实例变量没有;

  2. 静态变量可通过类名调用,实例变量通过对象名调用

  • 在语法定义上的区别:

    静态变量前要加 static 关键字,而实例变量前则不加。

  • 在程序运行时的区别:

    实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能进行使用。
    静态变量不属于某个实例对象,而是属于类,所以也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,就可以使用。
    总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。

    例如 :
    在这里插入图片描述
    无论创建多少个实例对象,永远都只分配了一个 staticVar 变量,并且每创建一个实例对象,这个 staticVar 就会加 1;但是,每创建一个实例对象,就会分配一个 instanceVar,即可能分配多个 instanceVar,并且每个 instanceVar 的值都只自加 了 1 次。

    备注:这个解答除了说清楚两者的区别外,最后还用一个具体的应用例子来说明两者的差异,体现了自己有很好的解说问题和设计案例的能力,思维敏捷,超过一般程序员,有写作能力!

12.是否可以从一个 static 方法内部发出对非 static 方法的调用?

不可以从一个 static 方法内部发出对非 static 方法的调用。

静态方法内部只能调用静态方法。

因为非静态方法是要与对象关联在一起的,必须创建一个对象后,才可以在该对象上进行方法调用,而静态方法调用时不需要创建对象,可以直接调用。
也就是说,当一个 static 方法被调用时,可能还没有创建任何实例对象,如果从一个 static 方法中发出对非 static 方法的调用,那个非 static 方法是关联到哪个对象上的呢?这个逻辑无法成立,所以,一个 static 方法内部不能发出对非 static 方法的调用。


13.Integer 与 int 的区别?

  1. int 是 java 的基本数据类型;
    Integer 是 java 为 int 提供的封装类。

  2. int 的默认值为 0,
    Integer 的默认值为 null,

Integer 可以区分出未赋值和值为 0 的区别,int 则无法表达出未赋值的情况,
例如,要想表达出没有参加考试和考试成绩为 0 的区别,则只能使用 Integer。
在 JSP 开发中,Integer 的默认为 null,所以用 el 表达式在文本框中显示时,值为空白字符串,而 int 默认的默认值为 0,所以用 el 表达式在文本框中显示时,结果为 0,所以,int 不适合作为 web 层的表单数据的 类型。

Integer 提供了多个与整数相关的操作方法,
例如,将一个字符串转换成整数,Integer 中还定义了表示整数的最大值和最小值的常量。

14.Math.round(11.5)等于多少? Math.round(-11.5)等于多少?

Math.round(11.5) 结果为 12,Math.round(-11.5) 结果为 -11。

Math 类中提供了三个与取整有关的方法:ceil、floor、round,这些方法的作用与它们的英文名称的含义相对应。

例如:

ceil 的英文意义是天花板,该方法表示向上取整,
Math.ceil(11.3)的结果为 12,Math.ceil(-11.3)的结果是-11;

floor 的英文意义是地板,该方法表示向下取整,
Math.floor(11.6)的结果为 11,Math.floor(-11.6)的结果是-12;

Math.round(x) , 算法:Math.floor(x+0.5)

即将原来的数字加上 0.5 后再向下取整,所以,
Math.round(11.5)的结果为 12,Math.round(-11.5)的结果为-11。
在这里插入图片描述

15.作用域 public,private,protected,以及不写(friendly)时的区别

用 public 修饰时,在当前类、同一包内、子孙类、其他包内中都可调用;
用 protected 修饰时,在当前类、同一包内、子孙类中可调用,在其他包内不可调用;
用 friendly 修饰(不写)时,在当前类、同一包内中可调用,在子孙类、其他包内不可调用;
用 private 修饰时,只能在当前类中调用;

这四个作用域的可见范围如下表所示。
在这里插入图片描述
如果在修饰的元素上面没有写任何访问修饰符,则表示 friendly。

备注:只要记住了有 4 种访问权限,4 个访问范围,然后将全选和范围在水平和垂直方向上分别按排从小到大或从大到小的顺序排列,就很容易画出上面的图了。

16.Overload 重载 和 Override 重写 的区别。重载的方法是否可以改变返回值的类型?

重载:类中的构造方法同名不同参(多个方法,方法名相同,但参数列表不同(个数、类型));
重写:子类重写父类方法(子类的方法名、返回值、参数与父类一致)可补充父类的方法,删除重写方法中的 super.() ,即推翻父类的写法,异常修饰符只可高或相等。

Overload 是重载的意思,Override 是覆盖的意思,也就是重写。

重载 :表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同(即参数个数或类型不同)。

重写 :表示子类中的方法可以与父类中的某个方法的名称和参数完全相同,通过子类创建的实例对象调用这个方法时,将调用子类中的定义方法,这相当于把父类中定义的那个完全相同的方法给覆盖了,这也是面向对象编程的多态性的一种表现。
子类覆盖父类的方法时,只能比父类抛出更少的异常,或者是抛出父类抛出的异常的子异常,因为子类可以解决父类的一些问题,不能比父类有更多的问题。子类方法的访问权限只能比父类的更大,不能更小。

重载 的方法是否可以改变返回值的类型?

  • 如果几个重载方法的参数列表不一样,它们的返回者类型当然也可以不一样;

  • 如果两个方法的参数列表完全一样,是否可以让它们的返回值不同来实现重载?这是不行的。

    我们可以用反证法来说明这个问题,因为我们有时候调用一个方法时也可以不定义返回结果变量,即不要关心其返回结果,

    例如:
    我们调用 map.remove(key) 方法时,虽然 remove 方法有返回值,但是我们 通常都不会定义接收返回结果的变量,这时候假设该类中有两个名称和参数列表完全相同的方法,仅仅是返回类型不同,java 就无法 确定编程者倒底是想调用哪个方法了,因为它无法通过返回结果类型来判断。

17.构造器 Constructor 是否可被 override 重写?

构造器不能被重写

构造器是不能被继承的,因为每个类的类名都不相同,而构造器名称与类名相同,所以根本谈不上继承。

又由于构造器不能继承,所以就不能被重写。但是,在同一个类中,构造器是可以被重载的。

18.接口是否可继承接口? 抽象类是否可实现接口? 抽象类是否可继承具体类? 抽象类中是否可以有静态的 main 方法?

接口可以继承接口(接口多继承)。
抽象类可以实现(implements)接口,
抽象类可继承实体类,但前提是实体类必须有明确的构造函数。
抽象类中可以有静态的 main 方法。

备注:只要明白了接口和抽象类的本质和作用,这些问题都很好回答,你想想,如果你是 java 语言的设计者,你是否会提供这样 的支持,如果不提供的话,有什么理由吗?如果你没有道理不提供,那答案就是肯定的了。


19.写 clone() 方法时,通常都有一行代码,是什么?

clone 有缺省行为,super.clone();
因为首先要把父类中的成员复制到位,然后才是复制自己的成员。

20.面向对象的特征有哪些方面?

计算机软件系统是现实生活中的业务在计算机中的映射,而现实生活中的业务其实就是一个个对象协作的过程。
面向对象编程就是按现实业务一样的方式将程序代码按一个个对象进行组织和编写,让计算机系统能够识别和理解用对象方式组织和编写的程序代码,这样就可以把现实生活中的业务对象映射到计算机系统中。

面向对象的编程语言有封装、继承 、抽象、多态等 4 个主要的特征。

  • 封装
    把对象内部的可透明性和隐藏的特性区分开。

    是保证软件部件具有优良的模块性的基础,封装的目标就是要实现软件部件的“高内聚、低耦合” ,防止程序相互依赖性而带来的变动影响。

    在面向对象的编程语言中,对象是封装的最基本单位,面向对象的封装比传统语言的封装更为清晰、更为有力。

    面向对象的封装就是把描述一个对象的属性和行为的代码封装在一个“模块”中,也就是一个类中,属性用变量定义,行为用方法进行定义,方法可以直接访问同一个对象中的属性。通常情况下,只要记住让变量和访问这个变量的方法放在一起,将一个类中的成员变量全部定义成私有的,只有这个类自己的方法才可以访问到这些成员变量,这就基本上实现对象的封装,就很容易找出要分配到这个类上的方法了,就基本上算是会面向对象的编程了。

    例如,人要在黑板上画圆,这一共涉及三个对象:人、黑板、圆,画圆的方法要分配给哪个对象呢?由于画圆需要使用到圆心和半径,圆心和半径显然是圆的属性,如果将它们在类中定义成了私有的成员变量,那么,画圆的方法必须分配给圆,它才能访问到圆心和半径这两个属性,人以后只是调用圆的画圆方法、表示给圆发给消息而已,画圆这个方法不应该分配在人这个对象上,这就是面向对象的封装性,即将对象封装成一个高度自治和相对封闭的个体,对象状态(属性)由这个对象自己的行为(方法)来读取和改变。

    一个更便于理解的例子就是,司机将火车刹住了,刹车的动作是分配给司机,还是分配给火车,显然,应该分配给火车,因为司机自身是不可能有那么大的力气将一个火车给停下来的,只有火车自己才能完成这一动作,火车需要调用内部的离合器和刹车片等多个器件协作才能完成刹车这个动作,司机刹车的过程只是给火车发了一个消息,通知火车要执行刹车动作而已。

  • 继承
    子类继承父类的特征和行为。

    在定义和实现一个类的时候,可以在一个已经存在的类的基础之上来进行,把这个已经存在的类所定义的内容作为自己的内容,并可以加入若干新的内容,或修改原来的方法使之更适合特殊的需要,这就是继承。

    继承是子类自动共享父类数据和方法的机制,这是类之间的一种关系,提高了软件的可重用性和可扩展性。

  • 多态
    同一事物有不同的表现形式。

    多态是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态, 这就是多态性。

    多态性增强了软件的灵活性和扩展性。

    例如,下面代码中的 UserDao 是一个接口,它定义引用变量 userDao 指向的实 例对象由 daofactory.getDao()在执行的时候返回,有时候指向的是 UserJdbcDao 这个实现,有时候指向的是 UserHibernateDao 这个实现, 这样,不用修改源代码,就可以改变 userDao 指向的具体类实现,从而导致 userDao.insertUser()方法调用的具体代码也随之改变,即有 时候调用的是 UserJdbcDao 的 insertUser 方法,有时候调用的是 UserHibernateDao 的 insertUser 方法:
    在这里插入图片描述

  • 抽象
    找出事物的共性之处,将之为一个类。

    就是找出一些事物的相似和共性之处,然后将这些事物归为一个类,这个类只考虑这些事物的相似和共性之处,并且会忽略与当前主题和目标无关的那些方面,将注意力集中在与当前目标有关的方面。

    抽象包括行为抽象和状态抽象两个方面。

    例如,定义一 个 Person 类,
    在这里插入图片描述
    人本来是很复杂的事物,有很多方面,但因为当前系统只需要了解人的姓名和年龄,所以上面定义的类中只包含姓名和年龄这两个属性,这就是一种抽像,使用抽象可以避免考虑一些与目标无关的细节。
    我对抽象的理解就是不要用显微镜去看一个事物的所有方面,这样涉及的内容就太多了,而是要善于划分问题的边界,当前系统需要什么,就只考虑什么。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值