Java笔记 (基础)

1. Java基本知识

  • 什么是java:

是一种面向对象的高级编程语言

  • java的组成:

javase/j2se(java标准版),javaee/j2ee(java企业版)(13几种技术)

  • java的应用:

internet程序(b/s)和桌面应用程序(c/s) browser

  1. 记事本开发程序的步骤

①编写:编写源文件Test.java 编译javac Test.java

②编译:字节码Test.class 运行java Test

③运行:运行结果

  1. java的基本机构
public class Test{
	public static void main(String[] args){
		System.out.println("你好");	
	}
}
  1. 注意四点:

①类名的首字母要大写,要保证类名与文件名一样

②所有的括号要成对出现,遇到大括号的开始要缩进,大括号的结束要与其对应大括号的开始最前端对齐

③所有标点符号都是英文的

④每行只能放一句代码,每句以分号结束

  • 用记事本开发程序的三步走

①编写

②编译

③运行

  • 打印

System.out.print(); 只打印

System.out.println(); 打印+换行

  • 转义\:反斜杠必须双引号

\t制表位

\n换行

  • 注释:

单行注释 ://注释内容 添加和取消:ctrl+/

段落注释:/*注释内容*/ 添加:ctrl+shift+/ 取消:ctrl+shift+/

2. 数据类型

1. java 数据类型分为两大类 基本数据类型引用类型

2. 基本数据类型有 8 中 数值型 [byte , short , int , long , float ,double] char , boolean ]

3. 引用类型 [类,接口, 数组]

注:

Math.abs( num1 - num2) 此方法运用于两个浮点数之间比较如果小于一定精度就可以认为两个数相同。因为两个浮点数如果出现乘除关系会出现以下情况:

此时可以用到 Math.abs 方法

数据类型char

char可以直接存放一个数;但是当输出时并不会直接输出数字:(这时控制台出现的a是97代表的是字符a)

也可以反向操作:比如:定义一个char为一个字符在输出语句上加上(int)可以输出对应的数字

数据类型char 只能用单引号

在Java中char的本质是一个数对应输出时输出unicode码对应的字符

布尔类型:boolean

存取 true 和 false 不能用0和1代替这点和c语言不同

基本数据类型的转换

自动类型转换:(图中箭头所指可自动转换)例如:double = 80;输出80.0

细节:

当我们把精度(容量)大的数据类型赋值给精度(容量)小的数据类型时就会报错,反之就会自动转换

byte 类型 char 类型 short类型 三种类型之间不会自动转换。

类型的强制转换: 会导精度损失

把精度大的赋给精度小的就会造成进度损失。

char可以保存int的常量值不能保存int的变量值

byte short char 三者相互计算时会自动转换成 int 型

基本数据类型可以转换成字符串类型String只需要加 +“”

将字符串的数字提取出来进行计算

根据索引将字符串的首位提取出来,必须用char接收(必须确定String里面存放的内容可以提取;比如存放的是字符“hello”就会抛出异常;所以说使用charAt提取时必须保证里面的是可以提取出的数值。

3. 运算符 (ArithmeticOperator)

3.1. 算术运算符:

➗ 的使用

% 取余数 (取模)

在 % 的本质,看一个公式: a % b = a - a/b * b (此时的a/b取整数不看余数)

例如: 10 % 3 = 10 - 10/3 * 3 整体算下来 等于1

-10 % 3 = -10 - (-10)/3 * 3 = -1

10 % -3 = 10 - 10/(-3) * (-3) = 1

++ 的使用 :(重点:i++和 ++i)

i++作为独立语句使用时 和++i的效果一样

作为表达式使用时候:

i++ :先赋值后自增

++i :先自增后赋值

-- 一样的道理同++ 还有 *

关系运算符:

3.2. 逻辑运算符

&& 和 & (只要有一个false结果就是false 两个只要有一个是false if语句里面的代码就不会被执行)

&& 短路,如果第一个条件为false后面的不在判断(不再执行后面的代码)

& 逻辑,如果第一个条件为false后面的会继续判断(执行后面的代码)

| 和 || (只要有一个为真结果就为真 if判断时用只要两者有一个为真if里面的代码就会被执行)

同上的不同是:( | | )如果第一个条件为真则后面的不会再执行(整体为真);效率高

( | )如果第一个条件为真则后面依旧会执行(第二个为真则整体真,为假则整体假)

! 取反(真变假 假变真) 真假互换

^ 异或 当两者不同时结果为 T 否则为 F

3.3. 赋值运算符

+= : A= A+B

-= :A= A-B

/= : A= A/B

%= : A = A%B

复合赋值运算会进行类型转换

3.4. 三元运算符

条件表达式? 表达式1: 表达式2;

运算规则:

1. 如果条件表达式为true,运算后的结果是表达式1;

2. 如果条件表达式为false,运算后的结果是表达式2;

口诀: [一灯大师:一真大师]

例如:

图中为三元运算符用法;若红色方框内成立则为真,整体为true 执 黄色方框

若红色方框内不成立则为假,整体为false 执行蓝色方框

一定要注意

这时会先把num1的值赋给num3然后num1再自增

3.5. 运算符的优先级

3.6. 进制

二进制(BIN):0,1 ,满2 进1.以0b 或0B 开头。

八进制(OCT):0-7 ,满8 进1. 以数字0 开头表示。

十进制(DEC ):0-9 ,满10 进1。

十六进制(HEX):0-9 及A(10)-F(15),满16 进1. 以0x 或0X 开头表示。此处的A-F 不区分大小写。

进制转换:(分三组)

第一组:

  1. 二进制转十进制

  1. 八进制转十进制

  1. 十六进制转十进制

规则:从最低位(右边)开始,将每个位上的数提取出来,乘以16 的(位数-1)次方,然后求和。

案例:请将0x23A 转成十进制的数

0x23A = 10 * 16^0 + 3 * 16 ^ 1 + 2 * 16^2 = 10 + 48 + 512 = 570

总结:几进制转十进制;将每个位上的数提取出来,乘以几的(位数-1)次方,然后求和。

第二组:

  1. 十进制转二进制

规则:将该数不断除以2,直到商为0 为止,然后将每步得到的余数倒过来,就是对应的二进制。

  1. 十进制转八进制

规则:将该数不断除以8,直到商为0 为止,然后将每步得到的余数倒过来,就是对应的二进制。

  1. 十进制转十六进制

规则:将该数不断除以16,直到商为0 为止,然后将每步得到的余数倒过来,就是对应的二进制。

总结:十进制转几进制;将该数不断除以几,直到商为0 为止,然后将每步得到的余数倒过来,就是对应的几进制

第三组

  1. 二进制转八进制

规则:从低位开始,将二进制数每三位一组,转成对应的八进制数即可。

  1. 二进制转十六进制

规则:从低位开始,将二进制数每四位一组,转成对应的十六进制数即可。

第四组

  1. 八进制转二进制

将八进制数每1 位,转成对应的一个3 位的二进制数即可

  1. 十六进制转二进制

规则:将十六进制数每1 位,转成对应的4 位的一个二进制数即可。

3.7. 位运算

3.8. 原码、反码、补码(重点难点)

4. 程序控制结构:

4.1. 顺序控制:

程序是自上而下执行的,中间没有任何判断和跳转。

4.2. 分支控制(if - else):

1) 单分支 if

2) 双分支 if-else

3) 多分支 if-elseif -....-else

5. 类和对象

对象:具体到某一个事物(实体)的时候,看的见,摸的着

:从相同类型的一组对象中抽象出来的共同特征和行为,看不见摸不着

对象是类的实体

类是对象的类型

类和对象:多个是类,单个理解对象,类无属性值,对象是有属性值

定义类

public class 类名{

成员变量(属性)

数据类型 变量名

...

成员方法(行为)

public void 方法名(){

}

...

}

创建对象

类名 对象名=new 类名();

对象的使用

对象名.属性

5.1. String类

方法

作用

用法

charAt()

返回指定索引位置的字符

concat()

在字符串的后面追加

equals()

equals属于object的方法 通常用于比较对象

在字符串里比较内容是否相等

equalsIgnoreCase()

将此 String 与另一个 String 比较,不考虑大小写。

indexOf()

返回指定字符在此字符串中第一次出现处的索引。

lastIndexOf()

从后往前寻找,与上一个相同

substring(2,3)

字符串截取,从2截到3

前包后不包,

length()

返回在字符串长度

compareTo()

按字典顺序比较两个字符串。

如果第一个字符和参数的第一个字符不等,结束比较,返回第一个字符的ASCII码差值。

split()

根据给定正则表达式的匹配拆分此字符串。

按,分开

trim()

返回字符串的副本,忽略前导空白和尾部空白。

isEmpty()

判断字符串是否为空。

contains()

判断是否包含指定的字符系列。

返回Boolean类型

replace()

String replace(char oldChar, char newChar)

oldChar :要替换的字符

newChar :替换成的字符

toUpperCase()

使用默认语言环境的规则将此 String 中的所有字符都转换为大写

toLowerCase()

使用默认语言环境的规则将此 String 中的所有字符都转换为小写

5.2. 包

5.2.1. 包的本质

5.2.2. 包的作用:

5.2.3. 包的基本语法

5.2.4. 包的命名规则

5.2.5. 常用包

一个包下,包含很多的类,java 中常用的包有:

1) java.lang.* //lang 包是基本包,默认引入,不需要再引入.

2) java.util.* //util 包,系统提供的工具包, 工具类,使用 Scanner

3) java.net.* //网络包,网络开发

4) java.awt.* //是做 java 的界面开发,GUI

5.3. 访问修饰符

5.3.1. 基本介绍:

java 提供四种访问控制修饰符号,用于控制方法和属性(成员变量)的访问权限(范围)

1) 公开级别:用 public 修饰,对外公开

2) 受保护级别:用 protected 修饰,对子类和同一个包中的类公开

3) 默认级别:没有修饰符号,向同一个包的类公开.

4) 私有级别:用 private 修饰,只有类本身可以访问,不对外公开

5.3.2. 4种访问修饰符的范围

1

访问级别

访问修饰符

本类

同包

子类

不同包

2

公开

public

3

受保护

protected

×

4

默认

没有修饰符

×

×

5

私有

private

×

×

×

5.3.3. 访问修饰符的细节

5.4. 方法的传参机制:

5.4.1.1. 返回值使用细节:
  1. 一个方法最多有一个返回值 [思考,如何返回多个结果 返回数组 ]
  2. 返回类型可以为任意类型,包含基本类型或引用类型(数组,对象)
  3. 如果方法要求有返回数据类型,则方法体中最后的执行语句必须为return 值;而且要求返回值类型必须和return的值类型一致或兼容
  4. 如果方法是void,则方法体中可以没有return语句,或者 只写 return

返回值类型与方法名前面的类型保持一致;

只能返回一个返回值,如果想要返回多个返回值,可以用数组

5.5. 递归的执行机制

5.5.1. 递归的规则

递归调用的过程中,每递归一次,就会创建一个新的栈空间,直到最后一次递归执行完毕,依次返回。

5.6. static 关键字:

  • 静态的不能访问非静态的,非静态的可以调用静态的
  • static静态的 只能修饰类成员,一但修饰了类成员,类成员属于类,不属于对象

作用:区分类和对象必须分清类和对象

  1. 被 static 修饰的成员属于类,类成员、静态成员 通过【类.成员】调用
  2. 不被 static 修饰的成员属于对象,对象成员,非静态成员 通过【成员.成员】调用
  3. 静态成员可以被所有对象共享

5.7. idea 加作者

/**
 * @program: ${PROJECT_NAME}
 * @description: ${description}
 * @author: 高元浩
 * @create: ${YEAR}-${MONTH}-${DAY} ${HOUR}:${MINUTE}
 **/

6. 面向对象编程三大特征

6.1. 封装(encapsulation)

6.1.1. 基本介绍

面向对象编程有三大特征:封装、继承和多态。

6.1.2. 封装介绍

6.1.3. 封装的理解和好处

6.1.4. 封装的实现步骤 (三步)

6.1.5. 构造器:

6.2. 继承(extends)

6.2.1. 为什么需要继承?

6.2.2. 继承基本介绍和示意图

继承可以解决代码复用,让我们的编程更加靠近人类思维.当多个类存在相同的属性(变量)和方法时,可以从这些类中

抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过extends 来

声明继承父类即可。画出继承的示意图

6.2.3. 继承的基本语法

有共同属性和方法的类;可以再建一个类将这些相同的属性和方法提取到另一个新的类里面,让其他类直接继承这个类就可以了

6.2.4. 继承给编程带来的便利

  1. 代码的复用性提高了
  2. 代码的扩展性和维护性提高了

6.2.5. 继承的的细节问题

  1. 子类继承了所有的属性和方法,非私有的属性和方法可以在子类直接访问, 但是私有属性和方法不能在子类直接访问,要通过父类提供公共的方法去访问
  2. 子类必须调用父类的构造器, 完成父类的初始化

  1. 当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中用super 去指定使用父类的哪个构造器完成对父类的初始化工作,否则,编译不会通过(怎么理解。)

也就是说父类中如果定义了带参构造器,没有写无参构造器,那么父类默认存在的(一个类不用写默认带无参构造器)无参构造器将会被定义的带参构造器覆盖掉,那么此时 子类中必须要使用super指明使用哪个构造器。

  1. 如果希望指定去调用父类的某个构造器,则显式的调用一下: super(参数列表)
  2. super 在使用时,必须放在构造器第一行(super 只能在构造器中使用)
  3. super() 和this() 都只能放在构造器第一行,因此这两个方法不能共存在一个构造器
  4. java 所有类都是Object 类的子类, Object 是所有类的基类.
  5. 父类构造器的调用不限于直接父类!将一直往上追溯直到Object 类(顶级父类)
  6. 子类最多只能继承一个父类(指直接继承),即java 中是单继承机制。

思考:如何让A 类继承B 类和C 类? 【A 继承B, B 继承C】

  1. 不能滥用继承,子类和父类之间必须满足is-a 的逻辑关系

6.2.6. 继承的内存布局:

案例中:grandPa类 被 father类继承 father被son继承

如果son调用一个自己没有的属性,那么就会向继承的父类以及爷爷类寻找一直到object类;

① 如果他的父亲类有此属性,则返回

② 如果他父亲和爷爷都有,但父亲的属性是私有的不能访问,那么他不会继续向上寻找而是直接报错!!!

6.2.7. super 关键字

6.2.7.1. 概念

super 代表父类的引用,用于访问父类的属性、方法、构造

6.2.7.2. 基本语法

在调用方法时:

方法名() 会先在本类寻找

      1. 本类找到直接用
      2. 本类找不到,向上寻找,找到了不能访问(私有的)直接报错
      3. 向上寻找,一直到object都没有找到,提示方法不存在

super.方法名()

会直接在父类中开始向上寻找,也就是省略了上面的

属性 和 this.属性

      1. 先找本类,如果有,则调用
      2. 如果没有,则找父类(如果有,并可以调用,则调用)
      3. 如果父类没有,则继续找父类的父类,整个规则,就是一样的,直到对象(Object)类提示:如果查找属性的过程中,找到了,但是不能访问,则报错,无法访问如果查找属性的过程中,没有找到,则提示属性不存在

super.属性 也是从父类开始寻找,其他规则一样

6.2.7.3. super 的使用细节和带来的便利

6.2.7.4. super 和 this 的比较

6.2.8. 方法重写/覆盖(override)

6.2.8.1. 概念:

6.2.8.2. 注意事项和使用细节

方法重写也叫方法覆盖,需要满足下面的条件

6.2.8.3. 重写 和 重载 (二者毫无关系)

6.3. 多态

6.3.1. 基本概念:

方法或对象具有多种形态。是面向对象的第三大特征,多态是建立在封装和继承基础之上的。

6.3.2. 多态的具体表现:

6.3.3. 多态的注意细节:

  • 多态的前提是:两个对象(类)存在继承关系
  • 多态的向上转型

//(1)可以调用父类中的所有成员(需遵守访问权限)

//(2)但是不能调用子类的特有的成员

//(#)因为在编译阶段,能调用哪些成员,是由编译类型来决定的

//(4)最终运行效果看子类(运行类型)的具体实现, 即调用方法时,按照从子类(运行类型)开始查找方法

//,然后调用,规则我前面我们讲的方法调用规则一致。

eg:

public class Test {
    public static void main(String[] args) {
        //编译类型        运行类型
        Animal animal = new Dog();
        animal.run();
        //编译时会在animal里找 eat 方法,
        //运行时会先在Dog类里找eat() 方法,
        //Java时先编译在运行的,如果编译都过不去,更运行不了
        //所以要想,调用子类(Dog)里面的eat 方法 首先 要让他编译通过,
        //编译要想通过animal里要有eat这个方法,同时Dog子类中也要有这个方法。
    }
}
//动物类
class Animal {
    public void eat(){System.out.println("eat");}
    public void sleep(){System.out.println("sleep");}
}
//狗类继承动物类
class Dog extends Animal {
    public void eat() {System.out.println("Dog eat");}
    public void run() {System.out.println("Dog run");}
}

  • 多态向下转型

  • 属性没有重写之说!属性的值看编译类型
  • instanceOf 比较操作符,用于判断对象的运行类型是否为 XX 类型或 XX 类型的子类型

6.3.4. java 的动态绑定机制

假如 B 继承 A类,在代码执行过程中,遇见调用方法的时候,会首先到绑定的运行类(等号的右边new 出来的)去寻找这个方法,如果在本类中并没有找到这个方法,那么就去父类中寻找这个方法,父类中有这个方法直接调用,如果在父类的这个方法体中还有调用别的方法的,还会首先在子类中寻找也就是B类中寻找,这便是Java的绑定机制;(只有方法🈶绑定机制,属性是没有绑定机制的。)

7. 常用方法

7.1.1. hashCode

老韩的 6 个小结:

  1. 提高具有哈希结构的容器的效率!
  2. 两个引用,如果指向的是同一个对象,则哈希值肯定是一样的!
  3. 两个引用,如果指向的是不同对象,则哈希值是不一样的
  4. 哈希值主要根据地址号来的!, 不能完全将哈希值等价于地址。
  5. 案例演示[HashCode_.java]: obj.hashCode() [测试:A obj1 = new A(); A obj2 = new A(); A obj3 = obj1]
  6. 后面在集合,中 hashCode 如果需要的话,也会重写, 在讲解集合时,老韩在说如何重写 hashCode()

7.1.2. toString()

  1. 默认返回:全类名+@+哈希值的十六进制,【查看 Object 的 toString 方法】 子类往往重写 toString 方法,用于返回对象的属性信息
  2. 重写 toString 方法,打印对象或拼接对象时,都会自动调用该对象的 toString 形式.
  3. 当直接输出一个对象时,toString 方法会被默认的调用, 比如 System.out.println(monster); 就会默认调用 monster.toString()也就是说,如果在类中没有改写 toString 会输出 全类名+@+哈希值的十六进制。

7.1.3. finalize 方法

  1. 当对象被回收时,系统自动调用该对象的 finalize 方法。子类可以重写该方法,做一些释放资源的操作
  2. 什么时候被回收:当某个对象没有任何引用时,则 jvm 就认为这个对象是一个垃圾对象,就会使用垃圾回收机制来 销毁该对象,在销毁该对象前,会先调用 finalize 方法。
  3. 垃圾回收机制的调用,是由系统来决定(即有自己的 GC 算法), 也可以通过System.gc() 主动触发垃圾回收机制

7.1. 断点调试

7.1.1. 为什么要断点调试

7.1.2. 断点调试的介绍:

7.1.3. 断点调试快捷键

跳入(跳入方法内)

F8

逐行执行代码

F9

resume,执行到下一个断点

shift+F8:

跳出方法

7.2. 接口:

7.2.1. 概念:

接口它是一个特殊的抽象类,特殊:接口中所有的方法都是抽象方法,而且接口中所有的属性都是静态常量。而且接口弥补了抽象类的单继承的缺点。--干爹。

7.2.2. 接口的定义语法:

public interface 接口名{
  //静态常量属性
  //抽象方法
}
public interface Usb {
    public static final double width=12;

    public abstract void useUsb();

    public abstract void show();
}
//我们发现接口中所有的属性都是静态常量属性而且所有的
//方法都是抽象方法。那么这些属性和方法都有固定的修饰符。
//那么我们是否可以省略这些修饰符。
public interface Usb {
    double width=12;//默认修饰符也是public static final
    void useUsb(); //默认public abstract
    void show();
}

接口和抽象类一样也是无法创建类对象。 需要让其他类来实现该接口。类在实现接口时需要把接口中所有的抽象方法重写。

7.2.3. 接口和接口之间

  1. 一个接口可以继承多个接口。
  2. 一个类实现了接口后是否还能继承别的类
public class 类名 extends 父类  implements 接口1,接口2...{
}

7.2.4. 接口和抽象类之间的区别

  1. 相同: 接口和抽象类都无法创建对象,他们都是用于作为父亲。用于多态的实现。
  2. 不同:
    1. 接口没有构造方法,抽象有构造方法。
    2. 抽象类中可以没有抽象方法,而接口中都是抽象方法。[1.8以前]
    3. 抽象类中可以有普通属性,而接口中所有的属性都是静态常量。
    4. 一个类可以实现多个接口,但是只能继承一个抽象类。

7.3. 包装类

概念:万事万物皆为对象,基本类型。为了满足这种需求,为基本数据类型提供了包装类。类中会包含想要的功能方法。有这些方法我就可以对基本类型进行操作了。"123"-->整型123.

**int-->Integer**(特殊)

byte-->Byte

short-->Short

long-->Long

double--->Double

float--->Float

boolean-->Boolean

**char--->Character**(特殊)

7.3.1. 自动装箱

装箱: 把基本数据类型转化为包装类的过程--装箱

public class Test {
    public static void main(String[] args) {
        int a=15;//基本类型
        Integer b=a;//自动装箱 必须保证1.5 
        Integer c=new Integer(a);//手动装箱--通用
    }
}

7.3.2. 自动拆箱

拆箱:把包装类转换为基本数据类型

int d=b;//把包装类转化为基本类--自动拆箱
int f=b.intValue();//手动拆箱

7.4. String StringBuffer 和 StringBuilder

String StringBuffer StringBuilder 三个都可以操作字符串。

  • String底层,每次变化都会生成一个新的字符串对象。安全的。
  • StringBuffer和StringBuilder它字符串可以变,每次变化不会生成新的空间。
  • StringBuffer它是线程安全的,因为它加了同步锁。
  • 而StringBuilder它是线程不安全。效率高。

一般我们使用StringBuffer就可以

7.5. Arrays数组工具类

sort

排序

copyOf(数组,newLength)

复制并扩容

binarySearch()

二分查找(必须是排好序的数组)

fill

填充

7.6. Object类

equals方法

  • 调用的toString方法。默认来自Object类。如果打印对象想显示自己的属性信息可以重写toString

toString方法

  • Object类中equals方法本地比较的还是两个对象的引用地址。

hashcode方法。

  • 两个对象的hashcode相同,他们一定是同一个对象

两个对象的hashcode相同,equals一定相同吗

7.7. equals和==。

==:它可以比较基本类型和引用类型。比较基本类型比较的是值,而比较引用 类型比较的引用地址。

equals: 它只能比较引用类型。如果没有重写Object类中的equals方法它比较的 还是引用地址。如果想比较值则需要重写equals

7.8. 关键字的加深理解

7.8.1. static

7.8.2. final

可以修饰 : 类,方法,变量

在某些情况下:

  1. 当不希望类被继承时候使用 final 修饰(给父类加 final ,在 class 前加)
  2. 当不希望某个方法被重写使用 final 修饰(给 方法名前加 加 final ,)
  3. 当不希望某个局部变量被修改的时候,用 final 修饰

7.9. 抽象类

  1. 用abstract 关键字来修饰一个类时,这个类就叫抽象类访问修饰符 abstract 类名{
  2. 用abstract 关键字来修饰一个方法时,这个方法就是抽象方法访问修饰符 abstract 返回类型 方法名(参数列表);//没有方法体
  3. 抽象类的价值更多作用是在于设计,是设计者设计好后,让子类继承并实现抽象类
  4. 抽象类,是考官比较爱问的知识点,在框架和设计模式使用较多
  5. 抽象类不能被实例化[举例]
  6. 抽象类不一定要包含abstract方法。也就是说,抽象类可以没有abstract方法[举例]
  7. 一旦类包含了abstract方法,则这个类必须声明为abstract[说明]
  8. abstract 只能修饰类和方法,不能修饰属性和其它的。[说明]

8. 异常

  1. 什么是异常?

异常就是程序在运行时出现的意外情况而导致程序无法正常往下执行[终止了]

  1. 为什么需要异常处理?

异常的目的就是想让程序继续执行。

public class Test {
    public static void main(String[] args) {
        int a=10;
        int b=0;
        System.out.println("开始计算===============");
        int result=a/b;
        System.out.println("结束计算==============");
    }
}
//我们发现上面再14行发生异常,而导致14行以下的内容都无法正常执行。
//从而导致程序再14终止了。我们应该处理这种异常。能让程序继续执行。

  1. 异常处理的方式?

java 提供了两种处理异常的方式:

①第一种: try{可能发生异常的代码}catch(异常类型 对象){捕获异常}finally{异常的出口 }

②抛出异常throws

3.1、try -- catch 方式:

public class Test {
    public static void main(String[] args) {
        int a=10;
        int b=0;
        System.out.println("开始计算===============");
        try {
            int result = a / b;
        }catch (ArithmeticException e){
            System.out.println("捕获算术异常");
        }
        System.out.println("结束计算==============");
    }
}
//处理完异常之后代码可以继续执行

3.1.1、处理多种异常

try后面可以根多个catch捕获。不同的catch捕获不同的异常。但是这样会先的比较麻烦。

public class Test {
    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        System.out.print("请输入一个数字:");
        String c1=scanner.next();
        System.out.print("请输入二个数字:");
        String c2=scanner.next();
        System.out.println("开始计算===============");
        try {
            int a=Integer.parseInt(c1);
            int b=Integer.parseInt(c2);
            int result = a / b;
            }catch(Exception e){
                System.out.println("捕获异常!");
        }
 /*     }catch (ArithmeticException e){
            System.out.println("捕获算术异常");
        }catch (NumberFormatException e){
            System.out.println("格式化转化异常");
        }*/
        System.out.println("结束计算==============");
    }
}

这些异常都有一个公共的父类根类是Throwable. Throwable下有两个子类

①Exception: 异常类,我们程序员可以处理的异常。一般使用该异常就了。

②Error: 错误类。这种异常程序员无法处理。比如内存溢出。

根据多态,再异常捕获时可以使用Exception异常来捕获

注意:如果使用到多个 catch 时候范围大的放后面,范围小的放前面

3.2、抛出 throws 异常

把异常抛出,使用方法名()后面.抛给了方法的调用者。

public static void main(String[] args) throws Exception {//JVM
            fun();//方法调用者
    }
    public static void fun() throws Exception{
        int a=10;
        int b=0;
        int c=a/b;
    }

如果我们抛出的异常为RuntimeException下的异常。不要强制调用者处理

  1. throw关键字.

我们前面讲解的异常,都是程序自己产生的异常对象。 我们也可以自己定义异常对象。并把该异常对象抛出

  1. finally 关键字

使用异常处理中,作为最终执行的代码。不管有没有异常都会执行finally中代码。

后期==使用再资源关闭中==。不论是否执行了return,finally也会被执行

注意:try{}可以finally单独使用。try{}finally{}//没有捕获异常

public class Test02 {
    public static void main(String[] args) {
        int c = fun();
        System.out.println("c========" + c);
    }
    public static int fun() {
        int a = 10;
        int b = 2;
        int c = a / b;
        try {
            return c;
        } catch (Exception e) {
            System.out.println("异常");
        } finally {
            c = 15;
            System.out.println("finally~~~~~~~");
//          return c;
        }
        return 0;
    }
}
  1. 自定义异常-----了解

当系统提供的异常类型无法满足客户需求时,程序员可以自己定义异常类型。目的可以达到见名知意

public static void fun() throws Exception{
            throw new RuntimeException("呵呵"); // 自己产生了一个异常
        }
  1. IO流中的File文件对象

在java jdk关于对文件【目录和文件】的操作都封装到File类。该类中包含了文件的各种属性以及操作方法。该类放在jdk--java.io包下

public static void main(String[] args) {
        File file = new File("01.txt");//新建对象
        try {
            file.createNewFile();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
public static void main(String[] args) {
        File file = new File("01.txt");
        file.delete();
    }
public static void main(String[] args) {
        File file=new File("D://gyh//zql//ldh");
       //创建目录
       file.mkdir();
       //创建多级目录 /a/b/c/d
       file.mkdirs();
    }
public static void main(String[] args) {
        //删除文件或目录
       File file02=new File("D:\\aaaaaaa");
       //删除目录时只能删除空目录
       file02.delete();
    }
public static void main(String[] args) {
        File file02=new File("qy174.txt");
        File file01=new File("zhenshuai.txt");
        file02.renameTo(file01);
    }
public class Test02 {
    public static void main(String[] args) {
        File file01=new File("D:\\aaaaaaa");
//        File file01=new File("zhenshuai.txt");
        //获取文件名
        String name = file01.getName();
        System.out.println("文件名:"+name);
        //获取文件的父路径
        String parent = file01.getParent();
        System.out.println("父路径:"+parent);
        //获取文件相对路径
        String path = file01.getPath();
        System.out.println("文件路径:"+path);
        //绝对路径
        String absolutePath = file01.getAbsolutePath();
        System.out.println(absolutePath);
        System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
        //获取该目录下所有的子文件名
        String[] list = file01.list();
        for(String s:list){
            System.out.println(s);
        }
        System.out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~");
        //获取当前目录下的所有子文件对象
        File[] files = file01.listFiles();
        for(File f:files){
            String absolutePath1 = f.getAbsolutePath();
            System.out.println(absolutePath1);
        }
    }
}

9. IO 流

9.1. 分类:

根据流的方向分为输入流 输出流

根据流的内容分为: 字节流 字符流

9.2. 字节输入流

以字节的方式读取文件中的内容。读取到程序中【内存中】。

字节输入流的父类InputStream,它里面包含操作字节的方法,

它也是一个抽象类,最常见的子类:FileInputStream

步骤 ① 创建对象:

② 读取:

public class Test01 {
    public static void main(String[] args) {
        try {
            InputStream is = new FileInputStream(new File("src/a.txt"));
            
            //使用缓冲流使其效率更加高效速度更快
            BufferedInputStream bis = new BufferedInputStream(is);
            int a = -1;
            while ((a = is.read()) != -1){
                System.out.print((char) a);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

9.3. 通过流完成文件复制

public class Test01 {
    public static void main(String[] args) {
        InputStream is = null;
        BufferedInputStream bis = null;
        OutputStream os = null;
        BufferedOutputStream bos = null;
        try {
            is = Files.newInputStream(Paths.get("D:/aDrive.zip"));
            //bis = new BufferedInputStream(is);  //缓冲流
            os = Files.newOutputStream(Paths.get("D:\\A.zip"));
            //bos = new BufferedOutputStream(os);  //缓冲流
            int a = -1;
            while ((a = bis.read()) != -1){
                bos.write(a);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }finally {
            try {
                if (bos != null) {
                    bos.close();
                }
                if (os != null) {
                    os.close();
                }
                if (bis != null) {
                    bis.close();
                }
                if (is != null) {
                    is.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

9.4. 字符输入流

字符流它只能复制文本内容---无法复制文本之外的内容:比如视频,音频,图片 word

 public class Test02Chars {
    public static void main(String[] args) {
        Reader r = null;
        try {
            r = new FileReader("src/a.txt");
            int a = -1;
            while ((a = r.read()) != -1){
                System.out.print((char)a);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }finally {
            try {
                if (r != null) {
                    r.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
 }

9.5. 字符输出流:

public class Test03 {
    public static void main(String[] args) {
        Writer w = null;
        Reader r =null;
        BufferedReader br = null;//加读的缓冲区
        BufferedWriter bw = null;//加写的缓冲区
        try {
            r = new FileReader("src/a.txt");
            br = new BufferedReader(r);
            w = new FileWriter("src/b.txt");
            bw = new BufferedWriter(w);
            int a = -1;
            while ((a = br.read()) != -1){
                bw.write(a);
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());;
        }finally {
            try {
                if (bw != null) {
                    bw.close();
                }
                if (w != null) {
                    w.close();
                }
                if (br != null) {
                    br.close();
                }
                if (r != null) {
                    r.close();
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }

        }
    }
}

9.6. 对象流

操作java类对象。把java类对象写入到文件中,或者从文件中读取写入的java对象。

序列化: 把内存中的java对象写入到文件中的过程--序列化。

反序列化: 把文件中的对象读取到内存中---反序列化。

ObjectInputStream 和 ObjectOutputStream

9.6.1. 对象的写入

先创建一个学生类

值得注意的是:序列化和反序列化,都有将这个对象实现 Serializable 接口

序列化过程: 借助ObjectOutputStream流 调用writeObject() 注意: 该类必须实现序列化接口Serializable

class Student implements Serializable{
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}
public class Test04 {
    public static void main(String[] args) {
        Student s = new Student("高元浩",18);
        File file =new File("src/c.txt");
        try {
            OutputStream is = Files.newOutputStream(file.toPath());
            ObjectOutputStream oos = new ObjectOutputStream(is);
            oos.writeObject(s);
            oos.close();
            is.close();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    try {
        InputStream is = new FileInputStream(file);
        ObjectInputStream ois = new ObjectInputStream(is);
        Object o = ois.readObject();
        System.out.println(o);
        ois.close();
        is.close();
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
    }

9.6.2. 总结图:

10. 集合

集合的体系结构:

10.1. Collection

概念:它是单值集合的根==接口==,如果想使用Collection集合中的功能,需要创建该接口的子类。以ArrayList为例. 集合既然是容器,无外乎包含的功能就是增加,删除,修改元素,查询元素。

10.1.1. 增加: add()

public static void main(String[] args) {
        Collection c = new ArrayList();
        c.add("高元浩");
        System.out.println(c);
    }

10.1.2. 移除 remove() removeAll()

public static void main(String[] args) {
        Collection c = new ArrayList();
        c.add("gyh");c.add("wjy");c.add("gyh");
        c.remove("gyh");
        System.out.println(c);
        Collection c2 = new ArrayList();
        c2.add("gyh");
        c.removeAll(c2);
        System.out.println(c);
    }
==========================================
[wjy, gyh]
[wjy]

10.1.3. 查找

查找需遍历:遍历的两种方式:
for(Object o:c){//c为创建的集合对象
            System.out.println(o);
        }
 Iterator iterator = c.iterator();
        while (iterator.hasNext()){
            Object o = iterator.next();
            System.out.println(o);
        }

10.1.4. 清空集合: clear()

c.clear();

10.2. List

Collection它是所有单值集合的根接口,它下面有两个子接口。List和Set.

List: 有序允许元素重复。

Set: 无序不可重复

10.2.1. List ( 增加 删除 修改 查找 遍历集合)

public static void main(String[] args) {
        List list = new ArrayList();
        list.add("第一个");
        list.add("第二个");
        list.add("第三个");
        list.add("第四个");
        list.add(1,"第五个");
        System.out.println(list);
        //[第一个, 第五个, 第二个, 第三个, 第四个]
    
        list.remove(2);  // 删除下标为 2 的内容
        System.out.println(list);
        //[第一个, 第五个, 第三个, 第四个]
    
        list.set(0,"刘德华"); // 修改下标为零的位置的内容
        System.out.println(list);
        //[刘德华, 第五个, 第三个, 第四个]
    
        System.out.println(list.get(1));  // 查找下标为1位置的内容
    
        // 根据下标遍历
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
    }

10.3. Set 集合

特点: 无序,不可重复。

public static void main(String[] args) {
        Set set=new HashSet();
        //set集合中的方法和Collection中的方法一样
        set.add("java01");
        set.add("java05");
        set.add("java03");
        set.add("java04");
        set.add("java05");
        //集合无序且不允许重复。
        System.out.println(set);
        //长度  4 
        System.out.println("长度:"+set.size());
        //遍历:增强for循环以及迭代器

    }

10.4. ArrayList

属于List的子类,具备list的特点之外,还具备自己的

特点: 它的底层使用数组,查询效率快,

缺点: 中间:插入和删除慢--因为设计到元素的位移.

public static void main(String[] args) {
    ArrayList list = new ArrayList();
    list.add("gyh");
    list.add("wjy");
    list.add("wjy");
    list.remove("gyh");
    System.out.println(list); // [gyh, wjy, wjy]
    System.out.println(list.size()); // 3
    System.out.println(list.get(1)); // wjy
}

10.5. LinkedList

它也属于 List 的子类,他的底层使用链表;特点:增删速度快,查询速度慢!!

void linkLast(E e) {
        final Node<E> l = last;//l=null       //先将最后一位给l
        //newNode=
        final Node<E> newNode = new Node<>(l, e, null);    //创建一个新节点
        last = newNode;  //把新节点给last
        if (l == null)     //看l是否为空,若一开始链表为空则会执行if里面的代码块
            first = newNode;
        else          //如果不为空就将l的next指向改为新节点的pre指向 
            l.next = newNode;
        size++;
        modCount++;
    }

10.6. 泛型

观察: 创建集合时<E> 他就是泛型标志, 限制集合中元素的类型。

如果没有指定泛型,那么集合中可以存放任意类型的对象Object

当然如果指定了泛型,集合就只能存放泛型指定好的类型。

public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("gyh");
        list.add("wjy");
}

10.7. HashSet底层原理

HashSet它和Set接口中的方法一样。 底层元素不允许重复,而且无序。底层按照Hashcode以及Equals方法判断元素是否重复的。

流程: 先执行hashcode方法,如果hashcode值不同,则认为 不同元素,而且不会执行equals方法了,

如果hashcode相同,则执行equals方法,如果equals也相同则认为相同元素。

//元素不允许重复:

按照hashcode以及equals来判断。 先判断hashcode是否相同,如果hashcode不同,则认为不同的元素 不会执行equals方法。如果hashcode相同,判断equals是否相同(也可以在对象的抽象类中改写 hashcode 方法和 equals 方法 定义新的规则判断)

10.8. TreeSet

它是Set的子类,它的底层使用的是红黑二叉树。它里面的元素 会自动排序

public class Test01 {
    public static void main(String[] args) {
        TreeSet<String> set=new TreeSet<String>();
        set.add("java02");
        set.add("java05");
        set.add("java03");
        set.add("java04");
        set.add("java01");
        //结果:发现为里面的元素排序了。安装treeset排序的。ascii码的值排序
        System.out.println(set);
        //遍历输出。--增强循环以及迭代器
        Iterator<String> iterator = set.iterator();
        while (iterator.hasNext()){
            String next = iterator.next();
            System.out.println(next);
        }
    }
}

假如里面要存对象:(有一个 Student 类 里面有 get set 方法 全参无参构造方法,toString 方法)

public class Test01 {
    public static void main(String[] args) {
        TreeSet<Student> students = new TreeSet<Student>();
        students.add(new Student("高XX",20));
        students.add(new Student("杨UU",6));
        students.add(new Student("王XX",20));
        System.out.println(students);
    }

此时控制台肯定报错因为无法排序,

我们往TreeSet中添加Student对象,出现了错误。由于字符串实现了Comparable接口,该接口是一个排序规则接口。 我们需要为Student类实现Comparable接口

解决方式有两种:

① 泛型里面写的类 也就是 Student 类去实现这个接口并改写排序规则:

public static class Student implements Comparable<Student>{
        private String name;
        private int age;
        @Override
        public int compareTo(Student o) {
            int i = this.age-o.age;
            if(i==0){
                return this.name.compareTo(o.name);
            }
            return i;
        }

② 使用定制排序

上面我们在创建Student类对象时,实现类排序规则的接口,如果你往TreeSet中添加的对象,是别人写好的类,没有实现排序规则的接口。如果别人写的类排序规则满足不了你的要求。比如按照字符串的长度排序。

public static void main(String[] args) {
        TreeSet<Student> students = new TreeSet<Student>(new Comparator<Student>() {

            @Override
            public int compare(Student o1, Student o2) {
                int diff = o2.getName().length() - o1.getName().length();
                if (diff == 0) {
                    int diff1 = o1.getAge() - o2.getAge();
                    if (diff1 == 0) {
                        return 1;
                    }
                }
                return diff;
            }
        });
        students.add(new Student("高元浩",20));
        students.add(new Student("杨U",6));
        students.add(new Student("王佳瑶",20));
        System.out.println(students);
    }

10.9. Map 键值对

Map 是一个键值对集合,map 集合中的元素有 key 和 value 组成 。底层实现类 Hash Map

public class Test04 {
    public static void main(String[] args) {
        //key:必须为字符串  value:为Object类型
        Map<String,Object> map=new HashMap<>();
        //存储元素:必须为key和value  注意: key是唯一的。key如果相同后置回覆盖前置
        map.put("k1","v1");
        map.put("k2","v2");
        map.put("k3","v3");
        map.put("k1","v4");
        //求map中元素的个数
        int size = map.size();
        System.out.println("元素个数:"+size);
        //打印集合
        System.out.println(map);
        //根据key查询对应的value
        Object v1 = map.get("k1");
        System.out.println("k1对应的value===="+v1);
        //获取所有的key
        Set<String> keys = map.keySet();
        System.out.println("所有的key: "+keys);

        //根据key移除元素
        map.remove("k2");
        //清空map
        //map.clear();
        //判断指定的key是否在map中存在
        boolean b = map.containsKey("k1");
        System.out.println("是否存在:"+b);
        //遍历map中每个元素key---value
        for(String k:keys){
            Object o = map.get(k);
            System.out.println(k+"===========>"+o);
        }
    }
}
存放元素:  put(key,value)
获取map元素个数: size()
根据key获取对应的value: get(key)
判断某个key是否在map中: containsKey()
清空: clear()
根据key移除: remove()
获取map中所有key:  keySet()
遍历map对象

10.10. Collections 集合类的工具类

工具类中所有的方法都是静态方法直接通过类名调用

  1. 动态添加元素: Collections.add ( list, 1,8,1,6,9,5,7 )
  2. 填充(将集合的所有元素都填充为一个数):Collections.fill(list,9)
  3. 洗牌(打乱):Collections.shuffle(list);
  4. 对集合排序(默认从小到大)Collections.sort(list);

若要从大到小要重写:

Collections.sort(list, new Comparator<Integer>() {
           @Override
           public int compare(Integer o1, Integer o2) {
               return o2-o1;
           }
       });
  • 32
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值