点击上方“罗晓胜”,马上关注,您的支持对我帮助很大
上期文章
/ 前言 /
从本章开始,文章内容会逐渐深入,如果看的吃力请多回顾之前的“从0到1学java”系列文章,多动手实操,敲敲代码,最后运行起来看看程序到底是如何跑起来的。看文章千遍,也不如自己动手敲一遍。
/ 正文 /
老规矩,先来聊聊Java面向对象
谈到面对对象,必然要提到三大特性:
-
继承:继承是从已有类得到继承信息创建新类的过程。提供继承信息的类被称为父类(超类、基类);得到继承信息的类被称为子类(派生类)。继承让变化中的软件系统有了一定的延续性,同时继承也是封装程序中可变因素的重要手段。
-
封装:通常认为封装是把数据和操作数据的方法绑定起来,对数据的访问只能通过已定义的接口。面向对象的本质就是将现实世界描绘成一系列完全自治、封闭的对象。我们在类中编写的方法就是对实现细节的一种封装;我们编写一个类就是对数据和数据操作的封装。可以说,封装就是隐藏一切可隐藏的东西,只向外界提供最简单的编程接口(可以想想普通洗衣机和全自动洗衣机的差别,明显全自动洗衣机封装更好因此操作起来更简单;我们现在使用的智能手机也是封装得足够好的,因为几个按键就搞定了所有的事情)。
-
多态:多态性是指允许不同子类型的对象对同一消息作出不同的响应。简单的说就是用同样的对象引用调用同样的方法但是做了不同的事情。多态性分为编译时的多态性和运行时的多态性。如果将对象的方法视为对象向外界提供的服务,那么运行时的多态性可以解释为:当A系统访问B系统提供的服务时,B系统有多种提供服务的方式,但一切对A系统来说都是透明的(就像电动剃须刀是A系统,它的供电系统是B系统,B系统可以使用电池供电或者用交流电,甚至还有可能是太阳能,A系统只会通过B类对象调用供电的方法,但并不知道供电系统的底层实现是什么,究竟通过何种方式获得了动力)。方法重载(overload)实现的是编译时的多态性(也称为前绑定),而方法重写(override)实现的是运行时的多态性(也称为后绑定)。运行时的多态是面向对象最精髓的东西,要实现多态需要做两件事:1. 方法重写(子类继承父类并重写父类中已有的或抽象的方法);2. 对象造型(用父类型引用引用子类型对象,这样同样的引用调用同样的方法就会根据子类对象的不同而表现出不同的行为)。
那么有没有想过java多态的到底是怎样实现的呢
-
当JVM执行Java字节码时,类型信息会存储在方法区中,为了优化对象的调用方法的速度,方法区的类型信息会增加一个指针,该指针指向一个记录该类方法的方法表,方法表中的每一个项都是对应方法的指针。
-
方法区:方法区和JAVA堆一样,是各个线程共享的内存区域,用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
-
运行时常量池:它是方法区的一部分,Class文件中除了有类的版本、方法、字段等描述信息外,还有一项信息是常量池,用于存放编译器生成的各种符号引用,这部分信息在类加载时进入方法区的运行时常量池中。
-
方法区的内存回收目标是针对常量池的回收及对类型的卸载。
-
方法表的构造
-
由于java的单继承机制,一个类只能继承一个父类,而所有的类又都继承Object类,方法表中最先存放的是Object的方法,接下来是父类的方法,最后是该类本身的方法。如果子类改写了父类的方法,那么子类和父类的那些同名的方法共享一个方法表项。
-
由于这样的特性,使得方法表的偏移量总是固定的,例如,对于任何类来说,其方法表的equals方法的偏移量总是一个定值,所有继承父类的子类的方法表中,其父类所定义的方法的偏移量也总是一个定值。
-
-
实例
-
假设Class A是Class B的子类,并且A改写了B的方法的method(),那么B来说,method方法的指针指向B的method方法入口;对于A来说,A的方法表的method项指向自身的method而非父类的。
-
流程:调用方法时,虚拟机通过对象引用得到方法区中类型信息的方法表的指针入口,查询类的方法表 ,根据实例方法的符号引用解析出该方法在方法表的偏移量,子类对象声明为父类类型时,形式上调用的是父类的方法,此时虚拟机会从实际的方法表中找到方法地址,从而定位到实际类的方法。
-
注:所有引用为父类,但方法区的类型信息中存放的是子类的信息,所以调用的是子类的方法表。
-
反射机制
什么是java语言的反射机制
-
JAVA反射机制是在运行状态中, 动态获取的信息以及动态调用对象的方法
-
对于任意一个类, 都能够知道这个类的所有属性和方法;
-
对于任意一个对象, 都能够调用它的任意一个方法和属性;
-
-
主要作用有三:
-
运行时取得类的方法和字段的相关信息。
-
创建某个类的新实例(.newInstance())
-
取得字段引用直接获取和设置对象字段,无论访问修饰符是什么。
-
-
用处如下:
-
观察或操作应用程序的运行时行为。
-
调试或测试程序,因为可以直接访问方法、构造函数和成员字段。
-
通过名字调用不知道的方法并使用该信息来创建对象和调用方法。
-
泛型的优缺点
-
优点:
-
使用泛型类型可以最大限度地重用代码、保护类型的安全以及提高性能。泛型最常见的用途是创建集合类。
-
-
缺点:
-
在性能上不如数组快。
-
-
泛型常用特点,List
<String>能否转为List<Object>**-
能,但是利用类都继承自Object,所以使用是每次调用里面的函数都要通过强制转换还原回原来的类,这样既不安全,运行速度也慢。
-
集合
Collection包结构,与Collections的区别
-
Collection是一个接口,它是Set、List等容器的父接口;
-
Collections是一个工具类,提供了一系列的静态方法来辅助容器操作,这些方法包括对容器的搜索、排序、线程安全化等等。
ArrayList、LinkedList、Vector的底层实现和区别
-
从同步性来看,ArrayList和LinkedList是不同步的,而Vector是的。所以线程安全的话,可以使用ArrayList或LinkedList,可以节省为同步而耗费的开销。但在多线程下,有时候就不得不使用Vector了。当然,也可以通过一些办法包装ArrayList、LinkedList,使我们也达到同步,但效率可能会有所降低。
-
从内部实现机制来讲ArrayList和Vector都是使用Object的数组形式来存储的。当你向这两种类型中增加元素的时候,如果元素的数目超出了内部数组目前的长度它们都需要扩展内部数组的长度,Vector缺省情况下自动增长原来一倍的数组长度,ArrayList是原来的50%,所以最后你获得的这个集合所占的空间总是比你实际需要的要大。如果你要在集合中保存大量的数据,那么使用Vector有一些优势,因为你可以通过设置集合的初始化大小来避免不必要的资源开销。
-
ArrayList和Vector中,从指定的位置(用index)检索一个对象,或在集合的末尾插入、删除一个对象的时间是一样的,可表示为O(1)。但是,如果在集合的其他位置增加或者删除元素那么花费的时间会呈线性增长O(n-i),其中n代表集合中元素的个数,i代表元素增加或移除元素的索引位置,因为在进行上述操作的时候集合中第i和第i个元素之后的所有元素都要执行(n-i)个对象的位移操作。LinkedList底层是由双向循环链表实现的,LinkedList在插入、删除集合中任何位置的元素所花费的时间都是一样的O(1),但它在索引一个元素的时候比较慢,为O(i),其中i是索引的位置,如果只是查找特定位置的元素或只在集合的末端增加、移除元素,那么使用Vector或ArrayList都可以。如果是对其它指定位置的插入、删除操作,最好选择LinkedList。
Map、HashMap、HashTable、LinkedHashMap、TreeMap的底层实现区别
-
Map主要用于存储健值对,根据键得到值,因此不允许键重复(重复了覆盖了),但允许值重复。
-
Hashmap 是一个最常用的Map,它根据键的HashCode 值存储数据,根据键可以直接获取它的值,具有很快的访问速度,遍历时,取得数据的顺序是完全随机的。HashMap最多只允许一条记录的键为Null;允许多条记录的值为 Null;HashMap不支持线程的同步,即任一时刻可以有多个线程同时写HashMap;可能会导致数据的不一致。如果需要同步,可以用 Collections的synchronizedMap方法使HashMap具有同步的能力,或者使用ConcurrentHashMap。
-
Hashtable与 HashMap类似,它继承自Dictionary类,不同的是:它不允许记录的键或者值为空;它支持线程的同步,即任一时刻只有一个线程能写Hashtable,因此也导致了 Hashtable在写入时会比较慢。
-
LinkedHashMap保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的.也可以在构造时用带参数,按照应用次数排序。在遍历的时候会比HashMap慢,不过有种情况例外,当HashMap容量很大,实际数据较少时,遍历起来可能会比LinkedHashMap慢,因为LinkedHashMap的遍历速度只和实际数据有关,和容量无关,而HashMap的遍历速度和他的容量有关。
-
TreeMap实现SortMap接口,能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的
Map、Set、List、Queue、Stack的特点与用法
-
Collection 是对象集合,
-
Collection 有两个子接口 List 和 Set
-
List 可以通过下标 (1,2..) 来取得值,值可以重复,而 Set 只能通过游标来取值,并且值是不能重复的
-
-
ArrayList , Vector , LinkedList 是 List 的实现类
-
ArrayList 是线程不安全的, Vector 是线程安全的,这两个类底层都是由数组实现的
-
LinkedList 是线程不安全的,底层是由链表实现的
-
-
Map 是键值对集合
-
HashTable 和 HashMap 是 Map 的实现类
-
HashTable 是线程安全的,不能存储 null 值
-
HashMap 不是线程安全的,可以存储 null 值
-
Stack类:继承自Vector,实现一个后进先出的栈。提供了几个基本方法,push、pop、peak、empty、search等。
-
Queue接口:提供了几个基本方法,offer、poll、peek等。已知实现类有LinkedList、PriorityQueue等。
-
/ 总结 /
本文主要讲了对java开发中面对对象的特性,反射,泛型以及集合的思考和运用,这些是常用的技术中都会使用到的知识。
往期推荐:
关注我的公众号,学习技术或投稿