Java面试面向对象篇(三)

面向对象与面向过程的区别?

什么是面向过程?

例如要实现五子棋游戏,面向过程的实现方式是,游戏开始,绘制棋盘,白棋执行,绘制棋盘,黑棋执行,绘制棋盘,判断胜负,返回第二步,游戏结束。面向过程是具体化的流程化的,解决一个问题要一步一步分析,一步一步实现。面向对象的实现方式是,棋盘对象,负责实时更新棋盘,棋子对象,白棋和黑棋行为是相同的,规则对象,负责判断游戏流程与胜负。面向对象是抽象化的,模型化的,你只需抽象出一个类,这是一个封闭的盒子,在这里你拥有数据,也拥有解决问题的方法。需要什么功能直接使用就行,不必去一步一步实现,至于这个功能是如何实现的,我们也不用太关心。面向对象的底层其实还是面向过程,把面向过程抽象成类,然后封装,方便我们使用的就是面向对象了。

面向过程:

优点:没有类的调用与实例化,性能快。

缺点:没有面向对象的易维护、易复用、易扩展。

面向对象:

优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态的特性,可以设计出低耦合的程序,使程序更加灵活,更容易维护。

面向对象的三大特性

面向对象的特征主要有一下几个方面:

抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两个方面,抽象只关注对象有哪些属性和行为,不关注这些行为的细节。

其中Java面向对象编程的三大特性:封装、继承、多态。

封装:封装是指将一个对象的属性私有化,隐藏内部实现细节,提供外部访问方法,有效的提高了安全性和复用性,便于使用。

继承:继承是指在已经存在的类的基础上,创建新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性的继承父类,通过继承可以提高代码复用性,继承是多态的前提。

关于继承,以下3点需记住:

1、子类拥有父类所有属性和方法(private修饰的和构造方法除外);

2、子类可以有自己的属性和方法,即对父类进行扩展;

3、子类可以用自己的方式实现父类的方法,即重写。

多态:要实现多态必须要做两件事,子类继承父类并重写父类的方法,用父类引用子类对象,这样同样的引用调用同样的方法,会根据子类对象的不同而表现出不同的行为。

多态的作用:在同一个继承结构中使用统一的逻辑实现代码,处理不同的对象,从而达到实现不同的行为。

抽象类和接口的对比

抽象类是用来捕捉对象的通用特性的,实现代码重用,从语义上讲,抽象类是一种严格的is-a关系,比如,学生是人,老师也是人,因此可以将学生和老师继承people类;而接口更倾向于实现类具有一些公共的特性或方法,比如人会拍球,海豚也会排球,接口可以理解为一系列公共方法的集合。

相同点:

接口和抽象类都不能实例化;

都位于继承的顶端,用于被其他类继承或实现;

都包含抽象方法,子类都必须重写这些抽象方法。

不同点:

抽象类:使用abstract声明;子类使用extends继承抽象类;如果一个类继承了抽象类,那么该子类必须实现抽象类的所有抽象方法;抽象类可以有构造器;抽象类中的方法可以是任意访问修饰符;抽象类的字段声明可以是任意的;一个类最多只能继承一个抽象类。

接口:使用interface关键字声明;子类使用implements实现接口;如果一个类实现了接口,那么该类必须实现接口中的所有方法;接口不能有构造器;接口中的方法默认修饰符是public,并且不允许定义为private和protected;接口的字段默认都是static和final的;一个类可以实现多个接口。

备注:Java8接口中引入默认方法和静态方法,以此来减小抽象类和接口的差异。现在我们可以为接口提供默认实现的方法了,并且不用强制子类来实现它。

接口和抽象类各有优缺点,在抽象类和接口的选择中,应当遵循以下原则:

1、抽象类用来定义某个领域的固有属性,即抽象类表示它是什么,接口用来定义某个领域的扩展功能,即接口表示他能做什么。

2、当我们需要为子类提供公共的实现代码时,应当优先考虑抽象类,因为抽象类中的非抽象方法可以让子类继承,从而实现代码复用,使代码更加整洁。

3、当注重代码的扩展性和可维护性时,应当优先采用接口。接口与实现类之间可以不存在任何层次关系,接口可以实现毫不相关类的行为,比抽象类更加灵活。接口只关心对象之间的交互方法,而不关心对象所对应的具体类,接口是程序当中的一个协议,比抽象类更安全、清晰。一般使用接口的情况更多。

成员变量与局部变量的区别?

变量:在程序的运行过程中,其值可以在一定范围内改变的量,从本质上讲,变量其实是内存中的一小块区域。

各变量联系与区别:

成员变量:作用范围是整个类,定义在方法体和语句块之外,一般声明在类名下方,包含实例变量和静态变量,存储在堆内存中。

实例变量:独立于方法之外的变量,无static修饰,定义在方法体和语句块之外,数值默认值为0,布尔类型默认值为false,引用类型默认值为null。

静态变量(类变量):独立于方法之外的变量,用static修饰,一般定义在static静态语句块中,默认值与实例变量相似,一个类中只有一份,属于对象共有,经常被声明为常量,调用一般用类名.变量名或对象.变量名;

局部变量:类的方法中的变量,不能用访问修饰符修饰,定义在方法、语句块或构造方法中,在栈上分配,无默认值,需要初始化后才可使用。

重载(overload)和重载(override)的区别。重载的方法能否根据返回类型进行区分?

方法的重载和重写都是实现多态的方式,区别在于前者是编译时多态,而后者是运行时多态。

重载:发生在同一类中,方法名相同,参数列表不同(参数个数,参数类型,参数顺序),与方法返回值和访问修饰符无关,即重载的方法不能根据返回值类型区分。

重写:发生在父子类中,方法名参数列表相同,返回值类型、抛出的异常小于等于父类,访问修饰符权限大于等于父类,父类中的private方法和构造方法不能被重写。

==和equals的区别?

==:它的作用是判断两个对象的内存地址是否相等。即判断两个对象是不是同一个对象。(基本数据类型==比较的是值,引用类型==比较的是地址)

equals:它的作用也是用来判断对象是否相等,有两种情况:

1、类没有重写过equals方法,等价于==比较。

2、类重写过equals方法。一般我们都重写equals方法来判断两个对象的内容是否相等,即返回true。

当创建String类型的变量时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相等的对象,如果有就把他赋给当前引用。如果没有就在常量池中重新创建一个String对象。

hashCode与equals

hashCode介绍:hashCode的作用是获取哈希码,也称散列码;它实际上是返回一个int类型的整数。这个哈希码的作用是获取该对象在哈希表上的位置。hashCode定义在JDK的Object类中,这就意味着每个类都有hashCode方法。

散列表存储的是键值对(key-value),它的特点是:能根据键迅速的检索出对应的值,这其中就应用到了散列码。

为什么要有hashCode?

我们以hashSet为例,当你把对象加入到hashSet中时,hashSet会先计算对象的hashCode值来判断对象应该加入的位置,同时也会与其他已经加入的对象的hashCode值进行比较,如果没有相同的hashCode,那么hashSet会认为没有重复的对象出现。但是如果发现有相同的hashCode值的对象,这时会调用equals方法来判断对象的值是否相等。如果二者相同,hashSet就不会让其插入成功,如果不同,就会重新散列到别的位置。

hashCode与equals的相关规定:

如果两个对象的值相同,那么他们的hashCode一定相同。

如果两个对象的hashCode值相同,两个对象不一定相同。

两个对象的值相同,那么分别对这两个对象调用equals都返回true。

因此,当重写equals时一定要重写hashCode,这样才不违背相同对象有相同哈希值的规定。

值传递和引用传递的区别?

值传递,按值调用(call by value):指的是在方法调用时,传递的参数是值的拷贝,传递后就互不相关了。

引用传递,引用调用(call by reference):指的是在方法调用时,传递的参数是引用变量所对应的内存地址。传递前和传递后都指向同一个引用(也就是同一个内存空间)。

一个方法可以修改引用传递所对应的变量值,而不能修改值传递所对应的变量值。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值