一、前言: 本来想看完书再整理下自己的笔记的,可是书才看了一半发现笔记有点多,有点乱,就先整理一份吧,顺便复习下前面的知识,之后的再补上。 真的感觉,看书是个好习惯啊,难怪人家说“书籍是人类进步的阶梯”。之前学知识,喜欢网上找份教程,看点视频,照着做呗,秉着”我做过的东西反正别人肯定玩过“的观念,一通乱学,学的又多又杂,现在细细想来,很多东西我只是学到了它的形,却没有学到它的神,只是在抄别人的代码。为什么这么做?这么写是出于什么考虑?我都一脸懵懂!而现在我喜欢看书,花时间来沉淀自己的知识,与大家共勉!另外,真的不推荐零基础的看这本书,讲的太拗口了。或者说翻译的太拗口了。 二、面向对象 1、对象存储到什么地方?
2、基本成员默认值 如果类的某个成员是基本数据类型,即使没有进行初始化,Java也会确保他获得一个默认值。 boolean false char null byte 0 short 0 int 0 long 0 float 0.0 double 0.0 3、在采取其他任何操作之前,为对象分配的存储空间初始化成二进制零。在一个类里,初始化的顺序是由变量在类内的定义顺序决定的。即使变量定义大量遍布于方法定义的中间,那些变量仍会在调用任何方法之前得到初始化—— 甚至在构建器调用之前。 static 初始化只有在必要的时候才会进行。如果不创建一个 Table 对象,而且永远都不引用 Table.b1 或Table.b2,那么 static Bowl b1 和 b2 永远都不会创建。然而,只有在创建了第一个 Table 对象之后(或者发生了第一次 static 访问),它们才会创建。在那以后, static 对象不会重新初始化。初始化的顺序是首先 static(如果它们尚未由前一次对象创建过程初始化),接着是非static 对象 4、类的设计中为什么要控制对成员的访问? 1、防止用户接触那些他们不应碰的工具。对于数据类型的内部机制,那些工具是必需的。但它们并不属于用户接口的一部分,用户不必用它来解决自己的特定问题。比如private的方法,有些是不希望被用户使用的。 2、允许类设计者改变类的内部工作机制,同时不必担心它会对客户程序员产生什么影响。 3、防止类的成员被用户随意修改,比如用户通过 类名.成员名 就可以改变类的属性值。 5、为什么优先使用组合而非继承? 1、继承破坏封装性。基类的很多内部细节都是对派生类可见的,因此这种复用是“白箱复用”; 2、如果基类的实现发生改变,那么派生类的实现也将随之改变。这样就导致了子类行为的不可预知性; 3、组成不会强迫我们的程序设计进入继承的分级结构中。同时,组成显得更加灵活,因为可以动态选择一种类型(以及行为),而继承要求在编译期间准确地知道一种类型。因此降低了应用的灵活性。 6、一条常规的设计准则是:用继承表达行为间的差异,并用成员变量表达状态的变化。 7、为什么要向上转型? 好处:向上转型主要是为了用变量来接收不同的子类对象,调用方法的时候传参父类对象,可以调用子类中不同的重写方法,实现不同的效果。 坏处:屏蔽了子类中新增的变量和方法。 8、static关键字 强调他们只有一个,而final 关键字强调他们是一个常数。不能由于某样东西的属性是final,就认定他的值在编译的时候已经知道,其实final的值是进行类对象初始化的时候确定的。 9、final 关键字 修饰方法 的好处? 1、为方法“上锁”,防止任何继承类改变它的本来含义。设计程序时,若希望一个方法的行为在继承期间保持不变,而且不可被覆盖或改写,就可以采取这种做法。 2、将一个方法设成 final 后,编译器就可以把对那个方法的所有调用都置入“嵌入”调用里。只要编译器发现一个 final 方法调用,就会(根据它自己的判断)忽略为执行方法调用机制而采取的常规代码插入方法(将自变量压入堆栈;跳至方法代码并执行它;跳回来;清除堆栈自变量;最后对返回值进行处理)。相反,它会用方法主体内实际代码的一个副本来替换方法调用。这样做可避免方法调用时的系统开销。当然,若方法体积太大,那么程序也会变得雍肿,可能受到到不到嵌入代码所带来的任何性能提升。因为任何提升都被花在方法内部的时间抵消了。 Java 编译器能自动侦测这些情况,并颇为“明智”地决定是否嵌入一个 final 方法。然而,最好还是不要完全相信编译器能正确地作出所有判断。通常,只有在方法的代码量非常少,或者想明确禁止方法被覆盖的时候,才应考虑将一个方法设为final。 10、为什么要把方法定义成抽象或者定义接口? 1、它能为不同的子类型或者实现类作出不同的表示。它为我们建立了一种基本形式,使我们能定义在所有衍生类里“通用”的一些东西。比如 子类继承了父类,虽然如果方法名与父类相同,但自变量或参数不同,就会出现重载现象,那或许并非我们所愿意的。所以好一点的方法,就是在父类或者接口中建立一种标准。 2、还有就是父类中的方法实现其实很冗余,基本用不到 11、接口也包含了基本数据类型的数据成员,但他们都默认是static 和 final,必须获得初始化(所以可以借助此性质定义需要的“枚举值”,通过接口名.变量名来访问)。接口只提供一种形式,并不提供实施的细节。 12、接口当作方法的形参的时候,传入的不仅可以是接口的实现类,也可以是实现类的子类。 13、利用继承技术,可方便地为一个接口添加新的方法声明,也可以将几个接口合并成一个新接口。在这两种情况下,最终都得到一个新接口。接口的继承实际上是一个接口功能增加的过程,有些应用只需要简单的接口。通过继承,可以在简单的接口上得到适合自己需要的复杂接口。 14、可以在一个类的内部定义新的类,称为内部类,如果想生成内部类的一个对象,必须将那个对象的类型设为'外部类名.内部类名' 15、为什么需要定义内部类? 1、我们准备实现某种形式的接口,使自己能够创建和返回一个引用。 2、要解决一个复杂的问题,并希望创建一个类,用来辅助自己的程序方案。同时不愿意把它公开。 16、匿名内部类 1、如果是接口,相当于在内部返回了一个接口的实现类,并且实现方式是在类的内部进行的; 2、如果是普通类,匿名类相当于继承了父类,是一个子类,并可以重写父类的方法。 3、需要特别注意的是,匿名类没有名字,不能拥有一个构造器。如果想为匿名类初始化,让匿名类获得一个初始化值,或者说,想使用匿名内部类外部的一个对象,则编译器要求外部对象为final属性,否则在运行期间会报错。 17、实际上,内部类的一个实例初始化模块就是一个匿名内部类的构造器。初次之外,内部类拥有对封装类所有元素的访问权限。 18、设计构造器时一个特别有效的规则是:用尽可能简单的方法使对象进入就绪状态;如果可能,避免调用任何方法。在构造器内唯一能够安全调用的是在基础类中具有final 属性的那些方法(也适用于 private方法,它们自动具有 final 属性) 19、泛型类或者泛型方法中,不接受 8 种基本数据类型。 三、集合 1、为容纳一组对象,最适宜的选择应当是数组,但是数组也有他明显的缺点,即容量有限。而且假如容纳的是一系列基本数据类型,更是必须采用数组。集合实际容纳的类型为Object的引用,这当然包括一切的java对象,因为Object是一切对象的基类。当然并不包括基本数据类型,因为它们并不是从“任何东西”继承来的。 2、Iterator接口的remove方法将会删除上次调用next方法时返回的元素。集合也有一个remove的方法,适用于List 和 Set ,boolean remove(Object)。 3、Listiterator和Iterator 的区别? 一.相同点 都是迭代器,当需要对集合中元素进行遍历不需要干涉其遍历过程时,这两种迭代器都可以使用。 二.不同点 1.使用范围不同,Iterator可以应用于所有的集合,Set、List和Map和这些集合的子类型。而ListIterator只能用于List及其子类型。 2.ListIterator有add方法,可以向List中添加对象,而Iterator不能。 3.ListIterator和Iterator都有hasNext()和next()方法,可以实现顺序向后遍历,但是ListIterator有hasPrevious()和previous()方法,可以实现逆向(顺序向前)遍历。Iterator不可以。 4.ListIterator可以定位当前索引的位置,nextIndex()和previousIndex()可以实现。Iterator没有此功能。 5.都可实现删除操作,但是ListIterator可以实现对象的修改,set()方法可以实现。Iterator仅能遍历,不能修改。 4、Set集合都不能保存重复的数据,即使是TreeSet也只是对不重复的数据进行排序罢了。对于TreeSet或者HashSet来说,在进行add()以及contain()操作时,HashSet显然要比ArraySet出色的多,而且性能明显与元素的多寡关系不大。一般在元素比较少,而且要进来遍历查询的时候,TreeSet会稍微快一些。 5、HashSet 与TreeSet和LinkedHashSet的区别? HaseSet: 1、不能保证元素的排列顺序,顺序有可能发生变化。 2、不是同步的。 3、集合元素可以为null,但只能放入一个null。 4、当向HashSet集合中存入一个元素时,会首先调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据 hashCode值来决定该对象在HashSet中存储位置。如果该HashSet集合中已经有这个对象的hashCode值,则调用该对象的equal()方法,返回true,就不插入,返回false,就另外找一个hashCode存储。 TreeSet: TreeSet底层是一个红黑二叉树结构,其中元是不可重复的。TreeSet类型是J2SE中唯一可实现自动排序的类型。TreeSet支持两种排序方式,自然排序和定制排序。向treeSet中加入的应该是同一个类的对象。向TreeSet插入基本数据类型时,Java已经定义好了CompareTo(Object obj)方法,采用自然排序,默认升序。如果放入的是自定义的对象类需要实现Comparable接口并重写compareTo()方法,相等返回0,大于返回正数,小于返回负数。同时treeSet的插入比较也是通过compareTo()或者equal()方法来比较插入的。 LinkedHashSet: LinkedHashSet集合同样是根据元素的hashCode值来决定元素的存储位置,但是它同时使用链表维护元素的次序。这样使得元素看起 来像是以插入顺 序保存的,也就是说,当遍历该集合时候,LinkedHashSet将会以元素的添加顺序访问集合的元素。 LinkedHashSet在迭代访问Set中的全部元素时,性能比HashSet好,但是插入时性能稍微逊色于HashSet 6、如果两个对象相同,那么他们的hashCode值一定相同。如果两个对象的hashCode值相同,他们不一定相同。 7、HashMap、TreeMap 的区别? 1、HashMap是基于散列表实现的,时间复杂度能达到O(1),是无序的。 2、TreeMap基于红黑树(一种自平衡二叉查找书)实现的,时间复杂度平均能达到O(log n),是有序的。 8、HashMap、HashTable的区别? 1、HashMap几乎可以等价于HashTable,都实现了Map接口。 2、HashMap是非同步的,线程不安全的。而HashTable是同步的,线程安全的。当然我们也可以手动进行HashMap同步(Collections.synchronizeMap(hashMap)) 3、HashTable中hash数组默认大小是11,增加的方式是 old*2+1。HashMap中hash数组的默认大小是16,而且一定是2的指数。 4、哈希值的使用不同,HashTable直接使用对象的hashCode。 9、从性能方面来说,对于Map的put()和get(),hashMap和hashTable都要优于TreeMap,而hashTable要多花一些开销在线程同步上,所以hashMap的性能又稍优于hashTable。而对于Map的遍历来说,treeSet的性能要稍优于hashMap和hashTable。 10、如果需要创建大量Map,TreeMap、hashMap的性能要优于hashTable。 11、对于Arrays和Collections来说,若在执行一次 binarySearch()之前不调用 sort(),便会发生不可预测的行为,其中甚至包括无限循环。排序遵守的是字典排序,亦即大写字母在字符集中位于小写字母的前面。 12、Comparator和Comparable的区别? 集合或者数组要实现自动排序功能,比如TreeSet、TreeMap、Arrays.sort()、Collections.sort(),有两种方式。 第一种:比较的类型内部实现了Comparable接口重写了compareTo()方法。 第二种:自己新建了一个比较类实现了Comparator接口,重写了compare方法。 13、使 Collection 或 Map 不可修改? Collections.unmodifiableCollection(c); Collections.unmodifiableList(a); Collections.unmodifiableSet(s); Collections.unmodifiableMap(m); 14、使Collection 或 Map 的同步? Collections.synchronizedCollection(new ArrayList()); Collections.synchronizedList(new ArrayList()); Collections.synchronizedSet(new HashSet()); Collections.synchronizedMap(new HashMap()); 四、其他 1、怎么理解TCP是可靠的协议,而HTTP基于IP/TCP协议,却是不可靠的? 1、首先IP 是网络层的协议,确认source和target的IP地址。 2、TCP是传输层的传输协议,传输基于三次握手过程提供可靠的传输协议。 3、HTTP是应用层协议,它只负责把服务器的资源反馈到客户端。 4、怎么理解三个协议之间的合作呢,IP提供源地址和目标地址,TCP建立可靠的通道,最后由HTTP来负责传输内容,如果一个会话需要多个层级的连接,会造成延迟大、资源浪费,所以如果一个层级已经提供了可靠连接,则其它层级完全没有必要连接,只需要交流信息即可,比如这里的HTTP。
|
|