
面向对象更注重事情的每一个步骤以及顺序,更注重有哪些参与者(对象),及各自需要做什么;面向过程是分析出解决问题所需要的步骤,然后按这些步骤一步步的实现下去,使用的时候一个一个调用就可以了;区别从概念就很明显了,前者注重的是参与的对象,后者注重的是步骤;面向对象的特点就是易维护,耦合度相对于面向过程低,系统更加灵活,并且具有一些特性;面向过程特点就是性能比面向对象高,类调用时需要实例化,所以比较消耗资源。面向对象的特性有继承,封装,多态,(抽象)。继承就是从已有类得到继承信息创建新类的过程,提供继承信息的类被称为父类(超类、基类),得到继承信息的类被称为子类(派生类),继承让变化中的软件系统有了一定的延续性,同时继承也是封装程序中可变因素的重要手段。封装通常认为封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口;面向对象的本质就是将现实世界描绘成一系列完全自治、封闭的对象。我们在类中编写的方法就是对实现细节的一种封装;我们编写一个类就是对数据和数据操作的封装。可以说,封装就是隐藏一切可隐藏的东西,只向外界提供最简单的编程接口。多态性是指允许不同子类型的对象对同一消息作出不同的响应;简单的说就是用同样的对象引用调用同样的方法但是做了不同的事情。多态性分为编译时的多态性和运行时的多态性。如果将对象的方法视为对象向外界提供的服务,那么运行时的多态性可以解释为:当 A 系统访问 B 系统提供的服务时, B 系统有多种提供服务的方式,但一切对 A 系统来说都是透明的。方法重载(overload)实现的是编译时的多态性(也称为前绑定),而方法重写(override)实现的是运行时的多态性(也称为后绑定)。运行时的多态是面向对象最精髓的东西,要实现多态需要做两件事: 1. 方法重写(子类继承父类并重写父类中已有的或抽象的方法); 2. 对象造型(用父类型引用引用子类型对象,这样同样的引用调用同样的方法就会根据子类对象的不同而表现出不同的行为)。抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。抽象只关注对象有哪些属性和行为。
JDK JRE JVM的区别和联系JDK:Java Development Kit java开发工具
JRE:Java Runtime Environment java运行时环境
JVM:Java Virtual Machine java虚拟机
具体看下图
通过上图可以看出来 JDK包含JRE JRE包含JVM
final:用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,被其修饰的类不可继承。
finally:异常处理语句结构的一部分,表示总是执行。
finalize:Object 类的一个方法,在垃圾回收器执行的时候会调用被回收对象的此方法,可以覆盖此方法
提供垃圾收集时的其他资源回收,例如关闭文件等。该方法更像是一个对象生命周期的临终方法,当该方法
被系统调用则代表该对象即将“死亡”,但是需要注意的是,我们主动行为上去调用该方法并不会导致该对
象“死亡”,这是一个被动的方法(其实就是回调方法),不需要我们调用
throw:(1)throw 语句用在方法体内,表示抛出异常,由方法体内的语句处理。
(2)throw 是具体向外抛出异常的动作,所以它抛出的是一个异常实例,执行 throw 一定是抛出了某种异常
throws:(1) throws 语句是用在方法声明后面,表示如果抛出异常,由该方法的调用者来进行异常的处理。
(2) throws 主要是声明这个方法会抛出某种类型的异常,让它的使用者要知道需要捕获的异常的类型。
(3) throws 表示出现异常的一种可能性,并不一定会发生这种异常。
String是被final修饰的,不可变,每次操作都会产生新的String对象
StringBuffer和StringBuilder都是在原对象上操作
StringBuffer是线程安全的,之所以线程安全是因为它的方法都是synchronized修饰的,StringBuilder是线程不安全的;性能:StringBuilder>StringBuffer>String
场景:经常需要改变字符串内容的话就用前两个(优先选择StringBuilder,多线程共享变量使用StringBuffer)
重载:发生在同一类中,方法名必须相同,参数类型不同,个数不同,顺序不同,方法返回值和访问修饰符可以不同,发生在编译时。
重写:发生在父子类中;方法名,参数列表必须相同,返回值范围小于等于父类,抛出的异常范围≤父类,访问修饰符范围≥父类;如果父类方法访问修饰符为private则子类就不能重写该方法。
相同:(1)不能实例化
(2)可以将抽象类和接口类型作为引用类型
(3).一个类如果继承了某个抽象类或者实现了某个接口都需要对其中的抽象方法全部进行实现,否则该类仍然需要被声明为抽象类
不同:
抽象类:
(1)抽象类中可以定义构造器
(2)可以有抽象方法和具体方法
(3)接口中的成员全都是 public 的
(4)抽象类中可以定义成员变量
(5)有抽象方法的类必须被声明为抽象类,而抽象类未必要有抽象方法
(6)抽象类中可以包含静态方法
(7)一个类只能继承一个抽象类
接口:
(1)接口中不能定义构造器
(2)方法全部都是抽象方法
(3)抽象类中的成员可以是private,default,protected,public
(4)接口中定义的成员变量实际上都是常量
(5)接口中不能有静态方法
(6)一个类可以实现多个接口
接口的设计目的:是对类的行为进行约束(更准确的说是一种“有”约束,因为接口不能规定类不可以有什么行为),也就是提供一种机制,可以强制要求不同的类具有相同的行为(共有的特征)。它只约束了行为的有无,但不对如何实现行为进行限制。
而抽象类的设计目的是代码复用,当不同的类具有某些相同的行为(记为行为集合A),且其中一部分行为的实现方式一致时(A的非真子集记为B),可以让这些类都派生于一个抽象类。在这个 抽象类中实现了B,避免让所有的的子类来实现B,这就达到了代码复用的目的。而A减B的部分,留给各个子类自己实现,正是因为A-B在这里没有实现,所以抽象类不允许实例化出来,否则当调用A-B的时候,无法执行。
抽象类是对类本质的抽象,表达的是is a的关系,比如 Porsche is Car。抽象类包含并实现子类的通用特性,将子类存在差异化的特性进行抽象,交由子类去实现。
而接口是对行为的抽象,表达的是like a的关系,比如 Birds like a Aircraft(像飞行器一样可以飞),但其本质上 is a bird ,接口的核心是定义行为,即实现类可以做什么,至于实现类主体是谁,是如何实现的,接口并不关心。
使用场景:当你关注一个事物的本质的时候,用抽象类;当你关注一个操作的时候,用接口。
抽象类的功能远远超过接口,但是定义抽象类的代价高,因为高级语言来说(从实际设计上来说也是)每个类只能继承一个类。在这个类中,你必须继承或编写出其所有子类的所有共性。虽然接口在功能上弱化了很多,但是它只是针对一个动作的描述,而且你可以在一个类中同事实现多个接口,在设计阶段会降低难度
结构特点:
List 和 Set 是存储单列数据的集合, Map 是存储键和值这样的双列数据的集合; List 中存储的数据是有顺序,并且允许重复; Map 中存储的数据是没有顺序的,其键是不能重复的,它的值是可以有重复的, Set 中存储的数据是无序的,且不允许有重复,但元素在集合中的位置由元素的 hashcode 定,位置是固定的(Set 集合根据 hashcode 来进行数据的存储,所以位置是固定的,但是位置不是用户可以控制的,所以对于用户来说 set 中的元素还是无序的) ;
实现类:
List 接口有三个实现类(LinkedList:基于链表实现,链表内存是散乱的,每一个元素存储本身内存地址的同时还存储下一个元素的地址。链表增删快,查找慢; ArrayList:基于数组实现,非线程安全的,效率高,便于索引,但不便于插入删除; Vector:基于数组实现,线程安全的,效率低)。Map 接口有三个实现类(HashMap:基于 hash 表的 Map 接口实现,非线程安全,高效,支持 null 值和 null键; HashTable:线程安全,低效,不支持 null 值和 null 键; LinkedHashMap:是 HashMap 的一个子类,保存了
记录的插入顺序; SortMap 接口: TreeMap,能够把它保存的记录根据键排序,默认是键值的升序排序)。Set 接口有两个实现类(HashSet:底层是由 HashMap 实现,不允许集合中有重复的值,使用该方式时需要重写 equals()和 hashCode()方法; LinkedHashSet:继承与 HashSet,同时又基于 LinkedHashMap 来进行实现,底层使用的是 LinkedHashMp)。
区别:
List 集合中对象按照索引位置排序,可以有重复对象,允许按照对象在集合中的索引位置检索对象,例如通过list.get(i)方法来获取集合中的元素; Map 中的每一个元素包含一个键和一个值,成对出现,键对象不可以重复,值对
象可以重复; Set 集合中的对象不按照特定的方式排序,并且没有重复对象,但它的实现类能对集合中的对象按照特定的方式排序,例如 TreeSet 类,可以按照默认顺序,也可以通过实现 Java.util.Comparator接口来自定义排序方式。
equals 和== 最大的区别是一个是方法一个是运算符。
==:如果比较的对象是基本数据类型,则比较的是数值是否相等;如果比较的是引用数据类型,则比较的是对象的地址值是否相等。
equals():用来比较方法两个对象的内容是否相等。
注意: equals 方法不能用于基本数据类型的变量,如果没有对 equals 方法进行重写,则比较的是引用类型的变量所指向的对象的地址。
hashCode是一种编码方式,hash一般翻译成散列,也有直接音译为"哈希"的,就是把任意长度的输入(又叫做预映射, pre-maping),通过散列算法,变换成固定长度的输出,该输出就是散列值。这种转换是一种压缩映射,也就是,散列值的空间通常远小于输入的空间,不同的输入可能会散列成相同的输出,而不可能从散列值来唯一的确定输入值。在java的定义中,对象相等则hashCode一定相等,hashCode相等的对象未必相等。
为什么要有hashCode?
以hashSet如何检查重复为例子来说明为什么要有hashCode
对象加入HashSet时,HashSet会先计算对象的hashCode值来判断对象加入的位置,看该位置是否有值,如果没有,HashSet会假设对象没有重复出现。但是如果发现有值,这时会调用equals()方法来检查两个对象是否真的相同。如果两者相同,HashSet就不会让其加入操作成功,如果不同的话,就会重新散列到其他位置,这样就打打减少了equals的次数,相应就大大提高了执行速度。
ArrayList和LinkedList都实现了List接口,他们有以下的不同点:
ArrayList是基于索引的数据接口,它的底层是数组。它可以以O(1)时间复杂度对元素进行随机访问。与此对应LinkedList是以元素列表的形式存储它的数据,每一个元素都和它的前一个和后一个元素链表在一起,在这种情况下,查找某个元素的时间复杂度是O(n)。
相对于ArrayList,LinkedList的插入,添加,删除操作速度更快,因为当元素呗添加到天河任意位置的时候,不需要像数组那样重新计算大小或者是更新索引。
LinkedList比ArrayList更占内存没因为LinkedList为每一个节点存储了两个引用,一个指向前一个元素,一个指向下一个元素 。
(1)因为Array是基于索引(index)的数据结构,它使用索引在数组中搜索和读取数据是很快的。Array获取数据的时间复杂度是O(1),但是要删除数据却是开销很大的,因为这需要重排数组中的所有数据。
(2)相对于ArrayList,LinkedList插入是更快的,因为LinkedList不像ArrayList一样,不需要改变数组的大小,也不需要在数组装满的时候要将所有的数据重新装入一个新的数组,这是ArrayList最坏的一种情况,时间复杂度是O(n),而LinkedList中插入或删除的时间复杂度仅为O(1)。ArrayList在插入数据时还需要更新索引(除了插入数组的尾部)
(3)类似于插入数据,删除数据时,LinkedList也优于ArrayList
(4)LinkedList需要更多的内存,因为ArrayList的每个索引的位置是实际的数据,而LinkedList中的每个节点中存储的事实际的数据和前后节点的位置(一个LinkedList实例存储了两个值:Node first和Node last 分别表示链表的其实节点和尾节点,每个Node实例存储了三个值:E item,Node next,Node pre)。
什么场景下更适合使用LinkedList,而不用ArrayList
(1)你的应用不会随机访问数据,因为如果你需要LinkedList中的第n个元素的时候,你需要从第一个元素顺序数到第n个数据,然后读取数据
(2)你的应用更多而插入和删除元素,更少的读取数据,因为插入和删除元素不涉及重排数据,所以它要比ArrayList更快
1.hashMap 去掉了 HashTable 的 contains 方法,但是加上了 containsValue()和 containsKey()方法。
2.hashTable 同步的,而 HashMap 是非同步的,效率上逼 hashTable 要高。
3.hashMap 允许空键值,而 hashTable 不允许。
一般用 hashmap 代替 hashtable
注意:
TreeMap:非线程安全基于红黑树实现。TreeMap 没有调优选项,因为该树总处于平衡状态。
Treemap:适用于按自然顺序或自定义顺序遍历键(key)。