面向对象和面向过程的区别
两者的主要区别在于解决问题的方式不同
面向过程把解决问题的过程拆成一个个方法,通过一个个方法的执行解决问题。
面向对象会先抽象出对象,然后用对象执行方法的方式解决问题。
另外,面向对象开发的程序一般更易维护、易复用 易扩展。
创建一个对象用什么运算符?对象实体与对象引用有何不同?
new运算符,new创建对象实例(对象实例在堆内存中),对象引用指向对象实例(对象引用存放在栈内存中)
一个对象引用可以指向0个或1个对象(一根绳子可以不系气球,也可以系一个气球)一个对象可以有n个引用指向它(可以用n条绳子系住一个气球)。
对象的相等和引用相等的区别
对象的相等一般比较的是内存中存放的内容是否相等
引用相等一般比较的是他们指向的内存地址是否相等
类的构造方法的作用是什么
沟造方法是一种特殊的方法,主要作用是完成对象的初始化工作。
如果一个类没有声明构造方法, 该程序能正确执行吗?
如果一个类没有声明构造方法,也可以执行! 因为一个类即使没有声明构造方法也会有默认的不带参数的构造方法。如果我们自己添加了类的构造方法(无论是否有参),ava就不会再添加默认的
无参数的构造方法了,我们一直在不知不觉地使用构造方法,这也是为什么我们在创建对象的时候
后面要加一个括号(因为要调用无参的构造方法)。如果我们重载了有参的构造方法,记得都要把无参的构造方法也写出来(无论是否用到),因为这可以帮助我们在创建对象的时候少踩。
沟造方法有哪些特点? 是否可被override
构造方法特点如下:
名字与类名相同
没有返回值,但不能用void声明构造函数
生成类的对象时自动执行,无需调用
构造方法不能被override (重写),但是可以overload (重载)所以你可以看到一个类中有多个构造函数的情况
面向对象的三大特征
封装
封装是指把一个对象的状态信息(也就是属性)隐藏在对象内部,不允许外部对象直接访问对象的为部信息。但是可以提供一些可以被外界访问的方法来操作属性。
继承
不同类型的对象,相互之间经常有一定数量的共同点。
接口和抽象类有什么共同点和区别
共同点:
都不能被实例化
都可以包含抽象方法
都可以有默认实现的方法(java8可以用 default 关键字在接口中定义默认方法)
区别:
接口主要用于对类的行为进行约束,你实现了某个接口就具有了对应的行为。抽象类主要用于
代码复用,强调的是所属关系
一个类只能继承一个类, 但是可以实现多个接口
接口中的成员变量只能是 public static final 类型的,不能被修改且必须有初始值,而抽
象类的成员变量默认default, 可在子类中被重新定义,也可被重新赋值。
深接贝和浅贝区别了解吗?什么是引用贝?
关于深贝和浅贝区别,我这里先给结论
浅拷贝:浅贝会在堆上创建一个新的对象(区别于引用拷贝的一点),不过,如果原对象内
部的属性是引用类型的话,浅贝会直接复制内部对象的引用地址,也就是说贝对象和原对象共用同一个内部对象
深拷贝:深拷贝会完全复制整个对象,包括这个对象所包含的内部对象。
Object类的常见方法有哪些?
Object类是一个特殊的类,是所有类的父类。它主要提供了以下11个方法
== 和equals的区别
对于基本类型和引用类型的作用效果是不同的:
对于基本数据类型来说, 比较的是值。
对于引用数据类型来说, 比较的是对象的内存地址,
因为java只有值传递,所以,对于==来说,不管是比较基本数据类型,还是引用数据类型的变量,其本质比较的都是值,只是引用类型变量存的值是对象的地址
equals) 不能用于判断基本数据类型的变量,只能用来判断两个对象是否相等。 equals()方法存在于bject类中,而object类是所有类的直接或间接父类,因此所有的类都有equalsC)方法。
Object类 equalsC) 方法:
equals) 方法存在两种使用情况:
类没有重写 equas()方法:通过equals()比较该类的两个对象时,等价于通过 == 比较
这两个对象,使用的默认是 object类equals()方法
类重写了 equals()方法: 般我们都重写 equas()方法来比较两个对象中的属性是否柜等;若它们的属性相等,则返回true(即,认为这两个对象相等)
举个例子 (这里只是为了举例。 实际上, 你按照下面这种写法的话,像IDEA这种比较智能的IDEA 都会提示你将 == 换成 equals()。
String 中的 equals 方法是被重写过的,因为 Object 的 equals 方法是比较的对象的内存
地址,而 String 的 equals 方法比较的是对象的值
当创建 String 类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同
的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个 String 对象。
String类equals()方法:
hashCodeO有什么用?
hashcodeC 的作用是获取哈希码(int整数),也称为散列码。这个哈希码的作用是确定该对象在哈希表中的索引位置
hashcode()定义在DK的 Object 类中,这就意味着java中的任何类都包含有
hashcode() 函数。另外需要注意的是:Object的hashcode()方法是本地方法,也就是用C语言或c++实现的,该方法通常用来将对象的内存地址转换为整数之后返回。
散列表存储的是键值对(key-value),它的特点是:能根据键“快速的检索出对应的值”。这其中就利用到了散列码! (可以快速找到所需要的对象)
为什么要有hashCode?
我们以HashSet 如何检查重复为例子来说明为什么要有 hashcode
下面这段内容摘自我的Java启蒙书 《HeadFirst java》:
当你把对象加入 HashSet 时, HashSet 会先计算对象的 hashcode 值来判断对象加入的位置,同时也会与其他已经加入的对象的 hashcode值作比较,如果没有相符的 hashcode
HashSet 会假设对象没有重复出现。但是如果发现有相同hashcode 值的对象,这时会调用equals) 方法来检查 hashcode 相等的对象是否真的相同。如果两者相同,HashSet就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。这样我们就大大减少了
equals 的次数,相应就大大提高了执行速度。
其实, hashcodeC) 和 equals)都是用于比较两个对象是否相等
那为什么JDK还要同时提供这两个方法呢?
这是因为在一些容器(比如 HashMap、 HashSet)中,有了 hashcodeC)之后,判断元素是否在对应容器中的效率会更高 (参考添加元素进HashSet的过程)
我们在前面也提到了添加元素进Hashset的过程,如果HashSet在对比的时候,同样的
hashcode 有多个对象,它会继续使用 equals) 来判断是否真的相同。也就是说 hashcode
帮助我们大大缩小了查找成本。
那为什么不只提供 hashcodeO 方法呢?
这是因为两个对象的hashcode 值相等并不代表两个对象就相等
那为什么两个对象有相同的 hashcode 值,它们也不一定是相等的?
因为 hashcodeC 所使用的哈希算法也许刚好会让多个对象传回相同的哈希值。越糟糕的哈希算法越容易碰撞,但这也与数据值域分布的特性有关 (所请哈希碰撞也就是指的是不同的对象得到柜同的 hashcode)
总结下来就是:
如果两个对象的hashcode 值相等,那这两个对象不一定相等(哈希碰撞)。
如果两个对象的hashcode 相等并且equals()方法也返回 true,我们才认为这两个对象
相等。
如果两个对象的hashcode 值不相等,我们就可以直接认为这两个对象不相等
相信大家看了我前面对 hashcodeO) 和equalsO 的介绍之后, 下面这个问题已经难不倒你们
了。
为什么重写equals() 时必须重写hashCode() 方法?
因为两个相等的对象的 hashcode 值必须是相等。也就是说如果 equals 方法判断两个对象是相等的,那这两个对象的 hashcode 值也要相等,
如果重写 equals) 时没有重写 hashcode() 方法的话就可能会导致 equals 方法判断是相等的两个对象, hashcode 值却不相等
思考:重写 equals) 时没有重写 hashcode) 方法的话,使用 HashMap 可能会出现什么问
题。
总结:
equals 方法判断两个对象是相等的,那这两个对象的 hashcode 值也要相等
两个对象有相同的 hashcode 值,他们也不一定是相等的(哈希碰撞)
String
String、 StringBuffer、StringBuilder的区别?
可变性
String 是不可变的
StringBuilder 与 StringBuffer 都继承自 AbstractStringBuilder 类,在
AbstractStringBuilder 中也是使用字符数组保存字符串,不过没有使用final和
private 关键字修饰,最关键的是这个 AbstractstringBuilder 类还提供了很多修改字符串的方法比如 append 方法。
线程安全性
String 中的对象是不可变的,也就可以理解为常量,线程安全。AbstractstringBuilder是StringBuilder 与 StringBuffer 的公共父类,定义了一些字符串的基本操作,如
expandcapacity、 append、insert、indexOf 等公共方法。 StringBuffer对方法加了司步锁或者对调用的方法加了同步锁,所以是线程安全的。 StringBuilder并没有对方法进行加同步锁,所以是非线程安全的。
性能
每次对String 类型进行改变的时候,都会生成一个新的 String对象,然后将指针指向新的String对象。 StringBuffer 每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用。相同情况下使用StringBuilder 相比使用 StringBuffer仅能获得10%~15%左右的性能提升,但却要冒多线程不安全的风险。
对于三者使用的总结:
1操作少量的数据:适用String
2单线程操作字符串缓冲区下操作大量数据:适用 StringBuilder
3多线程操作字符串缓冲区下操作大量数据:适用 StringBuffer