JAVA基础复习资料必备(一)

java自学必备

JAVA基础复习资料必备(二)

第一章 Java概述

1.1 java历史

Java诞生于SUN(Stanford University Network),09年被Oracle(甲骨文)收购。
Java之父是詹姆斯.高斯林(James Gosling)。
1996年发布JDK1.0版

1.2 Java语言的主要特点

  • 特点一:面向对象
    两个基本概念:类和对象
    三大特征:封装、继承、多态【抽象】
  • 特点二:健壮性
      吸收了C/C++语言的优点,丢弃了其影响健壮性的部分(指针、内存的申请与释放等),提供了一个相对安全的内存管理和访问机制
  • 特点三:跨平台性
    通过Java语言编写的运用程序在不同的系统平台上都可以运行,‘一次编译,到处运行’。
    实现跨平台的原理:Java程序是通过JVM在操作系统上运行的,只要安装了相对应的JVM,该系统就可以运行JAVA程序,通过源文件(.java)---->编译(.class)字节码文件---->解释----->操作系统
    JVM的作用:将字节码(.class)解释成对应的系统平台机器码并执行
    JAVA基础复习资料必备(一)_第1张图片

1.3 Java环境的搭建

Java开发人员需要安装JDK。如果只是运行Java程序那么只需要安装JRE就可以了。
JDK(Java Developement kits):Java开发工具包
JRE(Java Runtime Environment):Java运行环境
JVM (Java Virtual Machine):Java虚拟机
JDK = JRE + 开发工具(javac.exe,java.exe,javadoc.exe等)
JRE = JVM + Java核心类库(常用类:String(字符串),Date(日期时间),Math(数字),IO(输入输出流),net(网络),集合,多线程等)

1.3.2 Java的环境搭建

1、安装JDK
2、配置JDK的开发工具集(bin)目录到path环境变量中
例如:D:\ApacheSoftwareFoundation\Java\jdk1.8.0_221;(注意:以自己的安装目录为准)
JAVA基础复习资料必备(一)_第2张图片
3、如何配置环境变量:【计算机】右键【属性】,选择【高级系统设置】,选择【高级】,选择【环境变量】
JAVA基础复习资料必备(一)_第3张图片
4、配置path系统变量的作用:%PATH%代表可执行文件的搜索路径,默认为 Windows 目录和系统目录,配置后可以直接打开可执行文件
5、为什么要配置环境变量:希望在命令行使用javac.exe等工具时,任意目录文件都可以找到这个工具所在的目录。

1.4 第一个Java应用程序

class HelloWorld{
	public static void main(String[] args){
		System.out.println("Hello world!");
	}
}
1.4.1 Java程序的开发步骤

1、编写:编写.java文件
2、编译:通过javac.exe编译成.class字节码文件(因为JVM只认识字节码)

javac 源文件名称.java

3、运行:通过java.exe文件运行

Javac 类名.java
java 字节码文件
JAVA基础复习资料必备(一)_第4张图片

1.4.2 Java程序的结构与格式

结构:

{
	方法{
		语句;
	}
}

格式:
(1)每一级缩进一个Tab键;
(2){}的左半部分在行尾,右半部分单独一行,与和它成对的"{"的行首对齐,{}成对出现;

1.4.3 Java程序的入口

Java程序的入口是main方法

public void void main(String[] args){
}
1.4.4 Java注释

1、单行注释

//注释内容

2、多行注释

/*
注释内容
*/

3、文档注释

/**
注释内容(可以使用注释注解)
*/

1.5 编写Java程序时应该注意的问题

1、字符编码格式问题
  使用cmd命令行的字符编码格式与源文件.java的字符编码不一致如何解决(原因:大部分cmd命令行默认的字符编码格式和系统相同为"GBK",而.java文件的编码格式为其他,通过命令行的方式去解码不为"GBK"编码的文件时,就会导致乱码)
JAVA基础复习资料必备(一)_第5张图片
解决方案一:使用javac -encoding指定源文件的字符编码(格式:javac -encoding 字符编码 类文件.java)
JAVA基础复习资料必备(一)_第6张图片
解决方法二:使用Notepad++等编辑器修改字符编码
JAVA基础复习资料必备(一)_第7张图片
2、大小写问题:Java语言严格区分大小写
(1)源文件名称不区分大小写(建议区分);
(2)字节码文件、类名、代码中都区分大小写;

3、源文件名称和类名一致问题
(1)如果这个类不是public修饰的,源文件名称可以和类名不同;
(2)一个文件中可以存在多个非public修饰的类;
(3)如果这个类是public修饰的,源文件名称必须和public修饰的类名相同;
(4)一个文件中最多只能存在一个public修饰的类(不包括内部类);
建议:不管是不是public修饰的类,都与源文件的名称相同,且一个源文件只写一个类(原因:好维护);
(5)main方法必须在public修饰的类中?
可以在其他类中,由于代码习惯,基本上写在public修饰的类中。

第二章 Java的基本语法

2.1 标识符

凡是可以自己命名的地方都可以称作标识符
例如:类名,变量名,方法名等

1、标识符的命名规则
(1)Java中的标识符由26个英文字母大小写,数字0-9,美元符号&和下划线_组成;
(2)不可以使用Java的关键字,特殊值和保留字;
(3)不可以以数字开头;
(4)不可以包含空格;
(5)严格区分大小写;

2、标识符的命名规范
(1)见名知意;
(2)类名,接口名等:采用大驼峰命名法也就是单词首字母大写(XxxYyyZzz);
(3)变量名,方法名等:采用小驼峰命名法也就是第二个单词的首字母开始大写(xxxYyyZzz);
(4)包名:全部字母小写,单词之间使用.隔开(xxx.yyy.zzz);
(5)常量名:全部字母大写,单词之间使用_隔开(XXX_YYY_ZZZ);

2.2 变量

2.2.1 概念

变量的作用:用来存储数据,代表内存中的一块存储空间,变量中的值是可以改变的

2.2.2 变量使用的三要素

(1)类型名称
(2)变量名
(3)变量值

2.2.3 变量使用的注意事项

(1)先声明后使用
(2)变量名有作用域
(3)同一个作用域下不能重名
(4)使用前必须先初始化

2.2.4 变量的声明赋值的语法格式

声明:数据类型 变量名 = 变量值;
例如:int num = 10;

2.3 数据类型

2.3.1 数据类型的分类

1、基本数据类型(8种):byte,short,char,int,long,float,double,boolean;
2、引用数据类型:String、enum、数组、接口等;

2.3.2 基本数据类型

1、整数系列
(1)byte(字节型):1个字节(取值范围:-27~27-1)
(2)short(短整型):2个字节(取值范围:-215~215-1)
(3)int(整型):4个字节(取值范围-231~231-1)
(4)long(长整型):8个字节(取值范围-263~263-1)

注意:如果要表示某个常量数字它是long类型,那么需要在数字后面加L或l

2、浮点系列
(1)float(单精度浮点):4个字节(精度:科学记数法的小数点后6~7位)

注意:如果要表示某个常量数字是float类型,那么需要在数字后面加F或f

(2)double(双精度浮点):8个字节(精度:科学记数法的小数点后15~16位)

3、字符类型:char(字符):2个字节
(1)Java中使用的字符集:Unicode编码集
(2)字符的三种使用方式

(1)表示单个字符
例如 :‘A’;
(2)转义字符
例如:\t,\n等;
 Unicode的十六进制表示
 x4E2D代表’中’;

4、布尔类型:boolean:只能存储true或false

2.3.3 进制

(1)进制类型:
二进制:逢二进一,由数字0-1组成
八进制:逢八进一,由数字0-7组成
十进制:逢十进一,由数字0-9组成
十六进制:逢十六进一,由数字0-9,A-F组成
(2)为什么byte的取值范围是-128~127?
1个字节:8bit
0000 0001 ~ 0111 1111 ===> 1 ~ 127;
1000 0001 ~ 1111 1111 ===> -127 ~ -1;
0000 0000 = 0;
1000 0000 = -128;(特殊规定)

计算机中的数据存储
计算机数据的存储使用二进制补码形式存储,并且最高位是符号位,1是负
数,0是正数。
规定:正数的补码与反码、原码一样,称为三码合一;负数的补码与反码、原码不一样:
​(1)负数的原码:把十进制转为二进制,然后最高位设置为1
​(2)负数的反码:在原码的基础上,最高位不变,其余位取反(0变1,1变0)
(3) 负数的补码:反码+1
例如:byte类型(1个字节,8位)
25 ==> 原码 0001 1001 ==> 反码 0001 1001 ==> 补码 0001 1001
-25 ==> 原码 1001 1001 ==> 反码 1110 0110 ==> 补码 1110 0111
底层使用加法代替减法:-128 ==> -127 - 1 ==> -127 + (-1) ==> 1111 1111 + 1000 0001 ==> 1000 0000 ==> -128

(3)为什么float(4个字节)的存储范围比long(8个字节)的存储范围大

因为float、double底层也是二进制,先把小数转为二进制,然后把二进制表示为科学记数法,然后只保存:
浮点类型的存储由符号位、指数、尾数部分组成
格式
float:SEEE EEEE EMMM MMMM MMMM MMMM MMMM MMMM
double:SEEE EEEE EEEE MMMM MMMM MMMM MMMM MMMM MMMM MMMM MMMM MMMM MMMM MMMM MMMM MMMM
S:符号位
E:指数,十进制指数加上127后的值得二进制数据
M:底数
③尾数部分:尾数部分
任何一个数都的科学计数法表示都为1.xxxx*2n。尾数部分就可以表示为xxxx,第一位都是1,可以省略
float的存储是科学计数法(指数的增长为2n),而long存储是普通的二进制

(4)为什么double(8个字节)比float(4个字节)精度范围大?

float 可以保证十进制科学计数法小数点后6位有效精度和第7位的部分精度
double 可以保证十进制科学计数法小数点后15位有效精度和第16位的部分精度。

2.3.4 基本数据类型的转换

1、自动类型转换
(1)当把存储范围小的值(常量值,变量值,表达式中的计算结果)赋值给存储范围大的变量时会发生自动类型转换

byte -> short -> int -> long ->float ->double
   char ->

(2)当存储范围小的数据类型和存储范围大的数据类型进行混合运算时,会按照其中最大的类型运算
(3)当byte,short,char数据类型进行算术运行时会按照intl类型处理

2、强制类型转换
(1)当把存储范围大的值(常量值,变量值,表达式中的计算结果)赋值给存储范围小的变量时,需要进行强制类型转换(注意:可能会损失精度或者溢出)

dounble -> float -> long -> int -> short -> byte
             -> char

(2)当某个值想要提升数据类型时也可以使用强制类型转换
(3)boolean类型不参与

2.3.5 特殊的数据类型转换

1、任意数据类型的数据和String类型进行"+"运算时,结果一定是String类型
2、String类型不可以通过强制类型转换,转为其他类型

2.4 运算符

1、按照操作符的个数分类:
(1)一元运算符:操作数只有一个

例如:正号(+),负号(-),自增(++),自减(–),逻辑非(!),按位取反(~)

(2)二元操作符:操作数有两个

例如:加(+),减(-),乘(),除(/),取模(%),大于(>),小于(<),大于等于(>=),小于等于(<=),等于(==),不等于(!=)
赋值(=,+=,-=,
=,/=,%=,>>=,<<=)
逻辑与(&),逻辑或(|),逻辑异或(^),短路与(&&),短路或(||)
左移(<<),右移(>>),无符号右移(>>>),按位与(&),按位或(|),按位异或(^)

(3)三元运算符:操作数三个

例如: ? :

2、Java基本数据类型的运算符:

2.4.1 算术运算符

说明:数字和单个字符可以使用算术运算符。其中+,当用于字符串时,表示拼接。

加法:+
减法:-
乘法:*
除法:/

注意:整数与整数相除,只保留整数部分

取模:% 取余

注意:取模结果的正负号只看被模数

正号:+
负号:-
自增:++
自减:–

原则:自增与自减
++/–在前的,就先自增/自减,后取值
++/–在后的,就先取值,后自增/自减

整个表达式的扫描,是从左往右扫描,如果后面的先计算的,那么前面的就暂时先放到“操作数栈”中

2.4.2 赋值运算符

说明:右边的常量值、表达式的值、变量的值的类型必须与左边的变量一致或兼容(可以实现自动类型转换)或使用强制类型转换可以成功。

基本赋值运算符:=
扩展赋值运算符:+=,-=,*=,/=,%=…

注意:
 所有的赋值运算符的=左边一定是一个变量
 扩展赋值运算符=右边的计算结果的类型如果比左边的大的话会强制类型转换,所以结果可能有风险。

扩展赋值运算符的计算:

(1)赋值最后算
(2)加载数据的顺序是把左边的变量的值先加载,再去与右边的表达式进行计算

2.4.3 比较运算符

说明:其他的比较运算符都是只能用于8种基本数据类型。其中的==和!=可以用于引用数据类型的比较,用于比较对象的地址

大于:>
小于:<
大于等于:>=
小于等于:<=
等于:== 注意区分赋值运算符的=
不等于:!=

注意:
 比较表达式的运算结果一定只有true/false
 比较表达式可以作为(1)条件(2)逻辑运算符的操作数

2.4.4 逻辑运算符

说明:逻辑运算符的操作数必须是布尔值,结果也是布尔值

逻辑与:&

运算规则:只有左右两边都为true,结果才为true。
例如:true & true 结果为true
   false & true 结果为false
   true & false 结果为false
   false & false 结果为false

逻辑或:|

运算规则:只要左右两边有一个为true,结果就为true。
例如:true | true 结果为true
   false | true 结果为true
   true | false 结果为true
   false | false 结果为false

逻辑异或:^

运算规则:只有左右两边不同,结果才为true。
例如:true ^ true 结果为false
   false ^ true 结果为true
   true ^ false 结果为true
   false ^ false 结果为false

逻辑非:!

运算规则:布尔值取反
例如:!true 为false
   !false 为true

短路与:&&

运算规则:只有左右两边都为true,结果才为true。
例如:true & true 结果为true
   true & false 结果为false
   false & ? 结果就为false
它和逻辑与不同的是当&&左边为false时,右边就不看了。

短路或:||

运算规则:只要左右两边有一个为true,结果就为true。
例如:true | ? 结果为treu
   false | true 结果为true
   false | false 结果为false
它和逻辑或不同的是当||左边为true时,右边就不看了。

2.4.5 条件运算符

? :

?前面必须是条件,必须是boolean值
语法:
 条件表达式 ? 结果表达式1 : 结果表达式2(结果表达式1和结果表达式2要保持类型一致或兼容)
 运算规则:整个表达式的结果:当条件表达式为true时,就取结果表达式1的值,否则就取结果表达式2的值

2.4.6 位运算符

说明:一般用于整数系列

左移:<<

运算规则:左移几位就相当于乘以2的几次方

右移:>>

​ 运算规则:右移几位就相当于除以2的几次方

无符号右移:>>>

​ 运算规则:往右移动后,左边空出来的位直接补0,不看符号位

按位与:&

​ 运算规则:
 1 & 1 结果为1
 1 & 0 结果为0
 0 & 1 结果为0
 0 & 0 结果为0

按位或:|

​ 运算规则:
 1 | 1 结果为1
 1 | 0 结果为1
 0 | 1 结果为1
 0 & 0 结果为0

按位异或:^​

运算规则:
 1 ^ 1 结果为0
 1 ^ 0 结果为1
​ 0 ^ 1 结果为1
 0 ^ 0 结果为0

按位取反:~

运算规则:
 ~0就是1
 ~1就是0

如何区分&,|,^是逻辑运算符还是位运算符?

如果操作数是boolean类型,就是逻辑运算符,如果操作数是整数,那么就位运算符。

3、运算符的优先级
JAVA基础复习资料必备(一)_第8张图片
说明:
(1)表达式不要太复杂
(2)先算的使用()

第三章 流程控制语句结构

流程控制语句结构分为:
1、顺序结构:从上到下依次执行
2、分支结构:多个分支选择其中一个分支执行
3、循环结构:重复执行某些代码

3.1 分支结构

3.1.1 条件判断

1、单分支结构
语法格式:

if(条件表达式){
	 当条件表达式成立(true)时需要执行的语句块;
}

执行过程:w条件成立,就执行{}其中的语句块,不成立就不执行。

2、双分支结构
语法格式:

if(条件表达式){
    当条件表达式成立(true)时需要执行的语句块1;
}else{
    当条件表达式不成立(false)时需要执行的语句块2;
}

执行过程:当条件表达式成立(true)时执行语句块1,否则执行语句块2

3、多分支结构
语法格式:

if(条件表达式1){
    当条件表达式1成立的时候,执行的语句块1}else if(条件表达式2){
    当条件表达式1不成立,
      条件表达式2成立的时候,执行的语句块2}else if(条件表达式3){
    当条件表达式1不成立,
       条件表达式2也不成立,
      条件表达式3成立的时候,执行的语句块3}
。。。
【else{
	当以上所有的条件表达式都不成立,需要执行的语句块n+1;
}

执行过程:
(1)多个条件顺序往下判断,如果上面有一个条件成立了,下面的条件就不看了
(2)多个分支也只会执行其中的一个

注意:
(1)每一个条件表达式都必须是boolean值
(2)当{}中的语句只有一个语句(简单的语句,也可以是一个复合语句)时,可以省略{},但是我们不建议省略
(3)当多个条件是“互斥”关系(没有重叠部分),顺序可以随意;
  当多个条件是“包含”关系(有重叠部分),顺序不能随意,小的在上,大的在下面

4、嵌套
执行过程:
​ (1)当嵌套在if中,当外面的if成立时,才会看里面的条件判断
​ (2)当嵌套在else中,当外面的else满足时,才会看里面的条件判断

3.1.2 选择结构

语法格式:

switch(表达式){
    case 常量值1:
        语句块1;break;case 常量值2:
        语句块2;break;】   
    。。。
   【default:
        语句块n+1;break;】
     】
}

执行过程:
(1)入口
①当switch(表达式)的值和case后面的某个常量匹配时,就会从这个case进入
②当switch(表达式)的值和case后面的所有常量值不匹配时,就会寻找default分支进入
(2)一旦从“入口”进入switch,就会顺序往下执行,知道遇到“出口”
(3)出口
①自然出口:遇到了对于switch的结束}
②中断出口:遇到了break等

注意:
(1)switch(表达式)的值的类型只能是4种数据类型(byte,short,char,int),两种引用数据类型(枚举,String)
(2)case后面的值必须是常量值且不能重复

3.2 循环结构

循环结构:重复执行某段代码
循环结构的分类:
1、for循环
2、while循环
3、do…while循环

3.2.1 for循环

语法格式:

for(;;){
    循环体语句块;
    if(条件表达式){
    	break;
    }
}
for(初始化表达式; 循环条件; 迭代表达式){
    循环体语句块;(需要重复执行的代码)
}

执行过程:
(1)初始化表达式;
(2)判断循环条件
(3)如果循环条件成立,那么执行循环体语句,然后执行迭代表达式再回到(2)…
(4)如果循环条件不成立,结束for循环(或者当前循环中遇到了break语句也会结束当前for循环)
注意:

(1)for(;;)中的两个;一个也不能多也不能少
(2)循环条件必须是boolean类型

3.2.2 while循环

语法格式:

while(循环条件){
	循环体语句块;
}

经典的形式
while(true){
	循环体语句块
	if(条件表达式){
		break;
	}
}

执行过程:
(1)先判断循环条件
(2)若循环条件成立,则执行循环体语句块;然后回到(1)…
(3)若循环条件不成立(循环体语句块中遇到了break),则结束while循环
注意:

while(循环条件)中循环条件必须是boolean类型

3.2.3 do…while循环

语法格式:

do{
	循环体语句块;
}while(循环条件);

执行过程:
(1)先执行循环体语句块;
(2)判断循环条件
(3)若循环成立回到(1)…
(4)若循环条件不成立(遇到break),结束do…while循环
注意:

(1)while(循环条件)中循环条件必须是boolean类型
(2)do{}while();最后有一个分号
(3)do…while的循环体语句块至少会执行一次

3.2.4 三种循环结构的选择

原则:三种循环之间是可以互相转换的,都能实现循环功能
建议:当次数比较明显时,优先考虑for结构;
   当循环体语句块至少执行一次时,优先考虑do…while结构;
   当循环条件比较明显但是次数不明显时,优先考虑while结构

三种循环结构都要具有的四要素:
(1)循环变量的初始化表达式;
(2)循环条件
(3)迭代条件
(4)循环体语句块

3.2.5 跳转语句

1、break:结束当前循环,一般用于switch结构和循环结构;
2、continue:跳出当此循环,继续下一次循环,只用于循环结构;
3、return:当前方法的返回值类型为void时,表示结束当前方法;

第四章 数组

4.1 数组的相关概念和名词

1、数组(array):一组具有相同数据类型的数据按照一定顺序排列的集合。

2、数组名
(1)代表的是一组数
(2)这个数组名存储的是整个数组的首地址

3、下标(index)
我们使用索引、下标、编号来区别一组数中的某一个
范围[0,array.length)

4、元素(element)
(1)数组中的每一个数据都是一个元素
(2)如何表示数组中的元素(数组名[下标])

5、数组的长度(length)
(1)数组中元素的总个数
(2)如何获取数组的总长度(数组名.length)

4.2 数组的相关语法

4.2.1 数组的声明

语法格式:

元素数据类型[] 数组名称;
4.2.2 数组的初始化

数组初始化目的:
(1)确认数组的长度
(2)为数组中的元素赋值

1、动态初始化

语法格式:

//初始化
元素数据类型[] 数组名称 = new 元素数据类型[长度];
//为元素赋值
数组名称[下标] =;
//循环赋值
for(int i = 0;i < 长度;i++){
	数组名[下标] =;
}

当数组只动态初始化,没有进行赋值,那么元素都有默认值:

(1)基本数据类型
①整数类型:byte,short,int,long:默认值为0
②小数类型:float,double:默认值为0.0
③布尔类型:boolean:默认值为false
④字符类型:char:默认值为\u0000
(2)引用数据类型:默认值为null

2、静态初始化

语法结构:

元素数据类型[] 数组名称 = new 元素数据类型[]{值列表};
//简化
元素数据类型[] 数组名称 = {值列表};

使用场景:当数组的元素个数是有限时,可以使用静态初始化。

4.2.3 数组的遍历

for循环遍历数组:

for(int i=0; i<数组名.lenght; i++){
    //赋值
    数组名[i] =;
    //显示
    System.out.println(数组名[i])//其他操作
    //例如:判断是否是偶数
    if(数组名[i]%2==0){
          //...
    }
}

增强for循环(foreach)

for(数组元素类型 值:数组名){
	System.out.println();
}
4.2.4 数组的内存分析

元素是基本数据类型的一维数组解析:

int[] arr = {1,2,3,4,5};

JAVA基础复习资料必备(一)_第9张图片

4.3 数组的相关算法

4.3.1 数组中找最值

实现思路:
1、数组中找最值
(1)假设第一个元素最大/最小
(2)设置一个变量max/min与后面的元素比较

2、数组中找最值及其下标
(1)(2)设置一个变量用来记录当前最值得下标

4.3.2 数组统计

(1)求总和
示例代码:

int[] arr = {4,5,6,1,9};
//求总和、均值
int sum = 0;//因为0加上任何数都不影响结果
for(int i=0; i<arr.length; i++){
    sum += arr[i];
}
double avg = (double)sum/arr.length;

(2)求均值
示例代码:

int[] arr = {4,5,6,1,9};
//求总乘积
long result = 1;//因为1乘以任何数都不影响结果
for(int i=0; i<arr.length; i++){
    result *= arr[i];
}

(3)统计偶数个数
示例代码:

int[] arr = {4,5,6,1,9};
//统计偶数个数
int even = 0;
for(int i=0; i<arr.length; i++){
    if(arr[i]%2==0){
        even++;
    }
}
4.3.3 反转

思路:
(1)借助一个新数组
示例代码:

int[] arr = {1,2,3,4,5,6,7,8,9};
//(1)先创建一个新数组
int[] newArr = new int[arr.length];
//(2)复制元素
int len = arr.length;
for(int i=0; i<newArr.length; i++){
    newArr[i] = arr[len -1 - i];
}
//(3)舍弃旧的,让arr指向新数组
arr = newArr;//这里把新数组的首地址赋值给了arr
//(4)遍历显示
for(int i=0; i<arr.length; i++){
    System.out.println(arr[i]);
}

(2)首尾对应位置交换
示例代码:

int[] arr = {1,2,3,4,5,6,7,8,9};
//(1)计算要交换的次数:次数 = arr.length/2
//(2)首尾交换
for(int i=0; i<arr.length/2; i++){//循环的次数就是交换的次数
    //首与尾交换
    int temp = arr[i];
    arr[i] = arr[arr.length-1-i];
	arr[arr.length-1-i] = temp;
}
//(3)遍历显示
for(int i=0; i<arr.length; i++){
    System.out.println(arr[i]);
}
4.3.4 复制

示例代码:扩容

int[] arr = {1,2,3,4,5,6,7,8,9};
//如果要把arr数组扩容,增加1个位置
//(1)先创建一个新数组,它的长度 = 旧数组的长度+1
int[] newArr = new int[arr.length + 1];
//(2)复制元素
//注意:i
for(int i=0; i<arr.length; i++){
    newArr[i] = arr[i];
}
//(3)把新元素添加到newArr的最后
newArr[newArr.length-1] = 新值;
//(4)如果下面继续使用arr,可以让arr指向新数组
arr = newArr;
//(5)遍历显示
for(int i=0; i<arr.length; i++){
    System.out.println(arr[i]);
}

示例代码:备份

int[] arr = {1,2,3,4,5,6,7,8,9};
//1、创建一个长度和原来的数组一样的新数组
int[] newArr = new int[arr.length];
//2、复制元素
for(int i=0; i<arr.length; i++){
    newArr[i] = arr[i];
}
//3、遍历显示
for(int i=0; i<arr.length; i++){
    System.out.println(arr[i]);
}

示例代码:截取

int[] arr = {1,2,3,4,5,6,7,8,9};
int start = 2;
int end = 5;
//1、创建一个新数组,新数组的长度 = end-start + 1;
int[] newArr = new int[end-start+1];
//2、赋值元素
for(int i=0; i<newArr.length; i++){
    newArr[i] = arr[start + i];
}
//3、遍历显示
for(int i=0; i<newArr.length; i++){
    System.out.println(newArr[i]);
}
4.3.5 查找

1、顺序查找:对数组没要求(原理:依次对比)
示例代码:

int[] arr = {4,5,6,1,9};
int value = 1;
int index = -1;
for(int i = 0,i < arr.length; i++){
	if(value == arr[i]){
		index = i;
		break;
	}
}
if(index==-1){
    System.out.println(value + "不存在");
}else{
    System.out.println(value + "的下标是" + index);
}

2、二分查找:对数组有要求,元素必须有大小顺序的(原理:对折对折再对折,比较中间值)
示例代码:

/*
2、编写代码,使用二分查找法在数组中查找 int value = 2;是否存在,如果存在显示下标,不存在显示不存在。
已知数组:int[] arr = {1,2,3,4,5,6,7,8,9,10};
*/
class Exam2{
	public static void main(String[] args){
		int[] arr = {1,2,3,4,5,6,7,8,9};//数组是有序的
		int value = 2;
        int index = -1;
		int left = 0;
        int right = arr.length - 1;
        int mid = (left + right)/2;
        while(left<=right){
            //找到结束
            if(value == arr[mid]){
                index = mid;
                break;
            }//没找到
            else if(value > arr[mid]){//往右继续查找
                //移动左边界,使得mid往右移动
                left = mid + 1;
            }else if(value < arr[mid]){//往左边继续查找
                right = mid - 1;
            }
            mid = (left + right)/2;
        }
        if(index==-1){
    		System.out.println(value + "不存在");
		}else{
    		System.out.println(value + "的下标是" + index);
		} 
	}
}
4.3.6 排序

1、冒泡排序(原理:相邻元素两两比较)
示例代码:
示例代码:冒泡:从小到大,从左到右两两比较

int[] arr = {5,4,6,3,1};
for(int i=1; i<arr.length; i++){//外循环的次数 = 轮数 = 数组的长度-1
    /*
    第1轮,i=1,从左到右两两比较,arr[0]与arr[1]。。。。。arr[3]与arr[4]
    第2轮,i=2,从左到右两两比较,arr[0]与arr[1]。。。。。arr[2]与arr[3]
    ...
    				arr[j]与arr[j+1]比较
    找两个关键点:(1)j的起始值:0(2)找j的终止值,依次是3,2,1,0,得出j
    for(int j=0; j<arr.length-i; j++){
        //两两比较
        //从小到大,说明前面的比后面的大,就交换
        if(arr[j] > arr[j+1]){
            int temp = arr[j];
            arr[j] = arr[j+1];
            arr[j+1] = temp;
        }
    }
}

2、选择排序(原理:每次循环找出本轮未排序元素中的最值)
示例代码:

int[] arr = {3,2,6,1,8};
for(int i=1; i<arr.length; i++){//外循环的次数 = 轮数 = 数组的长度-1
    //(1)找出本轮未排序元素中的最值
    /*
    未排序元素:
    第1轮:i=1,未排序,[0,4]
    第2轮:i=2,未排序,[1,4]
    ...
    每一轮未排序元素的起始下标:0,1,2,3,正好是i-1的
    未排序的后面的元素依次:
    第1轮:[1,4]  j=1,2,3,4
    第2轮:[2,4]  j=2,3,4
    第3轮:[3,4]  j=3,4
    第4轮:[4,4]  j=4
    j的起点是i,终点都是4
    */
    int max = arr[i-1];
    int index = i-1;
    for(int j=i; j<arr.length; j++){
        if(arr[j] > max){
            max = arr[j];
            index = j;
        }
    }
    
    //(2)如果这个最值没有在它应该在的位置,就与这个位置的元素交换
    /*
    第1轮,最大值应该在[0]
    第2轮,最大值应该在[1]
    第3轮,最大值应该在[2]
    第4轮,最大值应该在[3]
    正好是i-1的值
    */
    if(index != i-1){
        //交换arr[i-1]与arr[index]
        int temp = arr[i-1];
        arr[i-1] = arr[index];
        arr[index] = temp;
    }
}
//显示结果
for(int i=0; i<arr.length; i++){
	System.out.print(arr[i]);
}

4.4 二维数组

4.4.1 二维数组的声明和初始化

1、二维数组的声明

元素的数据类型[][] 二维数组的名称;

2、二维数组的初始化
(1)静态初始化

二维数组名 = new 元素的数据类型[][]{
			{第一行的值列表}, 
			{第二行的值列表},
			...
			{第n行的值列表}
		};
//如果声明与静态初始化一起完成
元素的数据类型[][] 二维数组的名称 = {
			{第一行的值列表}, 
			{第二行的值列表},
			...
			{第n行的值列表}
		};

(2)动态初始化(不规则:每一行的列数可能不一样)

//(1)先确定总行数
二维数组名 = new 元素的数据类型[总行数][];
//(2)再确定每一行的列数
二维数组名[行下标] = new 元素的数据类型[该行的总列数];
//(3)再为元素赋值
二维数组名[行下标][列下标] =;

(3)动态初始化(规则:每一行的列数是相同的)

//(1)确定行数和列数
二维数组名 = new 元素的数据类型[总行数][每一行的列数];
//(2)再为元素赋值
二维数组名[行下标][列下标] =;
4.4.2 二维数组的遍历
for(int i=0; i<二维数组名.length; i++){
    for(int j=0; j<二维数组名[i].length; j++){
        System.out.print(二维数组名[i][j]);
    }
    System.out.println();
}

第五章 面向对象基础

5.1 类与对象

1、类:一类具有相同特征事物的抽象描述
2、对象:类的实例
3、如何声明类
语法:

【修饰符】 class 类名{
	类的成员(属性、构造器、方法、内部内、代码块)
}

4、如何创建对象

new 类名();//匿名对象
类名 对象名 = new 类名();//有名对象

5.2 类的成员之一:属性

1、声明(属性的类型可以是Java的任意类型,包括基本数据类型、引用数据类型(类、接口、数组等))

【修饰符】 class 类名{
	【修饰符】 数据类型 属性名;
}

2、赋值
(1)在声明属性时赋值

【修饰符】 class 类名{
	【修饰符】 数据类型 属性名 =;
}

(2)在创建对象时赋值

//创建对象
类名 对象名 = new  类名();
//为对象的属性赋值
对象名.属性名 =;

3、如何访问属性中的值
(1)在本类中访问示例代码:

class Circle{
    double radius;
    
    double getArea(){
        return 3.14 * radius * radius;//直接访问
    }
}

(2)在其他类的方法中访问

class Circle{
    double radius;
}
class TestCircle{
    public static void main(String[] args){
        Circle c1 = new Circle();
        double area = 3.14 * c1.radius * c1.radius;//对象名.属性名
    }
}

4、属性的特点
(1)属性有默认值
(2)每个对象的属性是独立的

5、对象属性的内存图

class Student{
    String name;
    char gender = '男';//显式赋值
}
class TestStudent{
    public static void main(String[] args){
        Student s1 = new Student();
        System.out.println("姓名:" + s1.name);//null
        System.out.println("性别:" + s1.gender);//男
        s1.name = "小薇";
        s1.gender = '女';
        System.out.println("姓名:" + s1.name);//小薇
        System.out.println("性别:" + s1.gender);//女
        
        Student s2 = new Student();
        System.out.println("姓名:" + s2.name);//null
        System.out.println("性别:" + s2.gender);//男
    }
}

JAVA基础复习资料必备(一)_第10张图片

5.3 类的成员之二:方法

5.3.1 方法的概念

方法:代表一个独立的可复用功能
好处:
(1)代码复用
(2)简化代码

5.4.2 方法的语法

1、声明

【修饰符】 class 类名{
	【修饰符】 返回值类型 方法名(【形参列表】){
		方法体
	}
}

说明:
(1)修饰符:public、protected、缺省、private、static、final、abstract、native、synchronization
(2)返回值类型:
  ①void:无返回值
  ②非void:所有的java类型
(3)方法名:可以很好的体现方法的功能(见名知意,第二个单词开始首字母大写)
(4)形参列表:在完成这个方法的功能时,需要一些数据,这些数据要由“调用者”来决定,那我们就可以设计形参。
语法格式:

  ():无参,空参
​  (数据类型  形参名):一个形参
​  (数据类型1  形参名1,  ......,   数据类型n  形参名n):n个形参
    (数据类型...形参名):可变形参,0个或多个

(5)方法体:实现方法的功能,最好一个方法就完成一个独立的功能。

2、方法的调用格式:

//本类同级别方法调用:直接调用
【变量 = 】 方法名(【实参列表】);
//在其他类的方法中调用
【变量 = 】 对象名.方法名(【实参列表】);

(1)是否传实参:看被调用的方法是否有形参
(2)是否接收返回值:看被调用的方法是否是void,如果是void,就不需要也不能接收,如果不是void,就可以接收。

3、方法声明与调用的原则
(1)方法必须先声明后调用

如果调用方法时,如果方法名写错或调用一个不存在的方法,编译会报错

(2)方法声明的位置必须在类中方法外

{
    方法1(){
        
    }
    方法2(){
        
    }
}

(3)方法调用的位置必须在类中方法内

{
    方法1(){
        调用方法
    }
}

(4)方法的调用格式要与方法的声明格式对应
  ①是否要加“对象.”:看是否在本类中,还是其他类中
  ②是否要接收返回值:看被调用方法是否是void
  ③是否要传实参:看被调用方法是有形参列表

5.4.3 方法的重载Overload

概念:同一个类两个及以上个方法,方法名相同,形参列表不同,与权限修饰符、返回值类型、抛出的异常无关

5.4.4 方法的参数传递机制

Java中方法的参数传递机制:值传递
(1)形参是基本数据类型时,实参给形参传递数据值,形参对值的修改不会影响实参
(2)形参是引用数据类型时,实参给形参传递地址值,形参对值得修改会影响对象的属性值,此时形参和实参指向同一个对象

5.4 对象数组

一维数组:
1、元素是基本数据类型
2、元素是引用数据类型,也称为对象数组,即数组的元素是对象

注意:对象数组,首先要创建数组对象本身,即确定数组的长度,然后再创建每一个元素对象,如果不创建,数组的元素的默认值就是null,所以很容易出现空指针异常NullPointerException。

示例代码:

class MyDate{
	int year;
	int month;
	int day;
}
class Test{
    public static void main(String[] args){
        MyDate[] arr = new MyDate[3];//创建数组对象本身,指定数组的长度
        
        for(int i=0; i<arr.length; i++){
            arr[i] = new MyDate();//每一个元素要创建对象
            arr[i].year = 1990 + i;
            arr[i].month = 1 + i;
            arr[i].day = 1 + i;
        }
    }
}

内存解析图:
JAVA基础复习资料必备(一)_第11张图片

第六章 面向对象的基本特征

1、封装
2、继承
3、多态

6.1 封装

1、好处:
(1)隐藏实现细节,方便使用者使用
(2)安全,可以控制可见范围

2、如何实现封装
通过权限修饰符

修饰符 本类 本包 其他包的子类 任意位置
private × × ×
缺省 × ×
protected ×
public

权限修饰符可以修饰的结构:

类(类、接口等)、属性、方法、构造器、内部类
类(外部类):public和缺省
属性:4种
方法:4种
构造器:4种
内部类:4种

3、通常属性封装,是将属性私有化,提供对应的get/set方法
标准的JavaBean写法

【修饰符】 class 类名{

	//属性
	private String name;
	private int age;
	private char gender;
	
	//构造器
	public 类名(【形参列表】){
		
	}

	//方法
	public int 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 int getGender(){
		return gender;
	}
	public void setGender(char gender){
		this.gender= gender;
	}
}

6.2 构造器

1、构造器的作用:
(1)创建对象
(2)在创建对象时可以为属性赋值
2、构造器的声明及语法格式:

【修饰符】 class 类名{
	【修饰符】 类名(【形参列表】){
	
	}
}

3、构造器的特点
(1)所有的类都有构造器
(2)如果一个类没有显示/明确声明一个构造器,那么编译器会自动添加一个无参构造
(3)如果一个类显示/明确声明一个构造器,那么编译器将不会自动添加一个无参构造,如果需要可以手动添加一个无参构造
(4)构造器的名称必须和类名相同
(5)构造器没有返回值类型
(6)多个构造器之间构成重载

6.3 this

1、this关键字
意思:当前对象
(1)用于构造器中:正在创建的对象
(2)用于成员方法中:正在调用当前方法的对象
2、this用法
(1)this.属性:当属性名称和形参列表同名时,用于区分
(2)this.方法:调用当前对象的方法(完全可以省略“this”)
(3)this()或this(实参列表):
   ①this():调用本类无参构造器
   ②this(实参列表):调用本类有参构造器

注意:this()或this(实参列表)要么没有要么出现在构造器语句块的首行

3、成员变量和局部变量的区别
(1)生命周期
成员变量:随着对象的创建而创建,随着对象被回收而消亡
局部变量:随着方法的调用而分配,方法执行完毕消亡
(2)声明的位置
成员变量:类中方法外
局部变量:类中方法内或代码块中
 ①方法形参
 ②方法体内
 ③代码块内
(3)修饰符
成员变量:4种权限修饰符、static、final等
局部变量:没有权限修饰符、只能加final
(4)初始化
成员变量:有默认值
局部变量:没有默认值,必须手动初始化
(5)运行时栈堆的位置
成员变量:堆
局部变量:栈

6.4 包

1、包的作用:
(1)分类管理
(2)避免类重名
(3)可以控制某些类型或成员的可见范围

2、声明包的语法格式:

package 包名;
注意:
(1)必须出现在源文件的首行
(2)一个源文件只能有一个

3、包的命名规范和习惯:
(1)所有的单词小写,单词之间用.隔开
(2)习惯使用公司域名倒置

4、使用其他包的类:
前提:其他包的类的权限修饰符>=缺省
(1)使用类型的全名称
(2)使用import语句,代码中使用简名称

5、import语句
语法:

import 包.类名;

注意:当使用两个不同包的同名类时,例如:java.util.Date和java.sql.Date。一个使用全名称,一个使用简名称

6.5 继承

1、为什么要继承?继承的好处?
(1)提高代码的复用性
(2)延伸代码的扩展

2、如何实现继承?
语法格式:

【修饰符】 class 子类 extends 父类{
}

3、继承的特点
(1)子类会继承父类的所有特征(属性,方法),但是权限私有化的特征不能在子类中之间使用。
(2)子类不会继承父类的构造器(因为父类的构造器用于创建父类的对象)
(3)子类的构造器必须调用父类的构造器(在创建子类对象时,为从父类继承的属性进行初始化用,可以通过父类的构造器中的代码进行初始化)
(4)Java只支持单继承,一个子类只能有一个直接父类
(5)Java支持多层继承,一个子类可以有多个间接父类
(6)一个父类可以拥有多个子类

6.6 super

super关键字:引用父类的xx
(1)super.属性:当子类中创建了和父类同名的属性时,可以使用super.属性名调用父类的属性
(2)super.方法:当子类重写了父类的方法时,可以使用super.方法名调用父类被重写的方法
(3)super()或super(实参列表)
super():表示调用父类的无参实例初始化方法
super(实参列表):表示调用父类的有参实例初始化方法

注意:
(1)如果要写super()或super(实参列表),必须写在子类构造器的首行
(2)如果子类的构造器中没有写:super()或super(实参列表),那么默认会有 super()
(3)如果父类没有无参构造,那么在子类的构造器的首行“必须”写super(实参列表)

6.7 方法的重写

1、概念:当子类继承了父类的方法时,父类的方法实现不满足子类的需求,那么子类可以重写父类的方法
2、方法的重写的要求
(1)修饰符>=父类的权限修饰符,其他修饰符:static,final,private不能被重写
(2)返回值类型:
  ①基本数据类型和void必须相同
  ②引用数据类型<=父类的返回值类型
(3)方法名:必须相同
(4)形参列表:必须相同
(5)抛出的异常类型<=父类抛出的异常
3、重载和重写的区别
(1)重载:同一个类、方法相同、形参列表不同、与返回值类型、权限修饰符无关;
(2)重写:见上↑方法的重写的要求

6.8 非静态代码块

语法格式:

【修饰符】 class 类名{
	{
		非静态代码块
	}
}

作用:在创建过程中为对象的属性赋值,协助完成实例初始化过程

执行条件:
(1)每次创建对象都会执行
(2)优先于构造器执行

6.9 实例初始化过程

1、概念描述

  • 实例初始化过程:实例对象创建过程
  • 实例初始化方法:实例对象创建时需要执行的方法
  • 实例初始化方法的由来:它是由编译器编译生成
  • 实例初始化的形式:(【形参列表】)
  • 实例初始化方法的构成:
    ①非静态属性的显示赋值
    ②非静态代码块的代码
    ③构造器的代码

注意:
①和②按顺序执行,从上往下
③在①和②的后面

因此一个类有几个构造器,就有几个实例初始化方法。

2、父子类的实例初始化
结论:
(1)执行顺序是先父类实例初始化方法,再子类实例初始化方法
(2)如果子类重写了方法,通过子类对象调用,一定是执行重写过的方法

6.10 多态

语法格式:

父类 引用/变量 = 子类的对象;

前提:
(1)继承
(2)方法重写
(3)多态引用

3、现象:
(1)编译看‘左’,运行看‘右’;
(2)编译按照父类类型编译,运行执行子类重写父类的方法,子类独有的方法无法执行

4、应用:
(1)多态数组:形参是父类,实参是子类对象
(2)多态参数:数组元素类型是父类,存储元素类型为子类对象

5、向上转型与向下转型:父子类之间的转换
(1)向上转型:自动类型转换
将子类的对象赋值给父类的变量(多态),无法执行子类独有的方法
(2)向下转型:强制转换。有风险,可能会报ClassCastException异常。
​当需要把父类的变量赋值给一个子类的变量时,就需要向下转型。

注意:要想转型成功,必须保证该变量中保存的对象的运行时类型是<=强转的类型

6、instanceof
语法格式:

对象/变量 instanceof 类型

运算结果:true 或 false

作用:用于判断这个对象是否属于这个类型,或者判断是否是这个类型的对象或者这个类型的子类对象

第七章 面向对象的高级特性

7.1 final

final:最终的
1、用法:
(1)修饰类(外部类和内部类):表示这个类无法被继承,没有子类
(2)修饰变量(成员变量(类变量、实例变量),局部变量):表示这个变量的值不能被更改
(3)修饰方法:表示这个方法不能被重写

注意:如果某个成员变量用final修饰后,也得手动赋值,而且这个值一旦赋完,就不能修改了,即没有set方法

7.2 native

native:本地的
1、用法:只能修饰方法,表示这个方法体不是由Java语言实现的, 但是对于Java程序员来说,可以当做Java的方法一样去正常调用它,或者子类重写它。

2、JVM内存的管理:

  • 方法区:类的信息、常量、静态变量、动态编译生成的字节码信息
  • 虚拟机栈:Java语言实现的方法的局部变量
  • 本地方法栈:非Java语言实现的方法的局部变量,即
    native方法执行时的内存区域
  • 堆:new出来的对象
  • 程序计数器:记录每个线程目前执行到哪一个指令

7.3 static

static:静态的
1、用法:
(1)修饰成员变量:一般称之为类变量,静态变量
  ①静态变量的值是该类所有对象共享的
  ②静态变量存储在方法区
  ③静态变量对应的get/set方法也是静态的
  ④静态变量和局部变量同名时,可以使用类名.静态变量名进行区分
(2)修饰成员方法:一般称之为类方法,静态方法
  ①静态方法不能被重写
  ②在本类中其他方法可以直接使用,其他类可以使用类名.方法名进行调用
  ③在静态方法中,不能出现:this,super等非静态成员
(3) 修饰代码块:静态代码块
(4) 修饰内部类:静态内部类
(5) 静态导入(JDK1.5引入)

7.4 静态代码块

语法格式:

【修饰符】 class 类名{
	static{
		  静态代码块;
	}
}

作用:帮助完成类初始化过程,可以为类变量进行赋值

1、类初始化:
 ①静态属性的显示赋值
 ②静态代码块中的代码

注意:①和②按顺序执行,类初始化方法一个类只有一个

2、类的初始化的执行特点:
(1)一个类只执行一次
(2)如果子类在类初始化时发现父类没有类初始化会先初始化父类
(3)如果既要类初始化又要实例初始化,先类初始化在完成实例初始化

7.5 变量的分类和区别

1、按照数据类型分类
(1)基本数据类型:存储数据值
(2)引用数据类型:存储对象的地址值

2、按照声明位置分类
(1)成员变量
(2)局部变量

3、成员变量与局部变量的区别
(1)声明的位置不同:
成员变量:类中方法外
局部变量:类中方法内、代码块内、形参
(2)作用域不同:
成员变量:
①静态变量:在本类中直接使用,在其他类中使用类名.静态变量名使用
②非静态变量:只能被本类中的非静态成员中使用,在其他类中使用对象名.非静态变量名
局部变量:作用域{}内

7.6 根父类

1、java.lang.Object类是类层次结构的根父类,包括数组对象。
(1)Object中所有声明的方法都会被子类继承,即子类拥有Object中的所有方法
(2)每当对象创建,都会调用Object类的实例初始化方法
(3)Object类型变量、形参、数组,可以存储任意类型的对象
2、Object类的常用方法:
(1)public String toString():
①默认情况下,返回是对象的运行时类型@对象的hashCode值的十六进制
②通常建议重写
③直接使用System.out.println(对象),会默认调用这个对象的toString();
(2)public final Class getClass():获取当前对象的运行时类型
(3)protected void finalize():当对象被GC确认为要回收的垃圾,在回收之间由GC帮你调用这个方法,而且这个方法只会被调用一次,子类可以选择重写
(4)public int hashCode():返回当前对象的hash值
①如果两个对象的hash值相同,那么这个两个对象不一定相等
②如果两个镀锡的hash值不同,那么这两个对象一定不相等
(5)public boolean equals(Object obj):用于判断当前对象this与指定对象obj是否相等
①默认情况下,equals方法的实现等价于“==”,比较的是对象的地址值
②可以选择重写equals,重写的要求:

  1. 如果重写equals,那么一定要重写hashCode()方法,因为规定:
  • 如果两个对象调用equals返回为true,那么要求这两个对象的hashCode值也相同
  • 如果两个对象的hashCode值不同,那么要求这两个对象的equals方法一定为false;
  • 如果两个对象的hashCode值相同,那么这两个对象调用equals可能为true,也可能为false
  1. 如果重写equals,一定要遵循以下原则:
  • 自反性:x.equals(x)返回值为true
  • 传递性:x.equals(y)为true,y.equals(z)为true,那么x.equals(z)也应该为true
  • 一致性:只要参与equals比较的属性值没有修改,那么无论何时调用,结果应该一致
  • 对称性:x.equals(y)与y.equals(x)结果应该一样
  • 非空对象与null的equals一定是false

7.7 abstract

1、什么时候会用到抽象方法和抽象类:当声明父类的时候,在父类的某些方法的方法体的实现不能确定时,只能由子类决定。但是父类中又要体现子类的相同特性,即他要包含这个方法,为了统一管理子类的对象,即为多态的应用,那么可以把这样的方法声明为抽象方法,那么一个类包含了抽象方法,这个类就必须是一个抽象类

2、抽象类的语法格式

【修饰符】 abstract class 类名{
}

3、抽象方法的语法格式

【其他修饰符】 abstract 返回值类型 方法名(【形参列表】);

4、抽象类的特点
(1)抽象方法不能直接实例化,即不能直接new对象
(2)抽象类被子类继承后,子类需要重写所有的抽象方法,否则这个子类也是一个抽象类
(3)抽象类也有构造器,这个构造器是用于给子类实例初始化时调用的,不能创建抽象类自己的对象
(4)抽象类也可以没有抽象方法,目的是不让你创建对象,让你创建子类对象
(5)抽象类的变量和它子类的对象构成多态引用

5、不能和abstract一起使用的修饰符
(1)final
(2)static
(3)native
(4)private

7.8 接口

1、接口的概念:接口是一种标准。注意关注行为标准,面向对象的开发原则中有一条:面向接口编程

2、接口的声明格式

【修饰符】 interface 接口名{
 	接口的成员列表;
}

3、类实现接口的格式

【修饰符】 class 实现类 implements 父接口们{
}
【修饰符】 class 实现类 extends 父类 implements 父接口们{
}

4、接口继承接口的格式

【修饰符】 interface 接口 extends 父接口们{
	接口的成员列表;
}

5、接口的特点
(1)不能直接实例化,即不能直接new对象
(2)只能创建接口的实现类对象,那么接口和它实现类对象之间构成多态引用
(3)实现类在实现接口时,必须重写所有的抽象方法,否则这个类也是抽象类
(4)Java规定类与类之间只能单继承,类与接口之间可以多实现,即一个类可以有多个父接口
(5)Java支持接口与接口之间的多继承

6、接口的成员
JDK1.8之前:
(1)全局的静态常量:public static fianl 修饰的变量(这些修饰符可以省略)
(2)公共的抽象方法:public abstract 修饰的方法(这些修饰符可以省略)
JDK1.8之后:
(3)公共的静态方法:public static 修饰的方法
(4)公共的默认方法:public default 修饰的方法

7、默认方法冲突问题
(1) 当一个实现类同时实现了两个或多个接口,这个多个接口的默认方法的签名相同。
方案一:选择保留其中一个

接口名.super.方法名(【实参列表】);

方案二:完全重写

(2)当一个实现类同时继承父类,又实现接口,父类中有一个方法与接口的默认方法签名相同
方案一:默认方案,保留父类的
方案二:选择保留接口的

接口名.super.方法名(【实参列表】);

方案三:完全重写

8、常用的接口
(1)java.lang.Comparable接口:自然排序
抽象方法:int compareTo(Object obj)
(2)java.util.Comparator接口:定制排序
抽象方法:int compare(Object o1,Object o2)

7.9 内部类

1、内部类的概念:声明在一个类里面的类就是内部类
2、内部类的4种形式:
(1)静态内部类
(2)非静态内部类
(3)匿名内部类
(4)非匿名内部类

7.9.1 静态内部类

1、语法格式

【修饰符】 class 外部类{
	【其他修饰符】 static class 内部类 【extends 静态内部类自己的父类】 【implements 静态内部类的父接口们】{
	}
	外部类的其他成员列表;
}

2、使用注意事项
(1)包含成员的要求:可以包含类的所有成员
(2)修饰符的要求:4种权限修饰符、abstrac、final
(3)使用外部类的成员列表的要求:只能使用外部类的静态成员
(4)在外部类中使用内部类的成员要求:正常使用
(5)在外部类外面使用内部类成员的要求:
①如果使用的是静态内部类的静态成员:外部类.静态内部类名.静态成员
②如果使用的是静态内部类的非静态成员:

  • 创建内部类的对象:外部类名.静态内部类名 对象名 = new 外部类.静态内部类名(【形参列表】);
  • 通过对象调用非静态成员:对象名.非静态成员
  • 字节码文件形式:外部类名&静态内部类名.class
7.9.2 非静态内部类

1、语法格式

【修饰符】 class 外部类名 【extends 父类 implements 父接口们】{
	【修饰符】 class 非静态内部类【extends 非静态内部类自己的父类】 【implements 非静态内部类的父接口们】{
		非静态内部类的成员列表;
	}
	外部类的成员列表
}

2、 使用注意事项
(1)包含的成员要求:不允许出现静态成员
(2)修饰符要求:4中权限修饰符、abstract、final
(3)使用外部类成员的要求:都可以使用
(4)外部类中使用非静态内部类成员的要求:外部类的静态成员不能使用非静态内部类成员
(5)在外部类的外面使用非静态内部类的要求
①方式一:使用创建内部类对象

  • 创建外部类对象:外部类名 外部类对象名 = new 外部类(【形参类别】);
  • 创建内部类对象:外部类名.非静态内部类名 内部类对象名 = 外部类对象名.new 内部类名(【形参列表】);
    ②方式二:通过方法获取内部类对象
  • 创建外部类对象:外部类名 外部类对象名 = new 外部类(【形参类别】);
  • 获取对象:外部类名.非静态内部类名 = 外部类对象名.get非静态内部类对象的方法名(【参数列表】);
  • 通过对象调用非静态成员:对象名.非静态成员
  • 字节码文件形式:外部类名&非静态内部类名.class
7.9.3 局部内部类

1、语法格式

【修饰符】 class 外部类名 【extends 父类 implements 父接口们】{
	【修饰符】 返回值类型 方法名(【参数列表】){
		【修饰符】 class 局部内部类名 【extends 局部内部类的父类 implements 局部内部类的父接口们】{
			局部内部类的成员;
			}
		}
			类的其他成员;
	}

2、使用注意事项
(1)包含的成员要求:不允许出现静态成员
(2)修饰符要求:没有权限修饰符,abstract,final
(3)使用外部类的成员等上是否有要求:
①外部类的静态成员:随便使用
②外部类的非静态成员:看所在方法是否是静态的
③所在方法的局部变量:必须使用final修饰
(4)外部类中使用局部内部类成员的要求:有作用域
(5)外部类外使用局部内部类成员的要求:无法使用,外部类不可见
(6)字节码文件形式:外部类名$编号局部内部类名.class
3、示例代码

class Outer{
    private static int i = 10;
    private int j = 20;

    
    public void outMethod(){
        class Inner{
            public void method(){
                //...
                System.out.println(i);//可以
                System.out.println(j);//可以
            }
   		}
        Inner in = new Inner();
        in.method();
    }
    public static void outTest(){
        final int k = 30;
       class Inner{
            public void method(){
                //...
                System.out.println(i);//可以
                System.out.println(j);//不可以
                System.out.println(k);//可以
            }
   		}
        Inner in = new Inner();
        in.method();
    }
}
7.9.4 匿名内部类

1、语法格式:

//在匿名子类中调用父类的无参构造
new 父类(){
    内部类的成员列表
}

//在匿名子类中调用父类的有参构造
new 父类(实参列表){
    内部类的成员列表
}

//接口没有构造器,那么这里表示匿名子类调用自己的无参构造,调用默认父类Object的无参构造
new 父接口名(){
    
}

2、匿名内部类、匿名对象的区别?

System.out.println(new Student("张三"));//匿名对象

Student stu = new Student("张三");//这个对象有名字,stu

//既有匿名内部类,又是一个匿名的对象
new Object(){
    public void test(){
        .....
    }
}.test();

//这个匿名内部类的对象,使用obj这个名字引用它,既对象有名字,但是这个Object的子类没有名字
Object obj = new Object(){
    public void test(){
        .....
    }
};

3、使用的形式

(1)示例代码:继承式

abstract class Father{
    public abstract void test();
}
class Test{
    public static void main(String[] args){
        //用父类与匿名内部类的对象构成多态引用
        Father f = new Father(){
            public void test(){
                System.out.println("用匿名内部类继承了Father这个抽象类,重写了test抽象方法")
            }
        };
        f.test();
    }
}

(2)示例代码:实现式

interface Flyable{
    void fly();
}
class Test{
    public static void main(String[] args){
        //用父接口与匿名内部类的对象构成了多态引用
        Flyable f = new Flyable(){
            public void fly(){
                System.out.println("用匿名内部类实现了Flyable这个接口,重写了抽象方法");
            }
        };
        f.fly();
    }
}

(3)示例代码:用匿名内部类的匿名对象直接调用方法

new Object(){
    public void test(){
        System.out.println("用匿名内部类的匿名对象直接调用方法")
    }
}.test();

(4)示例代码:用匿名内部类的匿名对象直接作为实参

Student[] all = new Student[3];
all[0] = new Student("张三",23);
all[1] = new Student("李四",22);
all[2] = new Student("王五",20);

//用匿名内部类的匿名对象直接作为实参
//这个匿名内部类实现了Comparator接口
//这个匿名内部类的对象,是定制比较器的对象
Arrays.sort(all, new Comparator(){
    public int compare(Obeject o1, Object o2){
        Student s1 = (Student)o1;
        Student s2 = (Student)o2;
        return s1.getAge() - s2.getAge();
    }
});

第八章 枚举与注解

8.1 枚举:enum

1、概念:枚举(JDK1.5引入),枚举类型的对象是有限固定的几个常量对象

2、语法格式:

//形式一:枚举类型中只有常量对象列表
【修饰符】 enum 枚举类型名{
	常量对象列表
}

//形式二:枚举类型中只有常量对象列表
【修饰符】 enum 枚举类型名{
    常量对象列表;
    
    其他成员列表;
}

说明:常量对象列表必须在枚举类型的首行

3、在其他类如何获取枚举的常量对象

//获取一个常量对象
枚举类型名.常量对象名;

//获取一个常量对象
枚举类型名.valueOf("常量名");

//获取所有常量对象
枚举类型名[] all = 枚举类型名.values();

4、枚举类型的特点
(1)枚举类型由一个公共基本的父类java.lang.Enum类型,所以不能继承其他类型
(2)枚举的构造器必须私有化
(3)枚举可以实现接口

instanceof MyRunnable{
	void run();
}

enum gender implements MyRunnable{
	NAN,NV;
	 public void run(){
        //...
    }
}
//或者
enum Gender implements MyRunnable{
    NAN{
        public void run(){
       	 //...
    	}
    },NV{
        public void run(){
        //...
   		}
	};
}

5、父类java.lang.Enum类型
(1)构造器:protected Enum(String name, int ordinal):由编译器调用
(2)public final String name():枚举常量的名称
(3)public final int ordinal():枚举常量的序数
(4)public String toString():枚举常量的名称
(5)public final int compareTo(E o):按照常量对象的顺序比较,负整数、零或正整数,根据此对象是小于、等于还是大于指定对象。

8.2 注解

1、注解:它是代码级别的注释
2、标记符号:@
3、系统预定义的三个最基本的注解:
(1)@Override:表示某个方法是重写的方法
(2)@SuppressWarnings(xx):抑制警告
(3)@Deprecated:表示xx已过时

4、和文档注释相关的注解
(1)文档注释

/**
文档注释
*/

(2)常见的文档注释
@author:作者
@since:从xx版本加入的
@see:另请参考
@param:形参
@return:返回值
@throws或@exception:异常

5、JUnit相关的几个注解
@Test:单元测试方法,这个方法需要是public void xxx(){}
@Before:在每个单元测试之前执行,这个方法需要是:public void xxx(){}
@After:在每个单元测试之后执行,这个方法需要是:public void xxx(){}
@BeforeClass:表示在类初始化阶段执行,而且只执行一次,这个方法需要是:public static void xxx(){}
@AfterClass:表示在类卸载阶段执行,而且只执行一次,这个方法需要是:public static void xxx(){}

6、元注解(注解的注解)
(1)@Target(xx):用于标记注解使用xx位置(例如:TYPE、METHOD、FIELD等)
(2)@Retention(xx):用于标记注解可以滞留到xx阶段(例如:SOURCE、CLASS、RUNTIME)

注意:唯有RUNTIME阶段的注解才能被反射读取到

(3)@Documentd:用它标记的注解可以读取到API中
(4)@Inherited:用它标记的注解可以被子类继承

7、自定义注解
(1)元注解的语法格式:

@元注解
【修饰符】 @interface 注解名{
	
}

@元注解
【修饰符】 @interface 注解名{
    配置参数列表
}

(2)配置参数的语法格式:

数据类型 配置参数名();
或
数据类型  配置参数名() default 默认值;

(3)关于配置参数:
①配置参数的类型有要求:八种基本数据类型、String、枚举、Class类型、注解、它们的数组
②如果自定义注解声明了配置参数,那么在使用这个注解时必须为配置参数赋值,除非它有默认值

@自定义注解名(配置参数名1=值,配置参数名2=值。。。)
//如果配置参数类型是数组,那么赋值时,可以用{}表示数组
@自定义注解名(配置参数名1={值},配置参数名2=值。。。)

③如果配置参数只有一个,并且名称是value,那么赋值时可以省略value=
④如果读取这个注解时,要获取配置参数的值的话,可以当成方法一样来访问

自定义注解对象.配置参数();

你可能感兴趣的:(JAVA基础篇,java)