Java面试(二)

1、静态变量和实例变量的区别?

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

3、Integer 与 int 的区别

4、Math.round(11.5)等於多少? Math.round(-11.5)等於多少?

5、请说出作用域 public,private,protected,以及不写时的区别

6、Overload 和 Override 的区别。Overloaded 的方法是否可以改变返回值的类型?

7、构造器 Constructor 是否可被 override?

8、接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承具体类(concrete class)? 抽象 类中是否可以有静态的 main 方法?

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

10、面向对象的特征有哪些方面


1、静态变量和实例变量的区别?

在语法定义上的区别:静态变量前要加 static 关键字,而实例变量前则不加。

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

例如,对于下面的程序,无论创建多少个实例对象,永远都只分配了一个 staticVar 变量,并且每创建一个实例 对象,这个 staticVar 就会加 1;但是,每创建一个实例对象,就会分配一个 instanceVar,即可能分配多个 instanceVar, 并且每个 instanceVar 的值都只自加了 1 次。

public class VariantTest{
  public static int staticVar = 0; 
  public int instanceVar = 0;  

public VariantTest(){
staticVar++;
instanceVar++;
System.out.println(staticVar= + staticVar + ,instanceVar= + instanceVar);
}
}


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

不可以。

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

3、Integer 与 int 的区别

int 是 java 提供的 8 种原始数据类型之一。

Java 为每个原始类型提供了封装类,Integer 是 java 为 int 提供的封装类。

int 的默认值为 0,而 Integer 的默认值为 null,即 Integer 可以区分出未赋值和值为 0 的区别,int 则无法表达 出未赋值的情况。

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

在 Hibernate 中,如果将 OID 定义为 Integer 类型,那么 Hibernate 就可以根据其值是否为 null 而判断一个对象 是否是临时的,如果将 OID 定义为了 int 类型,还需要在 hbm 映射文件中设置其 unsaved-value 属性为 0。
另外,Integer 提供了多个与整数相关的操作方法,例如,将一个字符串转换成整数,Integer 中还定义了表示整 数的最大值和最小值的常量。

4、Math.round(11.5)等於多少? Math.round(-11.5)等於多少?

Math 类中提供了三个与取整有关的方法:ceil、floor、round,这些方法的作用与它们的英文名称的含义相对应, 例如,ceil 的英文意义是天花板,该方法就表示向上取整,Math.ceil(11.3)的结果为 12,Math.ceil(-11.3)的结果是-11; floor 的英文意义是地板,该方法就表示向下取整,Math.ceil(11.6)的结果为 11,Math.ceil(-11.6)的结果是-12;最难 掌握的是 round 方法,它表示“四舍五入”,算法为 Math.floor(x+0.5),即将原来的数字加上 0.5 后再向下取整, 所以,Math.round(11.5)的结果为 12,Math.round(-11.5)的结果为-11。

5、请说出作用域 public,private,protected,以及不写时的区别


6、Overload 和 Override 的区别。Overloaded 的方法是否可以改变返回值的类型?

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

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

重写 Override 表示子类中的方法可以与父类中的某个方法的名称和参数完全相同,通过子类创建的实例对象调 用这个方法时,将调用子类中的定义方法,这相当于把父类中定义的那个完全相同的方法给覆盖了,这也是面向 对象编程的多态性的一种表现。子类覆盖父类的方法时,只能比父类抛出更少的异常,或者是抛出父类抛出的异 常的子异常,因为子类可以解决父类的一些问题,不能比父类有更多的问题。子类方法的访问权限只能比父类的 更大,不能更小。如果父类的方法是 private 类型,那么,子类则不存在覆盖的限制,相当于子类中增加了一个全新的方法。
至于 Overloaded 的方法是否可以改变返回值的类型这个问题,要看你倒底想问什么呢?这个题目很模糊。如果
几个 Overloaded 的方法的参数列表不一样,它们的返回者类型当然也可以不一样。但我估计你想问的问题是:如 果两个方法的参数列表完全一样,是否可以让它们的返回值不同来实现重载 Overload。这是不行的,我们可以用 反证法来说明这个问题,因为我们有时候调用一个方法时也可以不定义返回结果变量,即不要关心其返回结果, 例如,我们调用 map.remove(key)方法时,虽然 remove 方法有返回值,但是我们通常都不会定义接收返回结果的 变量,这时候假设该类中有两个名称和参数列表完全相同的方法,仅仅是返回类型不同,java 就无法确定编程者 倒底是想调用哪个方法了,因为它无法通过返回结果类型来判断。

override 可以翻译为覆盖,从字面就可以知道,它是覆盖了一个方法并且对其重写,以求达到不同的作用。对我 们来说最熟悉的覆盖就是对接口方法的实现,在接口中一般只是对方法进行了声明,而我们在实现时,就需要实 现接口声明的所有方法。除了这个典型的用法以外,我们在继承中也可能会在子类覆盖父类中的方法。在覆盖要 注意以下的几点:
1、覆盖的方法的标志必须要和被覆盖的方法的标志完全匹配,才能达到覆盖的效果;

2、覆盖的方法的返回值必须和被覆盖的方法的返回一致;

3、覆盖的方法所抛出的异常必须和被覆盖方法的所抛出的异常一致,或者是其子类;
4、被覆盖的方法不能为 private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。
overload 对我们来说可能比较熟悉,可以翻译为重载,它是指我们可以定义一些名称相同的方法,通过定义不同 的输入参数来区分这些方法,然后再调用时,VM 就会根据不同的参数样式,来选择合适的方法执行。在使用重载要注意以下的几点:

1、在使用重载时只能通过不同的参数样式。例如,不同的参数类型,不同的参数个数,不同的参数顺序(当然, 同一方法内的几个参数类型必须不一样,例如可以是 fun(int,float),但是不能为 fun(int,int));

2、不能通过访问权限、返回类型、抛出的异常进行重载;
3、方法的异常类型和数目不会对重载造成影响;
4、对于继承来说,如果某一方法在父类中是访问权限是 priavte,那么就不能在子类对其进行重载,如果定义的 话,也只是定义了一个新方法,而不会达到重载的效果。

7、构造器 Constructor 是否可被 override?

构造器 Constructor 不能被继承,因此不能重写 Override,但可以被重载 Overload。

8、接口是否可继承接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承具体类(concrete class)? 抽象 类中是否可以有静态的 main 方法?

接口可以继承接口。抽象类可以实现(implements)接口,抽象类是否可继承具体类。抽象类中可以有静态的 main 方法。

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

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

10、面向对象的特征有哪些方面

计算机软件系统是现实生活中的业务在计算机中的映射,而现实生活中的业务其实就是一个个对象协作的过 程。面向对象编程就是按现实业务一样的方式将程序代码按一个个对象进行组织和编写,让计算机系统能够识别 和理解用对象方式组织和编写的程序代码,这样就可以把现实生活中的业务对象映射到计算机系统中。
面向对象的编程语言有封装、继承 、抽象、多态等 4 个主要的特征。

1 封装:

封装是保证软件部件具有优良的模块性的基础,封装的目标就是要实现软件部件的“高内聚、低耦合”,防止程序相互依赖性而带来的变动影响。在面向对象的编程语言中,对象是封装的最基本单位,面向对象的封装比传统语言的封装更为清晰、更为有力。面向对象的封装就是把描述一个对象的属性和行为的代码封装在一个“模块” 中,也就是一个类中,属性用变量定义,行为用方法进行定义,方法可以直接访问同一个对象中的属性。通常情况下,只要记住让变量和访问这个变量的方法放在一起,将一个类中的成员变量全部定义成私有的,只有这个类自己的方法才可以访问到这些成员变量,这就基本上实现对象的封装,就很容易找出要分配到这个类上的方法了, 就基本上算是会面向对象的编程了。把握一个原则:把对同一事物进行操作的方法和相关的方法放在同一个类中, 把方法和它操作的数据放在同一个类中。

例如,人要在黑板上画圆,这一共涉及三个对象:人、黑板、圆,画圆的方法要分配给哪个对象呢?由于画圆 需要使用到圆心和半径,圆心和半径显然是圆的属性,如果将它们在类中定义成了私有的成员变量,那么,画圆 的方法必须分配给圆,它才能访问到圆心和半径这两个属性,人以后只是调用圆的画圆方法、表示给圆发给消息 而已,画圆这个方法不应该分配在人这个对象上,这就是面向对象的封装性,即将对象封装成一个高度自治和相 对封闭的个体,对象状态(属性)由这个对象自己的行为(方法)来读取和改变。一个更便于理解的例子就是, 司机将火车刹住了,刹车的动作是分配给司机,还是分配给火车,显然,应该分配给火车,因为司机自身是不可 能有那么大的力气将一个火车给停下来的,只有火车自己才能完成这一动作,火车需要调用内部的离合器和刹车 片等多个器件协作才能完成刹车这个动作,司机刹车的过程只是给火车发了一个消息,通知火车要执行刹车动作 而已。

2 抽象:
抽象就是找出一些事物的相似和共性之处,然后将这些事物归为一个类,这个类只考虑这些事物的相似和共性之处,并且会忽略与当前主题和目标无关的那些方面,将注意力集中在与当前目标有关的方面。例如,看到一只蚂蚁和大象,你能够想象出它们的相同之处,那就是抽象。抽象包括行为抽象和状态抽象两个方面。例如,定义 一个 Person 类,如下:

class Person{
String name;
int age;
}

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

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

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

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

UserDao userDao = daofactory.getDao();
userDao.insertUser(user);



原文转载:https://zhuanlan.zhihu.com/p/346821651

posted @ 2022-05-10 23:06  独苏  阅读(27)  评论(0编辑  收藏  举报