Java基础知识(全面)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章导航


前言

本文主要是总结了我学习java的基础知识点,比较详细!需要耐心食用!


一、java基础语法

1.java语言介绍

2.三大平台

JavaSE 标准版 桌面程序开发,是以下两者基础
JavaEE 企业版 网站的开发,重要
JavaME 微型版 服务端 逐渐淘汰

3.语言特点

简单开源:开放源代码; 跨平台; 面向对象; 编译性:java 代码需要进行编译,编译成字节码文件(.class),安全,高效 ;动态性:直接动态修改当前代码中的数据(反射)
跨平台性: 在多个操作系统中比如Windows,MAC,Linux上都可以运行java代码,可实现一次编写,到处执行,一次编译,到处执行(write once,run everywhere)原因: java 虚拟机:jvm ;不同操作系统,都提供了不同版本的虚拟机,又可以实现相同的功能,所以实现跨平台。

4.Jvm、jre 和 jdk

1、jvm:java virtual machine,java 虚拟机 用于运行 jvm 标准的语言,相当于 java 语言运行的一个容器。
2、Jre:java Runtime Environment,java 运行时环境 只有容器是不能单独运行的。在运行时,还需要使用其他已经定义好的类。类形成的库, 成为类库。 Jre = jvm + 运行时必须的类库
3、jdk:java development kit,java 开发工具包,(给开发人员使用) Jdk = jre + 开发工具
jdk=开发工具+jre; jre=类库+jvm; jvm=java 虚拟机

5.环境变量

java需要配置环境变量,目的是为了在任意目录下都可以直接执行java文件,因为正常来说java文件是在jdk中的bin目录下来执行的,所以我们需要在电脑的高级系统中设置path环境变量。%JAVA-HOME%\bin把它加在path里。%JAVA-HOME%表示你jdk的文件位置。

6.数据类型

java 是一个强类型语言:需要显式的说明内存空间的大小,声明变量的时候,就需要说 明变量的数据类型,以此来表示内存的大小。
1.基本数据类型:byte,short,int,long,float,double,boolean,char。数据类型表示范围的比较: byte < short = char < int < long < float < double。小的类型转为大的类型时直接转换。大的转小的时需要强转即(要转成的数据类型)需要转换的数据,例如int a;byte b = (byte)a;
2.引用数据类型:空间中存储的不是该数据本身,而是存储了某些数据的地址,数据 量比较大,数据本身比较复杂。引用:是栈内存当中的一个内存空间,存储的是一个数据的地址。

7.运算符

1.算数运算符:+ - * / % 2.自增自减运算符:++,–。++a:先去+1,再去赋值 a++:先去赋值,再去+1 。3.比较运算符,就是==,!=,<=,>=。逻辑运算符:&&与:一假为假。||或:一真即真。!非:取反。三元运算符:表达式 1?表达式 2:表达式 3;表达式1为布尔类型。结果只有真和假,真执行2,假执行3。

8.流程控制结构

顺序结构 代码从上往下执行
分支结构 if(布尔表达式){为真执行这段代码}else{为假,执行这段代码}。if(){}else if{}else{}。可以互相嵌套。
循环结构
for循环:
1、格式for(初始化表达式①;条件表达式②;变量改变④)
{ 循环体;③ }
2、执行流程: (1)初始化表达式 (2)判断条件表达式 (3)成立,进入循环体 (4)不成立,直接结束循环 (5)到循环体,变量变化情况(步进表达式) (6)回到第(2)步
while循环:
1、格式: 初始化表达式①; while(条件表达式②)
{ 循环体;③
变量改变;④ }
2、执行流程: (1)初始化表达式 (2)条件表达式 (3)成立,则执行循环体 (4)不成立,循环结束 (5)循环体,变量改变(自增) (6)第 2 步
死循环:
(1)for 语句的死循环: for ( ; ; ) { 循环体语句; }
(2)while 语句的死循环: while (true) { 循环体语句; }
死循环的作用: (1)在格式上使用了死循环,但是在循环体中,可能出现了需要循环结束的情况,准 备了一些跳出、终止循环的跳转语句。 (2)在服务器的设计中,希望服务器永远给我们服务下去,所以需要使用死循环。
跳转语句:
continue 语句: 跳出本次循环,继续下一次循环
break 语句: 终止循环

9.方法

方法的重载
1、重载:Overload
2、方法的重载: 在同一个类中,方法名相同,参数列表不同,与返回值类型无关。
3、说明: (1)在同一个类中。不同的类中,不可能发生方法的重载的。 (2)方法名称相同:一模一样。 (3)参数列表不同:参数类型不同;参数个数不同;参数类型的顺序不同; 参数的名称不同(不算) (4)与返回值类型无关。方法是否是重载,与返回值类型没有关系。 如果方法的名称和参数列表都一样,即使返回值类型不同,也不算重载,属于方法 的重复定义。
4、方法重载的好处: (1)没有重载的时候,相同逻辑相同功能的代码,需要定义很多个方法名称。调用者 在记忆方法名称的时候,就有很大的负担。 (2)有重载之后,相同功能逻辑的方法,只需要记忆一个名字。

10.数组

声明数组并分配空间:数据类型[] 数组名 = new 数据类型[数组内存大小];
数组的默认值:
1、基本数据类型
(1)整型 0
(2)浮点型 0.0
(3)字符型 空字符 ‘\u0000’
(4)布尔型 false
2、引用数据类型 null
数组的遍历:
可以通过普通for循环遍历,也可以通过增强for遍历:for(数组元素的数据类型 变量名 : 数组名){
输出变量名;
}
解释说明:
变量名就代表数组当中的依次每一个元素。java当中没有增强for循环,增强for循环只是一种特殊的编译形式。
数组的获取最值
1、给定一个数组,求出数组的最大值。
2、思路:
擂台思想:
(1)创建一个擂台,让数组当中的任意一个元素站在擂台上
(2)遍历数组,让数组当中的元素依次和擂台上的元素比较
(3)大的元素留到擂台上
(4)遍历完成之后,擂台上的元素就是最大的元素。
数组的反转
1、数组当中所存储的元素的顺序反过来,变成原来顺序的逆序,第一个元素变成最后一个元素,第二个元素变成倒数第二个元素。
2、思路:
让第一个元素和最后一个元素交换位置,第二个元素和倒数第二个元素交换位置。让对称的元素交换位置。
数组的异常
索引越界异常
1、发生的原因:
访问了数组当中不存在的索引位置,会发生索引越界异常。 数组索引的范围 0 —— 数组的长度-1
空指针异常
1、发生的原因:
引用当中存储的地址为空,不去指向数组的内存空间的时候,依旧去访问数组当中的元素,就会发生空指针异常。
2、null:表示为空,不记录任何数据以及内存地址

11.jvm的内存划分

1、jvm是java虚拟机,有很大的内存空间,在进行高效的内存使用的时候,需要根据内存功能的不同进行内存的划分,分为栈内存、堆内存、方法区、本地方法区、程序计数器。
2、栈内存【常用】:用来执行方法的,每一个需要被执行的方法都需要单独的分配一块栈内存空间,栈帧,把给方法分配栈内存空间的过程叫做方法进栈,方法执行完毕,释放栈内存的过程,叫做方法的出栈。
2、堆内存【常用】:用来存储一些引用数据类型的数据。
3、方法区【常用】:存储的是一些字节码文件,常量,静态资源。
4、本地方法区:用来执行本地方法,c语言的以及c++的一些方法。
5、程序计数器:java程序执行的时候,来记录class文件的位置以及
代码执行的行数。

二、面向对象

1.面向对象思想

1、面向对象是一种编程思想,编程思路。
2、例子:吃牛排
(1)面向过程:养牛 - 杀牛 - 洗肉 - 挖矿 - 冶炼铁 - 制造锅 - 种植调料作物 - 起锅烧油 - 放牛肉 - 放调料 - 掰树枝当筷子 - 拿出来 - 吹凉了 - 吃到了。
特点:注意力放在一步一步的步骤上,更加强调的是解决问题的细节,强调的是解决问题的方法。
(2)面向对象:找女朋友 - 让女朋友去做牛排喂我 - 吃到了
特点:注意力放在对象上,强调的是可以为我们解决问题的对象。
3、面向对象的好处:
(1)更加符合我们人类的思想习惯:人类遇到问题,都找对象解决,而不是自己解决。
(2)复杂的问题简单化
(3)由执行者上升为了指挥者
4、面向对象基于面向过程,面向过程是面向对象的基础。
5、面向对象的特征:(***)
封装
继承
多态

2.类与对象

1、类:类型,由于一些具体的事物在我们的脑海当中进行一个抽象的总结概括,抽取出来一个概念,这个概念叫类。例如:人类,手机,车,鸟类
2、对象:事物的具体体现(一个真实的存在的具体的事物)

对象的创建和使用

1、创建对象的格式: 类名 对象名 = new 类名();
2、解释说明: 类名:要创建对象所属的类的类型,例如Scanner 、Person
对象名:合法的标识符即可,和变量名字一样
= : 把创建出来的对象的内存地址复制给对象名
new:在堆内存当中开辟一块内存空间,用来存储该对象的数据。
类名:和前面声明的类名保持一致(目前)
();表示调用了一个方法,构造方法。
3、访问属性: 对象名.属性名 ;对象名.属性名 = 属性值;【赋值操作】
4、访问方法: 对象名.方法名();

对象的内存图

创建对象的步骤

1、将要创建对象的类型的class文件加载到方法区
2、在栈内存当中创建一个Phone类型的引用,将来存储Phone对象的堆内存地址
3、在堆内存开辟内存空间,对对象的成员变量进行分配内存,默认初始化值。(赋默认值,根据数据类型)
4、对堆内存当中所存储的值进行显示初始化。(String sex = “男 人”;) 5、把堆内存当中的对象的内存地址存储到栈内存当中的Phone类型的引用当中去

成员变量和局部变量的比较

1、成员变量:定义在类中方法外的变量,用来表示类的属性的变量,叫做成员变量。
2、局部变量:定义在方法中的变量以及定义在方法的形参列表上的变量,叫做局部变量。
3、不同点:
代码层面:定义的位置不同
局部变量:定义在方法内或者是方法的形参列表上。
成员变量:定义在类中方法外。
内存层面:存储空间不同
局部变量:属于方法,和方法的位置相同,在方法的运行的时候,存储在方法的栈帧中(栈内存)。
成员变量:属于对象,和对象存储的位置相同,存储在堆内存当中
生命周期:
局部变量:伴随着方法被调用才存在,随着方法的调用结束而消亡。(先于方法的结束而消亡)
成员变量:随着对象的创建而存在,随着对象的消亡而消失 初始化状态不同:
局部变量:使用之前必须手动赋值,没有默认的初始化。
成员变量:有默认的初始化的值,和数组元素的默认初始化一致
引用数据类型:null
基本数据类型: 整数型 0 浮点型 0.0字符型 空白 ‘\u0000’ 布尔型 false
4、对象的消亡: 在堆内存当中所存储的对象都是有引用指向的(栈内存当中存在一个引用存储着堆内存当中该对象的地址值),如果不存在一个引用指向这个对象,这个对象就变成了垃圾,经过一点时间之后就会被垃圾回收线程回收掉。

两个对象的内存图


1、需要被创建的类的字节码文件只加载一次
2、对象调用的方法的栈帧中隐含了该对象的堆内存的地址。
3、先进行默认初始化,然后再进行显示初始化

匿名对象

1、匿名对象就是没有名字的对象。
2、定义格式: new 类名();
3、使用场景:
(1)如果某个对象是用来调用方法的,这个方法只调用一次,这个对象不需要复用,就可以使用匿名对象来调用一次方法,调用完成之后等待垃圾回收机制回收此对象,节约内存。
(2)作为某一个方法的实际参数来进行传递,传递的是对象的地址值。
(3)作为某一个方法的返回值,在进行调用的时候,作为方法的返回值进行返回,返回的还是该对象的地址值。
4、注意事项: 匿名对象可以给成员变量赋值,但是没有意义,因为这个匿名对象一旦被赋值了,说明这个匿名对象就被使用了,因为匿名对象是没有名字的对象,只能使用一次,使用完成之后,很快就变成了垃圾,被回收了,找不到了,所以给成员变量赋值没有意义。

封装封装的概述:

1、生活当中的封装:发动地封装起来了机油和齿轮,电灯封装起来了钨丝和电
2、代码当中的封装:隐藏了事物的属性以及方法实现的细节,对外提供了公共的访问方式。
3、封装的好处: 隐藏事物的细节;提高代码的复用性;提高了安全性
4、封装的原则:
隐藏属性(不让用户直接去访问属性)
隐藏实现的细节
提供对外公共的访问方式

private关键字

1、private:私有的,私密的
2、private在java当中是一个关键字,也是一个修饰符。
修饰成员变量
修饰成员方法
修饰构造方法
修饰内部类(类里面的类)
3、被private修饰之后,只能在本类当中访问

getter和setter

1、当我们类中的属性被私有化了之后,外界不能直接去访问了,需要我们提供公共的方法(被public修饰的方法)来进行访问,包含设置值以及获取值,对于属性就可以控制外界访问的方式(设置的时候过滤违法数据)。
2、get和set方法,一般get方法用于获取成员变量的值,set用于设置成员变量的值
3、get和set方法的命名规范:get字符后面加成员变量名的首字母大写 例如 getName getAge
4.get和set方法一般自动自动生成就可以了。eclipse中alt+shift+s。idea中alt+insert

变量的访问原则和this关键字

变量的访问原则
1、根据就近原则:
定义变量,声明变量:带着数据类型的变量。
使用变量,访问变量:不带着数据类型的变量。
就近原则:访问某一个变量的时候,根据名字就近寻找和该名字相同的定义的变量,如果找到了,就使用,如果找不到,就去更远的地方去寻找。如果找不到,就编译报错。
寻找过程:先在方法内进行寻找,如果方法内没有,就在方法的参数列表的位置进行寻找,如果参数列表位置没有,就去成员位置(类中方法外)进行寻找。
this关键字
1、表示当前类的当前对象的引用
2、this写在方法当中,哪个对象调用这个方法,this就代表谁。
3、作用:用来区分局部变量和成员变量重名的情况,根据就近原则,如果在方法中使用了一个变量,这个变量在本方法中和成员变量中的名字相同,就会导致无法区分,只能就近访问本方法中定义的变量,如果需要访问成员变量,就需要使用到this关键字。 例如:this.name

构造方法

1、构造方法:构造函数、构造器
2、格式:
修饰符 方法名称(参数列表){
方法体;
}
3、格式说明:(1)构造方法的方法名和类名一样(连大小写都一样,完全一致)(2)构造方法没有返回值类型的,连void也没有(3)构造方法可以书写return语句,但是return不可以书写值。
4、其他说明:(1)构造方法不需要手动调用,在jvm虚拟机进行创建对象的时
候,自动调用。(2)使用对象不能调用构造方法(3)创建一个对象,构造方法只调用一次
5、作用: 初始化成员变量,在创建对象的时候,给对象的成员变量进行赋值。
构造方法的其他问题
1、构造方法是可以无参数的,也可以是有参数的。2、构造方法可以重载:方法名相同 【都写类名】 参数列表不同。 和返回值类型无【构造方法没有返回值类型】 写在同一个类中
3、如果一个类中没有任何的构造方法,那么会隐藏一个无参数的构造方法。
4、如果一个类中以及存在了构造方法,那么默认隐藏起来的无参数构造方法就不在提供了。
5、一旦自己书写了有参数的构造方法,建议也把无参数的构造方法也手动进行实现。

成员变量的初始化方式

1、方式: 默认初始化 显示初始化 构造方法初始化
2、三者之间的顺序 默认初始化在显示初始化之前,因为同时默认初始化和显示初始化,结果显示的是显示初始化的值。 显示初始化在构造初始化之前,因为同时使用显示初始化和构造初始化,结果显示构造初始化的值。
顺序:默认初始化、显示初始化、构造方法初始化
在这里插入图片描述
1、加载该对象类的class文件
2、在栈内存当中创建对象的引用,开辟一块内存空间
3、在堆内存当中为对象开辟空间,给成员变量分配内存空间
4、对成员变量进行默认初始化
5、对成员变量进行显示初始化
6、对成员变量进行构造方法初始化
7、将对象的地址赋值给栈内存当中对象的引用

静态

1、没有静态:如果一个类的对象有一些公共的一样的属性,这些属性的值都一样,因为属性是属于对象,所以伴随着对象存储在堆内存当中,创建一个对象,存储一份,浪费了内存空间,一旦需要修改,就需要修改所有对象的属性值,不容易维护,很麻烦。
2、有了静态:加了static关键字的属性不再是属于对象了,是属于类的,该属性(成员变量)存储在方法区的字节码文件当中静态区中,避免了所有的对象都必须要存储一次该数据,节约了内存空间,将来维护容易,只需要修改一次。
在这里插入图片描述
静态变量的特点
1、静态的关键字:static 静止不动的,静态变量不会随着对象的改变而改变。
2、加载时机:
成员变量:对象创建的时候,随着对象的创建而加载。
静态变量:随着类的字节码文件被加载的时候,而加载。
3、类是先于对象而存在的,因为对象根据类来创建。
4、静态变量是先于对象而存在的。
5、静态变量被所有的对象所共享。
6、代码层面:
(1)可以直接通过【类名.静态变量名】来直接访问
(2)也可以通过【对象名.静态变量名】来访问
7、因为静态变量是先于对象存在的。在创建了对象之后,说明静态变量已经存在了,所以对象可以访问到静态变量。

public class Demo01_静态变量 {
 public static void main(String[] args) {
 Cat huahua = new Cat("花花");
 Cat caocao = new Cat("草草");
 Cat jingzhang = new Cat("警长");
 huahua.show();
 caocao.show();
 caocao.setColor("花色");
 jingzhang.show();
 System.out.println("------------------------
");
// 类名.静态变量名
 System.out.println(Cat.color); 
 } }
class Cat {
 public static String color = "白色"; 
 private String name; 
 public static void setColor(String color) {
 Cat.color = color;
 }
 public Cat(String name) {
 this.name = name;
 }
 public void show() {
 System.out.println("名字:" + name + "\t颜
色:" + color);
 }}

静态访问的注意事项
1、静态方法:在方法的声明上,添加了static关键字的方法,就是静态方法。
2、静态的方法和变量在使用类名和对象都可以调用。
原因:
(1)类名之所以可以调用静态资源的原因,是因为使用这个类名的时候,就会加载这个类的字节码文件,静态资源就跟随着被加载以及初始化了,所以类名可以直接调用到。
(2)对象可以调用静态资源的原因,创建对象之前,就必须要加载类的字节码文件,静态资源就跟随着一起类的字节码文件一起被加载和初始化了,所以对象可以调用到静态资源。
3、非静态资源的访问:
(1)静态方法去访问非静态资源
《1》静态方法访问非静态的成员变量,会报错,是因为调用静态方法的时候,可能还没有对象创建,所以不能访问对象的非静态的
成员变量。
《2》静态方法不能直接访问非静态方法,非静态方法属于对象的,可能非静态方法当中会使用到非静态的成员变量,静态方法不能直接访问非静态方法,如果想要访问,创建对象去访问。
(2)非静态方法去访问非静态资源
非静态的方法可以访问非静态资源,也可以访问静态资源。
原因:非静态方法被对象调用,创建对象了,相当于类被加载了,静态资源被初始化了,非静态资源也被初始化了,非静态方法可以访问到静态资源也可以访问到非静态资源。
4、总结:
静态不能访问非静态。
静态变量和非静态变量的区别
1、概念上:所属不同
静态变量:数据类
非静态变量:属于对象
2、存储的空间不同,内存位置不同
静态变量:伴随着类的字节码文件,存储在方法区的静态区
非静态变量:和对象一起,存储在堆内存当中。
3、定义方式不同:
静态变量需要使用static关键字
4、生命周期不同,【内存时间】
静态变量:伴随着类的加载而存在,伴随着类的消亡而消亡。
非静态变量:伴随着对象的创建而存在,伴随着对象被垃圾回收机制【gc】回收,而消亡。
5、访问方式不同:
静态变量:
可以使用【对象名.变量名】也可以使用【类名.变量名】; 访问静态方法:【对象名.静态方法名】或者【类名.静态方法名】
非静态变量:只能使用【对象名.变量名】

工具类

1、工具类:
在工具类当中,一般不维护数据,没有任何的成员变量,只有一些
成员,这些成员方法都是静态方法,这些静态方法可以帮助我们解决一些常见的问题,整个类相当于一个工具。
2、名称:ArrayTool
3、作用:提供一些操作数组的静态方法
4、功能: 数组的遍历 数组的取最值 数组的反转 数组的元素交换
5、因为工具类都是静态方法,所以我们不希望他可以创建对象,使用private关键字修饰构造方法,让其他类不能去访问他的构造方法。 私有化构造方法。
Arrays工具类
1、在jdk当中已经存在了比较优秀的arrays工具类。
2、static String toString(int [] arr); 返回数组的字符串的表示形式
3、sort(int [] arr);将数组进行升序排序。
4、binarySearch(int[] a,int key); 在a数组当中,查询key这个元素的索引位置
前提:数组本身就是升序排列
效率:要高于遍历查询
如果找不到,返回的值是小于0

帮助文档

1、工具类准备好了之后,给第三者使用的时候,给的是class文件,第三者无法看懂,所以需要给他编写一个说明文档,来对其中的方法的参数以及功能做说明
2、文档注释:用于生成帮助文档的注释
格式:
/**
注释的内容
*/
不能嵌套
3、帮助文档的注解:将来可以被特定的解析,可以解析出当中的数据
@author xhl 作者
@version 1.0 版本号
@since 从java1.8版本开始 从哪个版本开始
@param arr 参数

继承

1、让类和类之间产生关系,子父类关系
2、关键字:extends,扩展,可伸张的,增加、延续
3、父类和子类:
父类:被继承的类,超类、基类
子类:用于继承的类,别名:派生类
4、继承格式:
class A {}
class B extends A {}
类B继承了类A
类B是类A的一个子类
类A是类B的父类
5、好处:
两个类公共的数据,可以提取到父类当中去声明。
让类之间有和我们现实生活当中的一些关系体现。
继承的注意事项
1、类中三元素:成员变量,成员方法,构造方法
2、成员变量的继承:
父类当中的私有成员变量,不能被继承(不能直接访问,但是可以
通过公共的方法进行访问)。
在代码的角度上,是私有成员变量不能继承,因为不能直接访问了。
在数据的角度上,是继承了父类的成员变量的了,子对象的堆内存
的内存空间当中也给父类的私有成员变量开辟了内存空间,用来存储父类的数据。
3、成员方法的继承: 私有的成员方法不能被继承。
4、构造方法的继承: 构造方法不能被继承
原因:
因为构造方法的方法名需要和类名一致,如果继承下来,就会和类名产生冲突,所以不能继承构造方法。
父类的构造方法用于给父类的成员变量赋值初始化,但是子类无法继承构造方法,可以继承成员变量,为了给继承下来的成员变量进行初始化,所以必须要访问父类的构造方法。
子类可以访问父类的构造方法。
java中继承的特点
1、java是支持单继承,不支持多继承,支持多重继承【多层继承】;
单继承:一个子类只可以继承一个父类【一个孩子只能有一个亲爹】
多继承:一个子类不能同时继承多个父类
多重继承:
A类被B类继承了
B类被C类继承了
C类就相当于是继承了A类和B类。
越顶层的类的功能就缺少,越底层的类功能就越强大。如果将来要学习一些子父类,应该从顶层父类开始学起。
2、如果支持多继承,那么就有可能一个类继承了两个父类,如果两个父类当中有同名的,但是功能不相同的方法,就会导致冲突,子类继承之后,将来调用的时候,就不知道应该去运行哪个父类的方法实现了。(安全隐患)
继承中成员变量的关系
1、在子类当中和父类当中定义了不同名称的成员变量,根据不同的名称就可以访问到子类自己的和父类的成员变量。
2、在子类和父类当中存在着相同名字的成员变量:根据就近原则来访问。
如果存在名字相同的成员变量,访问到的是子类自己的成员变量。
如果需要访问父类的同名的成员变量,使用【super.变量名】去
访问
3、查找变量的方式:
先在自己的类当中找该变量名的定义,如果没有,就去父类当中的
成员变量位置寻找,
如果父类还没有,就去父类的父类的成员位置去寻找,直到找到
Object类位置,就编译报错。
解释:所有的除了Object之外的类,都有父类,如果一个类没有
extends关键字来继承一个类,那么他会默认的去继承Object类。
Object类叫顶层父类。

继承中成员方法的关系(重写)

1、在子父类当中出现了不同名字的方法直接使用名字调用即可,子类对象可以调用父类的方法,也可以调用自己的方法
2、在子父类当中,出现了同名的方法。 在子父类当中,出现了方法名相同,参数列表页相同,但是实现的内容却不相同可以在子类当中创建一个其他的方法,来使用【super.父类的方法名】调用父类的和子类同名的方法,将来我需要去使用父类的这个同名的方法的时候,就调用子类当中创建出来的中间方法,就是调用了父类的同名方法。
3、方法的重写:
概述:从父类当中继承来了一个方法,子类当中需要更改方法的内
容,就需要子类重新书写一次继承来的方法,方法体改变了,这个重写
的过程,叫做方法的重写。
4、重写的前提条件:(***)
要有子父类的继承关系
私有方法不能被重写
重写的方法和原来的方法不在一个类中
重写的方法的修饰符的权限不能小于父类的被重写的方法的修饰符权限
5、说明:
概念上来说,这个方法还是归属于父类,但是方法的实现是由子类自己实现的。
6、方法重写的注解检查:
@Override
添加在重写的方法之上,可以检查这个方法是否是对父类方法的重
写,如果这个方法不是一个重写方法,就会编译报错。
重写与重载的区别
重载: 在同一个类中 方法名相同 参数列表不同 与返回值类型无关
重写: 不在同一个类中,在子父类两个类中 方法名相同 参数列表相同 与返回值类型有关(相容)
相容解释:
子类的返回的类型可以是父类的返回的类型的子类。
父类的返回值类型要大于子类的返回值类型

代码块

1、代码块就是使用一对大括号包裹起来的一段代码,放在不同的位置上,有不同的名字,就有不同的作用,有着不同的执行时机。
2、根据位置的不同和定义方式的不同:
局部代码块
构造代码块
静态代码块
同步代码块(多线程)
局部代码块
1、格式:使用大括号包裹起来即可
{
局部代码块的代码内容;
}
2、位置:方法当中
3、作用:
限制变量的生命周期(***)
在定义变量的时候,变量的作用范围限制于定义变量的花括号当中
(一般情况下)如果在局部代码块当中定义的变量,就只能在局部代码块当中去使用,出了局部代码块,就不能使用了。
4、注意事项:
如果局部代码块当中声明了变量,只能在局部代码块里面使用,会减少该变量的生命周期,出了局部代码块就不能再次使用。
局部代码块当中还可以正常去使用局部代码块外面的变量。如果局部代码块当中修改了局部代码块外边的变量,就算局部代码块执行结束了,对外边的变量产生的影响依旧存在。
构造代码块
1、格式:使用大括号包裹起来的一段代码; 2、位置:和构造方法的位置相同,类中方法外
3、作用:给成员变量进行初始化赋值。
4、构造代码块的执行说明:
(1)在创建对象的时候执行,jvm默认调用
(2)在构造方法执行之前
(3)有参构造和无参构造被调用之前,都会执行构造代码块
5、如果每一个构造方法都有一些公共的代码,就可以提取到构造代码块当中去。
静态代码块
1、格式:
static {
静态代码块的内容
}
2、位置:类中方法外
3、执行时机: 伴随着类的加载而执行 类只加载一次,所以静态代码块也只执行一次 执行是时机比对象的相关内容要早
4、作用: 给静态变量初始化赋值 用于执行那些只需要执行一次的代码,比如加载驱动。

内部类

1、定义在类的内部的类,就是内部类,可以定义在方法的内部,也可以定义在类的成员位置。
2、根据定义的位置不同:
成员内部类
局部内部类(***)
3、成员内部类:(根据修饰符不不同)
普通的成员内部类
私有的成员内部类
静态的成员内部类
4、局部内部类:
有名字的内部类
没有名字的内部类【匿名内部类】
普通的成员内部类
1、定义在类的成员位置上
2、定义格式:
class 内部类类名{
内部类的成员
}
3、成员内部类访问:
(1)内部类可以随意访问外部类的资源,包括私有成员
(2)外部类访问内部类,访问非静态资源,使用对象访问。
(3)外部类以外的类去访问内部类:
创建内部类对象:外部类类名.内部类类名 对象名 = new 外部类名().new 内部类名();
4、注意事项: 普通的成员内部类当中不能含有静态资源。
私有成员内部类
1、也是一个成员内部类,在class关键字前面加一个private关键字
2、访问说明:
(1)内部类可以访问外部类的资源
(2)外部类可以使用对象去访问内部类的资源
(3)外部类以外的类,就不能去直接创建对象去访问内部类的资源。
静态成员内部类
1、也是一个成员内部类,在普通成员内部类的前面加一个static关键字
2、访问特点:
(1)内部类访问外部类
如果访问的资源是静态的,就可以直接访问
如果访问的资源是非静态的,就需要创建对象再访问
(2)外部类访问内部类
如果访问的是静态资源,就直接通过【类名.变量名】或者【类名.方法名】
如果访问的是非静态资源,就通过对象去访问
(3)总结:如果需要访问非静态资源,就需要创建对象,如果访问的是静态资源,使用类名就可以直接访问。
(4)外部类以外的类访问内部类:
访问的是静态资源,就直接通过类名点的形式 【外部类名.内部类名.变量名】
访问的是非静态资源,创建内部类的对象: 外部类名.内部类名 内部类对象名 = new 外部类名.内部类名();
局部内部类
1、局部内部类:定义在方法的内部
2、局部内部类的访问说明:
内部类的成员变量和成员方法,只能在定义了内部类的方法中,并且是内部类的定义的下方去创建对象访问
定义了内部类的方法外边是没有办法访问到内部类的,因为访问的时候,方法还没有调用,内部类还不存在
3、访问方式:
(1)在方法的内部,并且是内部类定义的下方,
(2)去创建对象,进行局部内部类当中资源的访问
4、注意事项:局部内部类当中不能有静态资源。

权限修饰符

1、权限修饰符就是一些关键字,用来修饰成员,可以决定这些成员在什么位置被访问。
2、权限修饰符也是封装的一种形式。
3、权限修饰符 范围
【私有的】 private 只能在本类当中访问
【默认的】 默认的权限修饰符【什么都不写】 可以在本类当中访问 也可以在本包当中访问
【受保护的】 protected 可以在本类中访问 可以在本包中访问 在其他包中被【继承】的子类可以访问到
【公共的】 public 可以在本类本包其他包都可以访问

多态

1、多态:事物的多种状态。
对象的多态:同一个对象,可能有不同的名称。同一个对象,可能会有不同类型的引用去指向他,同一个物体,可能会有不同的名称和描述。
类型的多态性:不同的子父类当中,可能存在相同名字的方法,但是方法的实现缺各不相同,同样行为描述,行为的具体内容有多种状态,在不同的场景下有不同的实现。
2、形成多态的前提:
(1)要有子父类的关系【继承关系】【实现关系】
(2)要有方法的重写
(3)父类的引用指向了子类的对象
多态的成员变量和成员方法访问
1、编译看左边,运行看左边
2、编译的时候,查看左边的父类当中是否有这个变量/方法,如果有就编译成功,如果没有就编译失败。
3、运行的时候,也直接去左边的父类当中找变量/方法。
向上向下转型
1、向上转型
子类的引用指向子类的对象【正常情况】
使用父类的引用指向子类的对象【向上转型】
本质:缩小了对象可以访问数据的范围,减少了访问的权限。【只能去访问父类当中已经定义了的成员方法】
成员变量也不能访问子类的,只能访问父类的
2、向下转型:
概念:
本来是父类引用指向子类对象,恢复成子类引用指向子类对象。
本质:恢复了该子类对象应该有的访问权限:
格式:
子类类名 引用名称 = (子类类名) 父类类型的引用;
Zi z = (Zi) p;
多态的好处
1、提升了代码的扩拓展性
2、如果你定义一个方法,在方法的参数列表位置书写的是一个父类类型的变量,将来调用的时候,可以传入进去父类的对象,也可以传入进去子类的对象,都可以作为方法的实际参数。
3、在方法的方法体当中也可以使用多态,使用父类的引用去指向子类的对象,我们现在的对象是我们手动创建出来的,将来对象可能是我们从一个文件当中读取来的,也可能是通过网络来传递过来的,也可能是通过反射来的,有多种拥有对象的方式了,可能不知道对象的具体的类型,为了更加方便的接受对象,我们一般使用父类的引用去指向他,虽然使用父类引用去指向子类对象,但是调用的方法还是子类本身的方法。
最终的结果:我们可能都不知道对象具体是什么类型,但是还能调用它的方法。

抽象

抽象方法
1、抽象:抽取了一些公共的相似的内容出现。
2、抽象方法:只有方法的声明,没有方法的实现,这种方法叫做抽象方法。
3、抽象方法出现的原因:
父类:把子类当中公共的内容抽取到父类当中来实现,子类对于这些内容就不在需要多次书写了。
父类当中对于子类的方法进行抽取的时候,发现方法体不相同,无法进行抽取,但是方法的声明相同,可以把方法的声明抽取出来,这个抽取出来的只有方法声明,没有方法实现,这个方法就是抽象方法。
4、定义格式:
(1)没有方法的实现,所以说大括号也没有意义了,大括号在抽象方法中也不用书写了,使用一个分号来表示语句结束;
(2)为了标记这个方法是一个抽象方法,所以要在方法的声明上书写一个抽象的关键字【abstract】 5、注意事项: 抽象方法不能写在普通的类中,只能写在抽象的类中,或者是接口当中。
抽象类
1、可以定义抽象方法的类,就是一个抽象类。
2、定义格式
权限修饰符 abstract 类名 {
成员
}
抽象类的特点
1、抽象类和抽象方法都需要使用到abstract关键字修饰
抽象类 abstract 类名 {}
抽象方法 权限修饰符 abstract 返回值类型 方法名(参数列表);
2、抽象类和抽象方法的联系:
有抽象方法的类一定是抽象类(***)
抽象类当中不一定都是抽象方法,还可能有普通方法。
抽象类当中不一定有抽象方法。【抽象类当中可以没有抽象方法】
3、抽象类的实例化(抽象类怎么创建对象)
抽象类不能直接实例化 【不能直接创建对象】
抽象类借助普通的子类来进行实例化
使用抽象类的子类的对象来访问抽象类当中的方法。
4、抽象类的子类的分类:
普通类:因为是普通了,所以不能有抽象方法,所以必须去实现抽象父类当中定义的抽象方法的实现,也叫作方法的重写。必须去重写父类当中的抽象方法才可以。
抽象类:没有将父类当中所有的抽象方法全部实现,子类还是一个抽象类,还需要使用abstract关键字来修饰这个类,将来还需要借助子类来进行实例化。
抽象类的成员特点
1、成员变量:可以定义变量,也可以定义常量。但是不能被抽象
2、构造方法:有
虽然抽象类不能创建对象,但是抽象类可以被继承,创建子类对象的时候,子类的构造方法就会默认访问父类的构造的,所以说抽象类是
必须要有构造方法的,将来用于被子类的构造方法访问。虽然抽象类不能创建对象,但是抽象类当中可以有成员变量,有成员变量,就得被初始化,构造方法就是用来初始化成员变量的,所以必须要有构造方法。
3、成员方法:
可以是抽象方法:强制【普通子类】重写 也可以是非抽象方法:用于被子类继承,提高代码的复用性

接口

1、生活当中的:用来定义一些规则的就是接口
2、java当中:java当中的接口是用来定义方法的方法名,参数,以及返回值类型的规则。 java的接口当中,都是一些方法的声明,都是抽象方法。【目前】
3、好处:
可以提高程序的拓展性。
方法的声明和方法的实现分来了,根据多态的规则,使用接口的引用来调用方法,实现方法的调用和方法的实现相互分离,降低了代码的耦合度,提升开发效率,以及维护性。
接口特点
1、接口的定义:使用interface关键字,接口编译生成的也是【.class】文件
修饰符 interface 接口名 {
方法声明的定义;
}
2、接口中,只可以声明抽象方法【只能写方法的定义,不能写方法的实
现】【目前】
3、接口不能创建对象,但是类可以实现接口:使用关键字 implements实现:类实现了接口之后,因为接口当中只有方法的定义,所以实现了该接口的类,必须要接口中定义的抽象方法。
class 类名 implements 接口名 {
对接口当中抽象方法的实现。
}
4、接口不能创建对象【接口不能实例化】 接口不能实例化,但是可以借助其实现类来进行实例化。
5、接口的实现类:
普通类:该类实现了接口当中的所有的抽象方法。
抽象类:该类当中没有实现接口中所有的抽象方法。
接口当中的成员特点
1、成员变量:
接口当中只能是常量,不能是变量
如果你直接定义一个变量,默认会添加上public static final 建议手动添加
访问的时候,直接使用【接口名字.常量名】
2、构造方法:
父类相当于 子类的亲爹 接口相当于子类的干爹 亲爹只有一个 干爹可以有很多子类的构造方法访问的父类的构造方法,找亲爹的,也不需要去访问接口当中的构造方法。 接口当中是没有构造方法的,因为接口无法定义成员变量,所以也不需要构造方法对于成员变量进行初始化。
3、成员方法: 只能是抽象方法,不能是非抽象方法。【目前】
默认会添加一个public abstract修饰
建议手动添加

类和类、类和接口、接口和接口的关系

1、类是类 继承关系 关键字 extends 可以单继承、不可以多继承、可以多层继承。
2、类和接口: 实现关系 关键字 implements 可以单实现,也可以多实现,可以多层实现的【没必要,只实现最
底层的接口即可】
多实现的格式:
class 实现类类名 implements 接口名1,接口名2,接口名3…{
重写的所有的接口中的抽象方法
}
多实现是没有安全隐患的,即使实现的两个接口当中有一样的方法的声明,但是在类中也只有一个实现,将来在调用的时候,只能找到一个实现,不会出现找不到的情况。
格式:
class 子类类名 extends 父类的类名 implements
接口1,接口2… {重写的父类和所有接口当中的抽象方法
}
3、接口和接口: 继承关系 使用extends
可以单继承、可以多继承、可以多层继承【咋继承都行】
继承格式: interface 接口名 extends 父接口1,父接口2…{ 继承了父接口当中的所有的抽象方法 }
类和接口的区别
1、成员变量
类:可以有静态的变量、非静态的变量、常量
接口:只能是常量
2、构造方法:
类:有
接口:没有
3、成员方法:
类:可以有非静态的成员方法,也可以有抽象方法
接口:只能是抽象方法
4、程序思想设计上的区别:
抽象类:规定了物体的属性以及行为【存在没有实现的】
接口:规定了物体可以通过学习,拓展训练出来的行为。
区分示例图

三、API

API概念

1、API:application programming interface 应用程序编程接口
2、java的jdk中类的词典。
3、包含内容:包含了jdk当中的类、接口、类型、枚举这些信息。

Object类

1、Object类是所有类的顶层父类,java当中的所有的类都直接或者是间接的继承了Object类。
2、我们手动的创建一个类,如果这个类没有继承某一个类,那么他的父类就是Object类。
3、Object类没有父类。
构造方法
1、Object类没有显示的构造方法,只有一个隐藏起来的无参构造方法。
2、构造方法使用: 可以自己创建对象 还可以让子类去访问Object类的无参构造方法 Object类在进行无参构造方法使用的时候,不会再去访问自己的父类了,因为Object类没有父类
toString方法
1、返回当前对象的字符串的表示形式
1、实现方式:全类名+"@"+哈希码值的十六进制表示
2、简称这个我们看不懂的字符串为:对象的地址值
3、其实我们直接打印一个对象的时候,其实打印的是该对象调用toString方法返回回来的字符串
4、重写的原则:打印该类对象的属性的值。
5、最终学习:快捷键快速生成toString alt+shift+s 点击toString
6、直接打印一个对象,打印的就是该对象的属性的值【因为重写了toString方法】。
equals方法
1、用于比较两个对象是否相等的方法,比较的是【调用者】和【参数】这两个对象是否相等。
2、如果不重写equals方法,那么默认调用的是Object类的equals方法,其实本质上还是使用==号进行比较,我们希望的是比较两个对象的属性,所以需要重写equals方法
3、重写原则:比较两个对象当中的属性是否相同,如果相同返回true,否则返回false
4、操作:使用快捷键自动生成equals方法 alt+shift+s
==和equals的比较
1、都是用来比较两个数据相等的
2、不同点:
== 可以比较基本数据类型,也可以比较引用数据类型 比较基本数据类型的时候,比较的是值是否相同,比较引用数据类型的时候,比较的是地址值是否相同
equals只能比较引用数据类型,不能比较基本数据类型 比较引用数据类型的时候,如果没有重写object类的equals方法,比较的还是地址值,如果重写了,比较的是属性的值。

Scanner类

1、Scanner是一个文本扫描器,可以来扫描指定设备的基本数据类型以及字符串
2、构造方法:
Scanner(File source) 扫描指定的文件
Scanner(InputStream source) 扫描指定的输入流
Scanner(String source) 扫描指定的字符串
scanner对象 其实是通过Scanner(InputStream source)构造方法来进行创建的scanner对象,System.in其实就是一个InputStream的对象,System.in叫做标准输入流,默认关联到键盘上。
录入基本数据类型
1、方法:
nextInt() 录入int的数据
nextBoolean() 录入布尔类型的数据
依次类推
2、注意事项:
(1)没有nextChar这个方法,一般都是录入字符串
(2)在使用nextFloat方法的时候,键盘在控制台录入的信息,后面不需要加F
(3)如果需要录入多个数据,可以使用空格作为间隔,把空格当做扫描你结束的标志
录入字符串类型的数据
1、next():录入的不是一个,是空格或者是回车之前的内容,不能扫描一行,把空格或者是回车当做分隔的标记
2、nextLine():可以完整的扫描一行数据,可以扫描到空格,把回车当做是分隔的标记
Scanner类型的小问题
1、问题:如果使用了录入基本数据类型的方法,或者是next方法,紧接着去使用nextLine方法,nextLine方法就不会等待我们去录入数据,直接把之前的方法没有扫描进去的数据,就扫描到了nextLine方法当中去,结束了程序,不是我们想要的结果。
2、解决方式:
(1)可以调用两次nextLine方法,把错误的我们不想要的数据给扫描到,不使用,再次就可以让我们正常的去等待用户录入了。
(2)可以创建一个新的Scanner对象,新的对象当中没有上次遗留的数据,是干净的,不会影响下次的录入。
(3)可以把所有的需要输入进来的数据,都使用字符串的形式录入进来,录入到一行当中去,将来使用String类进行处理【数据的切割转换】

String类

1、String是字符串类型,是一个类,是java.lang包,所以不需要导包
2、所有的字符串常量【“aaaa”,“我爱你”】都是String类型的对象
3、字符串常量是属于常量,所以存在方法区的常量池
4、String类型是一个常量,在创建之后就无法改变。
5、String类型底层维护了一个用final修饰的char类型的数组,是不可变的,在创建完成之后,就不能修改里面的数据。
构造方法
1、String() 创建一个空的字符串的String类型的对象
2、String(String original) 使用original字符串创建一个String类型的对象
3、String(char[] value) 使用char数组来创建一个对象
4、String(byte[] bytes) 使用byte数组来创建一个对象,通过默认的编码叫进行字节转化为字符
5、String(byte[] bytes, int offset, int length) 使用byte数组的一部分来创建一个对象,从offset索引开始,使用length个byte数字来进行转换。
6、String(char[] value, int offset, int count) 使用char数组的一部分来创建一个对象,从offset开始,使用count个。
String类的判断方法
1、equals(String s )
判断两个String的对象中的字符串是否一致
2、equalsIgnoreCase(String s)
判断两个字符串是否一致,忽略大小写
3、contains(String s )
判断调用的字符串是否包含传递进来的字符串s
4、startsWith(String s )
判断字符串是否以s开头
5、endsWith(String s)
判断字符串是否以s结束
6、isEmpty()
判断字符串是否是一个空串
String类的获取功能
1、length()
获取字符串的长度【字符的个数】
2、s.charAt(int index)
根据传递进去的索引,返回该索引位置的字符
3、String substring(int beginIndex)
从调用者字符串的beginIndex索引位置之后开始切割出来一个新的字符串,
注意事项:
(1)包含传递进去的这个索引
(2)索引不能超过字符串的长度-1,会发生索引越界异常
4、String substring(int beginIndex, int endIndex)
从调用者字符串的beginIndex索引位置到endIndex索引位置来截取出一个字符串
注意事项:
(1)包含左边的beginIndex索引位置的字符,不包含右边的endIndex位置的字符
5、indexOf类方法:
int indexOf(int ch) 返回回来传入进去的ch字符的索引位置
注意事项:
(1)从左往右,返回第一次出现的位置
(2)如果没有出现,返回查不到,返回一个-1
indexOf(int ch, int fromIndex)
查找一个字符,从fromIndex索引位置来开始查找,也会查找fromIndex这个位置
int indexOf(String str)
返回回来传入进去的str字符串的第一次出现的索引位置,该索引是str第一个字符的索引
int indexOf(String str, int fromIndex)
返回回来的传入进去的str字符串的第一次出现的索引位置,从fromIndex索引开始查找
6、lastIndexOf类方法: 和indexOf类方法一样,只是从后往前找,返回的字符的索引位置和字符串的索引位置也不会发生变化,返回的都是该字符或者是该字符串的左边的第一个字符的索引位置。
String类的转换功能
1、byte[] getBytes()
把字符串转换为字节数组
2、char[] toCharArray()
把字符串转换为字符数组
3、String toUpperCase()
把字符串变成大写的
4、String toLowerCase()
把字符串变成小写的
5、String concat(String str)
字符串拼接,使用调用者字符串拼接上str,我们更多使用+
6、String.valueOf(任意类型)
可以把任意类型的数据变成字符串
String类的其他方法
1、String replace(String oldstr, String newstr)
把字符串当中的oldstr变成newstr字符串
2、trim()
去掉字符串的前后空格以及制表符
3、String[] split(String regex)
使用regex为分隔符来进行字符串的切割

System类

1、System类是一个和系统资源相关的类,该类没有构造方法,不能创建对象,直接使用静态的变量和方法即可
2、静态的量:
System.in 标准输入流,默认和键盘关联
System.out 标准输出流,默认和控制台关联
System.err 标准错误刘,和控制台关联
用于打印错误信息,在eclipse当中,打印出来的信息是红色的。
3、gc()
运行垃圾回收器。
对象如果没有引用指向了,就变成了垃圾 ,累计到一定的量才会去清扫,gc方法可以手动强制的帮助我们去清扫垃圾。
4、finalize()
是Object类当中的一个方法,当垃圾回收机制回收对象的时候,会默认调用这个方法。
5、currentTimeMillis()
返回当前时间的毫秒值,使用的是电脑系统时间。
计算机时间原点:1970年1月1日0时0点0分,格林尼治,时间为0毫秒,到现在的实现就是获取到的毫秒值。
可以通过某些手段,把他转换为时间对象。 计算代码的运行效率,在代码执行之前获取一下当前时间的毫秒值执行完成之后再获取一下当前时间的毫秒值,两个毫秒值之差就是代码的运行时间。

StringBuilder类

概述
1、StringBulider是一个可变的字符序列。因为它底层维护的字符数组没有添加final修饰,所以说是可变的,可以对StringBulider对象做操作和修改。
2、char[] value 维护的char数组的权限修饰符是默认的,只能在本类,本包中访问,我们不能直接去访问,所以说他里面提供了公共的方法来进行访问value
3、String和StringBulider的关系:都是用来描述和操作字符串的
(1)String是一个不可变的字符序列,也没有提供可以修改维护的char数组的方法,StringBuilde是一个可变的字符序列,提供了维护修改char数组的方法
(2)String的长度是不可以改变的,StringBulider的长度是可以改变了,我们可以认为StringBulider是一个长度不固定的容器,用来存储字符。
构造方法
1、StringBuilder()
使用空参数构造方法创建一个StringBuilder对象,默认容器长度是16.
2、StringBuilder(int capacity)
创建一个对象,默认长度是capacity
3、StringBuilder(String str)
创建一个对象,初始值就是传递进来的str字符串,默认的容器长度是str的长度+16 可以把String类型的对象转成成StringBuilder的对象
3、获取容器长度的方法:
length() 获取容器当中存储的字符的个数
capacity() 获取容器的长度
添加功能
1、append(任意数据类型) 可以把任意的数据类型转换为字符,添加到容器当中去
2、insert(int index,任意类型) 把任意类型的数据的字符串的表示形式插入到StringBulider的字符序列当中去
注意事项: 可以插入的位置是0到StringBulider使用了的字符序列的长度【使用了的最大索引+1】
删除功能
1、deleteCharAt(int index) 删除指定索引位置的单个字符
2、delete(int index1,int index2) 删除指定范围内的字符,包含index1索引位置,不包含index2索引位置。
替换和反转
1、replace(int start, int end, String str) 把字符串的start索引位置到end-1索引位置的字符替换为字符串str
2、reverse() 将原有的字符序列进行反转
StringBuffer和StringBuilder的区别
1、共同点: 都是字符串的可变序列。
2、不同点:(1)出现的版本不同StringBuffer jdk1.0StringBuilder jdk1.5
2)线程安全性不同 StringBuffer 是线程安全的,可以在多线程的情况下保证数据的安全性 StringBuilder 是线程不安全的在多线程的情况下不能保证数据的安全性
(3)效率不同 StringBuffer 效率低 StringBuilder 效率高

基本数据类型包装类

1、基本数据类型有8中,都是比较简单的数据,描述的都是数值本身。
2、这些类型的数据,只能是描述数据,不能去操作数据,这时候就需要有一个对应的特殊的引用数据类型来进行存储基本数据类型的这些数据和操作基本数据类型的这些数据,这些特殊的引用数据类型就叫做基本数据类型包装类。
3、基本数据类型包装类
byte Byte short Short int Integer long Long float Float double Double boolean Boolean char Character
构造方法1、Integer(int value) 把一个int类型的数据,转换为一个Integer类型的对象2、Integer(String str) 把一个字符串类型的数字,转换为一个Integer类型的对象
成员方法常用的是:valueOf(String s) 返回保存指定的 String 的值的 Integer 对象。
自动装箱和自动拆箱(jdk1.5):1、装箱: 把基本数据类型封装成一个基本类型包装类的对象,这个过程是装箱,是一种编译特效。2、拆箱: 把基本数据类型包装类当中的基本数据取出来,变成一个基本数据类型,这个过程是拆箱,也是编译特效。3、自动:在jdk1.5版本之后,基本数据类型和基本数据类型包装类可以通用, 但是基本数据类型的数据是不可以调用基本数据类型包装类的方法的。

四、集合

概述
1、数组 长度不可变 可以存储所有的数据类型
2、集合 长度可变 只能存储引用的数据类型
3、相同点:都是数据的容器

体系结构()

1、集合的分类
单列集合:存储的是一个一个的数据,每一个数据都是单独的。
双列集合:存储的是一对一对的数据,一两个数据是一对。
2、单列集合的体系:
Collection 【i】 单列集合的顶层的接口
List 【i】 有序的单列集合接口
ArrayList 【c】 顺序存储,查询效率快,底层的存储结构是数组
LinkedList 【c】 链式存储,增删快,查询慢
Set 【i】 无序的单列集合接口
HashSet 【c】 哈希表存储
LinkedHashSet 【c】
3、双列集合的体系:
Map 【i】 双列集合的顶层接口
HashMap 【c】 哈希表存储的一个map实现类
LinkedHashMap 【c】
4、注意【i】表示接口 【c】表示类

Collection接口

1、Collection是可以接口,是单列集合的顶层接口,里面有单列集合当中的共有的功能。
2、Collection是一个接口,我们不能创建他的对象,只能去通过他的实现类来对他进行实例化。 我们只能去创建ArrayList或者是LinkedList或者是HashSe或者是LinkedHashSet的对象,推荐选择使用ArrayList。
Collection接口的引用指向ArrayList的对象,是多态的体现。
3、常用的方法
add(Object e) 把元素e添加到集合当中去
remove(Object e )把元素e从集合当中删除
clear() 把集合当中的元素都删除掉
isEmpty() 判断是否为空
contains(Object obj) 判断集合当中是否有某一个元素
size() 返回集合中元素的个数
带all的方法:
1、addAll(Collection c)把集合c当中的元素都添加到调用者的集合当中去
2、removeAll(Collection c) 删除调用者集合和集合c当中的公共的元素【都有的元素】 【交集】
3、containsAll(Collection c)调用者是否包含集合c中的所有元素
4、retainAll(Collection c)求交集,只保留和c集合当中的交集元素
遍历
1、通过方法转换成一个数组,再来遍历数组
2、Object[] toArray() 返回一个Object类型的数组
迭代器遍历
1、迭代:一代一代的、更新换代、一个到下一个的交替过程
2、迭代器:是用来专门遍历集合当中的元素的,可以一个一个的迭代集合当中的元素
3、获得迭代器的方法:
Iterator iterator() 返回在此 collection 的元素上进行迭代的迭代器。
4、迭代器的使用方式: hasNext(): 判断集合当中还是否存在下一个元素,如果存在就返回true,否则返回false
next() 获取集合当中的下一个元素,并且移动迭代器
remove() 删除正在迭代的那个对象
5、注意事项:
(1)next()方法不仅仅会返回元素,还会去移动迭代器,如果移动的迭代器位置没有元素了,就会抛出异常。 如果没有下一个元素了,再次调用next()方法,就会抛出元素找不到异常。
(2)hasNext()方法不移动迭代器。
(3)不要判断一次hasNext(),就去调用多次next()方法,调用next()方法的时候,最好先去判断hasNext()是否为true。
(4)迭代器遍历,迭代器删除,不要使用集合去操作。

List

1、是一个Collection接口下面的一个有序子接口、
2、特点:
有序:元素存储进去之后,是具有顺序的【存储进去的顺序和取出来的顺序一样】
有索引:每个元素都有自己的索引
可以重复:相同的元素,可以重复的添加进去。
3、特有方法:
add(int index, Object element) 在指定的索引上添加元素
remove(int index) 移除列表中指定位置的元素(可选操作)。
set(int index, Object element) 用指定元素替换列表中指定位置的元素(可选操作)。
get(int index) 返回列表中指定位置的元素。

List的实现类

1、ArrayList:底层是数组存储,顺序存储
2、LinkedList:节点存储,链式存储
ArrayList
1、是List的一个实现类
2、基本没有特有的方法
3、存储方式:
数组存储,顺序实现
通过物理的位置来表示逻辑的位置相邻【通过物理内存地址的相邻来表示相邻原元素的相邻】
LinkedList
1、存储方式
节点存储,链式存储
不通过物理内存位置的相邻来表示逻辑的相邻 每一个元素都存储在一个节点当中,节点和节点的内存位置是不相邻的,节点当中除了存储元素之外,还存储了前后阶段的内存地址
2、特点: 查询慢,增删快
3、特有的方法: 由于在LinkedList的存储方式的不同,在LinkedList对象当中,维护了头节点和尾阶段的内存地址,所以说操作头节点和尾节点就比较的方便。
addFirst(Object e) 将指定元素插入此列表的开头。
addLast(Object e) 将指定元素添加到此列表的结尾。
getFirst() 返回此列表的第一个元素。
getLast() 返回此列表的最后一个元素。
removeFirst() 移除并返回此列表的第一个元素。
removeLast() 移除并返回此列表的最后一个元素。
pop() 弹出一个元素
push(Object e) 压入一个元素

泛型

1、泛型:广泛的类型。在我们定义写方法和类的时候,需要用到一些类型,将来一个方法或者是一个类的类型不确定的情况下,使用泛型来代替,表示那些不确定的类型
2、使用:(我们今后对于泛型主要是使用居多,自己书写的业务场景不是很多) 例如我们创建某一个类的对象时候,可能需要确定他的泛型,确定了泛型之后,其他类型就不能再进行使用了。
例如:Collection c = newArrayList();
3、泛型带来的好处:
(1)提高了安全性,运行时期的错误提前暴露在编译的时候。
(2)避免了强制转换
4、使用泛型的注意事项:
(1)前后一致:创建对象的时候,等号前面的泛型和等号后面的泛型必须要一样
(2)泛型推断: 如果说,使用的是jdk1.7以上的版本,等号后面的泛型可以不写,他会根据前面的泛型推断出后面的泛型,后面泛型叫做【菱形泛型】,因为后面的符号是【<>】,看起来比较像菱形,所以叫做菱形泛型。泛型符号:需要一个大写的字符,合法的标识符就可以了。
泛型通配符
1、使用泛型的时候,可能会去使用一个泛型,例如E,如果你使用了E这个泛型,将来我想要去使用一个和E类型相关的类型,就可以使用泛型的通配符来表示。泛型的通配符可以表示一个泛型和另外一个泛型之间的关系。
2、第一种形式, ?表示任意类型
removeAll(Collection<?> c) 表示可以传递进来一个Collection的集合,但是这个集合的泛型和我们方法调用者集合的泛型是没有任何的关系的。
3、第二种形式 【? extends E】 表示这个泛型必须是E类型或者是E类型的子类
addAll(Collection<? extends E> c) 表示可以传递进来一个Collection接口,但是传递进来的这个接口的泛型必须是方法调用者泛型的本身或者是子类。确定了泛型的上边界。
4、第三种形式 使用【? super E】 来表示这个泛型必须是E类型本身或者是E类型的父类 sort(T[] a, Comparator<? super T> c) T[] a传递进来一个T类型的数组,Comparator<? superT> c表示传递进来一个Comparator接口的实现类对象,这个对象的泛型必须是T类型或者是T类型的父类,此方法用来排序。 确定了泛型的下边界。

Set

概述1、Set是Collection下面的无序子接口
2、特点: 无序:里面的元素没有位置的区别,所有的元素在里面存放都相当于是打乱的。
没有索引:因为元素在集合当中是没有任何的确定的位置的,所以说元素也就没有索引
不能重复:集合当中不能去存储重复的元素。因为没有位置的区别,如果存储了重复的元素,那么这些重复的元素就无法区分了。
3、HashSet:是Set集合的一个实现类
存储:使用哈希表的方式进行存储
存储规则:
(1)相同的元素不能存储到集合当中去
(2)集合不能保证顺序性:存储进去的顺序不一定是取出来的顺序
Set遍历
1、Set集合没有特有的方法,只能去使用Collection接口当中的方法
2、使用toArray(),转换成一个数组,对数组进行遍历;
3、toArray(T[] a) 里面可以传递一个数组,把集合当中的元素存储到传入的数组当中去
(1)数组的类型和集合当中的元素的类型不一致报错,抛出异常:java.lang.ArrayStoreException
(2)数组的类型和集合当中的元素的类型一致
《1》数组的长度小于集合的长度
不使用我们传入进去的数组,自己创建一个和集合长度一致的数组,把元素放进去,返还给我们。
《2》数组的长度等于集合的长度
使用的是我们传入进去的数组,把集合当中的元素放进去了,返回的也是我们传入进去的数组。
《3》数组的长度大于集合的长度
使用的是我们传入进去的数组,把集合当中的元素按照索引从0开始依次放进去,返回的也是我们传入进去的数组。
4、迭代器遍历:
5、增强for遍历:
格式:
for(元素的类型 元素名 : 集合名){
System.out.println (元素名);
}
解释: 本质上,底层还是使用迭代器进行遍历,在遍历过程当中,也不能使用集合来删除元素,会发生并发修改异常。

HashSet保证元素唯一性原理

hashCode方法
1、Object当中的hashCode方法是根据地址值计算的,每一个对象返回的hash值都不同
2、重写的hashCode方法:
规则:根据成员变量的值来计算出来的一个hash值,如果对象的成员变量的值一样,产生的hash值也一样。
3、在set集合存储元素的时候,对于hashCode的调用:
(1)只要有元素存储,hashCode方法就被调用了;
4、hashCode方法重写的原则:
(1)为了表达对象是否一致,hash值的计算方式一定要和成员变量有关系。
(2)让不同的对象【成员变量值不同的对象】,尽量去产生不同的hash值。
5、总结:
如果hash值一样,对象不一定一样。
如果对象一样,那么产生的hash值一定一样。
equals方法的调用时机
Set集合存储一个元素的时候,先调用hashCode方法,如果hashCode
方法返回的hash值一样,就去调用equals方法,hashCode当中的代
码是使用成员变量来计算hash值,产生的结果就是:
成员变量一致:产生的hash值必定一致。
成员变量不一致:产生的hash值也可能一种。
为了让equals少被调用,所以说我们hashCode方法当中对于不同的对
象【成员变量值不一样的对象】,尽量别产生相同的hash值。
保证元素唯一性过程的结论
1、调用hashCode方法,返回hash值 2、比较是否容器当中存在着和这个hash值相同的元素
(1)如果存在hash值一样的,就调用equasl方法
《1》equasl方法为true,就证明真的一样,所以不添加
《2》equasl方法为false,就证明不一样,所以添加进去
(2)如果hash值没有一样的,就直接添加进去。
保证元素唯一性的操作
1、重写hashCode方法
相同的对象有相同的hash值。
不相同的对象尽量有不同的hash值。
根据对象的成员变量的值来计算生成hash值
2、重写equals方法
比较的不再是对象的地址值,比较的是对象的成员变量。

LinkedHashSet

1、LinkedHashSet是HashSet的一个子类,和hashSet的元素唯一原理相同。
2、不同点与HashSet:它在存储元素的时候,每一个元素都记录了前后元素的内存地址。
3、产生的结果: 元素存储的顺序和取出的顺序是一致的。
4、应用场景: 如果你继续要保证元素的唯一性,还需要保证元素的顺序性,就可以使用LinkedHashSet。

Map

概述

1、双列集合的顶层接口
2、map:地图
3、地图表示的是图上和现实的地理位置的一一对应关系,map表示的是两个数据的一一对应关系
4、数据结构:
存储的是一对一对的数据。
描述的是键(key)到值(value)的对应关系
存储的是键值对
5、键值对的特点:
键(key):在集合当中是不能重复出现的,一般存储的都是比较简单的数据。
值(value):在集合当中可以重复的出现,一把都是比较复杂的数据。
6、Map集合和Collection集合的区别:
Map集合是双列集合,存储的都是一对一对的数据
Collection集合是单列集合,存储的是单个的数据
Map集合将来操作的时候,都是针对于键来进行操作,Collection集合当中进行操作的时候,基本上都是直接正对于元素操作。

Map集合的常用方法

1、新增方法
put(K key, V value)
增加一个键值对
2、删除方法:
V remove(Object key)
根据传入的键,删除键值对,返回值
3、修改方法:
put(K key, V value)
传入的key是一个已经存在的,value就被覆盖了,相当于修改
4、获取方法:
V get(Object key)
根据传入的key来获取值
5、判断的方法:判断集合中是否存在某一个键或者某一个值
boolean containsKey(Object key)
判断是否集合当中存在一个键
boolean containsValue(Object key)
判断是否集合当中存在一个值

遍历

1、第一种思路,获得了所有的键,再去通过键获得值。
2、获得键的方法:返回所有的键的set集合 Set keySet();
3、遍历set集合,通过集合里面的键,来获取值。
迭代器
增强for
4、获取对应的值: V get(K key)

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class Demo02_遍历 {
 public static void main(String[] args) {
 Map<String, String> map = new
HashMap<String, String>();
// 增加方法
 map.put("邓超", "孙俪");
 map.put("张智霖", "袁咏仪");
 map.put("王宝强", "马蓉");
 map.put("贾乃亮", "李小璐");
 map.put("文章", "马伊琍");
// 获取所有的键   快速创建引用 alt+shift+L
 Set<String> set = map.keySet();
// 遍历键
//     包裹一段代码的快捷键   选中 alt+shift+z
 Iterator<String> it = set.iterator();
 while (it.hasNext()) {
 // 获得键
 String key = it.next();
 String value = map.get(key);
 System.out.println("key:" + key + "   
value:" + value);
 }
 System.out.println("------------------------
-----------");
 for (String s : set) {
 System.out.println("key:" + s + "  
value:" + map.get(s));
 }
 } }

遍历2
1、直接获取到所有的键值对,把所有的键值对放到set集合当中去,遍历键值对,通过键值对来获取键和值。
2、通过一个方法,可以获取到所有的键值对的集合 Set<Map.Entry<K,V>> entrySet()
3、遍历set集合,遍历方式:
迭代器
增强for
4、使用键值对对象来调用方法,获取其中的键和值。
Entry是Map接口当中的一个内部的接口,访问方式是Map.Entry
Entry:登录; 进入; 条目
常用的方法:
getKey(); 获取当前的键值对对象的键
getValue();获取当前的键值对的值

public class Demo03_遍历2 {
 public static void main(String[] args) {
 Map<String, String> map = new
HashMap<String, String>();
// 增加方法
 map.put("邓超", "孙俪");
 map.put("张智霖", "袁咏仪");
 map.put("王宝强", "马蓉");
 map.put("贾乃亮", "李小璐");
 map.put("文章", "马伊琍");
// 获取键值对的set集合
 Set<Map.Entry<String, String>> ens =
map.entrySet();
// 遍历set集合
 for (Map.Entry<String, String> en : ens) {
// 调用方法获取键和值
 System.out.println("老公名:" +
en.getKey() + "   老婆名:" + en.getValue());
 }
// 老公名:邓超   老婆名:孙俪
// 老公名:贾乃亮   老婆名:李小璐
// 老公名:王宝强   老婆名:马蓉
// 老公名:文章   老婆名:马伊琍
// 老公名:张智霖   老婆名:袁咏仪
 } }

HashMap

1、是Map接口的一个使用了哈希表存储的实现类
2、键:里面存储的元素是惟一的,如果存储的是jdk当中的类,可以保证唯一性
如果存储的是自定义类型的元素,需要在自定义的类中去重写hashCode和equals方法。
3、HashSet和HashMap的关系:
HashSet底层就是HashMap,使用了HashMap的键那一列,值那一列使用了一个Object的常量来代替了。HashSet底层的方法大量的借用了HashMap底层的方法。

LinkedHashMap

1、是HashMap的一个子类
2、和HashMap不同之处在于,存储进入的顺序和取出来的顺序一致。

Collections工具类

1、static int binarySearch(List list, E key)
使用二分法查询元素,返回索引值
2、addAll(Collection<? super T> c, T… elements)
把elements这些元素添加到c集合当中去
3、max 获取最大元素 min 获取最小元素
4、reverse(List<?> list)
反转集合
5、shuffle(List<?> list)
打乱集合顺序
6、swap(List<?> list, int i, int j)
交换i和j两个索引位置的元素
7、sort(List list)
按照自然顺序给集合当中的元素排序
8、replaceAll(List list, T oldVal, T newVal)
使用另一个值替换列表中出现的所有某一指定值。
9、返回线程安全集合的【***】
synchronizedCollection(Collection c)
返回指定 collection 支持的同步(线程安全的)
collection。
synchronizedSortedMap(SortedMap<K,V> m)
返回指定有序映射支持的同步(线程安全的)有序映射。
synchronizedSortedSet(SortedSet s)
返回指定有序 set 支持的同步(线程安全的)有序
set。

可变参数(jdk1.5)

1、使用格式:
修饰符 返回值类型 方法名字 (数据类型… 参数名){
方法体
}
2、解释说明:
数据类型… 表示可变参数,将来使用这个方法的时候,可以传递进来任意多个该数据类型的参数;
3、注意事项:1 可变参数只能用一个 2只能写在参数列表的最后面 3如果需要其他类型的参数,需要写在可变参数的前面

五、异常

异常概述

1、在java程序运行过程当中,出现了不正常的情况,就称之为异常。
2、在java当中,异常本质上其实是一个对象,定义异常对象的就是异常类,这个类中,定义了异常出现的原因,以及该异常的类型,以及该异常出现的位置等等信息,把这些信息都放到异常对象当中去。
3、异常也有处理的机制,可以进行程序运行的跳转,捕捉,以及结束程序。

异常的体系

1、Throwable:是所有异常体系的顶层父类。java当中的所有的异常或者是错误全部都是Throwable类的子类。
2、Error:错误:是Throwable的子类,用来描述那些无法捕获的处理的错误情况,属于很严重的错误,例如,栈内存溢出
StackOverflowError 把他当做无法解决的疾病: 例如 癌症 中了一万枪 不能认为解决
3、Exception:异常:是Throwable的子类,用于描述那些可以捕获或者处理的异常情况,属于不太严重的错误
例如:ArrayIndexOutOfBoundsException 把他当做 : 感冒 摔泥坑了
4、RuntimeException:运行时异常,是Exception的一个子类,在编译的时候,不会对这个异常进行检测,但是在运行的时候,会抛出这个异常。
5、体系图:(***)
Throwable 异常的顶层父类
Error 错误
Exception 异常
RuntimeException 运行时异常

jvm对异常的处理机制

1、在代码的某一个位置,发生了异常,就把异常情况封装成了一个对象
2、把这个异常对象跑出来给调用了这段代码的方法
3、该方法也把这个异常抛出来,跑给这个方法的调用者
4、一层一层的往上抛,知道抛给主方法。
5、主方法也不能解决这个异常,只能去抛给调用主方法的jvm虚拟机
6、jvm也不能解决这个异常,只能是把这个异常通过错误流来打印到控制台上,让程序员去解决。
总结:jvm解决异常,一层一层往上抛,直到抛给jvm,然后结束程序,打印异常。

手动处理异常的方式

1、有两种处理异常的方式
异常的声明:
如果某一个方法存在编译时异常的时候,编译就无法通过,就需要方法区声明可能会产生的异常,告诉方法的使用者,你使用这个方法,可能会出现异常,声明之后就可以使用了。
异常的捕获:
出现异常之后,可以通过一些手段【特殊的代码格式】来对于这些异常进行捕捉和处理,将来可以让程序在遇见异常之后,还可以继续的运行,可以自己去书写特殊的代码来对于异常进行处理。
2、异常的捕获格式:
try…catch
try…catch…finally
try…finally 【不捕获异常,只能保证某一段代码一定不
被异常打断】

捕获异常

try…catch语句
1、try…catch
try{
可能会出现异常的代码
}catch(可能会出现异常的类型 标识符){
处理异常的方式
}
2、解释说明:
try:尝试
try代码块当中,可能存在着运行出现异常的代码,是对于异常进行检测是
catch:抓取,捕获
catch代码块:捕获try语句当中可能会出现的异常,并且对于这个异常进行处理
catch小括号:里面书写的异常类型,就代表着将来可以捕获到的异常的类型,还可以捕获其子类的异常 标识符,就是捕获到的异常对象的名字
catch大括号:
定义了异常捕获完成之后的处理方式,例如:书写日志、打印出异常信息、结束程序、忽略异常
3、运行逻辑:
(1)运行try代码块当中的代码
《1》有异常
使用catch块来捕捉异常
①抓到了
运行catch代码块当中的语句
②没抓到
不运行catch代码块当中的语句,但是jvm就抛出了该异常打断程序的运行
《2》无异常
向下正常执行
4、try就理解为你的女神的生活,当女神没问题的时候,不去找备胎,catch块,如果出现了异常,就去寻找catch块【备胎】,处理完成之后,下面的代码接着运行。
try…catch…finally
1、格式
try{
可能出现异常的代码
}catch(可能发生异常的类型 异常对象名){
对异常的处理方式
}finally{
一定要执行的代码
}
2、finally{}:一定要执行的代码块
(1)如果try块里面的代码出现了异常,并且有一段代码,还不希望受到影响,那么就可以放到finally代码块当中去。
(2)一般用于关闭资源【关闭流】
3、注意事项: finally代码块当中的代码,也不一定肯定被执行到。

编译时异常和运行时异常

1、相同点:无论是编译时期异常还是运行时期异常,本质上都是程序运行的时候,才可能产生的异常。
2、区别:
(1)继承的体系不同:
编译时异常:是Exception以及下面的子类,除去RuntimeException以及它下面的子类。
运行时异常:都是RuntimeException以及其下面的子类
(2)对于异常的检测时期不同:
编译时异常:在javac编译的时候,对这些异常就会进行检测,如果检测到了编译时异常,就编译失败,给出异常提示。
运行时异常:是在java进行运行的时候,如果遇到了异常就做出处理

throw关键字

1、throw:扔、投、抛出,用于抛出异常
2、异常是一个对象,当程序发生了一些异常的情况,程序员认为这些情况和我们的生活不相符,就可以针对于这个情况把这些异常的信息封装成一个对象,使用throw关键字抛出这个异常对象。
3、作用: 创建一个异常对象,使用throw关键字跑出来,可以实现程序的跳转或者是结束。
4、说明: 抛出编译时异常:必须在编译的时候对他做处理,才可以编译成功。
抛出运行时异常:相当于编译的时候,没有异常,可以在编译的时候,不对这个异常做出处理。

throws关键字

1、用来声明异常
2、在一个方法当中,可能会出现一些异常,我们希望调用者可以考虑到出现异常这个因素,我们就可以在方法的声明上添加异常,让将来调用这个方法的程序员来解决。
3、声明格式
修饰符 返回值类型 方法名(参数列表) throws 异常类型1,异
常类型2…{
可能出现异常的代码
}
4、注意事项:
(1)如果将来可能会抛出运行时异常,那么就不需要声明,因为运行时异常,声明了,也相当于是没有声明,运行时异常在编译器可以不处理。
(2)如果声明了编译时一会吃那个,那么将来调用这个方法的时候,就必须要针对于这个异常做出处理。
(3)在声明异常的时候,尽量准确【声明小的异常类型】,如果有多个异常需要声明,尽量声明一个大的异常即可。
throw和throws的比较
1、throw用于抛出异常,throws用于声明异常
2、throw后面跟一个异常对象,throws后面跟着很多的异常类名
3、throw出现了,就真的有异常对象的产生,throws声明了异常,不一定会有异常对象的出现。

自定义异常

1、jdk当中虽然提供了非常多的异常,但是我们出错的时候,也不一定出的错误是它一定规定好的,所以我们就需要自定义异常
2、观察发现: jdk当中的异常没有自己的方法和参数,全部都是集成于Throwable类的参数和方法,只是名字和产生异常的原因相似。
3、当我们在生产环境当中,可能会出现的问题jdk当中的异常无法描述了,我们就需要去自定义异常。
4、步骤:
(1)选择定义的异常类型
《1》如果是运行时异常,就定义一个类,去继承RuntimeException
《2》如果是编译时异常,就定义一个类,去继承Exception
(2)提供构造方法,在构造方法中,直接去访问父类的构造方法就可以了

六、File类

1、File类是一个表示文件路径或者是文件夹路径的一个对象。
2、路径:是用来描述文件或者是文件夹在电脑当中所在位置的一个字符串
3、路径分类:绝对路径和相对路径
4、绝对路径:就是从根目录开始的路径,叫做绝对路径在windows当中,盘符路径叫做根目录,从盘符开始的路径,叫做绝对路径。 在Linux,/是根目录,从/开始的路径就是绝对路径。
5、相对路径: 相对于不同的路径,有不同的相对路径。
例如:
Dos命令当中,相对于当前的路径:b/c/ 就是相对路径
eclipse当用:相对路径是相对于当前工程的根目录

File类的构造方法

File(File parent, String child) 根据parent对象创建时候的路径,拼接上child路径,来创建一个新的File对象
File(String pathname) 根据给定的字符串路径,来创建一个File对象
File(String parent, String child) 根据字符串parent和child的拼接路径,来创建一个File对象

创建方法

1、boolean createNewFile() 创建一个当前file对象描述的文件
2、boolean mkdir() 创建当前file对象描述的文件夹,如果父路径不存在,不能创建。【只能创建一层】
3、boolean mkdirs() 创建当前file对象描述的文件夹,如果父路径不存在,依旧可以创建。【可以创建多层】

import java.io.File;
import java.io.IOException;
public class Demo03_练习 {
 public static void main(String[] args) throws
Exception {
// 在d盘下的a\b\c\d下面创建一个文件,名字叫做
Love.txt
 File f1 = new File("e:/a/b/c/d/");
 boolean mkdirs = f1.mkdirs();
 System.out.println(mkdirs);
 
 File f2 = new File(f1,"Love.txt");
 boolean createNewFile = f2.createNewFile();
 System.out.println(createNewFile);
 
 } }

删除方法

1、delete() 用来阐述对象描述的文件或者是文件夹
2、注意事项:(1)删除文件的时候,不走回收站 (2)删除文件夹,只能删除空的文件夹

重命名方法

1、renameTo(File f)
方法的调用者是当前文件或者文件夹对象
修改之后的路径是传入进来的f文件或者是文件夹对象
2、注意事项:
如果是在原来的目录下,是修改名字
如果不是在原来的目录下,是剪切并且修改名字
如果修改的路径不存在,则不能重命名

判断功能

1、exists() 判断该对象表示的路径是否存在
2、isFile() 判断该对象是否是一个文件
3、isDirectory() 判断该对象是否是一个文件夹

获取功能

1、getAbsolutePath() 获取当前File对象的绝对路径
2、getPath() 获取的是构造方法当中封装起来的路径
3、getName() 获取的是路径最下面的文件名或者是文件夹名字
4、length() 获取文件的字节数
如果被文件夹调用,返回的数据是0 5、String[] list() 返回当前文件夹下面的所有文件和文件夹的名称,放到一个String类型的数组当中去
6、File[] listFiles() 获取当前文件夹下面的所有的文件和文件夹对象的数组,返回的是File类型的数组

七、io流

概述

1、IO:input 输入 Output 输出
2、在看待输入输出方向的时候,我们要站在内存的角度上看问题【目前】 数据进入内存:输入 数据从内存当中写出到磁盘:输出
3、在java当中,负责各个设备之间数据传输的对象,都是IO流对象,这些IO流对象所在的 类,都在IO包当中

IO分类

1、分类的方式有两个,可以去按照流的方向去分类,可以按照功去分类
2、按照流的方向分类: 输入流:其他的设备的数据进入内存的对象 输出流:从内存当中把数据传入到其他设备的对象
3、按照功能分类:这个流来传输什么样的数据 字节流:传输操作字节的流对象 字符流:传输操作字符的流对象
4、共同结合分类: 字节流:字节输入流:InputStream 字节输出流:OutputStream 字符流:字符输入流:Reader 字符输出流:Writer

字节流

InputStream

1、字节输入流的顶层抽象父类
2、常用的方法: read()读取一个字节,并且返回,如果返回-1表示没有读取到 read(byte[] b) 读取字节,并放到传入的字节数组b当中去,返回读取到的个数 available() 返回还可以读取到的字节的个数 close() 关闭流对象
3、InputStream是一个抽象类,不能直接的创建对象,只能使用子类创建对象。

FileInputStream

1、它是InputStream的普通子类,用于和磁盘上的文件进行交互
2、FileInputStream不仅仅可以一次读取一个字节,还可以一次性读取多个字节,不仅仅可 以读取存文本文件,还可以读取其他的文件,例如照片、视频、录音。计算机当中文件的存 储,本质上存储的是二进制信息,这些二进制信息,可以使用字节来进行展示,计算机上存 储的是字节信息。
3、构造方法: FileInputStream(String path) 把字符串表示的路径封装成一个字节输入流,将来可以读取这个路径的文件信息 FileInputStream(File f) 可以把file对象封装成一个字节输入流,将来读取文件的信息。

OutputStream

1、字节输出流的顶层父类
2、常用方法: write(int b) 写出一个字节到指定的设备中 write(byte b[]) 写出一个字节数组的指定的设备中 write(byte b[], int off, int len) 写出字节数组的一部分到指定的设备中,从off索引开始,写出len个字节。
3、这个类是一个抽象类,不能直接创建对象

FileOutputStream

1、是OutputStream的一个普通的子类,可以把字节输出写出到指定的文件当中
2、构造方法: FileOutputStream(String path) 把文件的路径封装成一个字节输出流对象 FileOutputStream(File f) 把file对象f表示的路径信息封装成一个字节输出流对象
3、注意事项: (1)成员方法基本上都来自于父类 (2)使用该流写出到磁盘上的文件当中去,写出的是具体的字节信息,没有涉及到编 码,至于为什么我们写出的是字节信息,但是打开文件可以看到文字,是因为编辑器在打开 文件的时候,会对文件当中的字节信息做解码,所以说我们可以看到文字。

文件拷贝

1、含义: 将磁盘上一个文件当中的数据读取到内存当中,从内存当中再写出到磁盘当中的另外一 个位置的文件中。
2、代码: 使用字节输入流,把一个文件读取出来字节数组,在读取出来之后,使用字节输出流, 写出这些读取出来的字节数组到另外一个文件。
文件拷贝效率提升
1、使用一个一个字节的方式进行拷贝,效率低,原因是IO的次数过多,有多少个字节,就得 读写多少次。
2、提升的思路,一次多读取一些数据,一次多写出一些数据,减少IO的次数。
3、使用数组来进行读取,因为我们的内存是有限的,所以说使用数组的大小也有考究,如果 使用的数组太大,就超出了内存大小,如果说使用的数组太小,还是会IO次数太多。
4、输入流当中,使用read(byte[] arr,int off ,int len);
5、输出流当中,使用write(byte [] arr ,int off ,int len);
6、数组的大小: (1)数组的大小可以任意的选择,数组越大,拷贝的次数就越少,效率越高 (2)一般来说,数组可以使用1024的整数倍,jdk当中比较喜欢使用1024*8来作为缓冲 区大小。

read()和read(byte [] arr)的比较

1、读取字节数: read() 一次读取一个 read(byte [] arr) 一次读取多个,取决于数组的大小和文件的大小
2、读取到的字节信息存储位置的不同: read() 使用方法的返回值直接进行返回 read(byte [] arr) 存储到我们传递进去的指直接数组当中去 3、返回值的含义不同 read() 返回值就是读取到的字节本身 read(byte [] arr) 返回值是读取到的字节的个数 范围【-1,arr.length】

高效缓冲流

1、BufferedInputStream和BufferedOutputStream 2、是包装类型,本身不具备读写的功能,只是可以在某一个流对象的基础之上,做增强的效 果,例如原来的FileInputStream效率比较低,使用了BufferedInputStream的增强之后, 就可以调高效率 3、构造方法: BufferedInputStream(InputStream in) 传递进来一个InputStream 流对象,给这个流对象做加强,返回一个高效的字节 输入流BufferedOutputStream(OutputStream out) 传递进来一个OutputStream 流对象,给这个流对象做加强,返回一个高效的字节 输出流 4、使用: 这个个高效流还是字节流,所以说,他只是做增强,我们之前的InputStream和 OutputStream类中的方法还可以继续使用。 5、高效原理: BufferedInputStream高效原理:在这个类型当中有一个缓存的数组,存储字节信息, 当我们去调用read方法来读取一个字节的时候,直接从流当中读取了8192个字节放到了自己 的缓存数组当中,再从数组当中给我们返回回来这个字节,当我们下一次去读取字节的时 候,直接从缓存数组当中去读取即可,不需要再从文件当中去读取了减少了io的次数,直到 8192个字节都被读取完了,再次去文件当中读取8192个字节,放到缓存数组当中去。 BufferedOutputStream高效原理:在对象当中准备了一个缓存数组来存储字节信息, 当我们调用write方法写出一个字节的时候,其实是写出到缓存的字节数组当中去,直到去刷 新缓冲区才会把缓冲区数组当中的字节信息给写出到文件当中。在字节数组沾满了的时候会 自动的刷新缓冲区,调用flush方法的时候会刷新缓冲区,调用close方法关闭流的时候,也 会刷新缓冲区。

输出流当中的close()和flush()的区别

1、close方法会先去调用flush方法
2、close方法是用来关闭流对象的,在调用了close方法之后,该流对象就不能继续使用了
3、flush方法是用来将缓冲区数组当中的字节信息刷新到对应的文件当中去,不会关闭流对 象,调用了该方法之后,流对象还可以继续使用,但是,flush方法不能使用太频繁,使用的 太频繁,就失去了缓冲区的作用。

字符流

使用字节流来处理字符的问题

1、使用字节流写字符 可以,需要把字符串先转换为字节数组,然后在写出到文件当中,比较麻烦 2、使用字节流读取字符 纯英文:一次读取一个字节 纯中文:一次读取2个字节代表一个汉字【GBK】 如果有英文还有中文:每次就不知道读取多少个字节了,容易出现乱码 3、解决(1)出现乱码的原因: 每次不知道读取多少个字节转换为字符了 我们在代码当中,每次读取的字节数是固定了。 (2)解决办法:【gbk编码表】 因为英文字节是正数,而我们的中文的两个字节中的第一个一定是负数,所以遇见 了负数的就多读取一个,遇见了正数的,就可以直接转换,就可以保证不乱码。 (3)如果这么来操作的话,对于我们的字符的读取太过于复杂,所以说,在jdk当中给 我们提供了更加友好的解决方案:字符流 字符流:可以自动的根据编码表判断是中文还是英文,保证不乱码。

字符流的使用

1、抽象的顶层父类:Reader Writer
2、常用的方法:
(1)Reader read()读取一个字符,如果返回值是-1,就表示文件已经到结尾了 read(char [] arr ) 读取到一个char类型的数组当中去,返回值是读取到的字符的个数,如果 读到了文件的结尾,返回值是-1 read(char [] arr ,int off ,int len) 读取到一个char类型的数组当中去,使用off索引的len个索引位置。
(2)Writer write(int c ) 写出一个字符 write(char[] arr ) 写出一个字符数组 write(char[] arr,int off ,int len ) 写出一个字符数组的一部分 write(String s ) 写出一个字符串
3、抽象类不能创建对象,需要具体的子类来创建对象 4、使用FileReader和FileWriter类创建对象

多线程

概述

1、线程是一个动态的概念,从创建到消亡就有变化的过程,会出现各种各样的状态,这些状 态有时候还可以互相转换。
2、线程状态图、线程的声明周期图
3、线程状态: 新建态:刚创建出来线程,刚创建出来线程对象,使用了new 就绪态:调用了start方法,就转换为就绪态,就是线程准备好了运行需要的资源,等 待cpu来运行 运行态:cpu正在执行该线程的状态 阻塞态:线程主动的休息、缺少一些运行的资源、即使cpu来了,也不能运行 死亡态:线程运行完毕了、出现了异常、调用方法结束了

线程状态转换图

在这里插入图片描述

java当中对于线程状态的描述

1、我们对于线程状态的描述是概念上的,在java的代码当中具有更加准确的描述,可以将各 种线程的状态描述封装成具体的对象,存放起来。这些对象可能出现的时机也不相同
2、获取线程状态的方法: getState() 获取当前线程状态的对象,返回值类型是: Thread.State,它存放在Thread内 部,是一个内部类
3、Thread.State:在java当中,用于描述线程的状态 线程的状态的种类是有限的,也就是说,该类的对象的个数也是有限的,因为它的对象 有限,所以我不需要我们去创建他的对象,直接就在类当中帮我们创建好了,这种对象有限 个的一个类型叫做枚举类型,每一个对象,叫做枚举项,Thread.State当中,枚举项一个有 6个。
说明:NEW 新建态,没有开启线程,刚创建线程的状态 RUNNABLE 就绪态和运行态 BLOCKED 阻塞态【等待锁对象,进行IO操作】 WAITING 阻塞态【调用wait方法的时候,等待线程唤醒的时候,具有的 状态】 TIMED_WAITING 阻塞态【调用了有时间限制的方法,wait方法,sleep的方法 具有的状态】 TERMINATED 死亡态

线程池

概述

1、线程池的作用:相对于一个存放着线程的容器,里面可以有很多线程,使用完了之后,还可以把线程放回去,提供给我们下一次使用。
2、没有线程池: 当我们需要使用一个线程的时候,先去创建线程,启动线程,在运行的过程中,还有可 能会出现一些错误,会中途把这个执行任务的线程中断掉,任务还没有完成。 就算没有出现中断的现象,线程把任务执行完毕了,线程对象就变成了垃圾对象,线程 对象就被垃圾回收机制回收了。 发现问题:在我们使用线程之后某一个任务的时候,如果这个任务比较的简单,那么大 多数的时间都浪费在创建线程和线程死亡上了。 如果任务本身需要占用的资源比较多,他的破坏力比较大,可能会导致线程对象无法完 成这个任务,就已经死亡了,所以我们还得创建新的线程来完成这个任务,就比较的麻烦。 本质原因:线程的利用率低,一个线程只能执行一个任务,执行完毕后就消亡了,整个 线程的生命只为了执行一个任务。 3、有线程池的状态 没有任务需要执行的时候,我们就先把线程对象准备好,存储到一个容器当中去,一旦 有任务需要执行了,就不用创建线程对象了,从容器当中取出来一个线程,帮助我们去执行 任务,任务执行完毕,让该线程回到容器当中去,等待下一个任务。 如果任务比较麻烦,可能会把该线程整死,这个任务不会跟着消亡,线程池会提供一个 新的线程来执行这个任务,直到这个任务被执行完毕。

使用

1、步骤:获取线程池对象,创建任务对象,把任务对象提交给线程池当中的线程去执行。
2、获取线程池对象: 工具类:Executors:帮助我们去生成线程池,可以根据需要生成指定大小的线程池 ExecutorService newFixedThreadPool(int nThreads) 根据传递进来的nThreads,来返回一个数量具有nThreads多条的线程池 ExecutorService newSingleThreadExecutor() 返回一个只有一条线程的线程池
3、创建任务类对象:Runnable的实现类对象,用于定义任务的具体的内容
4、把任务对象加入到线程池当中去:
ExecutorService 是一个接口,我们使用的他的对象是由于Executors工具类帮助我们 创建的一个ExecutorService接口的实现类对象,我们也不知道该实现类当中具体有什么方 法,这个实现类对象是哪个类的对象,因为该对象实现了ExecutorService接口, ExecutorService当中的方法在此对象当中,一定也有。所以调用ExecutorService接口当 中的方法即可。 submit(Runnable task) 提交一个Runnable的任务给线程池,让线程池帮助我们去运行这个任务,如果有空闲的线程,就可以马上的去运行这个任务,如果没有空闲的线程,这个任务就需要等待。 shutdown() 关闭结束线程池,已经提交的任务可以保证全部都完成,不运行继续提交。 shutdownNow() 关闭结束线程池,以及开始运行的任务,保证完成,没有运行的任务,就不再去运 行了,作为返回值返回List,返回还没有来得及执行的任务,不准提交。


总结

以上就是对java基础知识一个大体的总结,知识点较多较杂,可以时常来回顾回顾!

  • 9
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值