javaSE基础知识(毕向东视频笔记)

代码仅仅是你思想的一种体现形式。

知识预备:

软件开发

软件:一系列按照特定顺序组织的计算机数据和指令的集合.

常用的软件;

系统软件(DOS,windows,Linux等)

应用软件(扫雷,迅雷,QQ等)

什么是开发?

制作软件

人机交互

软件的出现实现了人与计算机之间的更好的交互.

交互方式:图形化界面GUI简单直观,,易于接受,容易上手操作.

命令行方式:CLI需要有个控制台,输入特定的指令,让计算机完成一个操作,较为麻烦,,需要记录一些命令.

什么是计算机语言?

语言:是人与人之间用于沟通的一种方式。

计算机语言:人与计算机交流的方式,如:c、c++、java等。

java语言的三种技术架构

1,J2EE企业版(主要针对web应用程序开发)

2,J2SE标准版(开发普通桌面和商务应用)

3,J2ME小型版(开发电子消费产品和嵌入式设备,如手机中的应用程序)

java语言的特点:跨平台性

java语言的环境搭建:

JRE java运行环境

JDK java开发工具包(javac.exe编译工具、java.exe打包工具)

总之:使用JDK开发完成的java程序,交给JRE去运行。

dos命令行:

dir:列出当前目录下的文件以及文件夹。

md:创建目录

rd:删除目录

cd:进入指定目录

cd..:退回到上一级目录

cd\:退回到根目录

del:删除文件

exit:退出dos命令行

help:帮助

cls:清屏

set:修改path环境变量

set path:查看path环境变量

java语言基础:

关键字 运算符 标识符 语句 注释 函数 常量和变量数组

语言:    

1,表现形式

2,什么时候用

蓝色关键字 红色已有的类

class 用于定义类

void 没有返回值

用于定义访问权限修饰符的关键字

private(私有)       protected(受保护)    public(公有)

用于定义类,函数,变量修饰符的关键字

abstract(抽象)    final(最终)    static(静态)    synchronized(同步)

用于定义类与类之间关系的关键字

extends    implements

用于定义建立实例及引用实例,判断实例的关键字

new    this    super    instanceof(用于判断对象的具体类型)

用于异常处理的关键字

try    catch    finally    throw    throws

用于包的关键字

package    import

其他修饰符关键字

native    stricffp    transient    volatile    assert

类名:首字母大写、驼峰结构。


标识符

在程序中自定义的一些名称

由26个英文字母的大小写、数字0~9、符号_$组成。

定义合法标识符规则:

1,由数字、字母、下划线组成

2数字不可以开头。

3,不可以使用关键字。

java中严格区分大小写。

注意:为了提高阅读性,名称要尽量有意义。

注释

单行注释://注释文字

多行注释:/*注释文字*/

文档注释:/**注释文字*/

注释的作用:可以进行程序的调试

javadoc.exe 可以提取java文件中的文档注释

常量:表示不能改变的数值

java中常量的分类:

1,整数常量,所有整数。

2,小数常量,所有小数。

3,布尔(boolean)型常量,两个值true和false

4,字符常量,将一个数字字母或者符号用单引号标识

5,字符串常量,将一个或多个字符用双引号标识

6,null常量代表不确定的对象(注意空,零,无的区别)

对于整数:有四种表现形式

二进制    八进制    十六进制    十进制(计算机常用的为前三种)


变量

内存中的一个存储区域

该区域有自己的名称(变量名)和类型(数据类型

该区域的数据可以在同一类型范围内不断变化

为什么要定义变量?

用来不断的存放同一类型的常量并可以重复使用

使用变量注意:

变量的作用范围(一对{}之间有效)

初始化值:

定义变量的格式

数据类型 变量名 = 初始化值;

注:格式是固定的,记住格式,以不变应万变

理解:变量如同数学中的未知数

数据类型

基本数据类型

数值型

整数类型 byte    short    int    long

浮点类型 float    double

字符型 char

布尔型 boolean

引用数据类型

class

接口 interface

数组 [ ]

整数默认:int

小数默认:double

注意:自动类型提升与强制类型转换

^(异或):一个数异或同一个数两次,结果还是这个数(可用来交换两变量的值,而无需使用中间变量,可以少用一个存储空间,但在实际开发中可读性较差,不推荐使用,作为了解即可)

<<(左移):几位其实就是该数据乘以2的几次方,可以完成2的次幂运算

>>(右移):其实就是该数据除以2的几次幂,被右移数为负数,结果为负数

>>>(无符号右移):数据进行右移时,高位出现的空位,无论原高位是什么,空位都用0补齐

提高代码的健壮性

提高代码的复用性

if和switch的应用

if

1,对具体的值进行判断

2,对区间判断

3,对运算结果是boolean类型的表达式进行判断

switch

1,对具体的值进行判断

2,值的个数通常是固定的

对于几个固定的值判断,建议使用switch语句,因为switch语句会将具体的答案都加载进内存,效率高一点

什么时候使用循环结构呢?

当对某些代码执行很多次时,使用循环结构完成

当对一个条件进行一次判断时,可以使用if语句

当对一个条件进行多次判断时,可以使用while语句

注意:在使用循环时,一定要明确哪些语句需要参与循环,哪些不需要循环,通常情况下,需要定义条件,需要控制次数

转义字符:\n换行 \t 制表符\b 退格\r 按下回车键

break(跳出)

应用范围:选择结构和循环结构(可以标号)

continue(继续)

应用范围:循环结构

方法名:第一个单词小写,后面的单词首字母大写

内存的划分

1寄存器

2本地方法区

3方法区

4栈内存 (存储的都是局部变量)变量所属的作用域一旦结束,该变量就自动释放

5堆内存 存储的是数组和对象(其实数组就是对象)凡事new建立的都在堆中

特点:

1.每个实体都有首地址

2.堆内存中的每一个变量都有默认初始化值,根据类型的不同而不同,整数是0,小数0.0或0.0f,boolean型是false,char是\u0000

3.垃圾回收机制

常见错误提示:

ArrayIndexoutofBoundsExceppption 数组索引超出范围当访问到数组中不存在的角标时,就会发生该异常

NullpointerExceppption 空指针异常当引用型变量没有任何实体指向时,还在用其操作实体,就会发生该异常

[I @c171164 (实体的类型 哈希值)

new也是运算符

数组常见操作

1获取最值(最大值 最小值)

2排序    Arrays.sort()排序 通常情况下最快的排序:希尔排序(即直接插入排序的优化版本)

3折半查找(二分查找)    Arrays.binarysearch()二分查找 如果元素不存在,就返回元素的插入点变成负数-1

什么时候使用数组?

如果数据出现了对应关系,而且对应关系的一方是有序的数字编号,并作为角标使用,这时就必须想到数组

就可以将这些数据存储到数组中

根据运算的结果作为角标直接去查数组中对应的元素即可

这种方式称为:查表法

Integer.toBinaryString 十进制转为二进制

Integer.toOctalString 十进制转为八进制

Integer.toHexString 十进制转为十六进制

面向对象的三个特点:

1.封装

2.继承

3.多态

成员分为两种:

1.成员变量(属性)

2.成员函数(行为)

定义类其实就是定义类中的成员

成员变量和局部变量的区别:

1.成员变量定义在类中,整个类中都可以访问

局部变量定义在函数、语句、局部代码块中,只在所属的区域有效

2.成员变量存在于堆内存的对象中

局部变量存在于栈内存的方法中

3.成员变量随着对象的创建而存在,随着对象的消失而消失

局部变量随着所属区域的执行而存在,随着所属区域的结束而释放

4.成员变量都有默认初始化值

局部变量没有默认初始化值

new A(); 匿名对象 其实就是定义对象的简写格式

new A().fun(); 当对象对方法仅进行一次调用的时候,就可以简化成匿名对象

show(new A); 匿名对象可以作为实际参数进行传递


封装:是指隐藏对象的属性和实现细节 仅对外提供公共访问方式

好处:

1.将变化隔离

2.便于使用

3.提高重用性

4.提高安全性

封装原则 将不需要对外提供的内容都隐藏起来

把属性都隐藏 提供公共方法对其访问

private 私有  是一个权限修饰符 用于修饰成员

私有的内容只在本类中存放

注意: 私有仅仅是封装的一种体现而已

私有就是封装 但封装不仅仅是私有 函数也是封装

构造函数

特点: 函数名与类名相同

不用定义返回值类型

没有具体的返回值

作用: 给对象进行初始化

构造函数在new对象的时候就已经被调用了

创建对象都必须要通过构造函数初始化

一个类中如果没有定义过构造函数 那么该类中会有一个默认的空参数构造函数  如果在类中定义了指定的构造函数 那么类中的默认构造函数就没有了

一般函数和构造函数有什么区别呢?

构造函数: 对象创建时  就会调用与之对应的构造函数 对对象进行初始化

一般函数: 对象创建后  需要该函数功能时才调用

构造函数: 对象创建时  会调用且只调用一次

一般函数: 对象创建后  可以被调用多次

什么时候定义构造函数呢?

在描述事物时 该事物一存在就具备一些内容  这些内容都定义在构造函数中  构造函数可以重载

this 这个对象的

this  代表对象  代表哪个对象呢?当前对象

this就是所在函数所属对象的引用

简单说 哪个对象调用了this所在函数  this就代表哪个函数

this也可以用于在构造函数中调用其他构造函数

注意:只能定义在构造函数的第一行  因为初始化动作要执行

static的特点

1 static是一个修饰符 用于修饰成员

2 static修饰的成员被所有对象所共享

3 static优先于对象存在  因为static成员随着类的加载就已经存在了

4 static修饰的成员多了一种调用方式  就可以直接被类名所调用

5 static修饰的数据是共享数据  对象中存储的是特有数据  被static修饰的变量称为静态变量或类变量

成员变量和静态变量的区别?

1 两个变量的生命周期不同

成员变量随着对象的创建而存在 随着对象的回收而释放

静态变量随着类的加载而存在 随着类的消失而消失

2 调用方式不同

成员变量只能被对象调用

静态变量可以被对象调用  还可以被类名调用

3 别名不同

成员变量也称为实例变量

静态变量称为类变量

4 数据存储位置不同

成员变量数据存储在堆内存的对象中  所以也叫对象的特有数据

静态变量数据存储在方法区(静态区、共享数据区) 所以也叫对象的共享数据

静态使用的注意事项:

1 静态方法只能访问静态成员(非静态既可以访问静态  又可以访问非静态)

2 静态方法中不可以定义this或者super关键字

3 主函数是静态的

主函数的特殊之处:

1.格式是固定的

2.被jvm所识别和调用

public: 因为权限必须是最大的

static: 不需要对象

void: 主函数没有具体的返回值

main: 函数名 不是关键字  只是一个jvm识别的固定的名字

String[ ]  args:这是主函数的参数列表  是一个数组类型的参数  而且元素都是字符串类型

静态什么时候用?

1.静态变量

当分析对象中所具备的成员变量的值都是相同的

这时这个成员就可以被静态修饰

只要数据在对象中都是不同的 就是对象的特有数据 必须存储在对象中 是非静态的

如果是相同的数据  对象不需要做修改  只需要使用即可  不需要存储在对象中  定义成静态的

2.静态函数

函数是否用静态修饰 就参考一点  就是该函数功能是否有访问到对象中的特有数据

简单点说  从源代码看 该功能是否需要访问非静态的成员变量  如果需要  该功能就是非静态的

但是非静态需要被对象调用 而仅创建对象调用非静态的没有访问特有数据的方法  该对象的创建是没有意义的

静态代码块:

随着类的加载而执行 而且只执行一次

作用:用于给类进行初始化

构造代码块 可以给所有对象进行初始化

构造函数 是给对应的对象进行针对性的初始化

该类中的方法都是静态的  所以该类是不需要创建对象的  为了保证不让其创建该类对象  可以将构造函数私有化

设计模式(23种)

 对问题行之有效的就解决方式:其实它是一种思想

1.单例设计模式

解决的问题:可以保证一个类在内存中对象的唯一性

必须对于多个程序使用同一个配置信息对象时  就需要保证该对象的唯一性

如何保证对象唯一性呢?

1.不允许其他程序用new创建该类对象

2.在该类中创建一个本类实例

3.对外提供一个方法让其他程序可以获取该对象

步骤:

1.私有化该类的构造函数

2.通过new在本类中创建一个本类对象

3.定义一个公有的方法 将创建的对象返回

饿汉式用于开发  懒汉式(延迟加载)用于面试

extends 父类名(超类、基类)

继承的好处:

1.提高了代码的复用性

2.让类与类之间产生了关系  给第三个特征 多态 提供了前提

java中支持单继承 不直接支持多继承 但对C++中的多继承机制进行了改良

单继承:一个子类只能有一个直接父类

多继承:一个子类可以有多个直接父类(java中不允许进行改良 通过多实现)不直接支持 是因为会产生调用的不确定性

java支持多层继承(多重继承)

c继承b   b继承a  就会出现继承体系

当要使用过一个继承体系时

1.查看该体系中的顶层类  了解该体系的基本功能

2.创建体系中的最子类对象  完成功能的使用

什么时候定义继承呢?

当类与类之间存在着所属关系的时候  就定义继承

x是y中的一种  x  extends  y

所属关系: is  a  关系

在子父类中  成员的特点体现

1.成员变量

当本类的成员和局部变量同名用this区分

当子父类中的成员变量同名用super区分

this和super的用法很相似

this 代表一个本类对象的引用

super 代表一个父类空间

2.成员函数

当子父类中出现成员函数一模一样的情况  会运行子类的函数

这种现象 称为覆盖操作  这是函数在子父类中的特性

函数的两个特性:

1.重载  同一个类中

2.覆盖  子类中 也称为重写 覆写

覆盖注意事项:

1.子类方法覆盖父类方法时 子类的权限必须大于等于父类的权限

2.静态只能覆盖静态  或被静态覆盖

什么时候使用覆盖操作?

当对一个类进行子类的扩展时  子类需要保留父类的功能声明

但是要定义子类中该功能的特有内容时 就使用覆盖操作完成

3.构造函数

在子类构造对象时  发现 访问 子类构造函数时 父类也运行了 为什么呢?

原因是:在子类的构造函数中的第一行有一个默认的隐式语句:super();//调用的就是父类中的空参数的构造函数

子类的实例化过程:子类中所有的构造函数默认都会访问父类中的空参数的构造函数

为什么子类实例化的时候要访问父类中的构造函数呢?

那是因为子类继承了父类 获取到了父类中的内容(属性)所以在使用父类内容之前  要先看父类是如何对自己的内容初始化的 所以子类在构造对象时 必须访问父类中的构造函数

为了完成这个必须的动作 就在子类的构造函数中加入了super()语句  如果父类中没有定义空参数构造函数 那么子类的构造函数必须用super明确要调用父类中哪个构造函数  同时子类构造函数中如果使用this调用了本类构造函数时  那么this就没有了  因为super和this都只能定义在第一行

注意:super语句必须要定义在子类构造函数的第一行  因为父类的初始化动作要先完成

一个对象实例化过程:

1 jvm会读取指定的路径下的*.class文件 并加载进内存  并会先加载*的父类(如果有直接父类的情况下)

2 在堆内存中开辟空间 分配地址

3 并在对象空间中 对对象中的属性进行默认初始化

4 调用对应的构造函数进行初始化

5 在构造函数中 第一行会先调用父类中的构造函数进行初始化

6 父类初始化完毕后 再对子类的属性进行显示初始化

7 在进行子类构造函数的特定初始化

8 初始化完毕后 将地址值赋值给引用变量

继承弊端:打破了封装性

final关键字:

1.final是一个修饰符 可以修饰类 方法 变量

2.final修饰的类不可以被继承

3.final修饰的方法不可以被覆盖

4.final修饰的变量是一个常量 只能赋值一次

为什么要用final修饰变量 其实在程序中如果一个数据是固定的 那么直接使用这个数据就可以了 但是这样阅读性差 所以给该数据起个名称 而且这个变量名称的值不能变化 所以加上final固定

写法规法:常量所有字母都大写 多个单词 中间用_连接

抽象类:

抽象的概念:笼统、模糊、不具体

抽象的特点:

1.方法只有声明 没有实现时 该方法就是抽象方法 需要被abstract修饰 抽象方法必须定义在抽象类中 该类必须也被abstract修饰

2.抽象类不可以被实例化 为什么?

因为调用抽象方法没意义

3.抽象类必须有其子类覆盖了所有的抽象方法后 该子类才可以实例化 否则 这个子类还是抽象类

抽象类中有构造函数吗?

有 用于给子类对象进行初始化

抽象类可以不定义抽象方法吗?

可以的  但是很少见 目的就是不让该类创建对象 AWT的适配器就是这种类 通常这个类中的方法有方法体 但是却没有内容

抽象关键字不可以和哪些关键字共存?

private 因为抽象方法需要被覆盖

static 因为没有意义

final 因为不能被继承类和被覆盖抽象方法

抽象类和一般类的异同点:

相同点:抽象类和一般类都是用来描述事物的 都在内部定义了成员

不同点

1.一般类有足够的信息描述事物

抽象类描述事物的信息有可能不足

2.一般类中不能定义抽象方法 只能定义非抽象方法

抽象类中可以定义抽象方法 也可以定义非抽象方法

3.一般类可以被实例化

抽象类不可以被实例化

抽象类一定是个父类吗?

是的   因为需要子类覆盖其方法后才可以对子类实例化

当一个抽象类中的方法都是抽象的时候 这时可以将该抽象类用另一种形式定义和表示 就是接口 interface

定义接口使用的关键字不是class 时interface

接口中常见的成员:(这些成员都有固定的修饰符)

1.全局常量:public static  final

2.抽象方法:public abstract

由此得出结论 接口中的成员都是公共的权限

类与类之间是继承关系 类与接口之间是实现关系(implements)

接口不可以实例化

只能由实现了接口的子类并覆盖了接口中所有的抽象方法后  该子类才可以实例化 否则 这个子类就是一个抽象类

在java中不直接支持多继承 因为会出现调用的不确定性

所以java将多继承机制进行改良 在java中变成了多实现

多实现:一个类可以实现多个接口

接口的出现避免了单继承的局限性

接口可以继承接口 而且接口可以多继承

接口的特点:

接口是对外暴露的规则

接口是程序的功能扩展

接口的出现降低了耦合性

接口可以用来多实现

类与接口之间是实现关系 而且类可以继承一个类的同时实现多个接口

接口与接口之间可以有继承关系

多态的定义:某一类事物的多种存在形态(简单说 就是一个对象对应着不同类型)

多态在代码中的体现

父类或者接口的引用指向其子类的对象

多态的好处:

提高了代码的扩展性 前期定义的代码可以使用后期的内容

多态的弊端(局限性)

前期定义的内容不能使用(调用)后期子类的特有内容

多态的前提:

1.必须有关系 继承 实现

2.要有覆盖

向上转型:将子类型隐藏 就不能使用子类的特有方法了

向下转型:目的是为了使用子类中的特有方法

注意:对于转型 自始至终都是子类对象在做着类型的变化

常见异常:classcastException        //类型转换异常

instanceof:用于判断对象的具体类型 只能用于引用数据类型判断,通常在向下转型前用于健壮性的判断

多态时成员的特点:

1.成员变量

编译时:参考引用类型变量所属的类中是否有调用的成员变量 有 编译直接通过 没有 编译失败

运行时:参考引用类型变量所属的类中是否有调用的成员变量  并运行该所属类中的成员变量

简单说:编译和运行都参考符号的左边

2.成员函数

编译时:参考引用类型变量所属的类中是否有调用的函数 有 编译直接通过 没有 编译失败

运行时:参考的是对象所属的类中是否有调用的函数

简单说:编译看左边 运行看右边

3.静态函数

编译时:参考引用类型变量所属的类中是否有调用的静态方法 

运行时:参考引用类型变量所属的类中是否有调用的静态方法 

简单说:编译和运行都看左边 其实对于静态方法 是不需要对象的 直接用类名调用即可

内部类

将一个类定义在另一个类的里面 对里面的那个类就称为内部类(内置类、嵌套类)

访问特点

内部类可以直接访问外部类中的成员 包括私有成员

而外部类要访问内部类中的成员 必须要建立内部类的对象

一般用于类的设计

分析事物时 发现该事物的描述中还有事物 而且这个事物还在访问被描述事物的内容 这时就把还有的事物定义成内部类来描述

如果内部类是静态的 相当于一个外部类

如果内部类中定义了静态成员 该内部类也必须是静态的

为什么内部类能直接访问外部类中的成员呢?

那是因为内部类持有了外部类的引用 外部类名.this

内部类可以存放在局部位置上

内部类在局部位置上 只能访问局部中被final修饰的局部变量

匿名内部类:就是内部类的简写格式

使用匿名内部类必须有前提:内部类必须继承或者实现一个外部类或者接口

匿名内部类:其实就是一个匿名子类对象

格式:new 父类or接口(){子类内容}

通常的使用场景之一

当函数参数是接口类型时  而且接口中的方法不超过三个  可以用匿名内部类作为实际参数进行传递

因为匿名内部类这个子类对象被向上转型为了Object类型  这样就不能再使用子类的特有方法了

异常Exception

异常的体系

Throwable可抛

Error(错误)通常出现重大问题 如:运行的类不存在或者内存溢出等 不编写针对代码对其处理

Exception(异常)在运行时运行出现的一起情况 可以通过try catch finally 

ExceptionError的子类名都是以父类名作为后缀

异常:是在运行时期发生的不正常情况

在java中用类的形式对不正常情况进行了描述和封装对象

描述不正常情况的类,就称为异常类

以前正常流程代码和问题代码相结合

现在将正常流程代码和问题处理代码分离   提高阅读性

其实异常就是java通过面向对象的思想将问题封装成了对象

用异常类对其进行描述

不同的问题用不同的类进行具体的描述  比如角标越界  空指针等

问题很多 意味着描述的类也很多

将其共性进行向上抽取  形成了异常体系

最终问题(不正常情况)就分成了两大类 Error  exception

Throwable:无论是error  还是Exception  问题发生就应该可以抛出 让调用者知道并处理   //该体系的特点就在于Throwable及其所有的子类都具有可抛性

可抛性到底是指什么呢?怎么体现可抛性呢?

其实是通过两个关键字来体现的

throws   throw   凡是可以被这两个关键字所操作的类和对象都具备可抛性

1.一般不可处理的:Error

特点:是由jvm抛出的严重性的问题

这种问题发生 一般不针对性处理 直接修改程序

2.可以处理的:Exception

该体系的特点:

子类的后缀都是用其父类名作为后缀  阅读性很强

负数角标这种异常在java中并没有定义过

那就按照java异常的创建思想 面向对象 将负数角标进行自定义描述  并封装成对象 

这种自定义的问题描述称为自定义异常

注意:如果过让一个类称为异常类  必须要继承异常体系 因为只有成为异常体系的子类才有资格具备可抛性  才可以被两个关键字所操作  throw  throws

异常的分类:

1.编译时被检测异常:只要是Exception和其子类都是 出了特殊子类RuntimeException体系

这种问题一旦出现 希望在编译时就进行检测 让这种问题有对应的处理方式  这样的问题都可以针对性的处理

2.编译时不检测异常(运行时异常):就是Exception中的RuntimeException和其子类

这种问题的发生 无法让功能继续 运算无法进行 更多是因为调用者的原因导致的  或者引发了内部状态的改变导致的 那么这种问题一般不处理 直接接编译通过 在运行时 让调用者调用时的程序强制停止 让调用者对代码进行修正 所以自定义异常时 要么继成功Exception 要么继承RuntimeException

throws和throw的区别

1.throws使用在函数上

throw使用在函数内

2.throws抛出的时异常类 可以抛出多个 用逗号隔开

throw抛出的时异常对象

异常处理的描述形式:

这是可以对异常进行针对性处理的方式

具体格式是:

try{

//需要被检测异常的代码

}

catch(异常类 变量){//该变量用于接收发生的异常对象

//处理异常的代码

}

finally{

//一定会被执行的代码

}

多catch 父类的catch放在最下面

异常处理的原则:

1.函数内部如果抛出需要检测的异常 那么函数上必须要声明 否则必须在函数内用try catch 捕捉 否则编译失败

2.如果调用到了声明异常的函数 要么try catch 要么throws 否则编译失败

3.什么时候catch 什么时候throws呢?

功能内部可以解决 用catch

解决不了 用throws告诉调用者 由调用者解决

4.一个功能如果抛出了多个异常 那么调用时 必须有对应多个catch进行针对性的处理 内部有几个需要检测的异常 就抛几个异常 抛出几个 就catch几个

System.exit(0);//退出jvm

finally    //通常用于关闭(释放)资源

try catch finally 代码块的组合特点:

1.try catch finally

2.try catch(多个) 当没有必要资源需要释放时 可以不用定义finally

3.try finally 异常无法直接catch处理 但是资源需要关闭

异常的注意事项:

1.子类在覆盖父类方法时 父类的方法如果抛出了异常 那么子类的方法只能抛出父类的异常或者该异常的子类

2.如果过父类抛出多个异常 那么子类只能抛出父类异常的子集

简单说:子类覆盖父类只能抛出父类的异常或子类或者子集

注意:如果父类的方法没有抛出异常 那么子类覆盖时绝对不能抛 就只能try

Object:所有类的根类

equals():比较两个对象是否相等(判断地址还有内容)

一般都会覆盖此方法,根据对象的特有内容建立判断对象是否相同的依据

注意:当此方法被重写时,通常有必要重写hashCode方法,以维护hashCode

hashCode():返回此对象的一个哈希码值

该方法的常规协定:该协定声明相等对象必须具有相等的哈希码

getClass()返回表示此对象运行时类的class对象

getName()以String的形式返回此Class对象所表示的实体(类,接口,数组类,基本类型或void)名称

toString()返回该对象的字符表示

package(包)

对类文件进行分类管理

给类提供多层命名空间

写在程序的第一行

类名的全称是:包名.类名

包也是一种封装的形式

protected(保护)

各种情况下的访问权限

  public protected default private
同一类中 ok ok ok ok
同一个包中 ok ok ok  
子类中 ok ok    
不同包中 ok      

import(导入)

导包的原则:用到那个类,就导入哪个类

jar:java的压缩包

进程:正在进行中的程序

线程:就是进程中一个负责程序执行的控制单元(执行路径),一个进程中可以有多个执行路径,称为多线程

一个进程中至少有一个线程

开启多个线程是为了同时运行多部分代码

每一个线程都有自己运行的内容,这个内容可以称为线程要执行的任务

多线程的好处:解决了多部分同时运行的问题

多线程的弊端:线程太多,会导致效率降低

其实应用程序的执行都是cpu在做着快速的切换来完成的,这个切换是随机的

jvm启动时就启动了多个线程,至少有两个线程是可以分析出来的

1.执行main函数的线程,该线程的任务代码都定义在main函数中

2.负责垃圾回收的线程

如何创建一个线程呢?

步骤

1.定义一个类继承Thread类

2.覆盖Thread类中的run方法

3.直接创建Thread的子类对象 创建线程

4.调用start方法开启线程的任务run方法执行

创建线程的目的是为了开启一条新的执行路线,去运行指定的代码块和其他代码,实现同时运行,而运行的指定代码就是这个执行路径的任务

jvm创建的主线程的任务都定义在了主函数中,而自定义的线程他的任务在哪儿呢?

Thread类用于描述线程,线程是需要任务的,所以Thread类也有对任务的描述,这个任务就通过Thread类中的run方法来体现,也就是说run方法就是封装自定义线程运行任务的函数,run方法中定义的就是线程要执行的任务代码

开启线程是为了运行指定代码,所以只有继承Thread类并复写run方法,将运行的代码定义在run方法中即可

start()开启线程并调用run方法

可以通过Thread的getName()获取线程的名字

Thread-编号(从0开始)

主线程的名字就是main

线程的四种状态:1.被创建2.运行3.冻结.4.消亡

sleep()睡眠    sleep方法需要指定睡眠时间,单位是毫秒

wait()等待

notify()唤醒

stop()结束线程(较暴力)

cpu的执行资格:可以被cpu处理,在处理队列中排队

cpu的执行权:正在被cpu处理

运行:具备着执行资格并具备着执行权

冻结:释放执行权并释放执行资格

临时阻塞状态(就绪状态):具备执行资格,但不具备执行权,正在等待执行权

创建线程的第二种方式:实现Runnable接口

步骤

1.定义类实现Runnable接口

2.覆盖接口中的run方法,将线程的任务代码封装到run方法中

3.通过Thread类创建线程对象,并将Runnable接口的子类对象作为Thread类的构造函数的参数进行传递

为什么?因为线程的任务都封装在Runnable接口子类对象的run方法中,所以要在线程对象创建时就必须明确要运行的任务

4.调用线程对象的start方法开启线程

实现Runnable接口的好处:

1.将线程的任务从线程的子类中分离出来,进行了单独的封装,按照面向对象的思想将任务封装成对象

2.避免了java单继承的局限性,所以,创建线程的第二种方式较为常用

线程安全问题产生的原因:

1.多个线程在操作共享的数据

2.操作共享数据的线程代码有多条

当一个线程在执行操作共享数据的多条代码的过程中,其他线程参与了运算,就会导致线程安全问题的产生

解决思路:

就是将多条操作共享数据的线程代码封装起来,当有线程在执行这些代码的时候,其他线程是不可以参与运算的,必须要当前线程把这些代码都执行完毕后,其他线程才可以参与运算,在java中,同步代码块就可以解决这个问题

同步代码块的格式:

synchronize(对象)

{

需要被同步的代码

}

同步的好处:解决了线程的安全问题

同步的弊端:相对降低了效率,因为同步外的线程都会判断同步锁

同步的前提:同步中必须有多个线程并使用同一个锁

同步函数

同步函数使用的锁是this

同步函数和同步代码块的区别:

1.同步函数的锁是固定的this

2.同步代码块的锁是任意的对象

建议使用同步代码块

静态的同步函数使用的锁是该函数所属字节码文件对象,可以用getClass方法获取,也可以用当前类名.class来表示

多线程下的单例设计模式(叽哩哇啦%#$^%@)

死锁常见于:

1.同步的嵌套

2.线程间通讯(多个线程在处理同一资源,但是任务却不同)

等待/唤醒机制

涉及的方法:

1.wait():让线程处于冻结状态,被wait的线程会被存储到线程池中

2.notify()唤醒线程池中一个线程(任意)

3.notifyAll()唤醒线程池中的所有线程

注:这些方法都必须定义在同步中,因为这些方法是用于操作线程状态的方法,必须要明确到底操作的是哪个锁上的线程

为什么操作线程的方法wait    notify    notifyAll都定义在了Object类中?

因为这些方法是监视器的方法,监视器其实就是锁,锁可以是任意的对象,任意的对象调用的方式一定定义在Object类中

生产者/消费者模式(所生产者/多消费者问题)

叽哩哇啦%#%

while判断标记,解决了线程获取执行权后,是否要运行!

notifyAll解决了,本方线程一定会唤醒对方线程

if判断标记,只有一次,会导致不该运行的程序运行了,出现了数据错误的情况

notify()只能唤醒一个线程,如果本方唤醒了本方,没有意义,而且while判断标记+notify会导致死锁

jdk1.5以后将同步和锁封装成了对象,并将操作锁的隐式方式定义到了该对象中,从而将隐式动作变成了显式动作

lock.lock()获取锁

lock.unlock()释放锁,通常需要定义到finally代码块中

Lock lock = new ReentrantLock();//创建一个锁对象
Condition con = lock.newCondtion();//通过已有的锁获取该锁上的监视器对象
Condition con1 = lock.newCondtion();//通过已有的锁获取该锁上的监视器对象,一组监视生产者,一组监视消费者
Condition con2 = lock.newCondtion();//通过已有的锁获取该锁上的监视器对象,一组监视生产者,一组监视消费者
await()等待
signal()唤醒一个等待线程

signalAll()唤醒所有等待线程

Lock接口:出现替代了同步代码块或者同步函数,将同步的隐式锁操作变成显示锁操作,同时更为灵活,可以一个锁加上多组监视器

Condition接口:出现替代了Object中的wait    notify    notifyAll方法,将这些监视器方法单独进行了封装,变成condition监视器对象,可以与任意锁进行组合

wait和sleep区别?

1.wait可以指定时间,也可以不指定,sleep必须指定时间

2.在同步中,对cpu执行权和锁的处理不同

wait:释放执行权,释放锁

sleep:是执行权,不释放锁

停止线程

1.定义循环结束标记,因为线程运行代码一般都是循环,只要控制了循环即可

2.使用interrupt(中断)方法,该方法是结束线程的冻结状态,使线程回到运行状态

注:stop方法已经废弃,不再使用,因为太过暴力,会导致数据不同步

停止线程的方法

1.stop方法

2.run方法结束

怎么控制线程的任务结束呢?

任务中都会有循环结构,只要控制住循环就可以结束任务,控制循环通常就用定义判断标记来完成,但是如果线程处于了冻结状态,无法读取标记,如何结束呢?

可以使用interrupt()方法将线程从冻结状态强制恢复到运行状态中来,让线程具备cpu执行资格

当使用强制动作会发生InterruptedException,记得要处理

线程类的其他方法

setPriority(int num)更改线程的优先级

setDaemon(boolean b)将该线程标记为守护线程或用户线程

























































































猜你喜欢

转载自blog.csdn.net/qq_40925525/article/details/78480689
今日推荐