JavaSE-知识点总结
远离颠倒梦想 人气:1Java名词
变量、运算符、类、接口、枚举、参数、注解、异常、包装类、多线程、 集合、IO流、网络编程、反射、Lambda、API
源文件:.java文件,存储Java源代码的文件
字节码文件:.class文件,由Java源代码编译后生成的.class文件,可以被JVM读取和执行的文件。
运行Java程序,其实就是执行.class字节码文件,由JVM把字节码数据再转为二进制的机器指令执行。
数据类型
基本数据类型:8种,byte,short,int,long,float,double,char,boolean
引用数据类型:类、接口、枚举、数组、注解
变量
变量根据数据类型的不同分为基本数据类型的变量和引用数据类型的变量。
变量根据声明位置不同分为成员变量和局部变量
(A)局部变量声明位置:
①方法的形参列表
②方法体{}中
③代码块{}中
成员变量声明位置:类中,方法和代码块外面,按照是否有static修饰分为:类变量(静态变量) 和 实例变量(非静态变量)
(B)内存存储的位置不同
局部变量:栈
实例变量:堆
类变量:方法区
(C)生命周期
局部变量
每一个线程每一次调用都是一次新的生命周期
实例变量:每一个对象的成员变量是独立的,和对象的生命周期一致
类变量:和类的生命周期一致
(D)作用域
局部变量:作用域非常小,从声明它的位置开始,到它所属的}结束,可能只属于某个if,for,方法等
类变量:整个类中
实例变量:整个类中除了静态方法和静态代码块中不能使用
(E)修饰符
局部变量:唯一可以有的修饰符是final
成员变量:权限修饰符、static、final、....
运算符
整数与整数相除,只保留整数部分
取模结果的正负号只看被模数
++/--在前的,就先自增/自减,后取值
++/--在后的,就先取值,后自增/自减
所有的赋值运算符的=左边一定是一个变量,而且先算右边,然后最后把值赋值给左边的变量
扩展赋值运算符+=右边的计算结果的类型如果比左边的大的话会强制类型转换,所以结果可能有风险。
比较表达式的运算结果一定只有true/false
& 只有左右两边都为true,结果才为true。
| 只要左右两边有一个为true,结果就为true。
^ 只有左右两边不同,结果才为true。
! 布尔值取反
&&它和逻辑与不同的是当&&左边为false时,右边就不看了。
||它和逻辑或不同的时当||左边为true时,右边就不看了。
条件表达式 ? 结果表达式1 : 结果表达式2 //为true返回1,否则返回2
位运算符:所有的位运算符的规则都是用数字的二进制补码形式进行运算的
<< 左移动几位,右边补0。左移几位就是乘以2的几次方
>> 右移动几位,左边补0或1,看最高位。右移几位就是除以2的几次方
>>> 右移动几位,左边一律补0
按位与:& 运算规则,把两个数的二进制一一对应,对应位按位与。
按位或:| 运算规则,把两个数的二进制一一对应,对应位按位或。
按位异或:^ 运算规则,把两个数的二进制一一对应,对应位按位或。
按位取反:~ 运算规则,把某个数的二进制,按位取反,注意:包括最高位也会取反,这个和从原码到反码是不一样的。
优先级:需要先计算的就用()括起来
对象1 == 对象2 //比较的是地址,而且对象1和对象2的类型要一致或者是父子类关系,否则编译不通过
对象 instanceof 类型
只有当该对象属于这个类型才会返回true,而且要求该对象的编译时类型必须与要判断的类型一致或有父子类关系
引用数据类型的类型或对象,可以通过 . 来访问属性、方法等。
()用于强制类型转换或优先计算强制类型转换
流程:解决问题的步骤
(1)顺序语句:顺序结构
(2)分支语句:选择其中一个分支执行
(3)循环语句:重复执行某些代码
凡是有[]的都是数组
类(class)
使用class声明的类型都是类
【修饰符】 class 类名 【extends 父类】 【implements 父接口n】{
}
类中可以包含5个部分:
(1)成员变量:
静态成员变量:存储类共享数据
非静态成员变量:存储对象独立数据
(2)成员方法:完成功能
(3)构造器:创建对象,是实例初始化的一部分
(4)代码块:
静态代码块:类初始化的一部分
非静态代码块:实例初始化的一部分
(5)成员内部类/成员内部接口:为外部类服务
接口(interface)
使用interface声明的类型都是接口
【修饰符】 interface 接口 【extends 父接口们】{
}
接口中的成员有限制要求:
JDK1.8之前:
(1)公共的静态的常量:public static final
(2)公共的抽象方法:public abstract
JDK1.8之后,增加了:
(3)公共的静态方法:public static
(4)公共的默认方法:public default
方法重写的要求
(1)修饰符:>=父类权限
(2)返回值类型
基本数据类型和void:必须相同
引用数据类型:<=父类类型
(3)方法名:必须相同
(4) 形参列表:必须相同
(5)抛出的异常类型:<=父类类型
(6)被重写的方法不能是:static,final,private等
枚举(enum)
使用enum声明的类型都是枚举
【修饰符】 enum 枚举类型名 【implements 父接口们】{
}
枚举是一种特殊的类:
(1)枚举的首行必须是枚举的常量对象列表;
(2)枚举的构造器都是private
(3)枚举的直接父类一定是java.lang.Enum类
参数
参数就是一种传递数据的方式,所以参数就是一个变量,具有特殊作用的特殊位置的变量。
和参数相关的几个名词:
(1)形参(formal parameter)
在声明方法时()中的参数
(2)实参(actual parameter)
在调用方法时()中的参数,实参是给形参赋值的,所以实参的个数、类型、顺序必须与形参一一对应。
(3)有参(has parameter)
声明方法时有形参列表,调用方法时有实参列表
(4)无参(no parameter)
声明方法时没有形参列表,调用方法时没有实参列表
(5)命令行参数(command line parameter/ arguments)
运行main时,给main传的参数
java 类名 命令行参数1 命令行参数2 ....
(6)可变参数(variable parameter)
声明:
【修饰符】 返回值类型 方法名(【非可变参数部分的形参列表,】 可变参数类型... args)throws 异常列表{
for(int i=0; i<args.length; i++){ //可变参数部分当做数组使用
//...
}
}
(7)类型参数(type parameter,generic Type)
凡是代码中出现在<>中的类型,就是类型参数。
(8)类型形参(type parameter)
在声明类/接口时声明的类型参数,也称为泛型形参
【修饰符】 class 类名/接口<类型形参列表>{}
【修饰符】 class 类名/接口<类型形参1 extends 父类上限 & 父接口上限>{}
在声明方法时声明的类型参数
【修饰符】 <泛型形参列表> 返回值类型 方法名(【数据形参列表】)【throws 异常列表】{}
【修饰符】 <泛型形参 extends 父类上限 & 父接口上限> 返回值类型 方法名(【数据形参列表】)【throws 异常列表】{}
(9)类型实参(type arguments)
在使用泛型类/接口时指定泛型类型的类型参数
在使用泛型方法时传给泛型类的变量会自动识别变量类型,即为泛型方法实参
(10)传参(pass parameter)
凡是实参给形参赋值都是叫做传参。
记住:实参与形参的类型、个数、顺序一一对应即可。
注解(annotation)
使用@interface声明的类型都是注解,只要使用@标记符的都是注解
@元注解
【修饰符】 @interface 注解名{
数据类型 参数名();
数据类型 参数名() default 默认值;
}
(1)如果注解有配置参数,那么在使用时,需要给配置参数赋值,除非有默认值
(2)给配置参数赋值的标准格式:参数名 = 参数值,但是如果注解的配置参数只有一个,而且名称是value,那么在赋值时可以省略value=
(3)如果配置参数是数组类型,那么赋值时可以用“{多个值}”
@Override
用于检测被修饰的方法为有效的重写方法,如果不是,则报编译错误!
只能标记在方法上。
JUnit单元测试
- @Test:标记在非静态的测试方法上。需导入junit包
文档注解:
-
@author 标明开发该类模块的作者,多个作者之间使用,分割
-
@version 标明该类模块的版本
-
@see 参考转向,也就是相关主题
-
@since 从哪个版本开始增加的
-
@param 对方法中某参数的说明,如果没有参数就不能写
-
@return 对方法返回值的说明,如果方法的返回值类型是void就不能写
-
@throws/@exception 对方法可能抛出的异常进行说明 ,如果方法没有用throws显式抛出的异常就不能写
-
其中 @param @return 和 @exception 这三个标记都是只用于方法的。
-
@param的格式要求:@param 形参名 形参类型 形参说明
-
@return 的格式要求:@return 返回值类型 返回值说明
-
@exception 的格式要求:@exception 异常类型 异常说明
-
@param和@exception可以并列多个
-
异常(Exception)
Java异常和错误的根父类:java.lang.Throwable
(1)只有是这个类或它的子类的对象,才能被JVM或throw语句“抛”出
(2)也只有这个类或它的子类的对象,才能被catch给“捕获”
(3)如果用户需要自定义异常,那么必须继承Throwable或它的子类。
Java异常的分类:
- Error:错误,合理的应用程序不应该试图捕获的异常.
- Exception:异常,合理的应用程序应该、想要捕获的异常。 Java异常的分类:
- 运行时异常(非受检异常):RuntimeException及其子类,编译器不会提示你需要加try...catch处理
- 编译时异常(受检异常):RuntimeException系列以外的,编译器一定会要求你加try...catch处理的
不管是什么异常,最终都要进行处理,如果不处理,会导致程序终止运行
try:尝试执行某些代码,看是否会发生异常
catch:尝试捕获某个异常,如果可以捕获,就处理它
finally:无论try中是否有异常发生,也不管catch是否可以捕获这个异常, 哪怕try或catch有return,都无法阻止我运行finally中的代码。
throw:手动抛出异常对象
throws:在方法声明时,显式的说明该方法会抛出xx异常,提醒调用者要处理这些异常。
语法:
try{
}catch(...){
}finally{
//无论try中是否发生异常,也无论catch是否捕获异常,也不管try和catch中是否有return语句,都一定会执行
}
或
try{
}finally{
//无论try中是否发生异常,也不管try中是否有return语句,都一定会执行
}
新try..catch
语法格式:
try(需要关闭的资源对象的声明){
业务逻辑代码
}catch(异常类型 e){
处理异常代码
....
它没有finally,也不需要程序员去关闭资源对象,无论是否发生异常,都会关闭资源对象
常见的异常类型
包装类
char ->Character
byte -> Byte
short -> Short
int -> Integer
long -> Long
float -> Float
double -> Double
boolean -> Boolean
void -> Void
装箱:把基本数据类型转为包装类对象。
拆箱:把包装类对象拆为基本数据类型。
包装类对象有缓存问题
在缓存范围内的对象,缓冲的常量对象在方法区直接引用。没有缓存的对象,每一个都是新new的
多线程
创建多线程的两种方式(JavaSE阶段)
1、 继承Thread类
(1)编写线程类,继承Thread类
(2)必须重写public void run(){}
(3)创建自定义线程类的对象
(4)调用start()方法启动线程
2、实现Runnable接口
(1)编写线程类,实现Runnable接口
(2)必须重写public void run(){}
(3)创建自定义线程类的对象
(4)通过Thread类的代理对象,调用start()方法启动线程
如:MyRunnable my = new MyRunnable();
Thread t = new Thread(my);
t.start();
线程安全问题
1、什么情况下会有线程安全问题? 多个线程使用了共享数据
2、如何解决线程安全问题? SE阶段:synchronized
(1)同步代码块
synchronized(锁对象){
//在一个线程执行期间,不想要被其他线程打扰的代码,一般是一次事务的原子性操作。
}
锁对象:自选的,但是要保证使用共享数据的这多个线程必须共用一个锁对象(监视器对象)
至于是否可以选用this作为锁对象,要看是否多个线程共用同一个this对象
(2)同步方法
【修饰符】 synchronized 返回值类型 方法名(【形参列表】){
//在一个线程执行期间,不想要被其他线程打扰的代码,一般是一次事务的原子性操作。
}
锁对象:固定,非静态方法就是this,静态方法就是当前类的Class对象
多线程间的通信就是通过锁对象调用wait()等待与锁对象调用notify()唤醒来达到多线程间的调度
集合
集合:是一种容器,用来装对象的容器,不能装基本数据类型。也可以说是一种数据结构
Collection
中的集合称为单列集合,Map
中的集合称为双列集合。
Iterator迭代器
元素的通用获取方式。在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续在判断,如果还有就再取出出来。一直把集合中的所有元素全部取出。
List 集合额外提供了一个ListIterator迭代器用来专门操作 List 集合的一些方法
List
- List集合所有的元素是以一种线性方式进行存储的
- 它是一个元素存取有序的集合。
- 它是一个带有索引的集合
- 集合中可以有重复的元素
ArrayList、Vector 顺序结构,线性的,动态数组的实现
Stock 链式结构,先进后出,栈结构
LinkedList 链式顺序结构,双端队列,双链表的实现,既可以用作FILO堆栈使用,又可以用作FIFO队列使用。
Set
- Set接口是Collection的子接口,set接口没有提供额外的方法
- Set 集合不允许包含相同的元素
HashSet、底层new的 HashMap
- HashSet 按 Hash 算法来存储集合中的元素,因此具有很好的存取和查找性能。
- 存储到HashSet的元素要重写hashCode和equals方法。
LinkedHashSet 、底层new的 LinkedHashMap
- LinkedHashSet是HashSet的子类,增加两个属性before和after维护了结点的前后添加顺序
- LinkedHashSet插入性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很好的性能。
TreeSet 底层new的TreeMap
- 不允许重复
- 实现排序 自然排序或定制排序
Map
- Map中的集合不能包含重复的键,值可以重复;每个键只能对应一个值
- Map.Entry是Map接口的内部接口,实际上是将Key---->value的数据存储在Map.Entry接口的实例中,再在Map集合中插入Map.Entry的实例化对象
- 判断两个 key 相等的标准是:两个 key 的hashCode 值相等,并且 equals() 方法也返回 true,用作键的对象必须实现 hashCode 方法和 equals 方法
HashMap、Hashtable
- 动态数组结构+链式结构或哈希结构, 是个散列表,其中维护了一个长度为2的幂次方的Entry类型的数组table,数组每个元素又由链表或红黑树结构组成
LinkedHashMap
- 是HashMap的子类,与之不同的在于LinkedHashMap维护着一个运行于所有条目的双重链接列表,此链接列表定义了迭代顺序,该迭代顺序通常就是(插入顺序)
TreeMap
- 基于红黑树的 NavigableMap 接口实现。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator 进行排序,具体取决于使用的构造方法。
Properties
- 是 Hashtable 的子类,Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串
Collections 是一个操作 Set、List 和 Map 等集合的工具类
IO流
File类:文件和目录路径名的抽象表示形式。File
类的实例是不可变的
IO流是用于数据输入与输出
1、四大超类,抽象类
(1)InputStream:字节输入流
(2)OutputStream:字节输出流
(3)Reader:字符输入流
(4)Writer:字符输出流
2、常见IO流
(1)文件IO流
FileInputStream:文件字节输入流,可以读取任意类型的文件
FileOutputStream:文件字节输出流,可以把字节数据输出到任意类型的文件
FileReader:文件字符输入流,只能读取纯文本的文件。按照平台默认的字符编码进行解码。
FileWriter:文件字符输出流,只能把字符数据输出到纯文本文件。按照平台默认的字符编码进行编码。
(2)缓冲IO流
BufferedInputStream:字节输入缓冲流,给InputStream系列IO流增加缓冲效果
BufferedOutputStream:字节输出缓冲流,给OutputStream系列IO流增加缓冲效果
BufferedReader:字符输入缓冲流,给Reader系列IO流增加缓冲效果
String readLine():按行读取
BufferedWriter:字符输出缓冲流,给Writer系列IO流增加缓冲效果
void newLine():输出换行符
void flush()
(3)编码与解码的转换流
编码:OutputStreamWriter
可以把字符流转为字节流输出,并且可以指定字符编码。
应用场景:可将要写入的字符源为字节流的数据转为字符类型写入并可按指定字符集再编码成字节存储
解码:InputStreamReader
可以把字节输入流转为字符输入流,并且可以指定字符编码。
应用场景:读取源为字符类型的字节流可指定字符集解码成字符流,以便阅读
(4)数据IO流
DataInputStream:允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型。
DataOutputStream:允许应用程序以适当方式将基本 Java 数据类型写入输出流中。
它俩必须配对使用,读的顺序要与写的顺序一致
(5)对象IO流,同上也需配对,读写顺序一致
ObjectOutputStream:对象序列化,输出对象,把对象转为字节序列输出
void writeObject(Object obj)
- 所有要序列化的对象的类型都必须实现java.io.Serializable接口
- 如果对象的属性类型也是引用数据类型,那么也要实现java.io.Serializable接口
- 希望类的修改对象反序列化不产生影响,需增加一个序列化版本ID
- private static final long serialVersionUID = 1L;
- 如果有些属性不想要序列化,可以加transient
- 如果某个属性前面有static修饰,也不参与序列化
ObjectInputStream:对象反序列化,读取对象,把字节序列重构成Java对象
Object readObject()
(6)打印流
PrintStream、PrintWriter:println()和 print()
(7)文本扫描仪
Scanner
网络编程
三要素:1.协议。2.IP地址。3.端口号
Socket:通信的两端都要有Socket(也可以叫“套接字”),是两台机器间通信的端点。网络通信其实就是Socket间的通信。
TCP
TCP协议是面向连接的通信协议,即传输数据之前,在发送端和接收端建立逻辑连接,是一种面向连接的、可靠的、基于字节流的传输层的通信协议,可以连续传输大量的数据。
服务器端
-
调用 ServerSocket(int port) :创建一个服务器端套接字,并绑定到指定端口上。用于监听客户端的请求。
-
调用 accept() :监听连接请求,如果客户端请求连接,则接受连接,返回通信套接字对象。
-
调用 该Socket 类对象的 getOutputStream() 和 getInputStream () :获取输出流和输入流,开始网络数据的发送和接收。
-
关闭Socket 对象:客户端访问结束,关闭通信套接字。
客户端
-
创建 Socket :根据指定服务端的 IP 地址或端口号构造 Socket 类对象。若服务器端响应,则建立客户端到服务器的通信线路。若连接失败,会出现异常。
-
打开连接到 Socket 的输入/ 出流: 使用 getInputStream()方法获得输入流,使用getOutputStream()方法获得输出流,进行数据传输
-
按照一定的协议对 Socket 进行读/ 写操作:通过输入流读取服务器放入线路的信息(但不能读取自己放入线路的信息),通过输出流将信息写入线路。
-
关闭 Socket :断开客户端到服务器的连接,释放线路
UDP
UDP协议是一种面向非连接的协议,无连接的好处就是快,省内存空间和流量,因为维护连接需要创建大量的数据结构。UDP会尽最大努力交付数据,但不保证可靠交付,没有TCP的确认机制、重传机制,如果因为网络原因没有传送到对端,UDP也不会给应用层返回错误信息。
反射
类的加载又分为三个阶段
(1)加载:load (2)连接:link ①验证②准备③解析 (3)初始化:initialize(类初始化)即执行<clinit>类初始化方法
不会导致类的初始化的情况,其他都会
(1)使用某个类的静态的常量(static final)
(2)通过子类调用父类的静态变量,静态方法,只会导致父类初始化,不会导致子类初始化,即只有声明静态成员的类才会初始化
(3)用某个类型声明数组并创建数组对象时,不会导致这个类初始化
类加载器
(1)引导类加载器(Bootstrap Classloader)又称为根类加载器
(2)扩展类加载器(Extension ClassLoader)
(3)应用程序类加载器(Application Classloader)
(4)自定义类加载器
获取Class对象的四种方式
(1)类型名.class
(2)对象.getClass()
(3)Class.forName(类型全名称)
(4)ClassLoader的类加载器对象.loadClass(类型全名称)
反射可获取类型的详细信息
可以获取:包、修饰符、类型名、父类(包括泛型父类)、父接口(包括泛型父接口)、成员(属性、构造器、方法)、注解(类上的、方法上的、属性上的)
创建任意引用类型的对象两种方式
1、直接通过Class对象来实例化(要求必须有无参构造)
2、通过获取构造器对象来进行实例化
操作任意类型的属性
(1)获取该类型的Class对象 Class clazz = Class.forName("com.atguigu.bean.User");
(2)获取属性对象 Field field = clazz.getDeclaredField("username");
(3)设置属性可访问 field.setAccessible(true);
(4)创建实例对象:如果操作的是非静态属性,需要创建实例对象 Object obj = clazz.newInstance();
(4)设置属性值 field.set(obj,"chai");
(5)获取属性值 Object value = field.get(obj);
如果操作静态变量,那么实例对象可以省略,用null表示
调用任意类型的方法
(1)获取该类型的Class对象 Class clazz = Class.forName("com.atguigu.service.UserService");
(2)获取方法对象 Method method = clazz.getDeclaredMethod("login",String.class,String.class);
(3)创建实例对象 Object obj = clazz.newInstance();
(4)调用方法 Object result = method.invoke(obj,"chai","123);
如果方法的权限修饰符修饰的范围不可见,也可以调用setAccessible(true)
如果方法是静态方法,实例对象也可以省略,用null代替
Lambda
函数式编程思想:强调做什么,而不是以什么形式做
只要能获取到结果,谁去做的,怎么做的都不重要,重视的是结果,不重视过程
函数式接口
标记了@FunctionalInterface
自定义函数式接口:只要确保接口中有且仅有一个抽象方法即可
Java8新增了四大类,消费型、供给型、判断型、功能型。
Lambda表达式语法格式
(形参列表) -> {Lambda体}
说明:
-
(形参列表)它就是你要赋值的函数式接口的抽象方法的(形参列表),照抄
-
{Lambda体}就是实现这个抽象方法的方法体
-
->称为Lambda操作符(减号和大于号中间不能有空格,而且必须是英文状态下半角输入方式)
优化:Lambda表达式可以精简
-
当{Lambda体}中只有一句语句时,可以省略{}和{;}
-
当{Lambda体}中只有一句语句时,并且这个语句还是一个return语句,那么return也可以省略,但是如果{;}没有省略的话,return是不能省略的
-
(形参列表)的类型可以省略
-
当(形参列表)的形参个数只有一个,那么可以把数据类型和()一起省略,但是形参名不能省略
-
当(形参列表)是空参时,()不能省略
方法引用与构造器引用
方法引用的语法格式:
(1)实例对象名::实例方法
(2)类名::静态方法
(3)类名::实例方法
说明:
-
::称为方法引用操作符(两个:中间不能有空格,而且必须英文状态下半角输入)
-
Lambda表达式的形参列表,全部在Lambda体中使用上了,要么是作为调用方法的对象,要么是作为方法的实参。
-
在整个Lambda体中没有额外的数据。
构造器引用的语法格式:
-
类名::new
-
数组类型名::new
(1)当Lambda表达式是创建一个对象,并且满足Lambda表达式形参,正好是给创建这个对象的构造器的实参列表。
(2) 当Lambda表达式是创建一个数组对象,并且满足Lambda表达式形参,正好是给创建这个数组对象的长度
StreamAPI
①Stream 自己不会存储元素。
②Stream 不会改变源对象。每次处理都会返回一个持有结果的新Stream。
③Stream 操作是延迟执行的。这意味着他们会等到需要结果的时候才执行。
加载全部内容