Java
1、Java 简介
Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表,极好地实现了面向对象理论,允许程序员以优雅的思维方式进行复杂的编程 。
Java具有简单性、面向对象、分布式、健壮性、安全性、平台独立与可移植性、多线程、动态性、开源等特点 。Java可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式系统应用程序等 。
2、java主要特性
Java语言是简单的
- Java语言的语法与C语言和C++语言很接近,使得大多数程序员很容易学习和使用。另一方面,Java丢弃了C++中很少使用的、很难理解的、令人迷惑的那些特性,如操作符重载、多继承、自动的强制类型转换。特别地,Java语言不使用指针,而是引用。并提供了自动的废料收集,使得程序员不必为内存管理而担忧。简化流程处理,语义清晰、
Java语言是面向对象的
- Java语言提供类、接口和继承等原语,为了简单起见,只支持类之间的单继承,但支持接口之间的多继承,并支持类与接口之间的实现机制(关键字为implements)。Java语言全面支持动态绑定,而C++语言只对虚函数使用动态绑定。总之,Java语言是一个纯的面向对象程序设计语言。
Java语言是分布式的
- Java语言支持Internet应用的开发,在基本的Java应用编程接口中有一个网络应用编程接口(java net),它提供了用于网络应用编程的类库,包括URL、URLConnection、Socket、ServerSocket等。Java的RMI(远程方法激活)机制也是开发分布式应用的重要手段。
Java语言是健壮的
- Java的强类型机制、异常处理、垃圾的自动收集等是Java程序健壮性的重要保证。对指针的丢弃是Java的明智选择。Java的安全检查机制使得Java更具健壮性。
Java语言是安全的
- Java通常被用在网络环境中,为此,Java提供了一个安全机制以防恶意代码的攻击。除了Java语言具有的许多安全特性以外,Java对通过网络下载的类具有一个安全防范机制(类ClassLoader),如分配不同的名字空间以防替代本地的同名类、字节代码检查,并提供安全管理机制(类SecurityManager)让Java应用设置安全哨兵。
Java语言是体系结构中立的
- Java程序(后缀为java的文件)在Java平台上被编译为体系结构中立的字节码格式(后缀为class的文件),然后可以在实现这个Java平台的任何系统中运行。这种途径适合于异构的网络环境和软件的分发。
Java语言是可移植的
- 这种可移植性来源于体系结构中立性,另外,Java还严格规定了各个基本数据类型的长度。Java系统本身也具有很强的可移植性,Java编译器是用Java实现的,Java的运行环境是用ANSI C实现的。
Java语言是解释型的
- 如前所述,Java程序在Java平台上被编译为字节码格式,然后可以在实现这个Java平台的任何系统中运行。在运行时,Java平台中的Java解释器对这些字节码进行解释执行,执行过程中需要的类在联接阶段被载入到运行环境中。
Java是高性能的
-
与那些解释型的高级脚本语言相比,Java的确是高性能的。事实上,Java的运行速度随着JIT(Just-In-Time)编译器技术的发展越来越接近于C++。
-
JIT
- JIT:Just In Time Compiler,一般翻译为即时编译器,这是是针对解释型语言而言的,而且并非虚拟机必须,是一种优化手段,Java的商用虚拟机HotSpot就有这种技术手段,Java虚拟机标准对JIT的存在没有作出任何规范,所以这是虚拟机实现的自定义优化技术。
HotSpot虚拟机的执行引擎在执行Java代码是可以采用【解释执行】和【编译执行】两种方式的,如果采用的是编译执行方式,那么就会使用到JIT,而解释执行就不会使用到JIT,所以,早期说Java是解释型语言,是没有任何问题的,而在拥有JIT的Java虚拟机环境下,说Java是解释型语言严格意义上已经不正确了。
HotSpot中的编译器是javac,他的工作是将源代码编译成字节码,这部分工作是完全独立的,完全不需要运行时参与,所以Java程序的编译是半独立的实现。有了字节码,就有解释器来进行解释执行,这是早期虚拟机的工作流程,后来,虚拟机会将执行频率高的方法或语句块通过JIT编译成本地机器码,提高了代码执行的效率,至此你已经了解了JIT在Java虚拟机中所处的地位和工作的主要内容。
- 工作原理
当JIT编译启用时(默认是启用的),JVM读入.class文件解释后,将其发给JIT编译器。JIT编译器将字节码编译成本机机器代码。 -
通常javac将程序源码编译,转换成java字节码,JVM通过解释字节码将其翻译成相应的机器指令,逐条读入,逐条解释翻译。非常显然,经过解释运行,其运行速度必定会比可运行的二进制字节码程序慢。为了提高运行速度,引入了JIT技术。
在执行时JIT会把翻译过的机器码保存起来,已备下次使用,因此从理论上来说,採用该JIT技术能够,能够接近曾经纯编译技术。
- 相关知识
JIT是just in time,即时编译技术。使用该技术,可以加速java程序的运行速度。
JIT并不总是奏效,不能期望JIT一定可以加速你代码运行的速度,更糟糕的是她有可能减少代码的运行速度。这取决于你的代码结构,当然非常多情况下我们还是可以如愿以偿的。
从上面我们知道了之所以要关闭JITjava.lang.Compiler.disable(); 是由于加快运行的速度。由于JIT对每条字节码都进行编译,造成了编译过程负担过重。为了避免这样的情况,当前的JIT仅仅对常常运行的字节码进行编译,如循环等
Java语言是多线程的
- 在Java语言中,线程是一种特殊的对象,它必须由Thread类或其子(孙)类来创建。通常有两种方法来创建线程:其一,使用型构为Thread(Runnable)的构造子将一个实现了Runnable接口的对象包装成一个线程,其二,从Thread类派生出子类并重写run方法,使用该子类创建的对象即为线程。值得注意的是Thread类已经实现了Runnable接口,因此,任何一个线程均有它的run方法,而run方法中包含了线程所要运行的代码。线程的活动由一组方法来控制。Java语言支持多个线程的同时执行,并提供多线程之间的同步机制(关键字为synchronized)。
Java语言是动态的
- Java语言的设计目标之一是适应于动态变化的环境。Java程序需要的类能够动态地被载入到运行环境,也可以通过网络来载入所需要的类。这也有利于软件的升级。另外,Java中的类有一个运行时刻的表示,能进行运行时刻的类型检查。
3、java发展历史
1995年5月23日,Java语言诞生
1996年1月,第一个JDK-JDK1.0诞生
1996年4月,10个最主要的操作系统供应商申明将在其产品中嵌入JAVA技术
1996年9月,约8.3万个网页应用了JAVA技术来制作
1997年2月18日,JDK1.1发布
1997年4月2日,JavaOne会议召开,参与者逾一万人,创当时全球同类会议规模之纪录
1997年9月,JavaDeveloperConnection社区成员超过十万
1998年2月,JDK1.1被下载超过2,000,000次
1998年12月8日,JAVA2企业平台J2EE发布。Java 2平台的发布,是Java发展过程中最重要的一个里程碑,标志着Java的应用开始普及
1999年4月27日,HotSpot虚拟机发布。HotSpot虚拟机发布时是作为JDK 1.2的附加程序提供的,后来它成为了JDK 1.3及之后所有版本的Sun JDK的默认虚拟机[7] 。
1999年6月,SUN公司发布Java的三个版本:标准版(JavaSE,以前是J2SE)、企业版(JavaEE以前是J2EE)和微型版(JavaME,以前是J2ME)
2000年5月8日,JDK1.3发布
2000年5月29日,JDK1.4发布
2001年6月5日,NOKIA宣布,到2003年将出售1亿部支持Java的手机
2001年9月24日,J2EE1.3发布
2002年2月26日,J2SE1.4发布,自此Java的计算能力有了大幅提升
2004年9月30日18:00PM,J2SE1.5发布,成为Java语言发展史上的又一里程碑。为了表示该版本的重要性,J2SE1.5更名为Java SE 5.0
2005年6月,JavaOne大会召开,SUN公司公开Java SE 6。此时,Java的各种版本已经更名,以取消其中的数字"2":J2EE更名为Java EE,J2SE更名为Java SE,J2ME更名为Java ME
2006年11月13日,Java技术的发明者Sun公司宣布,将Java技术作为免费软件对外发布。Sun公司正式发布的有关Java平台标准版的第一批源代码,以及Java迷你版的可执行源代码。从2007年3月起,全世界所有的开发人员均可对Java源代码进行修改[9] 。
2009年04月20日,甲骨文74亿美元收购Sun。取得java的版权。
2010年11月,由于甲骨文对于Java社区的不友善,因此Apache扬言将退出JCP[4]。
2011年7月28日,甲骨文发布java7.0的正式版。
2014年3月18日,Oracle公司发表Java SE 8。
4、java 开发环境配置
下载JDK
-
- 安装软件不能安装到C盘,防止系统奔溃没有任何的挽回余地
- 安装路径中不能出现任何的中文,防止因为国外软件对于支持不友好的情况出现
配置环境变量
- Windows + E 我的电脑
我的电脑空白处 ==> 属性 ==> 高级系统设置 ==> 环境变量 ==>
系统变量修改:
JAVA_HOME 设置
- 变量名:JAVA_HOME
变量值:D:\Program Files\Java\jdk1.8.0_211
PATH设置
- 变量名:path
添加内容:
;%JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;
CLASSPATH 设置
- 变量名:CLASS_PATH
变量值:.;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar
测试JDK是否安装成功
- java -version
这个命令来检查当前电脑上安装的jdk的版本。
安装java开发工具(eclipse、IntelliJ IDEA)
dos命令
Windows + R 弹出对话框 输入cmd
dir
查看当前工作目录的所有文件和文件夹
cd
切换工作目录
格式 cd 路径
路径【小重点】
相对路径
我在你隔壁,隔离老刘
. 当前工作目录
… 当前工作目录的父目录
绝对路径
河南省郑州市二七区航海中路60号海为科技园C区10/12楼 唯一性
mkdir
创建文件夹
格式 mkdir 文件夹名
例如: mkdir test
mkdir a b c d 同时创建四个文件夹
rd
删除文件夹
【注意事项】
1. 慎用 粉碎性删除
2. 无法删除非空文件夹
echo
[了解]
格式 echo 123>1.txt
文件拓展名 文件后缀名 【重点】
.exe .doc .ppt .pdf .java .php .py .mp4 .avi .rmvb
.txt .htm .html
涉及到文件操作,一定要带有文件后缀名,没有文件后缀名的文件可以认为不是一个文
件
.dll
第一源动力
无所不能 问题能力,动手能力,阅读能力,搜索能力
del
删除普通文件
操作的过程中必须带有文件后缀名!!!
【注意事项】
1. 慎用,删除文件是直接抹掉数据不是放入回收站
方向键上下
回顾之前的命令
通配符,匹配
cls
清理屏幕
exit
退出终端
装 后期操作某些软件为了防止不必要的麻烦
copy 源文件夹 目标文件夹
xcopy 源文件夹 目标文件夹 /e 复制子文件夹中内容
javap -c HelloWorld 虚拟机指令基本信息
javap -v HelloWorld 虚拟机指令详细信息
5、java 基础语法
概念
-
对象
- 对象是类的一个实例,有状态和行为。例如,一条狗是一个对象,它的状态有:颜色、名字、品种;行为有:摇尾巴、叫、吃等。
-
类
- 类是一个模板,它描述一类对象的行为和状态。
-
方法
- 方法就是行为,一个类可以有很多方法。逻辑运算、数据修改以及所有动作都是在方法中完成的。
-
实例变量
- 每个对象都有独特的实例变量,对象的状态由这些实例变量的值决定。
基本语法
-
大小写敏感
- Java是大小写敏感的,这就意味着标识符Hello与hello是不同的。
-
类名
- 对于所有的类来说,类名的首字母应该大写。如果类名由若干单词组成,那么每个单词的首字母应该大写,例如 MyFirstJavaClass 。
-
方法名
- 所有的方法名都应该以小写字母开头。如果方法名含有若干单词,则后面的每个单词首字母大写。
-
源文件名
- 源文件名必须和类名相同。当保存文件的时候,你应该使用类名作为文件名保存(切记Java是大小写敏感的),文件名的后缀为.java。。
-
主方法入口
- 所有的Java 程序由public static void main(String []args)方法开始执行。
java修饰符
-
概念
- 修饰符用来定义类、方法或者变量,通常放在语句的最前端。
-
访问控制修饰符
-
Java中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。Java支持4种不同的访问权限
-
访问控制
-
访问控制和继承
- 父类中声明为 public 的方法在子类中也必须为 public。
- 父类中声明为 protected 的方法在子类中要么声明为 protected,要么声明为 public,不能声明为 private。
- 父类中声明为 private 的方法,不能够被继承。
-
-
非访问修饰符
- static 修饰符,用来创建类方法和类变量。
- final 修饰符,用来修饰类、方法和变量,final 修饰的类不能够被继承,修饰的方法不能被继承类重新定义,修饰的变量为常量,是不可修改的。
- abstract 修饰符,用来创建抽象类和抽象方法。
- synchronized 和 volatile 修饰符,主要用于线程的编程。
标识符
-
概念
- Java所有的组成部分都需要名字。类名、变量名以及方法名都被称为标识符。
-
注意点
- 所有的标识符都应该以字母(A-Z或者a-z),美元符($)、或者下划线(_)开始
- 首字符之后可以是字母(A-Z或者a-z),美元符($)、下划线(_)或数字的任何字符组合
- 关键字不能用作标识符
- 标识符是大小写敏感的
- 合法标识符举例:age、$salary、_value、__1_value
- 非法标识符举例:123abc、-salary
-
规范AJCG
-
标识符可以使用的字符范围,英文字母(A ~ Z a ~ z) 数字(0 ~ 9) 唯一可以使用的标点符号 _
-
标识符要求必须英文字母开头
-
标识符严格区分大小写,大写A和小写a完全不一样!
-
标识符没有严格的长度限制,但是会根据实际需求来限制标识符的长度
-
标识符组需要做到见名知意,动宾结构!!!
-
推荐使用驼峰命名法和下划线命名法
- 小驼峰命名法:【适用于 变量名,方法名】
- 大驼峰命名法:【适用于 类名,接口名】
- 下划线命名法:
所有的字母都是大写的情况下,为了区分单词直接的间隔,使用下划线命名法
-
已经被Java使用的关键字和保留字不得用于自定义标识符使用。(变色的不能使用,大写开头的不能使用)
-
数组
- 数组是储存在堆上的对象,可以保存多个同类型变量。
枚举
-
概念
- 枚举限制变量只能是预先设定好的值。
-
注意点
- 枚举可以单独声明或者声明在类里面。
- 方法、变量、构造函数也可以在枚举中定义。
java关键字
- 50个Java保留字
- 不能用于常量、变量、和任何标识符的名称。
注释
- 单行(//)以及多行注释(/* */)
- 注释中的字符将被Java编译器忽略。
空行
- 空白行,或者有注释的行,Java编译器都会忽略掉
继承
- 在Java中,一个类可以由其他类派生。
- 被继承的类称为超类(super class)
- 派生类称为子类(subclass)。
- 利用继承的方法,可以重用已存在类的方法和属性,而不用重写这些代码。
接口
- 接口可理解为对象间相互通信的协议。
- 接口只定义派生要用到的方法,但是方法的具体实现完全取决于派生类。
Java 源程序与编译型运行区别
常量
- 字面常量
- 符号常量
6、java基本数据类型
内置数据类型
-
概述
- Java语言提供了八种基本类型。六种数字类型(四个整数型,两个浮点型),一种字符类型,还有一种布尔型。
-
类型转换
-
自动类型转换
- 小数据类型转换到大数据类型
-
强制类型转换
- 大数据类型到小数据类型的转换
【个人建议】
对于基本数据类型的强制类型转换,个人不建议使用,这里会导致数据精度的丢失,并且有可能导致其他问题。
- 大数据类型到小数据类型的转换
强制类型转换在面向对象开发中,可以用来操作对象直接的关系
-
-
基本类型包装类
-
基本类型的取值范围,都以常量的形式定义在对应的包装类中
-
例子
- Byte.MIN_VALUE
-
-
类型
-
byte
- byte数据类型是8位、有符号的,以二进制补码表示的整数
- 最小值是-128(-2^7)
- 最大值是127(2^7-1)
- 默认值是0
- byte类型用在大型数组中节约空间,主要代替整数,因为byte变量占用的空间只有int类型的四分之一
- 例子:byte a = 100,byte b = -50
-
short
- short数据类型是16位、有符号的以二进制补码表示的整数
- 最小值是-32768(-2^15);
- 最大值是32767(2^15 - 1);
- Short数据类型也可以像byte那样节省空间。一个short变量是int型变量所占空间的二分之一;
- 默认值是0;
- 例子:short s = 1000,short r = -20000。
-
int
- int数据类型是32位、有符号的以二进制补码表示的整数;
- 最小值是-2,147,483,648(-2^31);
- 最大值是2,147,483,647(2^31 - 1);
- 一般地整型变量默认为int类型;
- 默认值是0;
- 例子:int a = 100000, int b = -200000。
-
long
- long数据类型是64位、有符号的以二进制补码表示的整数;
- 最小值是-9,223,372,036,854,775,808(-2^63);
- 最大值是9,223,372,036,854,775,807(2^63 -1);
- 这种类型主要使用在需要比较大整数的系统上;
- 默认值是0L;
- 例子: long a = 100000L,Long b = -200000L。
-
float
- float数据类型是单精度、32位、符合IEEE 754标准的浮点数;
- float在储存大型浮点数组的时候可节省内存空间;
- 默认值是0.0f;
- 浮点数不能用来表示精确的值,如货币;
- 例子:float f1 = 234.5f。
-
double
- double数据类型是双精度、64位、符合IEEE 754标准的浮点数;
- 浮点数的默认类型为double类型;
- double类型同样不能表示精确的值,如货币;
- 默认值是0.0d;
- 例子:double d1 = 123.4。
-
boolean
- boolean数据类型表示一位的信息;
- 只有两个取值:true和false;
- 这种类型只作为一种标志来记录true/false情况;
- 默认值是false;
- 例子:boolean one = true。
-
char
- char类型是一个单一的16位Unicode字符;
- 最小值是’\u0000’(即为0);
- 最大值是’\uffff’(即为65,535);
- char数据类型可以储存任何字符;
- 例子:char letter = ‘A’。
-
引用数据类型
- 在Java中,引用类型的变量非常类似于C/C++的指针。引用类型指向一个对象,指向对象的变量是引用变量。这些变量在声明时被指定为一个特定的类型,比如Employee、Pubby等。变量一旦声明后,类型就不能被改变了。
- 对象、数组都是引用数据类型。
- 所有引用类型的默认值都是null。
- 一个引用变量可以用来引用与任何与之兼容的类型。
- 例子:Site site = new Site(“Runoob”)。
7、变量
局部变量
- 局部变量声明在方法、构造方法或者语句块中;
- 局部变量在方法、构造方法、或者语句块被执行的时候创建,当它们执行完成后,变量将会被销毁;
- 访问修饰符不能用于局部变量;
- 局部变量只在声明它的方法、构造方法或者语句块中可见;
- 局部变量是在栈上分配的。
- 局部变量没有默认值,所以局部变量被声明后,必须经过初始化,才可以使用。
实例变量
- 实例变量声明在一个类中,但在方法、构造方法和语句块之外;
- 当一个对象被实例化之后,每个实例变量的值就跟着确定;
- 实例变量在对象创建的时候创建,在对象被销毁的时候销毁;
- 实例变量的值应该至少被一个方法、构造方法或者语句块引用,使得外部能够通过这些方式获取实例变量信息;
- 实例变量可以声明在使用前或者使用后;
- 访问修饰符可以修饰实例变量;
- 实例变量对于类中的方法、构造方法或者语句块是可见的。一般情况下应该把实例变量设为私有。通过使用访问修饰符可以使实例变量对子类可见;
- 实例变量具有默认值。数值型变量的默认值是0,布尔型变量的默认值是false,引用类型变量的默认值是null。变量的值可以在声明时指定,也可以在构造方法中指定;
- 实例变量可以直接通过变量名访问。但在静态方法以及其他类中,就应该使用完全限定名:ObejectReference.VariableName。
类变量(静态变量)
- 类变量也称为静态变量,在类中以static关键字声明,但必须在方法构造方法和语句块之外。
- 无论一个类创建了多少个对象,类只拥有类变量的一份拷贝。
- 静态变量除了被声明为常量外很少使用。常量是指声明为public/private,final和static类型的变量。常量初始化后不可改变。
- 静态变量储存在静态存储区。经常被声明为常量,很少单独使用static声明变量。
- 静态变量在程序开始时创建,在程序结束时销毁。
- 与实例变量具有相似的可见性。但为了对类的使用者可见,大多数静态变量声明为public类型。
- 默认值和实例变量相似。数值型变量默认值是0,布尔型默认值是false,引用类型默认值是null。变量的值可以在声明的时候指定,也可以在构造方法中指定。此外,静态变量还可以在静态语句块中初始化。
- 静态变量可以通过:ClassName.VariableName的方式访问。
- 类变量被声明为public static final类型时,类变量名称一般建议使用大写字母。如果静态变量不是public和final类型,其命名方式与实例变量以及局部变量的命名方式一致。
8、java运算符
算术运算符
-
- 加法 - 相加运算符两侧的值 A + B 等于 30
-
- 减法 - 左操作数减去右操作数 A – B 等于 -10
-
- 乘法 - 相乘操作符两侧的值 A * B等于200
-
/ 除法 - 左操作数除以右操作数 B / A等于2
-
% 取模 - 左操作数除右操作数的余数 B%A等于0
-
++ 自增: 操作数的值增加1 B++ 或 ++B 等于 21(区别详见下文)
-
– 自减: 操作数的值减少1 B-- 或 --B 等于 19(区别详见下文)
-
自增自减运算符
- 自增(++)自减(–)运算符是一种特殊的算术运算符,在算术运算符中需要两个操作数来进行运算,而自增自减运算符是一个操作数
- (i ++)表示运算完成之后增1,(++ i)表示增1之后再运算
关系运算符
- == 检查如果两个操作数的值是否相等,如果相等则条件为真。 (A == B)为假(非真)。
- != 检查如果两个操作数的值是否相等,如果值不相等则条件为真。 (A != B) 为真。
-
检查左操作数的值是否大于右操作数的值,如果是那么条件为真。 (A> B)非真。
- < 检查左操作数的值是否小于右操作数的值,如果是那么条件为真。 (A <B)为真。
-
= 检查左操作数的值是否大于或等于右操作数的值,如果是那么条件为真。 (A> = B)为假。
- <= 检查左操作数的值是否小于或等于右操作数的值,如果是那么条件为真。 (A <= B)为真。
位运算符
- Java定义了位运算符,应用于整数类型(int),长整型(long),短整型(short),字符型(char),和字节型(byte)等类型。位运算符作用在所有的位上,并且按位运算
- & 如果相对应位都是1,则结果为1,否则为0 (A&B),得到12,即0000 1100
- | 如果相对应位都是0,则结果为0,否则为1 (A | B)得到61,即 0011 1101
- ^ 如果相对应位值相同,则结果为0,否则为1 (A ^ B)得到49,即 0011 0001
- 〜 按位补运算符翻转操作数的每一位,即0变成1,1变成0。 (〜A)得到-61,即1100 0011
- << 按位左移运算符。左操作数按位左移右操作数指定的位数。 A << 2得到240,即 1111 0000
-
按位右移运算符。左操作数按位右移右操作数指定的位数。 A >> 2得到15即 1111
-
按位右移补零操作符。左操作数的值按右操作数指定的位数右移,移动得到的空位以零填充。 A>>>2得到15即0000 1111
逻辑运算符
- && 称为逻辑与运算符。当且仅当两个操作数都为真,条件才为真。 (A && B)为假。
- | | 称为逻辑或操作符。如果任何两个操作数任何一个为真,条件为真。 (A | | B)为真。
- ! 称为逻辑非运算符。用来反转操作数的逻辑状态。如果条件为true,则逻辑非运算符将得到false。 !(A && B)为真。
- 当使用与逻辑运算符时,在两个操作数都为true时,结果才为true,但是当得到第一个操作为false时,其结果就必定是false,这时候就不会再判断第二个操作了。在逻辑或表达式中,出现了第一个为true条件,整个
表达式结果已经明确为true,不需要在进行之后的判
断,节约计算机资源,提供效率。
赋值运算符
- = 简单的赋值运算符,将右操作数的值赋给左侧操作数 C = A + B将把A + B得到的值赋给C
-
- = 加和赋值操作符,它把左操作数和右操作数相加赋值给左操作数 C + = A等价于C = C + A
-
- = 减和赋值操作符,它把左操作数和右操作数相减赋值给左操作数 C - = A等价于C = C -
- A
-
- = 乘和赋值操作符,它把左操作数和右操作数相乘赋值给左操作数 C * = A等价于C = C * A
- / = 除和赋值操作符,它把左操作数和右操作数相除赋值给左操作数 C / = A等价于C = C / A
- (%)= 取模和赋值操作符,它把左操作数和右操作数取模后赋值给左操作数 C%= A等价于C = C%A
- << = 左移位赋值运算符 C << = 2等价于C = C << 2
-
= 右移位赋值运算符 C >> = 2等价于C = C >> 2
- &= 按位与赋值运算符 C&= 2等价于C = C&2
- ^ = 按位异或赋值操作符 C ^ = 2等价于C = C ^ 2
- | = 按位或赋值操作符 C | = 2等价于C = C | 2
其他运算符
-
条件运算符(?:)
- 条件运算符也被称为三元运算符。该运算符有3个操作数,并且需要判断布尔表达式的值。该运算符的主要是决定哪个值应该赋值给变量
- variable x = (expression) ? value if true : value if false
-
instanceof 运算符
- 该运算符用于操作对象实例,检查该对象是否是一个特定类型(类类型或接口类型)
- ( Object reference variable ) instanceof (class/interface type)
Java运算符优先级
- 后缀 () [] . (点操作符) 左到右
- 一元 + + - !〜 一元运算符有:“delete”、”sizeof"、“void”、’+’——正号,’-’——负号,’!’, ‘++’, ‘–’ , ‘~’——位非,返回数字的非。从右到左
- 乘性 * /% 左到右
- 加性 + - 左到右
- 移位 >> >>> << 左到右
- 关系 >> = << = 左到右
- 相等 == != 左到右
- 按位与 & 左到右
- 按位异或 ^ 左到右
- 按位或 | 左到右
- 逻辑与 && 左到右
- 逻辑或 | | 左到右
- 条件 ?: 从右到左
- 赋值 = += -= *= /= %= >>= <<= &= ^= |= 从右到左
- 逗号 , 左到右
9、java分支结构
if 语句
-
if(布尔表达式)
{
//如果布尔表达式为true将执行的语句
} -
if 语句
- 一个 if 语句包含一个布尔表达式和一条或多条语句
-
if…else语句
- if 语句后面可以跟 else 语句,当 if 语句的布尔表达式值为 false 时,else 语句块会被执行
-
if…else if…else 语句
- if 语句至多有 1 个 else 语句,else 语句在所有的 elseif 语句之后。
- if 语句可以有若干个 elseif 语句,它们必须在 else 语句之前。
- 一旦其中一个 else if 语句检测为 true,其他的 else if 以及 else 语句都将跳过执行。
-
嵌套的 if…else 语句
switch 语句
- switch 语句判断一个变量与一系列值中某个值是否相等,每个值称为一个分支
- switch 语句中的变量类型可以是: byte、short、int 或者 char、枚举。从 Java SE 7 开始,switch 支持字符串类型了,同时 case 标签必须为字符串常量或字面量。
- switch 语句可以拥有多个 case 语句。每个 case 后面跟一个要比较的值和冒号。
- case 语句中的值的数据类型必须与变量的数据类型相同,而且只能是常量或者字面常量。
- 当变量的值与 case 语句的值相等时,那么 case 语句之后的语句开始执行,直到 break 语句出现才会跳出 switch 语句。
- 当遇到 break 语句时,switch 语句终止。程序跳转到 switch 语句后面的语句执行。case 语句不必须要包含 break 语句。如果没有 break 语句出现,程序会继续执行下一条 case 语句,直到出现 break 语句。
- switch 语句可以包含一个 default 分支,该分支必须是 switch 语句的最后一个分支。default 在没有 case 语句的值和变量值相等的时候执行。default 分支不需要 break 语句。
用于输入数据的合法性判断问题
- 在实际开发中,存在生活中数据的合法性和程序运行的语法要求冲突问题。
在程序的运行过程中,我们需要用户输入的数据进行合法性判断,如果用户输入的数据不是合法范围以内的,需要给予用户提示,并且不可以进入正常的代码运行过程中。
10、java循环结构
while 循环
- 只要布尔表达式为 true,循环体会一直执行下去
- while( 布尔表达式 ) {
//循环内容
}
do…while 循环
- 对于 while 语句而言,如果不满足条件,则不能进入循环。但有时候我们需要即使不满足条件,也至少执行一次
- do {
//代码语句
}while(布尔表达式);
for 循环
- 最先执行初始化步骤。可以声明一种类型,但可初始化一个或多个循环控制变量,也可以是空语句。
- 然后,检测布尔表达式的值。如果为 true,循环体被执行。如果为false,循环终止,开始执行循环体后面的语句。
- 执行一次循环后,更新循环控制变量。
- 再次检测布尔表达式。循环执行上面的过程。
- for(初始化; 布尔表达式; 更新) {
//代码语句
}
Java 增强 for 循环
- for(声明语句 : 表达式)
{
//代码句子
} - 声明新的局部变量,该变量的类型必须和数组元素的类型匹配
- 其作用域限定在循环语句块,其值与此时数组元素的值相等。
break 关键字
- break 主要用在循环语句或者 switch 语句中,用来跳出整个语句块。
- break 跳出最里层的循环,并且继续执行该循环下面的语句。
continue 关键字
- continue 适用于任何循环控制结构中。作用是让程序立刻跳转到下一次循环的迭代。
- 在 for 循环中,continue 语句使程序立即跳转到更新语句。
- 在 while 或者 do…while 循环中,程序立即跳转到布尔表达式的判断语句。
11、java数组
声明数组变量
- dataType[] arrayRefVar; // 首选的方法
- dataType arrayRefVar[]; // 效果相同,但不是首选方法
创建数组
- arrayRefVar = new dataType[arraySize];
- dataType[] arrayRefVar = {value0, value1, …, valuek};
- 数组索引从 0 开始,所以索引值从 0 到 arrayRefVar.length-1
处理数组
- 数组的元素类型和数组的大小都是确定的,使用基本循环或者 foreach 循环处理数组元素
- double[] myList = {1.9, 2.9, 3.4, 3.5};
// 打印所有数组元素
for (double element: myList) {
System.out.println(element);
}
多维数组
- 多维数组的动态初始化(以二维数组为例)
- type[ ][ ] arrayName = new typ[arraylenght1][arraylenght2];
数组内存分析
插入
删除
排序
-
冒泡排序
两个相邻的元素进行比较,小的向前,大的向后
N个数字来排列,两两比较小靠前,外层循环n-1,内层循环n-i-1 -
选择排序
选择一个元素,让选择依次和后面的元素进行比较,小的向前,大的向后 -
插入排序
从第二元素开始,向前找到插入的位置,保证前面的元素都有顺序- 优化
-
希尔排序
-
快速排序
采用递归分治的思想
杨辉三角
数组查找
- 遍历查找
- 二分法查找
数组复制
-
for复制
-
System.arrayCopy
- public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
src 源数组 srcPos 源数组的位置 dest目标数组 destPos 目标数组的位置 length 元素长度
- public static native void arraycopy(Object src, int srcPos,
-
Arrays.copyOf
注意事项
- 可变参数:
1 一个方法只能有一个可变参数 2可变参数必须在方法参数列表的最后
12、面对对象
基本定义
-
1 基础
-
类
- 对事物、逻辑、算法或概念的抽象。描述一类对象的行为和特征。
类是对象的模板。
- 对事物、逻辑、算法或概念的抽象。描述一类对象的行为和特征。
-
对象(实例)
-
对象是类的一个实例,拥有多个特征和行为的实体。
-
创建对象
-
声明
- 声明一个对象,包括对象名称和对象类型
-
实例化
- 使用关键字new来创建一个对象
-
初始化
- 使用new创建对象时,会调用构造方法初始化对象
-
-
创建对象的四种方式:
-
- new 关键字创建
-
- 反射
-
- 反序列化
-
- 克隆
-
-
-
成员变量
-
实例变量(非静态变量)
- 默认值: 字面值
-
类变量(静态变量)
-
-
引用
- java中,一切都“看作”对象,但操纵的标识符实际是指向一个对象的“引用”(reference)。”
-
构造方法
- 新建对象时,执行的一个特殊方法
- 在创建一个对象的时候,至少要调用一个构造方法
- 构造方法的名称必须与类同名,一个类可以有多个构造方法
-
this
- 引用当前对象,调用实例属性,实例方法
- 构造方法之间调用
-
方法重载overload
- 定义:一个类中定义多个相同名称的方法
- 同名不同参: 方法名相同,参数列表不同(类型,个数,顺序)
与权限修饰符,返回值类型无关 - 调用带有重载的方法时,需要根据传入的实参找到与之匹配的方法
-
-
2 三个修饰符
-
abstract(抽象类)
-
作用
- 可被子类继承,提供共性属性和方法。
- 可声明为引用,更自然的使用多态。
-
注意点
- 不能new对象,但可以声明引用。
- abstract 类中可以没有abstract 方法
-
特点
- 抽象类不能实例化
- 抽象类可以包含抽象方法,也可以包含非抽象方法
- 抽象方法只有方法声明,没有方法实现
- 包含抽象方法的类,一定是抽象类
- 子类必须实现抽象类的抽象方法,除非子类也是抽象类
-
经验
- 抽象父类,可作为子类的组成部分, 依附于子类对象存在, 由父类共性+子类独有组成完整的子类对象。
-
-
final
-
特征
- 最终不可变的
- 修饰变量、方法、类
- 修饰类不能被继承
- 修饰方法不能被覆盖
-
final修饰实例变量(常量)
- 实例常量不再提供默认值,必须手动赋予初始值。
- 赋值时机:显示初始化(声明并赋值)、动态代码块、构造方法。
动态代码块本质就是把代码块内容放到构造代码块里面(反编译) - 注意:如果在构造方法中为实例常量赋值, 必须保证所有的构造方法都能对其正确赋值。
-
final修饰类变量(常量)
- 静态常量不再提供默认值,必须手动赋予初始值。
- 赋值时机:显示初始化(声明并赋值)、静态代码块。
-
final修饰基本类型: 值不可变
-
final修饰引用数据类型: 地址不可变
-
final修饰对象常量
- 不能修改地址,但是属性可以更改
-
-
static(静态)
-
特点:
- 静态方法中可以直接访问静态属性,不能访问非静态属性和方法
- 非静态方法中可以访问静态属性和方法
- 非静态成员属于实例
- 静态变量属于类,可以成为“类变量”
- 静态成员通常使用类名直接调用
- 静态方法中不允许使用this或是super关键字。
- 静态方法可以继承,不能重写、没有多态。
-
被static修饰的成员将最优先加载到内存
-
静态成员存在方法区(HotSpot虚拟机JDK1.7之前永久代,JDK1.8元空间)中
- 常量池在jdk1.6之前在永久代 jdk1.7在堆中
-
注意事项
- 实例属性是每个对象各自持有的独立空间(多份),对象单方面修改,不会影响其他对象。
- 静态属性是整个类共同持有的共享空间(一份),任何对象修改,都会影响其他对象。
-
static用法
-
修饰属性
-
修饰方法
-
修饰代码块
-
修饰内部类
-
静态导入
- import static java.lang.System.out;
-
-
-
类加载
-
JVM首次使用某个类时,需通过CLASSPATH查找该类的.class文件。
-
将.class文件中对类的描述信息加载到内存中,进行保存。
如:包名、类名、父类、属性、方法、构造方法… -
加载时机
- 创建对象。
- 创建子类对象。
- 访问静态属性。
- 调用静态方法。
- 主动加载:Class.forName(“全限定名”);
-
-
注意事项:
- abstract不能和static同时使用
- abstract不能和final同时使用
- abstract不能与private连用。private方法不能被继承,因此子类就无法覆盖父类的private方法。而abstract方法要求一定要被子类覆盖,矛 盾。
- abstract方法的访问修饰符也不能是(default),abstract修饰方法时,只能与访问修饰符public或protected连用。
-
-
代码块
-
局部代码块
- 局部代码块,会缩小变量的使 用范围,提前释放局部变量, 节省内存。
-
动态代码块(构造代码块)
- 创建对象时,触发动态代码块的执行。
- 执行地位:初始化属性之后、构造方法代码之前。
- 作用:可为实例属性赋值,或必要的初始行为。
-
静态代码块
- 类加载时,触发静态代码块的执行(仅一次)。
- 执行地位:静态属性初始化之后。
- 作用:可为静态属性赋值,或必要的初始行为。
-
对象创建过程
-
-
接口
-
作用
- 结构设计工具,用来解耦合
-
概念
-
微观概念: 接口是一种能力和约定。
- 接口的定义:代表了某种能力。
- 方法的定义:能力的具体要求。
-
宏观概念:接口是一种标准。
-
-
接口中只能定义
- 公共的常量
- 公共的抽象方法
- 公共的内部类、内部接口
-
用interface替代class
-
用implements替代extends
-
接口的规范
- 任何类在实现接口时,必须实现接口中所有的抽象方法,否则此类为抽象类。
- 实现接口中的抽象方法时,访问修饰符必须是public。
-
特征:
- 没有构造方法(不能创建对象)、动态代码块、静态代码块。
- 所有属性都是公开静态常量,隐式使用public static final修饰。
- 所有方法都是公开抽象方法,隐式使用public abstract修饰。
-
经验:Java为单继承,当父类的方法种类无法满足子类需求时,可实现接 口扩充子类能力。(接口多实现)
接口支持多实现,可为类扩充多种能力。 -
如果父类实现了某些接口,则子类自动就实现了这些接口。
-
接口引用
-
同父类一样,接口也可声明为引用,并指向实现类对象
-
注意:
- 仅可调用接口中所声明的方法,不可调用实现类中独有的方法。
- 可强转回实现类本身类型,进行独有方法调用。
-
-
接口的多态
- 多种不同类型的引用指向同一个对象时, 表示看待对象的视角不同。
- 不同引用所能看到的对象范围不同, 只能调用自身类型中所声明的部分。
-
接口回调
- 先有接口的使用者,后有接口的实现者
(先创造,等调用) - 回调原理
- 先有接口的使用者,后有接口的实现者
-
常见关系
-
类与类:
- 单继承
- extends 父类名称
-
类与接口
- 多实现
- implements 接口名称1 , 接口名称2 , 接口名称n
-
接口与接口
- 多继承
- extends 父接口1 , 父接口2 , 父接口n
-
-
常量接口
- 将多个常用于表示状态或固定值的变量,以静态常量的形式定义在接口中统一管理, 提高代码可读性。
-
标记接口
- 接口没有任何成员,仅仅是一个标记。Serializable、Cloneable
-
JDK1.8之后接口中可以包含静态方法和默认方法
- 静态方法:不能被继承,通过接口名.方法名调用
- 默认方法:可以被继承,通过实现类调用
-
接口的好处
- 程序的耦合度降低。
- 更自然的使用多态。
- 设计与实现完全分离。
- 更容易搭建程序框架。
- 更容易更换具体实现。
-
-
Java包
- 包主要用来对类和接口进行分类。
- 当开发Java程序时,可能编写成百上千的类,因此很有必要对类和接口进行分类
-
源文件声明规则
- 一个源文件中只能有一个public类
- 一个源文件可以有多个非public类
- 源文件的名称应该和public类的类名保持一致
- 如果一个类定义在某个包中,那么package语句应该在源文件的首行
- 如果源文件包含import语句,那么应该放在package语句和类定义之间。如果没有package语句,那么import语句应该在源文件中最前面
- import语句和package语句对源文件中定义的所有类都有效。在同一源文件中,不能给不同的类不同的包声明。
-
Import语句
- Import语句就是用来提供一个合理的路径,使得编译器可以找到某个类
三大特性
-
封装
-
概念:
- 尽可能隐藏对象的内部实现细节,控制对象的修改及访问权限
-
访问控制符
-
private
- 成员变量和方法只能在类内被访问,具有类可见性.
-
default
- 成员变量和方法只能被同一个包里的类访问,具有包可见性
-
protected
- 可以被同一个包中的类访问,被同一个项目中不同包中的子类访问
-
public
- 可以被同一个项目中所有类访问,具有项目可见性,这是最大的访问权限
-
-
好处
- 隐藏类的实现细节
- 让使用者只能通过程序员规定的方法来访问数据
- 可以方便的加入存取控制语句,限制不合理操作
-
具体步骤
- 修改属性的可见性来限制对属性的访问
- 公共访问方法: 为每个属性创建一对赋值(setter)方法和取值(getter)方法,用于对这些属性的存取
- 过滤有效数据: 在赋值方法中,加入对属性的存取控制语句
-
-
继承
-
概念
- 继承通过extends关键字来实现,其中SubClass称为子类,SuperClass称为父类,基类,或超类
类与类之间特征和行为的一种赠与或者获得. - 在一组相同或类似的类中,抽取出共性的特征和行为,定义在父类中,实现重用
- 继承通过extends关键字来实现,其中SubClass称为子类,SuperClass称为父类,基类,或超类
-
作用
- 代码重用,代码复用, 代码可扩展性
- 产生继承关系以后,子类可以使用父类的属性和方法,也可以定义子类独有的属性和方法.
-
单继承
- 一个类只能有一个直接父类
- 可以多级继承,属性和方法逐级叠加。
-
不可继承
-
构造方法不继承
-
没有访问权限的成员不继承
- private修饰的属性和方法
- 父子类不在同一个package中时,default修饰的属性和方法
-
静态成员不继承
-
-
重写:
- jdk1.7重写要求变化: 方法返回值类型(引用类型)和父类返回值类型相同或者是父类返回值的子类
- 方法重写原则: 方法名称,参数列表,返回值类型都必须与父类相同
访问修饰符可与父类相同或者比父类更宽泛
子类中的方法,不能抛出比父类更多、更宽的检查时异常。 - 优先执行子类重写后方法
-
super
-
在子类中,可直接访问从父类继承到的属性和方法,但如果父子类的属性或 方法存在重名(属性遮蔽、方法重写)时,需要加以区分,才可专项访问。
-
在具有继承关系的对象创建中,构建子类对象会先构建父类对象。
由父类的共性内容,叠加子类的独有内容,组合成完整的子类对象。 -
super关键字的用法
- 在子类的方法中使用“super.”的形式访问父类的属性和方法。
- 在子类的构造方法的首行,使用“super()”或“super(实参)”,调用父类构造方法。
-
注意
- 如果子类构造方法中,没有显示定义super()或super(实参),则默认提供super()。
- 同一个子类构造方法中,super()、this()不可同时存在。
-
-
-
多态
-
多态指的是编译器(申明变量是)和运行期(创建对象后)表现为不同的形态(数据类型)
概念:父类引用指向子类对象,从而产生多种形态。 -
三个条件
- 继承的存在(继承是多态的基础,没有继承就没有多态)
- 子类重写父类的方法(多态下调用子类重写的方法)
- 父类引用变量指向子类对象(子类到父类的类型转换)
-
子类转父类规则
- 将一个父类的引用指向一个子类的对象,称为向上转型(upcastiog),自动进行类型转换.
- 此时通过父类引用调用的方法是子类覆盖或继承父类的方法,不是父类的方法.
- 此时通过父类引用变量无法调用子类特有的方法
- 如果父类要调用子类的特有方法就得将一个指向子类对象的父类引用赋给一个子类的引用,称为向下转型,此时必须进行强制类型转换
-
instanceof关键字
- 向下转型前,应判断引用中的对象真实类型,保证类型转换的正确性。
- 语法:父类引用 instanceof 类型
-
多态使用形式
-
- 父类作为方法的形式参数,实际传递子类对象
(使用父类作为方法形参实现多态,使方法参数的类型更为宽泛。)
- 父类作为方法的形式参数,实际传递子类对象
-
- 父类作为方法的返回值,实际传递子类对象
(使用父类作为方法返回值实现多态,使方法可以返回不同子类对象。)
- 父类作为方法的返回值,实际传递子类对象
-
-
注意事项
- 父类引用仅可调用父类所声明的属性和方法,
不可调用子类独有的属性和方法。 - 依旧遵循重写原则,如果子类重写了父类中的方法,执行 子类中重写后的方法,否则执行父类中的方法。
- 父类引用仅可调用父类所声明的属性和方法,
-
面向对象的设计原则
(开口里合最单依)
-
总则:开闭原则(Open Close Principle,OCP)
- 开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改 原有的代码,而是要扩展原有代码,实现一个热插拔的效果。
-
接口隔离原则(Interface Segregation Principle,ISP)
- 每个接口中不存在子类用不到却必须实现的方法,如果不然,就要将接口拆分。使用 多个隔离的接口,比使用单个接口(多个接口方法集合到一个的接口)要好。
-
里氏替换原则(Liskov Substitution Principle,LSP)
- 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。(父类出现的地方,子类也可以出现)
- 里氏替换原则中,子类对父类的方法尽量不要重写和重载。因为父类代表了定义好的 结构,通过这个规范的接口与外界交互,子类不应该随便破坏它。
-
合成复用原则(Composite Reuse Principle,CRP)
- 原则是尽量首先使用合成/聚合的方式,而不是使用继承。(尽量创建对象调用方法,而不是继承)
-
迪米特法则(最少知道原则)(Demeter Principle,DP)
- 一个类对自己依赖的类知道的越少越好。也就是说无论被依赖的类多么复杂,都应该 将逻辑封装在方法的内部,通过public方法提供给外部。这样当被依赖的类变化时, 才能最小的影响该类。
-
单一职责原则(Single Responsibility Principle,SRP)
- 不要存在多于一个导致类变更的原因,也就是说每个类应该实现单一的职责,如若不 然,就应该把类拆分。
-
依赖倒置原则(Dependence Inversion Principle,DIP)
- 面向接口编程,依赖于抽象而不依赖于具体。写代码时用到具体类时,不与具体类交 互,而与具体类的上层接口交互。
13、常用类
内部类
-
定义
- 定义在类内部,方法内部或局部代码块中的类
-
特点
- 编译之后可生成独立的字节码文件。
- 内部类可直接访问外部类的私有成员,而不破坏封装。
- 可为外部类提供必要的内部功能组件。
-
成员内部类
-
在类(外部类)的内部,且与外部类的成员是“同一级别”的
-
特点
- 成员的内部类可以使用任意的权限修饰符
- 成员内部类可以直接访问外部的属性和方法
- 成员内部类的属性和外部类的属性重名时,使用外部类名.访问外部类的属性
- 成员内部类不能包含静态成员,但是可以包含静态常量(相当与字面值,不需要内部类调用)
-
-
静态内部类
-
使用static修饰的成员内部类,称之为静态内部类
-
特点:
- 静态内部类可以使用任意访问修饰符
- 静态内部类不能直接访问外部类的实例属性和方法(非静态成员),但是可以直接访问静态的属性和方法
- 静态内部类可以包含静态成员
-
-
局部内部类
-
定义
- 声明在方法内部的类
- 局部类型,适用范围只能在当前方法中
- 但它的实例,可以转为父类型传递出去
-
特点
- 不可以使用任何访问权限修饰符
- 如果局部内部类所在方法是非静态方法,可以直接访问外部类的实例属性和方法
如果局部内部类所在方法是静态方法,只能访问静态属性和方法 - 局部内部类可以访问局部变量,但是局部变量必须是final,JDK1.8 final可以省略
(不可以直接访问局部变量(方法的参数等效于局部变量))
如果一定需要访问,则需要使用final对局部变量进行修饰 - 局部内部类也不能声明静态成员,可以使用静态常量
-
-
匿名内部类
-
直接创建已知的类的子类的对象,则该对象的类型就是匿名内部类
-
特点
- 创建匿名内部类可以使用接口,抽象类,普通的父类(重写),必须实现接口或抽象类中的抽象方法
- 匿名内部类不能手动添加构造方法,不能包含静态的成员
- 匿名内部类中一般不包含特有的方法,不能直接访问,可以通过内部对象方法
- 匿名内部类生成的class文件类名$编号.class
-
-
非静态内部类
- 非静态内部类依赖于外部类对象存在
成员内部类必须先实例化外部类对象然后再实例化成员内部类; - 在非静态内部类中,不能定义静态成员
- 非静态内部类依赖于外部类对象存在
-
注意事项
- 外部类的权限修饰符只能用 public 或者默认
Object类
-
超类、基类,所有类的直接或间接父类,位于继承树的最顶层。
-
任何类,如没有书写extends显示继承某个类,都默认直接继承Object类, 否则为间接继承。
-
Object类中所定义的方法,是所有对象都具备的方法。
-
Object类型可以存储任何对象。
- 作为参数,可接受任何对象。
- 作为返回值,可返回任何对象。
-
getClass()方法
- public final Class<?> getClass(){}
- 返回引用中存储的实际对象类型。
- 应用:通常用于判断两个引用中实际存储对象类型是否一致。
-
hashCode()方法
- public int hashCode(){}
- 返回该对象的十进制的哈希码值。
- 哈希算法根据对象的地址或字符串或数字计算出来的int类型的数值。
- 哈希码并不唯一,可保证相同对象返回相同哈希码,尽量保证不同对象返回 不同哈希码。
-
toString()方法
- public String toString(){}
- 返回该对象的字符串表示(表现形式)。
- 可以根据程序需求覆盖该方法,如:展示对象各个属性值。
-
equals()方法
-
public boolean equals(Object obj){}
-
默认实现为(this == obj),比较两个对象地址是否相同。
-
可进行覆盖,比较两个对象的内容是否相同。
-
equals()方法覆盖步骤
- 比较两个引用是否指向同一个对象。
- 判断obj是否为null。
- 判断两个引用指向的实际对象类型是否一致。
- 强制类型转换。
- 依次比较各个属性值是否相同。
-
-
finalize()方法
- 当对象被判定为垃圾对象时,由JVM自动调用此方法,用以标记垃圾对象, 进入回收队列。
- 垃圾对象:没有有效引用指向此对象时,为垃圾对象。
- 垃圾回收: 由GC销毁垃圾对象,释放数据存储空间。
- 自动回收机制:JVM的内存耗尽,一次性回收所有垃圾对象。
- 手动回收机制:使用System.gc(); 通知JVM执行垃圾回收。
包装类
-
基本数据类型所对应的引用数据类型。
-
Object可统一所有数据,包装类的默认值是null。
-
8种包装类提供不同类型间的转换方式:
-
Number父类中提供的6个共性方法。
- Integer integer = Integer.valueOf(“110”);
int j = integer.intValue();
- Integer integer = Integer.valueOf(“110”);
-
parseXXX()静态方法(除了Character)。
- int i = Integer.parseInt(“100”);
-
valueOf()静态方法。
-
-
JDK 5.0之后,自动装箱、拆箱。基本数据类型和包装类自动转换。
-
整数缓冲区
- Java预先创建了256个常用的整数包装类型对象。
- 在实际应用当中,对已创建的对象进行复用。
String类
-
字符串字面值是常量,具有不可变性,创建之后不可改变。
-
常用创建方式:
- String str1 = “Hello”;
- String str2 = new String(“World”);
-
public char charAt(int index)
- 根据下标获取字符。
-
public boolean contains(String str)
- 判断当前字符串中是否包含str。
-
int compareTo(String anotherString)
- 按字典顺序比较两个字符串。
-
String concat(String str)
- 将指定字符串连接到此字符串的结尾。
-
boolean equals(Object anObject)
- 将此字符串与指定的对象比较。
-
byte[] getBytes()
- 使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。
-
int hashCode()
- 返回此字符串的哈希码。
-
String intern()
- 返回字符串对象的规范化表示形式。
-
int indexOf(String str)
- 返回指定子字符串在此字符串中第一次出现处的索引。
-
int lastIndexOf(int ch)
- 返回指定字符在此字符串中最后一次出现处的索引。
-
int length()
- 返回此字符串的长度。
-
String replace(char oldChar, char newChar)
- 返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。
-
String replaceAll(String regex, String replacement
- 使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。
-
String[] split(String regex)
- 根据给定正则表达式的匹配拆分此字符串。
-
boolean startsWith(String prefix)
- 测试此字符串是否以指定的前缀开始。
-
public boolean endsWith(String str)
- 判断字符串是否以str结尾。
-
String substring(int beginIndex)
- 返回一个新的字符串,它是此字符串的一个子字符串。
-
String substring(int beginIndex, int endIndex)
- 返回一个新字符串,它是此字符串的一个子字符串。
-
char[] toCharArray()
- 将此字符串转换为一个新的字符数组。
-
String trim()
- 返回字符串的副本,忽略前导空白和尾部空白。
-
public String toUpperCase()
- 将小写转成大写。
StringBuffer
和 StringBuilder 类
-
与String类区别
- StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象
-
StringBuffer与StringBuilder区别
- StringBuffer的方法是线程安全的(不能同步访问)
- StringBuilder 相较于 StringBuffer 有速度优势
-
public StringBuffer append(String s)
- 将指定的字符串追加到此字符序列。
-
public StringBuffer reverse()
- 将此字符序列用其反转形式取代。
-
public delete(int start, int end)
- 移除此序列的子字符串中的字符。
-
public insert(int offset, int i)
- 将 int 参数的字符串表示形式插入此序列中。
-
replace(int start, int end, String str)
- 使用给定 String 中的字符替换此序列的子字符串中的字符。
正则表达式
-
定义:
- 正则表达式就是一个验证字符串格式是否满足要求的字符串,使用一个字符 串匹配一组字符串,这个字符串就是正则表达式。
-
Pattern类
- 正则表达式编译类
-
Matcher类
- 匹配器
-
用途:
-
匹配
-
拆分
-
查找
-
替换
-
叠词处理
-
-
元字符
-
预定义字符
-
边界匹配
-
其他字符
BigDecimal
-
位置
- java.math包中
-
作用
- 精确计算浮点数
-
创建方式
- BigDecimal bd=new BigDecimal(“1.0”)
-
方法
-
加
- BigDecimal add(BigDecimal bd)
-
减
- BigDecimal subtract(BigDecimal bd)
-
乘
- BigDecimal multiply(BigDecimal bd)
-
除
-
BigDecimal divide(BigDecimal bd)
-
divide(BigDecimal bd,int scal,RoundingMode mode)
- 参数scale :指定精确到小数点后几位。
- 参数mode: 指定小数部分的取舍模式,通常采用四舍五入的模式
取值为BigDecimal.ROUND_HALF_UP。
-
-
Date
- Date表示特定的瞬间,精确到毫秒。
- Date类中的大部分方法都已经被Calendar类中的方法所取代。
Calendar
-
Calendar提供了获取或设置各种日历字段的方法。
-
protected Calendar() 构造方法为protected修饰,无法直接创建该对象。
-
方法
- Calendar calendar = Calendar.getInstance();
- System.out.println(calendar.get(Calendar.YEAR));
-
System.out.println(calendar.get(Calendar.MONTH) + 1);
-
System.out.println(calendar.get(Calendar.DAY_OF_MONTH));
-
System.out.println(calendar.get(Calendar.HOUR_OF_DAY));
-
System.out.println(calendar.get(Calendar.MINUTE));
-
System.out.println(calendar.get(Calendar.SECOND));
- //获取这个月最大的天数
-
System.out.println(calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
-
//这个最小天数
-
System.out.println(calendar.getActualMinimum(Calendar.DAY_OF_MONTH));
-
//获取月的最大天数
-
System.out.println(calendar.getMaximum(Calendar.DAY_OF_MONTH));
-
//获取月的最小天数
-
System.out.println(calendar.getMinimum(Calendar.DAY_OF_MONTH));
- //相当于减了一天
-
calendar1.add(Calendar.DAY_OF_MONTH,-1);
- //转换
-
//date --- calendar
-
Date date = new Date();
-
Calendar instance = Calendar.getInstance();
-
instance.setTime(date);
-
//calendar --- date
-
Date date1 = instance.getTime();
SimpleDateFormat
-
SimpleDateFormat是以与语言环境有关的方式来格式化和解析日期的类。
-
进行格式化(日期 -> 文本)
- Date date = new Date();
-
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
-
String format = simpleDateFormat.format(date);
-
解析(文本 -> 日期)
- SimpleDateFormat simpleDateFormat1 = new SimpleDateFormat(“yyyy-MM-dd”);
-
String string = "2020-07-30";
-
Date date1 = simpleDateFormat1.parse(string);
-
常用的时间模式字母
Math
-
Math类包含用于执行基本数学运算的方法,如初等指数、对数、平方根和 三角函数。
-
方法
- //绝对值
-
System.out.println(Math.abs(10));
-
System.out.println(Math.abs(-10));
-
//返回大于或等于这个数字的最小整数
-
System.out.println(Math.ceil(3.5));
-
//返回小于或等于这个数字的最大整数
-
System.out.println(Math.floor(3.5));
-
System.out.println(Math.pow(2, 10));
-
//返回四舍五入最接近的整数
-
System.out.println(Math.round(3.8));
-
//保留两位小数
-
System.out.println(Math.round(3.1415926*100)/100.0);
-
//返回0~1之间的小数 含头不含尾
-
System.out.println(Math.random());
-
//平方根
-
System.out.println(Math.sqrt(50));
-
//立方根
-
System.out.println(Math.cbrt(50));
Random
-
类的实例用于生成伪随机数流。
-
此类使用 48 位的种子,使用线性同余公式 (linear congruential form) 对其进行了修改所得。
-
注意事项:
- 若long种子确定,则在不同程序中,相同次数产生的随机数是相同的。
System
- System系统类,主要用于获取系统的属性数据和其他操作。
Runtime
-
每个 Java 应用程序都有一个Runtime类实例,使应用程序能够与其运行的 环境相连接。可以通过getRuntime方法获取当前运行时。
-
修改JVM运行内存
- 修改堆初始内存大小:-Xms300m
- 修改堆最大内存大小:-Xmx4000m
- 修改栈空间大小:-Xss2m jdk1.5之前256k jdk1.5之后1m
14、异常处理
异常发生的原因
- 概念:程序在运行过程中出现的特殊情况。
- 用户输入了非法数据。
- 要打开的文件不存在。
- 网络通信时连接中断,或者JVM内存溢出
异常处理的必要性
- 任何程序都可能存在大量的未知问题、错误;如果不对这 些问题进行正确处理,则可能导致程序的中断,造成不必要的损失。
相当于遇到 return语句,导致程序因异常而终止。
异常的产生
- 自动抛出异常:当程序在运行时遇到不符合规范的代码或结果时,会产生异常。
- 手动抛出异常:语法:throw new 异常类型(“实际参数”);
异常的传递
- 异常的传递:按照方法的调用链反向传递,如始终没有处理异常,最终会由 JVM进行默认异常处理(打印堆栈跟踪信息)并中断程序。
Throwable
-
Error
- JVM、硬件、执行逻辑错误,不能手动处理。
-
Exception
-
程序在运行和配置中产生的问题,可处理。
-
所有的异常类是从 java.lang.Exception 类继承的子类
Exception 类是 Throwable 类的子类 -
RuntimeException
-
运行时异常,又称不受检查异常,可处理,可不处理。无需声明异常。
系统运行时产生的异常,编译时不会告诉你有这个异常,只有运行时才会暴露出来 -
常见运行时异常
- NullPointerException 空指针异常
- ArrayIndexOutOfBoundsException 数组越界异常
- ClassCastException 类型转换异常
- NumberFormatException 数字格式化异常
- ArithmeticException 算术异常
-
-
CheckedException
-
检查时异常,必须处理。
- 1:throw到上层,
- 2,try-catch处理。
-
throws 声明异常,修饰在方法参数列表后端。
-
-
-
Throwable
-
public String getMessage()
- 返回关于发生的异常的详细信息
-
public void printStackTrace()
- 打印toString()结果和栈层次到System.err,即错误输出流
-
异常处理
-
try/catch
- try{
// 程序代码
}catch(异常类型1 异常的变量名1){
// 程序代码
}catch(异常类型2 异常的变量名2){
// 程序代码
}catch(异常类型2 异常的变量名2){
// 程序代码
}
- try{
-
throws/throw
-
如果一个方法没有捕获一个检查性异常,那么该方法必须使用 throws 关键字来声明
底层代码向上声明或者抛出异常,最上层一定要处理异常,否则程 序中断。 -
throws 关键字放在方法签名的尾部
-
也可以使用 throw 关键字抛出一个异常
- 语法: throw 异常对象
-
一个方法可以声明抛出多个异常,多个异常之间用逗号隔开
-
-
finally
- finally 关键字用来创建在 try 代码块后面执行的代码块。
- 无论是否发生异常,finally 代码块中的代码总会被执行。
- 在 finally 代码块中,可以运行清理类型等收尾善后性质的语句。
- finally 代码块出现在 catch 代码块最后
- try{
// 程序代码
}catch(异常类型1 异常的变量名1){
// 程序代码
}catch(异常类型2 异常的变量名2){
// 程序代码
}finally{
// 程序代码
}
自定义异常
-
概念:需继承Exception或Exception的子类,代表特定问题。
-
经验:异常类型名称望文生义,可在发生特定问题时抛出对应的异常。
-
常用构造方法:
- 无参数构造方法
- String message参数的构造方法
注意事项:
- 多重catch,遵循从子( 小 )到父( 大 )的顺序,父类异常在最后。
- finally块是否发生异常都执行
- finally块不执行的唯一情况,退出java虚拟机
- 子类异常在前,父类异常在后
发生异常时按顺序逐个匹配
只执行第一个与异常类型匹配的catch语句
finally根据需要可写或不写 - try…finally…不能捕获异常,仅仅用来当发生异常时,用来释放资源
一般用在底层代码,只释放资源不做异常处理,把异常向上抛出。
15、集合框架
Collection接口
-
Collection接口是最基本的容器接口,继承至Iterable接口,允许元素重复,可以无序,无下标
-
方法
- boolean add(Object obj) //添加一个对象。
- boolean addAll(Collection c) //将一个集合中的所有对象添加到此集合中。
- void clear() //清空此集合中的所有对象。
- boolean contains(Object o) //检查此集合中是否包含o对象
- boolean equals(Object o) //比较此集合是否与指定对象相等。
- boolean isEmpty() //判断此集合是否为空
- boolean remove(Object o) //在此集合中移除o对象
- int size() //返回此集合中的元素个数。
- Object[] toArray() //将此集合转换成数组。
-
迭代器
-
//Iterator
- Iterator iterator = collection.iterator();
-
//迭代器: 是一种专门用来遍历集合元素的一种方法
-
//hasNext(); 有下一个元素 返回true
-
//next(); 取下一个元素
-
//remove(); 删除元素
-
注意事项:
- //删除
-
//必须使用迭代器的删除方法
-
//iterator.remove();
-
//集合删除方法 :ConcurrentModificationException
-
//迭代过程中不能使用集合的删除方法,否则会出现并发修改异常
-
//collection.remove(o);
-
-
List接口
-
ArrayList
-
底层的数据结构使用的是数组结构,有序,有下标,可以重复,查询很快,但增删较慢,线程不安全
ArrayList的查找遍历比较快,插入和删除相对较慢,因为使用本地方法优化,并不一定比LinkedList慢 -
源码分析
-
- (1) 调用无参构造方法创建ArrayList集合,长度是0
-
- (2) Object[] elementData 储存元素个数 size初始为0
-
- (3) 当添加第一个元素时,容量扩容为10 每次扩容大小都是1.5倍
-
- (4) remove 方法使用System.arrayCopy实现移动,效率高
-
- (5) 迭代器中有一个cursor,获取一个元素侯,cursor+1,如果cursor == size,不能获取
-
-
-
LinkedList
-
底层的数据结构是双向链表结构,有序,有下标,可以重复LinkedList的插入和删除比较快,查找遍历比较慢
-
源码分析
-
- (1)构造没有任何操作,属性size=0,first头节点 last最后一个节点
-
- (2)静态内部类Node 包含三个属性 item 数据 next下一个元素 prev上一个元素
-
- (3)add方法 每添加一个元素都会形成一个节点 first属性指向第一个元素,last指向后一个元素
-
- 每一个节点都有前驱和后继(重点)
-
-
-
列表迭代器
- //列表迭代器
-
ListIterator listIterator = linkedListist.listIterator();
-
while (listIterator.hasNext()) {
-
System.out.println(listIterator.next());
-
}
-
while (listIterator.hasPrevious()) {
-
System.out.println(listIterator.previous());
-
}
-
Vector
-
底层是数组数据结构,查询快、增删慢,JDK1.0版本,运行效率慢、线程安全。
-
遍历
-
//枚举器
-
Enumeration elements = vector.elements();
-
while (elements.hasMoreElements()) {
-
System.out.println(elements.nextElement());
-
}
-
-
-
-
Set接口
-
不允许在其中放入重复的元素
-
最多只能包含一个null元素
-
HashSet类
- 底层实现是基于HashMap
- 不保证Set的迭代顺序
- 不保证该顺序永久不变
-
-
数据结构
-
栈
-
是一种先进后出的数据结构
-
Stack类:继承Vector类
-
push方法入栈、pop方法出栈
- //入栈 压栈
- stack.push(“王五”);
-
//出栈
-
int count = stack.size();
-
for (int i = 0; i < count; i++) {
-
System.out.println(stack.pop());
-
}
-
LinkedList也实现了栈结构
-
-
队列
-
是一种先进先出的数据结构
-
Queue接口:继承Collection接口
-
offer方法入队、pop方法出队
- //进队
-
queue.offer("桃子");
-
//出队
-
int count = queue.size();
-
for (int i = 0; i < count; i++) {
-
System.out.println(queue.poll());
-
}
-
LinkedList实现了Queue接口
-
-
-
注意事项:
- 不要在 foreach 循环里进行元素的 remove/add 操作。remove 元素请使用Iterator 方式,如果并发操作,需要对 Iterator 对象加锁。
Map接口
-
HashMap类
- 基于哈希表的Map接口实现,利用哈希算法根据hashCode()来配置存储地址
-
TreeMap类
- 基于红黑树(Red-Black tree)的NavigableMap 实现。该映射根据其键的自然顺序进行排序,或者 根据创建映射时提供的Comparator 进行排序,具体取决于使用的构造方法
-
SortedMap接口
- 进一步提供关于键的总体排序 的 Map
辅助工具类
-
Collections
-
提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作
-
方法
- Collections.max(arrayList)最大值
- Collections.reverse(arrayList)翻转
- Collections.shuffle(arrayList)打乱
- Collections.binarySearch(arrayList, 47)二分查找
- Collections.sort(arrayList)倒序
- Collections.frequency(arrayList, 10)查找元素出现的个数
- Collections.copy(arrayList1, arrayList);复制
-
-
Arrays类
-
Comparable
- Comparable用作默认的比较方式,实现了该接口的类之间可以相互进行比较,这个对象组成的集合就可以直接通过sort()进行排序了
-
Comparator接口
- Comparator是设计模式中策略模式的一种应用
数组和集合的转换
-
数组转成集合
- List integers = Arrays.asList(nums);
- add和remove方法不能使用会出现UnsupportedOperationException不支持操作异常
-
集合变成数组
-
注意点: 数组要给初始值
-
步骤
- ArrayList stringArrayList = new ArrayList<>();
-
stringArrayList.add("上海");
-
stringArrayList.add("北京");
-
String[] strings = stringArrayList.toArray(new String[0]);
-
15、泛型
概念
- 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型
- Java泛型是JDK1.5中引入的一个新特性,其本质是参数化类型,把类型作 为参数传递。
- T 占位符 表示一种引用数据类型
- 参数化类型、类型安全的集合,强制集合元素的类型必须一致。
特点
- 编译时即可检查,而非运行时抛出异常。
- 访问时,不必类型转换(拆箱)。
- 不同泛型之间引用不能相互赋值,泛型不存在多态。
注意:
- 1.不能使用t实例化对象
- 2.不能使用不同的泛型作为方法重载的依据
- jdk1.7之后 实例化泛型对象可以省略类型 <>钻石语法 diamond
泛型方法
-
简单定义
- public class Test{}
-
简单实例化
- Test t = new Test();
-
规则
- 所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前。
- 每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。
- 类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。
- 泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(像int,double,char的等)。
泛型类
-
泛型类的类型参数声明部分也包含一个或多个类型参数,参数间用逗号隔开
-
一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符
-
因为他们接受一个或多个参数,这些类被称为参数化的类或参数化的类型
-
例子
- public class Box {
private T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
}
- public class Box {
泛型接口
类型通配符
-
类型通配符一般是使用?代替具体的类型参数
- List<?>在逻辑上是List>,List 等所有List<具体类型实参>的父类
-
类型通配符上限
- List<? extends Number>如此定义就是通配符泛型值接受Number及其下层子类类型
-
类型通配符下限
- List<? super Number>表示类型只能接受Number及其三层父类类型
好处
- 提高代码的重用性
- 防止类型转换异常,提高代码的安全性
符号引用
- 定义:
在java中,一个java类将会编译成一个class文件。在编译时,java类并不知道引用类的实际内存地址,因此只能使用符号引用来代替。比如org.simple.People类要引用org.simple.Tool类,在编译时People类并不知道Tool类的实际内存地址,因此只能使用符号org.simple.Tool(假设)来表示Tool类的地址。而在类装载器装载People类时,此时可以通过虚拟机获取Tool类 的实际内存地址,因此便可以既将符号org.simple.Tool替换为Tool类的实际内存地址,及直接引用地址。
JVM字节码中dup指令
-
new Test()
-
1.创建并默认初始化一个Test类型的对象
new jvm.study.Test [1] -
dup
- new字节码指令的作用是创建指定类型的对象实例、对其进行默认初始化,并且将指向该实例的一个引用压入操作数栈顶;然后因为invokespecial会消耗掉操作数栈顶的引用作为传给构造器的“this”参数,所以如果我们希望在invokespecial调用后在操作数栈顶还维持有一个指向新建对象的引用,就得在invokespecial之前先“复制”一份引用——这就是这个dup的来源。
-
2.调用Test类的signature为 ()V 的构造器
invokespecial jvm.study.Test() [16] -
3.表达式的值为一个指向这个新建对家的引用。
astore_1 [t]- astore就会把操作数栈顶的那个引用消耗掉,保存到指定的局部变量去。
-
java常量池
- ** 程序计数器是jvm执行程序的流水线,存放一些跳转指令,这个太高深,小菜不懂。
- ** 本地方法栈是jvm调用操作系统方法所使用的栈。
- ** 虚拟机栈是jvm执行java代码所使用的栈。
- ** 方法区存放了一些常量、静态变量、类信息等,可以理解成class文件在内存中的存放位置。
- ** 虚拟机堆是jvm执行java代码所使用的堆。
- Java中的常量池,实际上分为两种形态:静态常量池和运行时常量池。
- 所谓静态常量池,即.class文件中的常量池,class文件中的常量池不仅仅包含字符串(数字)字面量,还包含类、方法的信息,占用class文件绝大部分空间。
- 而运行时常量池,则是jvm虚拟机在完成类装载操作后,将class文件中的常量池载入到内存中,并保存在方法区*中,我们常说的常量池,就是指方法区中的运行时常量池。