JavaSE学习笔记(还算细吧QAQ)(三)

JavaSE学习笔记(三)

有顺序的java程序:

第一:对于一个方法来说,方法体中的代码是有顺序的。
第二:静态代码块1和2是有先后顺序的。
第三:静态代码块和静态变量。

实例语句块:

{
	代码块;
}

实例语句块在类加载时没有执行。
实例语句块在实例方法执行之前执行。这也是一个时机,对象构建时机。

this:关键字,全小写。

一个对象一个this。
this是一个变量,是一个引用。this保存当前对象的内存地址,指向自身。
所以,严格意义上来说,this代码的就是“当前对象”。
this存储在堆内存当中对象的内部。

this只能使用在实例方法中。谁调用这个方法,this就指向谁。
所以this代表当前对象。

this. 大多时候可以省略。

this在实例方法或者构造方法中,为了区分局部变量和实例变量,this不能省略。

为什么this不能用在静态方法中?
this代表当前对象,静态方法不存在当前对象。

this还可以使用构造方法中:
	通过当前构造方法去调用另一个本类的构造方法,如:
		this(实际参数列表);
			通过一个构造方法1去调用构造方法2,可以做到代码复用。
			但需要注意的是,构造方法1和2必须在同一类中。
this()作用:代码复用。

对于this()的调用必须出现在代码的第一行。

继承extends

什么是继承?有什么用?
	继承的作用:
		基本作用:子类继承父类,代码可以得到复用。
		主要作用:因为有了继承关系,才有了后期的方法覆盖和多态机制。

继承的缺点:耦合度高,父类改变,子类受牵连。

在实际开发中,什么时候使用继承?
	凡是采用“A is B”能描述的,都可以继承。
		例如:cat is a animal。

方法覆盖override

什么时候考虑方法覆盖?
	子类继承父类后,当继承的方法无法满足子类的业务需求时,
	子类有权对这个方法进行重新编写,有必要进行“方法的覆盖”。

方法覆盖又叫做:方法重写,override、overwrite。

重要结论:当子类对父类继承过来的方法进行override后,
子类对象调用该方法的时候,一定执行覆盖之后的方法。

如何在代码级别上构成方法覆盖?
	条件一:两个类必须要有继承关系。
	条件二:重写之后的方法和之前的方法具有:
		相同的返回值类型
		相同的方法名
		相同的形式参数列表
	条件三:访问权限不能更低,可以更高。
	条件四:重写之后的方法不能比之前的方法抛出更多的异常,可以更少。

注意事项:
	第一:方法覆盖只针对方法,和属性无关。
	第二:私有方法无法覆盖。
	第三:构造方法不能继承,所以构造方法不能被覆盖。
	第四:方法覆盖只针对“实例方法”,“静态方法覆盖”没有意义。

关于Object中的toString()方法
	1、toString()方法的作用?
		将“java对象”转换成“字符串的形式”。

静态方法不存在方法覆盖。

私有方法不能覆盖。

在方法覆盖中,关于方法的返回值类型。
	对于返回值类型是基本数据类型来说,必须一致。
	对于返回值类型是引用数据类型来说,重写之后返回值类型可以变小。

多态

多态在开发中的作用:
	降低程序的耦合度,提高程序的扩展力。

多态的基础语法:
	1、学习多态基础语法之前,需要普及2个概念:
		一、向上转型(upcasting)
			子-->父(类似自动类型转换)
		二、向下转型(downcasting)
			父-->子(类似强制类型转换,需要加强制类型转换符)
		无论是哪种转型,都必须有继承关系。
多态表示多种形态:
	编译的时候是一种形态。(静态绑定)
	运行的时候另一种形态。(动态绑定)


什么时候必须使用向下转型?
	当你需要访问子类对象中“特有”的方法,此时必须进行向下转型。

运行时出现java.lang.ClassCastException:类转换异常,它和空指针异常一样重要,经典。

instanceof
	第一:instanceof可以在运行阶段动态判断引用指向的对象的类型。
	第二:instanceof语法:引用 instanceof 类型
	第三:instanceof运算符的运算结果只能是:true/false。
	第四:c是一个引用,c变量保存了内存地址指向了堆中的对象。
		假设(c instanceof Cat)为true表示:
			c引用指向的堆内存中的java对象是一个Cat。
			反之亦反。
	在对类型进行向下转型时,一定要使用instanceof运算符进行判断。
	这样可以很好的避免ClassCastException

	多态的典型代码:父类型的引用指向子类型的对象。

假设没有多态机制,只有方法覆盖机制,有意义吗?
	没有多态机制的话,方法覆盖可有可无。

方法覆盖和多态不能分开。

super

super是一个关键字,全部小写。
super和this对比着学习。
	this:
		能出现在实例方法和构造方法中。
		this语法:“this.” “this()”。
		this不能出现在静态方法中。
		this. 大部分情况是可以省略的。
		this. 在区分局部变量和实例变量时不能省略。
		this()只能出现在构造方法的第一行,通过当前构造方法去调用“本类”
		中其他构造方法。
	super:
		能出现在实例方法和构造方法中。
		super语法:“super.” “super()”。
		super不能出现在静态方法中。
		super. 大部分情况是可以省略的。
		super. 如果父类和子类中有同名属性,如果想在子类中访问父类中的同名属性,
		就不能省略。
		super()只能出现在构造方法的第一行,通过当前构造方法去调用“父类”
		中的构造方法。目的是,创建子类对象的时候,先初始化父类型特征。

super(实参) 调用父类的有参构造方法
super() 调用父类的无参构造方法
super. 

super 不是引用。super也不保存内存地址,super也不指向任何对象。
super 只是代表当前对象内部的那一块父类型的特征。

this可以单独用,super必须加个'.'。

super()和this()不能共存,因为两者都只能出现在构造方法的第一行。

无论如何,父类的构造方法一定执行。

在父和子中有同名的属性或者方法,如果此时想在子类中访问父中的数据,必须使用“super.”加以区分。

集合(重要)

什么是集合?有什么用?

集合实际上就是一个容器。可以来容纳其他类型的数据。

集合为什么说在开发中使用得多?

集合是一个容器,是一个载体,可以一次容纳多个对象。

集合最主要掌握什么内容?
	1、每个集合对象的创建(new)
	2、向集合中添加元素。
	3、从集合中提取元素。
	4、遍历集合
	5、主要的集合类:
		ArrayList
		LinkedList
		HashSet
		TreeSet			
		HashMap
		Properties
		TreeMap

集合不能直接存储基本数据类型,另外也不能直接存储java对象,
集合当中存储的都是java对象的内存地址。(或者说集合中存储的都是引用)
注意:
	集合在java中本身是一个容器,是一个对象。
	集合中任何时候存储的都是“引用”。

在java中每一个不同的集合,底层会对应不同的数据结构。往不同的集合中存储
元素,等于将数据放到了不同的数据结构当中。什么是数据结构?数据存储的结构
就是数据结构。不同的数据结构,数据存储方式不同。
使用不同的集合等同于使用不同的数据结构。

集合在java JDK的 java.util包下。

List集合存储元素特点:有序可重复,存储的元素有下标。
有序实际上是说存进去是这个顺序,取出来还是这个顺序。不是指大小排序。
并且因为List集合都有下标,从0开始。

ArrayList集合是非线程安全的。
Vector是线程安全的。(用得很少)

Set集合存储元素特点:无序不可重复。无序表示存进去是这个顺序,取出来就不一定是这个顺序,
另外Set集合中没有下标。

HashSet在new的时候,底层实际上new了一个HashMap集合。
SortedSet集合中的元素自动排序。

Map集合:
	和Collection集合没关系。
	以key和value这种键值对的方式存储元素。
	key和value都是存储java对象内存地址。
	所有Map集合的key特点:无序不可重复。

Collection接口中的常用方法:
	Collection中能存放什么元素?
		没有使用“泛型”之前,Collection中可以存储Object的所有子类型。
		使用了“泛型”之后,Collection中只能存储某个具体的类型。
	
	boolean add(Object e)向集合中添加元素
	int size() 获取集合中元素个数
	void clear() 清空集合
	boolean contains(Object e) 判断集合中是否包含指定元素
	boolean remove(Object e) 删除集合中某个元素
	boolean isEmpty() 判断集合是否为空
	Object[] toArray() 将集合转换为数组(作为了解,很少使用)
集合遍历/迭代专题(重点*****)
	Collection接口的全部实现类调用iterator方法得到迭代器对象Iterator。
	boolean hasNext()如果仍有元素可以迭代,返回true
	Object next() 返回迭代的下一个元素,编写代码时,next()的返回值必须是Object。
	代码实现:
		Collection c = new ArrayList();//创建一个集合对象
		c.add(Object e);//添加元素
		Iterator it = c.iterator();//获取迭代器
		while(it.hasNext()){
			System.out.println(it.next())
		}
深入Collection集合的contains和remove方法:
	boolean contains(Object e) 判断集合中是否包含指定元素。
	boolean remove(Object e) 删除集合中某个元素。
	在底层都调用了equals方法。
	放在集合里面的元 素需要重写equals方法。
关于集合元素的remove:
	重点:当集合结构发生了改变,迭代器没有重新获取,调用next()方法时,
	出现异常:ConcurrentModificationException。
	
	重点:在迭代集合元素的过程中,不呢调用集合对象的remove方法删除元素:
	c.remove(o);迭代过程中不能这样。会出现异常:ConcurrentModificationException。

	重点:在迭代元素的过程中,一定要使用迭代器Iterator的remove方法删除元素,
	不要使用集合自带的remove方法删除元素。
List接口特有方法(常用的):
	boolean add(Object o) 将指定的元素追加到此列表的末尾。  
	void add(int index, Object element) 将指定的元素插入此列表中的指定位置。
	Object get(int index) 返回此列表中指定位置的元素。 
	int indexOf(Object o) 返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1。 
	int lastIndexOf(Object o) 返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回-1。
	Object remove(int index) 删除该列表中指定位置的元素。  
ArrayList集合初始化容量和扩容(原容量的1.5倍):
	ArrayList底层是Object[]数组。如何优化?
		建议给定一个预估计的初始化容量,减少扩容。
		数组优点:检索效率高。
		数组缺点:随机增删元素效率比较低。另外数组无法存储大数据量。(很难找到一块非常巨大的连续的内存空间)
		想数组末尾添加元素,效率很高,不受影响。
	默认初始化容量为10。 Lost l = new ArrayList();
	指定初始化容量:Lost l = new ArrayList(20);
二进制位运算
	10 >> 1:即1010(10)-->0101(5)
单项链表数据结构:
链表优点:由于链表上的元素在空间存储上内存地址不连续,所以随机增删元素效率高(不涉及大量元素位移)。  
链表缺点:查询效率低,不能通过数学表达式计算被查找的内存地址,每一次查找某个元素都需要从头节点开始遍历。
LinkedList集合:
	没有初始化容量。
	双向链表。
	对于链表数据结构来说,随机增删效率较高,检索效率较低。
	链表中的元素在空间存储上,内存地址不连续。

ArrayList:把检索发挥到极致(末尾添加元素效率很高)。
LinkedList:把随机增删发挥到极致。
又因为加元素一般都是往末尾加,所以ArrayList用得更多。
Vector集合:
	初始化容量10。
	2倍扩容。
	线程安全。
泛型机制:
	只在编译阶段起作用,只是给编译器参考的。
	使用泛型的好处:
		第一:集合存储的元素类型统一。
		第二:从集合中取出的元素类型是泛型指定的类型,不需要进行大量的“向下转型”。
	缺点:
		导致集合中存储的元素缺乏多样性!
		大多数业务中,集合中的元素的类型还是统一的。所以泛型被认可。
foreach:增强for循环(JDK5.0)
for(元素类型 变量名 : 数据或集合){}
如:
int[] arr = {100,200};
    for(int date : arr){
        System.out.println(date);
    }
没有下标。在需要使用下标的循环中,不建议使用。

HashSet集合元素特点:无序不可重复。(无序指没有下标)
TreeSet集合元素特点:无序不可重复。但是除此的元素可以自动按照大小顺序排序,称为可排序集合。

Map接口:
Map和Collection没有继承关系。
Map集合以key和value的方式存储数据:键值对。
key和value都是引用数据类型。
key和value都是存储对象的内存地址。
key起主导的地位,value是key的一个附属品。

常用方法:
	V put(K key, V value) 将指定的值与该映射中的指定键相关联。
	V get(Object key) 返回到指定键所映射的值,或 null如果此映射包含该键的映射。 
	int size() 返回此地图中键值映射的数量。
	void clear() 从该地图中删除所有的映射 。
	boolean containsKey(Object key) 判断Map中是否包含某个key 。 
	boolean containsValue(Object value) 判断Map中是否包含某个value。 
	boolean isEmpty()  判断是否为空。
	V remove(Object key) 通过key删除键值对。
	Collection<V> values() 获取Map集合中的所有value,返回一个Collection视图。 
	Set<K> keySet() 获取Map集合中的所有key,返回此地图中包含的键的Set视图。 
HashMap集合:
	在JDK8之后,如果哈希表单向链表元素超过8个,单向链表这种数据结构会变成红黑树数据结构,
	当红黑树上的节点数量小于6时,会重新变成单向链表结构。(这种方式是为了提高检索效率)

	HashMap集合底层是哈希表/散列表的数据结构。
	默认初始化容量16,默认加载因子0.75(容量达到最大的0.75就开始扩容,2倍扩容)。
	允许key值为null,但只有一个null值。
	key部分特点:
		无序不可重复。
		为什么无序?
			因为不一定挂到哪个单向链表上。
		不可重复如何保证?
			equals方法来保证HashMap集合的key不可重复。如果重复,value会覆盖。
	放在HashMap集合key部分的元素其实就是放到HashSet集合中了。
	所以HashSet集合中的元素也需要重写HashCode()+equals()方法。

	哈希表是一个数据和单向链表的结合体。
	数据:在查询方面效率很高,随机增删方面效率很低。
	单向链表:在随机增删方面效率很高,在查询方面效率很低。
	哈希表将以上的两种数据结构融 合在一起,充分发挥他们各自的优点。

	为什么哈希表的随机增删,效率都高?
		增删是在链表上完成。
		查询也不需要都扫描,只需要部分扫描。
	重点:通过讲解可以得出HashMap集合的key,会先后调用两个方法,
	一个方法是hashCode(),一个方法是equals(),那么这两个方法需要重写。

	如果一个类的equals方法重写了,那么hashCode方法必须重写,并且equals方法返回true,
	hashCode方法返回的值必须一样。

	假设将所有的hashCode()方法返回值固定为某个值,那么会导致底层哈希表变成了纯单向链表。
	这种情况我们称为:散列分布不均匀。

	什么是散列分布均匀?
		假设有100个元素,10个单向链表,那么每个单向链表上都有10个节点,这是最好的。
		是散列分布均匀的。
	假设将所有的hashCode()方法返回值都设定为不一样的的值,可以吗,有什么问题?
		不行,因为这样的话会导致底层哈希表成为了一维数组,没有了链表的概念。
		也是散列分布不均匀。
	散列分布均匀需要在重写hashCode()方法时有一定的技巧。

	重点:HashMap集合初始化容量必须是2的倍数。这是因为达到散列均匀,为了提高HashMap集合的存取效率。

	终极结论:放在HashMap集合key部分的,以及放在HashSet集合中的元素,需要同时重写hashCode方法和equals方法。
HashSet:2倍扩容
Hashtable:
	key和value都不能为null。
	方法都带有synchonized:线程安全的。
	初始化容量11。
	扩容:原容量*2+1。

TreeSet:
	底层实际上是一个TreeMap。
	TreeMap集合底层是二叉树。
	放到TreeSet集合中的元素,等同于放到TreeMap集合key部分了。
	TreeSet集合中的元素:无序不可重复,但是可以按照元素的大小顺序自动排序。称为:可排序集合。
	TreeSet无法对自定义类型排序,除非实现java.lang.Comparable接口中的compareTo方法。

TreeSet集合和TreeMap集合采用的是:中序遍历方式。
Iterator迭代器采用的是中序遍历方式。

TreeSet集合中元素可排序的第二种方式:使用比较器。
	比较器实现java.util.Comparator接口。

Comparator和Comparable如何选择?
	当比较规则不会发生改变的时候,或者说当比较规则只有1种的时候,建议使用Comparable接口。
	如果比较规则有多个,并且需要多个比较规则之间频繁切换,建议使用Comparator接口。

Collections工具类:
方便集合的操作。

List list = new ArrayList();//list是非线程安全的
Collections.synchonizedList(list);//变成线程安全的

Collections.sort();//排序  
注意:对List集合中的元素排序,需要保证List集合中的元素实现了Comparable接口。

Properties
属性类。
线程安全的。
需要掌握的两个方法:
存:setProperty(“key”,“value”);
取:getProperty(“key”);

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值