JavaSE
一、 基础语法
1、 基本数据类型
1、
数据类型 |
字节数 |
二进制位数 |
byte |
1 |
8 |
short |
2 |
16 |
int |
4 |
32 |
long |
8 |
64 |
float |
4 |
32 |
double |
8 |
64 |
char |
2 |
16 |
boolean |
1 |
1 |
boolean类型的值只有true和false两种逻辑值,在编译后会使用1和0来表示,这两个数在内存中按位算,仅需1位(bit)即可存储,位是计算机最小的存储单位。
数据类型char在中文编码GBK-2312中占2个字节,在UTF-8中占3个字节。
2、判断与循环
逻辑运算符 |
作用 |
& |
与作用,左右两边两个判断结果都为true就是true,否则是false |
| |
或作用,左右两边两个判断结果只要有一边为true,结果就是true,否则就是false |
^ |
异或,你为true我就是false |
&& |
左右两边,左边如果为false,右边不执行,直接返回结果false |
|| |
同理:左边如果为true,右边不执行直接返回true |
第一种:
if(条件表达式){
语句块1
}else{
语句块2
}
第二种:
if(条件表达式){
语句块1
}else if{
语句块2
} else {
以上条件均不满足而执行的默认的逻辑
}
第三种:
switch(被判断的变量)
{
case 条件1:
执行条件1的逻辑
break;
case 条件2:
执行条件2的逻辑
break;
case n:
执行条件n的逻辑
break;
default:
以上条件均不满足而执行的默认的逻辑
}
第四种:
While(判断语句){
循环体
}
Do{
循环体
}while(判断语句);
While是先判断后执行,do while 是先执行循环体语句,然后进行判断语句,就是说无论判断是否为true都会至少执行一次循环体语句。
3、数组
1、 数组是对应的容器集合,需要存储同类的数据,在一个容器中。
2、 数组使用中,需要规定数组的长度,长度从1开始,设置后长度不可变。
3、 数组使用中,定义数据的类型为:Object,可以存储所有类型:,否则根据需要定义类型,可以是对象也可以是基本数据类型
4、 数组要想遍历(一个个的拿到数据内的数据),我们需要for循环来完成,知道循环的次数,一个个的获取。数组获取中,如果超过角标,那么就会报错:角标越
界异常:indexoutofboundsException,因为角标从0开始
5、 排序算法:(选择和冒泡)
1、冒泡排序算法
2、选择排序算法
二、 面向对象
1、 封装
1、封装属性:对属性的访问权限进行了封装,私有的只能自己用,公共的谁都可以用。
2、封装方法:普通方法也可以使用关键字进行封装,效果一样,私有的方法别人不能用。
3、对私有的属性,可以封装一套获取方法和设置方法,分别是set和get
Set别人设置我当前的私有属性的数据。
Get别人获取使用我当前的私有属性的数据。
4、在创建对象的时候进行封装:构造方法
创建对象的过程中,我需要创建出来的对象是空对象,那么就用空参构造方法。
创建对象的过程中,我需要创建出来的对象是带有数据的对象,不是一个空对象,那么我们就使用有参构造方法来创建。
如果对象中不写构造方法,默认就有空参,如果写了那么就使用写了的,如果只写有参不写空参,那么就无法使用空参创建对象。默认的空参在你写了有参的时候就会消失,需要手动再写空参才能正常使用。
5、构造方法和普通方法一样,可以方法名相同,但是参数数据类型与数量不能相同,必须在同一个对象中,我们称之为是方法的重载。
重载:方法名必须相同,参数类型不同。
重载:可以修改方法的访问修饰符,可以修改返回类型,无返回还是有返回。
6、封装四个关键字使用的范围
位置 |
private |
默认的 |
protected |
public |
同一个类 |
是 |
是 |
是 |
是 |
同一个包内的类 |
否 |
是 |
是 |
是 |
不同包内的子类 |
否 |
否 |
是 |
是 |
不同包并且不是子类 |
否 |
否 |
否 |
是 |
注意:当前属性如果需要完全给别人使用,我们就需要设置公共的:public
注意:当前属性如果只能自己完成,别人不能使用,我们就需要设置私有的:private
注意:private 使用:方法:get方法与set方法,可以被别人使用。
2、 继承
1、 继承:子类继承父类,子类可以使用父类的所有的非私有的属性和方法
2、方法的重写,需要注意事项:
1、方法名必须相同。
2、必须是继承或者实现关系。
3、重写方法传递的形参必须与父类的方法保持一致,不能设置其他形参。
4、重写的方法,访问权限封装关键字:子类的访问权限可以修改,但是权限的大小一定要比父类大。不能比父类小。
3、方法的重载和重写的区别
1、方法的重写:必须有子父类的关系,子类重写父类的方法,提升方法的功能,重写方法中,修饰符子类需要比父类更大不能更小,也可以相同。方法名必须相
同,参数和返回值也必须相同。
2、方法的重载:在当前自身对象中,提供多种相同的方法,但是有区别的是,修饰符可以不一样、返回值可以不一样、但是方法名必须相同、小括号内参数,参
数类型不同或者参数数量不同来区分。
一个是发生在自己当前对象的:方法重载:overload
一个是发生在子父类对象的:方法重写:override
3、 多态
1、多态创建出来的对象,可以执行调用父类的非私有的属性和方法。
2、使用多态,如果要想调用子类的方法,那么子类的方法,必须是父类重写的方法。否则无法调用。
当前使用多态创建出来的对象,如果当前的方法,是子类重写父类的方法,那么就优先调用执行。如果当前的方法,子类没有重写父类的方法,
那么调用的就是父类的方法。
3、多态调用执行:
1、多态优先调用子类重写父类的方法。
2、多态可以调用父类的非私有方法。
3、多态可以调用父类的非私有属性。
4、多态不能调用子类的非私有属性。
5、多态不能调用子类的非私有方法。
4、解决多态不能调用子类的非私有属性和方法。
如果使用多态想要调用子类的特有属性和方法的话。我们需要将多态创建出来的对象,进行强制类型转换。将父类转换成子类。
5、多态使用的细节总结:
1、使用多态必须是有继承或者实现关系的。
2、使用多态我们如果需要调用子类的方法,必须是重写方法,重写方法的权限最大。
3、使用多态创建出来的对象,不能调用子类的特有属性和方法,如果真想调用,我们就需要使用到强转。
注意:在强转的过程中,大家很有可能会出现一个异常:ClassCaseException:类型转换异常。
4、注意:为了避免后期大家出现类型转换的错误,我们事先可以先测试判断一下类型转换是否正确:instanceof
5、当前我们可以使用到,关键字进行判断,判断出来的结果,就是正确或者错误,我们判断当前转换的类型,是否合格,如果合格我们就转换,如果不合格我们
就不转换,就能解决类型异常的问题。
4、 抽象类
1、抽象类:光定义方法但不实现方法。
2、抽象方法,只能出现在抽象类或者是接口中,不能出现在普通方法中。抽象方法:当前只定义,不实现。例:父亲的愿望需要儿子去实现(俗称:负债子还)。
3、创建一个抽象类:关键字:abstract。
抽象类,其实和普通类类似,可以有属性、构造方法、普通方法、get方法set方法等等。但是,抽象类中还可以定义抽象方法。
4、在抽象类中,定义抽象方法
5、子类如果实现的是抽象类,那么必须实现抽象方法(一定要对抽象方法进行重写)
如果子类不重写父类的抽象方法,就会一直报错。
6、创建对象的过程中,抽象类是不允许被创建出来的
抽象的对象,是不允许直接被new创建的。
抽象类,如果要想创建,我们就需要使用对应的实现类(儿子创建)
7、 抽象类的出现:抽象类当中存在抽象方法,如果要想实现,那么就需要子类完成。但是抽象类,又不能直接初始化,还是得用多态来初始化。
多态的产生,其实有两部分的原因:
1、 多态让创建对象,变的更加的灵活,根据用户的选择可以动态的进行创建。
2、 抽象类与接口是不能直接被创建的,而是需要通过多态的创建方式,让子类具体实现,完成创建工作。
8、抽象类总结:
1、抽象类不能被final修饰,因为抽象类必须要有儿子。
2、抽象类不能在方法中使用 final修饰,因为抽象类的抽象方法必须要被重写。
3、抽象类可以继承抽象类,所有的抽象方法需要在实现类中一起实现。
4、抽象类中可以有抽象方法,也可以有普通方法、属性、构造方法。
5、 接口
1、定义接口关键字:interface
2、接口中方法都是抽象方法,不能有方法体。不能有普通方法,不能有构造方法。当前的接口中,只能有抽象方法,不能有实体方法。
3、定义接口中的属性:接口中不能有变量,只能存在常量。当前的属性也可以使用静态来修饰。
使用静态修饰的好处:接口对象名称调用属性可以直接调用。
4、接口能否被final修饰?
1、接口是不能被final修饰的。
2、接口中的方法不能被final修饰。
3、接口中的属性可以被final修饰,因为默认就是使用的final。
5、使用接口:接口是不能直接被new出来的。所以当前必须先有实现类。
6、Java的关系映射:单继承、多实现。
单继承:对象与对象间,继承只能继承1次。
多实现:对象与接口,一个对象可以实现多个接口。
7、接口和抽象类的区别:
1、抽象类可以有普通方法和抽象方法。
2、抽象类中定义的属性是变量。
3、抽象类可以继承抽象类或者普通类。
4、抽象类可以实现接口,但是没有必要。
5、抽象类不能直接创建,需要用多态的方法创建。
1、接口中只能有抽象的方法。
2、接口中属性是常量定义。
3、接口可以继承接口,但不能实现。
4、接口继承是多继承,抽象类继承是单继承。
5、不管是接口还是抽象类,对象不能使用final修饰。方法不能使用final修饰。
因为后期在Java中开发项目,项目后期肯定要维护升级的,我们如果使用抽象类,就只能单继承,不方便维护,让项目加大了局限性。而使用接口的话,实现的接口数
量不限,可以多实现,解决了项目后期更新的局限性问题。
理解:
抽象类就相当于是领导,领导定义任务,员工完成。
接口就相当于是规范,接口制定规范,所有员工需要遵守。
6、 关键字
1、 this关键字
this对象:this关键字就是当前对象的引用关键字,用来区分传递形参与当前对象内的参数区别开来。
2、 super关键字
1、构造方法中使用super:
Super必须放在前面。
Super需要带有小括号。带有小括号就会调用父类对应的构造方法。
2、super在普通方法中使用
Super如果在普通方法中使用,那么直接使用super即可,不需要添加小括号,不添加小括号的super,是直接引用的父类对象,不是构造方法。
3、 static关键字
1、static关键字修饰方法,我们无需new对象,即可通过类名调用方法。
2、static关键字修饰属性,我们无需new对象,即可通过类名调用属性。
3、原因:static修饰的属性和方法,在生成.class文件的时候就会被初始化出来。
4、static可以设置一个静态代码块:
Static{ }:运行的方式,是程序执行的时候,第一次就调用的,运行权限比构造方法还要大。程序一运行,第一个就调用的是静态代码块。
使用场景:后期初始化数据的时候,我们会使用到。
5、static缺点:如果是static修饰的属性和方法,声明周期就会拉长,内存数据回收就会变得不方便,有些占用内存,后期在项目中,如果数据庞大的情况下,还是尽量少使用。
4、 final关键字
1、final可以修饰class属性对象,被final所修饰的对象,将不能被继承。
2、final可以修饰属性,被修饰的属性,就从变量变成了常量,不可修改。
3、final修饰的方法,当前的方法只能使用,不能被重写。
7、 内部类
1、内部类:在当前的对象内,再创建一个对象,称之为内部类
2、我们创建内部类对象规则:
内部类,必须在类对象的括号内创建,命名不能带有小括号。
3、初始化内部类。
注意:因为当前的对象是内部对象,所以先要将外部对象创建出来,再来创建内部对象,外部对象创建内部对象中,使用到了调用,所以创建内部对象的时候,前面需要带
上小点,进行调用。
4、内部对象,是否会生成.class文件:
会生成一个Animal$Cat.class文件,因为是否生成class文件,取决于是否使用了class关键字
5、内部类一样和外部类使用,只是内部类是写在对象内的。一样也可以封装、继承、多态
6、匿名对象:就是没有名字的对象,一般使用在创建对象的时候。
注意:当前调用的方法与创建的对象,只会执行一次,它是一次性写法。因为没有给对象在创建的时候命名,所以方法执行完,对象也会随着消失销毁在内存中。所以如果
需要再次调用方法,那么就需要重新再次创建对象。
7、匿名内部类:在当前类中创建一个类,但是不给名称。(因为抽象类与接口不能直接被new,要先直接初始化其实也有方法,我们当前就需要使用匿名内部类)
8、匿名内部类,也会生成一个class文件,虽然没有明文写出,生成的class文件还是会出来,命名使用的是1命名。
三、 常用API
1、引用数据类型:
1、基本数据类型:8种:
整数类型:byte、short、int、long
浮点类型:float、double
判断类型:boolean
字符类型:char
2、引用数据类型:9种:
整数类型:Byte、Short、Integer、Long
浮点类型:Float、Double
判断类型:Boolean
字符类型:Character
字符串:String
3、字符和字符串的区别:
1、字符是基本数据类型,字符串是引用数据类型。
2、字符定义的字符可以转换为对应的ascii表,对应的数字,可以进行加减乘除。
3、字符串因为是常量,数据是在常量池中,只能做对应的加法,是拼接。其余的减乘除都是不行的,因为String是不支持的
4、String对象,创建的几种不同方式。
直接创建:从常量池就能直接拿到对应的常量数据
通过new关键字创建:常量池常量传递给堆,堆再给栈。
5、String创建的字符串都是常量,不能修改,修改的话就是重新在来生成一个,原有的就会等待回收机制回收。
6、String构造方法中,我们可以给空的、也可以给具体的String字符串、还可以给对应的数组让数组对应的字符或者数字来生成一个字符串。
7、 自动装箱与自动拆箱
基本数据类型,转换为引用数据类型,自动装箱。
引用数据类型,转换为基本数据类型,自动拆箱。
2、StringBuffer和StringBuilder
1、String:字符串常量
StringBuffer:字符串变量
StringBuilder:字符串变量
2、线程安全
StringBuilder:线程非安全的
StringBuffer:线程安全的
3、三者使用:
1.如果要操作少量的数据用 = String
2.单线程操作字符串缓冲区 下操作大量数据 = StringBuilder
3.多线程操作字符串缓冲区 下操作大量数据 = StringBuffer
4、
1、StringBuffer对象,默认长度是:16
2、StringBuilder对象,默认长度是:16
3、Date
1、Date日期对象,我们就是通过它将对应的毫秒值转化为我们看的懂的日期对象。
2、Date对象中,重写了toString方法,里面含有对应的返回日期格式。我们看完后,查看到了对应的英文字母,这些就是定义日期格式的关键字符。
3、当前我们如果需要自己定义日期显示的样式,我们就需要对应设置自己所需要的字母关键字符,但是Date里面是没有给我们提供设置方法的,我们需要使用到日期的帮助类:SimpleDateFormat
4、SimpleDateFormat对象,对Date日期对象进行了一个显示内容的封装,让当前的日期,可以根据用户自身的需求进行自定义格式。但是自定义格式中,我们需要通过字母将格式设置完成后,才能使用。
5、当前Date与SimpleDateFormat对象两个相结合,最终就能得到我们想要的日期格式,日期格式显示出来的内容,就是根据毫秒值来转换的。
6、日期为什么需要使用毫秒值,避免时间重复,时间计算是需要非常精准的。因为任何项目如果时间戳出了问题,就会产生不可逆的异常。
四、 集合
1、 三个集合的区别
List |
ArrayList |
底层是数组 |
查询速度快,增删改慢 |
线程不安全 |
效率高 |
LinkedList |
底层是双向链表 |
增删速度快,查询慢 |
线程不安全 |
效率高 |
|
Vector |
底层是数组 |
查询快,增删慢 |
线程安全 |
效率低 |
|
ArrayList 初始容量为10,自增长度是(10*3/2)+ 1。 Vector 内部数据数组的大小为10,其标准容量增量为零。 |
Set |
HashSet |
底层是HashMap |
存取速度快, |
线程不安全 |
无序,不可重复 |
可以存储null,但只能放入一个null |
TreeSet |
底层是红黑树 |
排序存储 |
线程不安全 |
有序,不可重复 |
不可以存储null |
|
HashSet其底层HashMap实例的默认初始容量是16,加载因子是0.75 |
Map |
HashMap |
底层是Hash表(数组+链表) |
效率高 |
线程不安全 |
键值可以存储null,但只能存储一次,不然会被覆盖 |
HashTable |
底层是Hash表(数组+链表) |
效率低 |
线程安全 |
不可以存储null |
|
HashMap 默认初始容量是16,加载因子是0.75 HashTable默认初始容量是11,加载因子是0.75 |
2、 集合的关系图
1、汇总:
Collection:是集合中的一个接口父类,它是一个分支,子类实现接口中:List和Set
Map:也是集合中的一个接口父类,子类中是:HashMap、HashTable
2、Map接口集合,与Collection区别:
Map结构分为:k v,俗称键值对。
K:key:键
V:value:值
在map集合中,k就是键,是主键的意思,不能重复。V就是值,值可以重复。
在List集合中,角标就是键,里面的内容就是值。角标从0开始,没有重复的。
五、 IO流
1、我们所学习的所有IO:
FileWriter:文件的字符输出流,是Writer的子类。
FileReader:文件的字符输入流,是Reader的子类。
BufferedWriter:字符高效输出流,当前默认有缓冲区。
BufferedReader:字符高效输入流,当前默认有缓冲区。
FileOutputStream:文件字节输出流,当前是万能输出流。
FileInputStream:文件字节输入流,当前是万能输入流。
BufferedOutputStream:文件高效字节输出流,当前默认有缓冲区。
BufferedInputStream:文件高效字节输入流,当前默认有缓冲区。
ObjectOutputStream:对象输出流
ObjectInputStream:对象输入流
只能将支持 java.io.Serializable 接口的对象写入和读取到流中。
2、文件的嵌套复制,递归
在文件夹复制的工作中,文件夹中还有存在子文件夹,嵌套存在深度不一致多,有的多有的少。我们需要复制过程中考虑全面,就需要将代码嵌套比较的多,效率极低。
当前解决的办法:使用的是递归来解决文件夹嵌套创建的问题。
递归的好处:不断调用自身,进行文件夹创建。
递归使用的注意事项:
需要递归的过程中,设置出口,停止定义,否则就会一直调用导致堆栈溢出。
递归的算法:当前重复调用方法,直到拿到预期的目标跳出递归,进入出口。
递归的使用中:
入口:调用自身。
出口:得到预期的目标,跳出进入出口,结束调用自己。
3、 IO流,分为字节流和字符流
1、字节流和字符流
字符流:只能对文本文档操作的流对象,因为当前读写设置的是char类型的容器。
字节流:是万能流,不仅可以对文本文档操作,还能对其他类型的文档操作,比如图片、视频、音频等等,因为当前读写设置的容器类型为byte类型,根据字符的编码存储编码的序号数字,进行转译。
2、字节流与字符流,当前的效率字节流要快于字符流。
字节流复制文件,一个需要800多毫秒即可,但是字符流复制文件,一个需要7秒,同样的大小200多MB的文件。
1、 在公司中开发,我们常用的是字节流,因为字节流对应功能局限性小,效率高。
2、 当前我们学习字符流和字节流中,我们还学习了对应的高效输出输入流。
3、 字节高效的输入输出流,要快于普通字节流,快的速度800毫秒可以缩短到300毫秒。
字符流也是同理,高效的要高于普通的,因为高效的可以读取一行,直接写入,需要换行写入的时候可以插入换行。
3、为什么高效的要快:因为当前底层设置了缓冲区,我们可以创建高效流的同时使用默认缓冲区,或者自定义缓冲区,我们一般使用默认即可,因为默认已经足够我们使用了。
默认缓冲区大小:8192字节。
六、 多线程
1、 多线程的开启方式
1、方法一:自己创建一个对象,继承多线程对象,进行创建多线程。
2、方法二:通过实现一个接口Runnable接口,让多线程对象使用。
2、 多线程设置同步锁
1、方式一:使用同步代码块:关键步骤上锁
注意:锁对象必须是一致的,一般使用class文件,保持一致。或者使用单例设计模式创建对象。
2、方式二:同步方法:将整个方法进行上锁
注意:当前线程可以开启多个,但是runnable实现类必须只有一个,不能实现多个实现类,否则同步方法无效
方法三:静态同步方法,所有的对象都上锁,一锁锁所有
注意:当前如果要实现多个runnable实现类,不同的对象间使用方法锁的话,可以使用静态同步方法,这样的话就能够解决方法二不能锁住的问题。
3、方法三:静态同步方法,所有的对象都上锁,一锁锁所有
注意:当前如果要实现多个runnable实现类,不同的对象间使用方法锁的话,可以使用静态同步方法,这样的话就能够解决方法二不能锁住的问题。
3、 两种设计模式
1、 单例设计模式
懒汉式:
饿汉式:
2、 生产者与消费者模式
1、生产者生产数据到缓冲区中,消费者从缓冲区中取数据。
如果缓冲区已经满了,则生产者线程阻塞;
如果缓冲区为空,那么消费者线程阻塞。
2、wait:等待方法
被等待的线程是自身唤醒的,必须得依靠别的线程或者对象唤醒,唤醒通过锁对象调用唤醒方法。
3、notify:唤醒方法(唤醒单个)
唤醒单个:随机唤醒等待的线程中的一个线程
4、notifyAll:唤醒方法(唤醒全部)
唤醒全部:将当前所有等待的线程进行唤醒,唤醒后不一定所有线程都执行,具体谁执行还需要看CPU给谁分配了资源抢占了锁对象。
注意:当前锁对象如果不是同一把锁,就无法唤醒,同时也可能产生一直等待的状态,线程堵塞
5、sleep方法,当前休息睡眠一定的时间后,自己就能够清醒过来,进行继续运行。
区别:等待唤醒机制,如果当前处于等待的状态,就会释放锁对象,丢给其他对象使用并且执行,当前自身处于等待不执行的状态。 睡眠方法,则不同,当前线程如果是睡眠方法,那么在睡眠的过程中是不会释放锁资源的,等清醒后,继续操作执行,直到执行结束,结束操作,释放锁资源,提供给其他对象使用。
七、 网络编程
1、网络编程的三要素:IP地址、端口号、网络协议。
2、网络协议:底层协议:UDP、TCP
UDP:直接连接的网络协议,一般使用的场景:视频、语音、聊天室。
TCP:三次握手连接,一般使用的场景:传输图片、发送聊天文字等等。
区别:
UDP:效率快,但是数据丢失无法找回,数据传输不稳定。
TCP:效率相对慢,传输的数据,稳定丢失比较低。
使用网络协议传输的过程中,我们基本上使用的都是流对象传输。
八、 反射与正则表达式
1、反射
1、对象反射的方式一共有:三种
第一种:创建出来对象,通过对象的引用获取。
第二种:通过类的包名 + 类名直接寻找。
第三种:直接通过类名调用class关键字。
2、暴力访问,将setAccessible的状态设为true,然后就可以获取私有的属性和方法。
2、正则表达式
1、使用一个正则对象
|
matcher |
|
matches |
使用示例: