Java基础——重要知识点

集合

Collection

List

Arraylist or Linkedlist contains方法和remove方法依赖的都是equals方法

不同的数据结构依赖的方法不同

集合中存储的其实都是对象的引用(地址),而不是对象实体
在这里插入图片描述
List特有方法都和索引有关。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
效果:

可以在迭代过程中进行增加、修改等操作
注意:arrayList有两个迭代方法,iterator()和listIterator()
LinkedList只有listiterator这一个方法
arrayList集合如果使用iterator()在迭代过程中对元素进行增删改操作,会发生并发修改异常(concurrentModificationException)
避免这种情况,调用listiterator()方法即可。
在这里插入图片描述
在这里插入图片描述
ArrayList和Vector的功能几乎一摸一样,Vector满了扩容是X2,ArrayList扩容是X1.5
在这里插入图片描述
枚举是Vector特有的迭代方式,因此除了同步和扩容方式这两点以外,迭代方式也是和ArrayList集合不相同的一个点。
在这里插入图片描述
除此之外,注意,LinkedList和ArrayList有一个不同之处在于,他可以不用迭代器就可以进行遍历:
在这里插入图片描述

在这里插入图片描述
因此对于自定义类,一定要覆写equals方法,而且注意,List即可对于equals方法,只看结果,不看过程。

Set

在这里插入图片描述
何时判断元素唯一?contains、add,remove等方法都会底层自动判断元素是否唯一!!!
在这里插入图片描述

TreeSet的排序应用:它有两种排序方式:
第一种:
在这里插入图片描述
在这里插入图片描述
当TreeSet集合add()时,会自动调用compaerTo方法进行比较。

第二种:让集合自身具备比较性,第一种是让元素自身具备比较小
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
TreeSet底层使用的是二叉树:
结构:
在这里插入图片描述

应用案例:
在这里插入图片描述
在这里插入图片描述

Map

在这里插入图片描述
remove方法:返回的是V,如果remove中的key不存在,则返回null。
put方法:返回的是被被覆盖掉的V,因此如果是第一次使用put方法,那么返回的V是null。

Map的数据结构:key必须实现hashcode和equals方法

在这里插入图片描述
上图就是hashtable和hashmap的区别!!!有两个区别,同步与否和是否键值为null!!!

注:Set集合的底层方法调用的都是Map集合的方法,因此他们很像

在这里插入图片描述
第一种取出方式:
在这里插入图片描述

第二种取出方式:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

泛型

泛型的使用:
注意集合使用了泛型,那么其迭代器也要使用对应的泛型
引用泛型的两大好处:
在这里插入图片描述
在这里插入图片描述
避免了强转,因为迭代器声明了泛型类型,取出来的元素必定都是这个类型的元素,因此无需强转
按照以往:String s=(String)it.next();

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
泛型类:
在这里插入图片描述
注意一下,调用方法往里面传参时,可以自动装箱、自动拆箱
在这里插入图片描述
泛型方法:
在这里插入图片描述
那么此时,可以往方法里面传不同类型的参数了
在这里插入图片描述
既有泛型类、也有泛型方法时
在这里插入图片描述
此时show方法的参数和New 对象往里面传的参数必须一致,而print方法啥类型的参数都可以

静态方法的情况:
在这里插入图片描述
原因就是,静态方法随类加载,而类的泛型类型需要创建对象的时候才能明确,所以两者起了冲突。
正确写法:
在这里插入图片描述
方法的泛型必须写在返回值类型的前面,修饰符(public static)的后面

泛型定义在接口上:
第一种:
类在实现该接口时就确定了类型
在这里插入图片描述

第二种:
类在实现该接口时也不知道啥类型:
在这里插入图片描述

IO流

字节流的两个抽象基类:InputStream、OutputStream

字符流

字符流的两个抽象基类:Reader、Writer

Writer

抽象类,有自己的构造方法,而接口没有。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
注意没有空构造方法,因为该类是用来操作文件的,因此,先有文件,我才有操作的需求,因此一初始化就要有文件。
在这里插入图片描述
为什么要close?
在这里插入图片描述
IO异常的专业处理:
每一个方法都被要求抛异常(凡是能和设备上的数据发生数据关系的,都会发生IO异常,无论读还是写),
那为什么不单独try呢
因为如果一句话一个try,那么如果我第一句话就出现异常了,try了以后,下面的语句执行了还有什么意义,这三句话是有关联的!
在这里插入图片描述
注意一下,

  1. 要是万一我在new
    FileWriter
    时出现了异常,那么fw对象就没创建成功,就为null,因此,执行**fw.close()**时会出现NullpointerException!!!
  2. 别忘了fw.close放在finally中也要再try一下,因为close方法也抛异常

文件内容续写
在这里插入图片描述
如果想换行咋整?
错误做法:写上\n,但并不是所有操作系统都是\n呀!!!
在这里插入图片描述

Reader

在这里插入图片描述
没有读 字符串的——String
在这里插入图片描述
read()方法一次读一个字符,而且会自动往下读
读取方式的第一种:
在这里插入图片描述
原理图:
在这里插入图片描述硬盘的数据都是一块一块存的,且是连续的,像g后面可能存放的就是电影数据了,但g后面会有一个Windows系统设置的结束标识符,java其实不认识这个标识符,但Java调用了操作系统,让windows去读,所以windows读到了这个标识符后就告诉了java,读到头了,返回结束标记-1
第二种读取的办法:
通过字符数组进行读取
在这里插入图片描述
这两个Int代表的含义不同,第一个int是读到的字符的int表示形式,第二个方法的int表示的是读到的字符数量!!!
在这里插入图片描述
注意!!不是读取buf数组里面的内容,而是把读到的数据存到buf数组里面去!!!
原理图:
在这里插入图片描述

  • 为什么这边最后取1,因为我在数据里面只读了1个,因此知道,read(char[])返回的是在硬盘上读到的数据,而不是数组里面已有的数据数量

  • 这边图中为什么数组覆盖之前的内容,因为数组是同一个数组。

  • 当数组读满了之后,指针超出了数组的范围,此时就不再读硬盘数据了,因为数组存不下了,此时指针会自动回来,重新指向数组第一个元素。

  • 当硬盘数据读完了之后,此时read(char[])和read()方法一样同样返回的是-1,表示读完了
    在这里插入图片描述
    在这里插入图片描述
    一般数组大小定义成1024的整数倍
    在这里插入图片描述注意:

  • 要是定义的数组足够大,所有数据可以一次性被打出来

  • 读取数据,不要使用println打印!!!以免自动换行

  • 如果数据大于数组的大小,比如2000,那么我读完1024之后,并没有读完,此时数组读满了,只要数组读满了,此时会把read(buf)读到的个数赋值给 num。然后num判断发现!=-1,满足循环条件,接着执行打印语句。第二次读只能读(2000-1024)个,那么此时又会打印num个,第三次读=-1,就不打印了。
    即,当数组读满了,存不下去的时候,就不再继续读数据了,而是返回读到的个数然后再打印出来,然后又调用了一次read方法,此时数据继续读,而数组指针会重新指向数组的第一位!!

文件复制:
在这里插入图片描述
第一种:
在这里插入图片描述
第二种:
在这里插入图片描述
在这里插入图片描述

开的流越多,需要关的也就越多。
在这里插入图片描述
两个流之间并没有关系,需要一个中转站,这边的中转站是char[ ]

字符流缓冲区

缓冲区的出现是为了提高流的读写效率!!因此这哥们出现之前得先有流。在这里插入图片描述
在这里插入图片描述
缓冲技术的原理实质上是在流对象里面封装了数组,先把数据存起来,然后再一次性写出去。把数组封装起来变成对象,这样不用自己定义数组,更方便

BufferedWriter

必须要搞清楚,BufferedWriter是为了提高Writer的效率而存在的,实质上真正写数据的还是Writer,读也是同理,因此缓冲区的关闭,其实关闭的不是缓冲区,而是他所提高效率的那个流对象,该流对象才是底层真正在调用资源的。
所以下边不需要写fw.close()了
在这里插入图片描述
在这里插入图片描述
newLine方法是用来换行的,它可以跨平台,因为不同平台的换行符号是不一样的,Linux是 \n, Windows中是 \r \n
应用代码:
在这里插入图片描述
对于上面为什么在for循环里面刷新,其实也可以放到for循环外面进行刷新,而放在里面,万一停电了,不至于损失太惨重,因为你不刷新,内容都在内存当中。

BufferedReader

BufferedReader也不遑多让,他读数据是一行一行地读的。。。。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
注:1.readLine无脑读,要么读到结束标志,要么读完一行,此时会把读到的内容变成字符串赋值给line
2.line有了值之后判断 !=null,满足循环条件
3.执行while循环中的语句
4.接着readLine读。。。。
还要注意,使用readLine()读的时候,println要加上,因为
在这里插入图片描述

通过缓冲区复制文件:
在这里插入图片描述
在这里插入图片描述
两个流之间并没有关系,需要一个中转站,这边的中转站是String line,以前的中转站是char数组
了解即可:readLine()方法原理图:
在这里插入图片描述
装饰设计模式:
在这里插入图片描述
在这里插入图片描述
装饰类与继承的区别:
在这里插入图片描述

字节流

注意,字符流使用的是字符数组(char[ ]),字节流使用的是字节数组(byte[ ])

OutputStream、InputStream

在这里插入图片描述
注意,没有write(String s )这么个方法,无法传入字符串
再注意,字节流write后,可以不用刷新!!!
原因:字符流其实一样是走的字节,但是它需要把字节临时存起来,因为一个中文有两个字节,我从一个硬盘上读了一个字节后无法立即操作,因此需要把字节临时存储起来,然后存储完之后去查码表。字符流底层用的是字节流的缓冲区,因此需要刷新动作。直接使用字节流,可以把字节一步一步都写到硬盘上,无需缓冲,因为对字节最小单位操作,中间无需转换。
写和读
在这里插入图片描述
但是还必须得关资源
第二种读
在这里插入图片描述
第三种读,字节流特有的
在这里插入图片描述
我们之前不知道到底有多大才循环遍历,现在我定义的数组大小刚刚好。注意,这边不需要判断是否读到末尾,返回-1什么的,因为我们之前需要-1来作为循环结束的标志,现在不需要判断循环结束了,而数据读完,read()方法会自动停止再读取
为什么不断地调用read()方法会不断的往下读数据,因为里面就是有一个指针在指向数组中的元素,读完一个数据,指针就往后移动一格,读到-1标志,指针就不往下移动了。
但是,这种方法要慎用,因为我要是读取的数据很大,超出内容,我这个数组还怎么创建呢???因此还是以new byte[1024]为主,性价比最高。

字节流无缓冲区的应用:
在这里插入图片描述

字节流缓冲区

字节流使用缓冲区的应用:
注意:字节流读的缓冲区和字符流的读方法不同,没有readLine()方法,readLine方法的意思是读一行文字
有了缓冲区就不需要在写的时候创建数组,先写进数组里了,因为缓冲区内部有数组来缓存
在这里插入图片描述
所以,这边的bufis.read()方法是从硬盘里面取的数据吗,不是,是从缓冲区里取得数据

对于字节流的扩展(标准输入、输出)

在这里插入图片描述
read()方法其实是一个阻塞式方法,没有读到数据就会停下等待
在这里插入图片描述
在这里插入图片描述
什么时候触发ch=in.read()=-1的条件呢?
Ctrl+C,其实这个按键就是在底层加入结束标记,这个标记返回的值是-1
下面代码不健壮
在这里插入图片描述
改进:
在这里插入图片描述
上述代码显然太复杂了,而且发现其实上述代码就是读一行readLine方法的原理
在这里插入图片描述

转换流

转换流定义在了字符流
InputStreamReader 用于操作字节流的的字符流对象,InputStreamReader是从字节流通向字符流的桥梁
在这里插入图片描述
可以自定义结束标记
在这里插入图片描述
OutputStreamWriter
该类和InputStreamReader不一样,它是字符流通向字节流的桥梁
使用场景:我有一些文字需要录入,这些文字传递用字符流,但是这些文字都是以字节的形式存在硬盘,因此需要用到字符——转字节
下述代码是上面代码的变形,**将System.out.print改写了!!!
**

在这里插入图片描述
小细节注意:字节流无法write(String),但是字符流可以。,字节流只能写一个字符或者写一个数组。
看来,输出语句,底层用的就是流对象。
三句话并成一句话:
要背下来,以后就这样用:
在这里插入图片描述
注意路径的写法:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
转换流的由来就是因为它可以指定编码
这才是真正的应用,可以把字节转换过来,并查指定的码表
指定的编码表只有转换流才可以指定!!!
而转换流都需要接受一个字节输出 / 输入流
在这里插入图片描述

在这里插入图片描述
写操作的效果一样。

File类

该对象用来操作文件以及文件夹
之前得流对象虽然可以操作文件,但操作不了文件夹和文件的属性信息。
在这里插入图片描述
封装的什么,打印的就是什么。
在这里插入图片描述
File.separator()方法可以跨平台
文件的创建、删除方法返回的是boolean目的就是为了看是否创建或者删除成功

deleteOnExit()方法是在文件退出时删除,因为delete方法在finally中不一定内被删掉(因为有可能此时文件还在被应用),因此deleteOnExit可以说是十分贴心了。
在这里插入图片描述
在这里插入图片描述

String类

在这里插入图片描述
final修饰的类,代表该类不能有子类
字符串他是一个特殊的对象,双引号引起来的全都是对象
字符串最大特点:一旦被初始化,就无法被改变

在这里插入图片描述
s1的地址变了,但是“abc”对象内容没有变化过,一旦初始化就不会被改变。

public class HumanDemo {
	public static void main(String[] args) {
		String s1="abc";
		String s2=new String("abc");
		String s3="abc";
		String s4=new String("abc");
		
		System.out.println(s1==s2);//false
		System.out.println(s1.equals(s2)); //true
		System.out.println(s1==s3); //true
		System.out.println(s1==s4); //false
	}
}

线程

线程运行各状态图:
在这里插入图片描述

创建线程的两种方式

第一种方式:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
第二种方式:
在这里插入图片描述
class Ticket implements Runnable
在这里插入图片描述
区别:
在这里插入图片描述
在这里插入图片描述

卖票小栗子

第一种方式卖票演变代码:
在这里插入图片描述
上述代码问题:我只要创建一个对象就有100张票,各卖各的。
解决方法,让四个线程共享一个变量,可以使用static。
但static修饰的变量难以被清理,只有类不执行了才会被清理,生命周期太长。
第二种:
在这里插入图片描述
在这里插入图片描述
一个线程start了四次,就像跑步,打了四次发令枪。本来已经在运行状态了,再开启运行状态毫无意义。线程状态出问题了!
已经运行的程序无须再次开启
使用第二种线程创建方式:

同步的方法

同步代码块

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

同步方法

在这里插入图片描述
在这里插入图片描述

静态方法同步

在这里插入图片描述
静态方法用的锁是 该方法所在类.class
在这里插入图片描述

单例模式

饿汉式:

public class Test extends Thread { // 饿汉式 
	private static final Test t = new Test();

	private Test() {

	}

	public static Test getInstance() {
		return t;
	}

}
class Single {     //懒汉式
	private static Single s = null;

	private Single() {

	}
懒汉式:
	public static Single getInstance() {
		if (s == null) {
			synchronized (Single.class) {
				if (s == null)
					s = new Single();
			}
		}
		
		return s;
	}
}

在这里插入图片描述
子类不能覆写父类的静态方法,但是可以使用父类的静态方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值