文章目录
Java基础编程
Java语言概述
Java语言简述
1.基础图解
2.常识
软件:即一系列按照特定顺序组织的计算机数据和指令的集合。分为:系统软件和应用软件
- 1.系统软件:windows,mac os,linux,unix,ios…
- 2.应用软件:word,ppt…
人机交互方式:图形化界面 vs 命令行方式
常用DOS命令:
dir: 列出当前目录下的文件以及文件夹
md: 创建目录
rd: 删除目录
cd: 进入指定目录
cd..: 退回到上一级目录
cd\: 退回到根目录
del: 删除文件
exit: 退出dos命令行
3.计算机语言的发展迭代
- 第一代: 机器语言。指令以二进制代码形式存在。
- 第二代: 汇编语言。使用助记符表示一条机器指令。
- 第三代: 高级语言
- 1.面向过程:C,Pascl、Fortran
- 2.面向对象:Java,Js,Python,Scala,…
4.Java语言版本迭代概述
5. Java语言应用的领域
- ava Web开发:后台开发
- 大数据开发
- Android应用程序开发:客户端开发
6.Java语言的特点
- 面向对象性:
- 两个要素:类、对象
- 三个特征:封装、继承、多态
- 健壮性:
- 1.去除了C语言中的指针
- 2.自动的垃圾回收机制—>仍然会出现内存溢出、内存泄漏
- 跨平台性:
- once ,run anywhere :一次编译,到处运行
- 归功于强大Jvm
开发环境的搭建
1. JDK、JRE、JVM的关系
2. JDK的下载安装
-
官网:Oracle官方网站( https://www.oracle.com)
-
配置环境变量
-
进入高级系统设置
- 方法1:选择桌面电脑鼠标右击此电脑,点击属性进入系统信息界面
- 方法2:通过“控制面板”,选择“系统和安全”,再选择“系统”,在系统信息界面左侧点击 高级系统设置
-
在高级系统设置界面,点击环境变量
-
环境变量的系统变量设置3项属性,JAVA_HOME,Path,CLASSPATH。若存在则在此基础上“编辑”,不存在则“新建”
- 新建JAVA_HOME,变量值为JDK安装目录
- 编辑 Path系统变量,新建值%JAVA_HOME%\bin
-
-
验证JDK是否安装成功
- win+R快捷键打开运行,输入cmd进入命令提示符
- 输入 java -version,(\Java\Javac)查看java版本,有版本信息表示安装成功
注释与API文档
1. 注释Comment
- 分类:
单行注释://
多行注释:/* */
文档注释:/** */
-
作用:
-
单行注释和多行注释的作用:
- 对所写的程序进行解释说明,增强可读性。方便自己,方便别人
- 调试所写的代码
-
文档注释的使用:
- 注释内容可以被JDK提供的工具 javadoc 所解析,生成一套以网页文件形式体现的该程序的说明文档。
-
-
特点:
- 单行注释和多行注释,注释了的内容不参与编译。
换句话说,编译以后生成的.class结尾的字节码文件中不包含注释掉的信息 - 多行注释不可以嵌套使用
- 单行注释和多行注释,注释了的内容不参与编译。
2. Java API 文档
API:application programming interface。习惯上:将语言提供的类库,都称为API。
API文档:针对于提供的类库如何使用,给的一个说明书。
3. 良好的编程风格
基本语法
关键字与标识符
关键字的使用
- 定义:被Java语言赋予了特殊含义,用做专门用途的字符串(单词)
- 特点:关键字中所有字母都为小写
- 具体有那些关键字:
保留字
(现Java版本未使用,但以后版本可能会作为关键字使用。)
- 具体哪些保留字:goto、const(注意:自己命名标识符时要避免使用这些保留字)
标识符的使用
定义:
- Java对各种变量、方法和类等要素命名时使用的字符序列称为标识符。
- 凡是自己可以起名字的地方都叫标识符。
规则:(必须要遵守,否则编译不通过)
- 由26个英文字母大小写,0-9,_或$组成
- 数字不可以开头
- 不可以使用关键字和保留字,但能包含关键字和保留字
- Java中严格区分大小写,长度无限制
- 标识符不能包含空格
规范:(可以不遵守,不影响编译运行,但是要求大家遵守)
- 包名:多单词组成时所有字母都小写:xxxyyyzzz
- 类名、接口名:多单词组成时,所有单词的首字母大写:XxxYyyZxx
- 变量名、方法名:多单词组成时,第一个单词首字母小写,第二个单词开始每个单词首字母大写:xxxYyyZzz
- 常量名:所有字母都大写。多单词每个单词用下划线连接:XXX_YYY_ZZZ
- 注意点:在起名字时为了提高阅读性,要尽量意义,“见名知意”。
变量的使用(重点)
变量的分类:
按数据类型分类:
详细说明:
- 整型:byte(1字节=8bt) \ short(2字节) \ int (4字节) \ long(8字节)
//1.byte范围:-128 ~ 127
byte b1 = 12;
byte b2 = -128;
//b3 = 128;编译不通过
//2.声明long型变量,必须以"l" \ "L"结尾
//3.通常定义整型时,使用int型。
short s1 = 128;
int i1 = 1234;
long l1 = 341434562L;
- 浮点型:float(4字节) \ double(8字节)
//1.浮点型,表示带小数点的数值
//2.float表示数值的范围比long还大
double d1 = 123.3;
//3.定义float类型变量时,变量要以"f" \ "F"结尾
float f1 = 12.3f;
//4.通常,定义浮点型变量时,使用double型
- 字符型:char(1字符=2字节)
//1.定义char型变量,通常使用一对 '' ,内部只能写一个字符
char c1 = 'a';
//2.表示方式:1.声明一个字符 2.转义字符 3.直接使用 Unicode 值来表示字符型常量
char c = '\n'; //换行符
c = '\t'; //制表符
- 布尔型:boolean
//只能两个值之一:true、false
//常常在条件判断、循环结构中使用
按声明位置分类:
定义变量的格式:
数据类型 变量名 = 变量值;或
数据类型 变量名;
变量名 = 变量值;
变量使用的注意点:
- 变量必须先声明,后使用
- 变量都定义在其作用域内。在作用域内,它是有效的。换句话说,出了作用域,就失效
- 同一个作用域内,不可以声明两个同名的变量
基本数据类型变量间运算规则:
涉及到的基本数据类型:除了boolean之外的其他7种
自动类型转换(7种)
结论:当容量小的数据类型的变量与容量大的数据类型的变量做运算时,结果自动提升为容量大的数据类型。
byte、char、short --> int --> long --> float --> double
特别的:当byte、char、short三种类型的变量做运算时,结果为int型
说明:此时的容量大小指的是,表示数的范围大小。比如float容量要大于long的容量。
强制类型转换(7种)
自动类型提升运算的逆运算。
- 需要使用强转符:()
- 注意点:强制类型转换,可能导致精度损失
//精度损失1
double d1 = 12.9;
int i1 = (int)d1;//截断操作
//精度损失2
int i2 = 128;
byte b = (byte)i2;//b = -128
//没有精度损失
long l1 = 123;
short s2 = (short)l1;
String与8种基本数据类型间的运算
- String属于引用数据类型,翻译为:字符串
- 声明String类型变量时,使用一对 “”
- String可以和8种基本数据类型变量做运算,且运算只能是连接运算:+
- 运算的结果仍然是String类型
//避免:
String s = 123;//编译错误
String s1 = "123";
int i = (int)s1; //编译错误
进制(了解
1. 编程中涉及的进制及表示方式:
2. 二进制的使用说明:
- 计算机底层的存储方式:所有数字在计算机底层都以二进制形式存在。
- 二进制数据的存储方式:所有的数值,不管正负,底层都以补码的方式存储。
- 原码、反码、补码的说明:
正数:三码合一
负数:
源码:直接将一个数值换成二进制数。最高位是符号位。
负数的反码:是对原码按位取反,只是最高位(符号位)确定为1。
负数的补码:其反码加1。
3. 进制间的转换:
图示:
图示二进制转换为十进制:
图示十进制转换为二进制:
图示二进制与八进制、十六进制的转换:
运算符
算数运算符
+ - * / % (前)++ (后)++ (前)-- (后)--
典型代码
//除号:/
int num1 = 12;
int num2 = 5;
int result1 = num1 / num2; //result1 = 2
//取余运算:%
//结果的符号与被模数的符号相同
//开发中,经常使用%判断能否被除尽的情况
int m1 = 12;
int n1 = 5;
System.out.println(m1 % n1);//2
int m2 = -12;
int n2 = 5;
System.out.println(m2 % n2);//-2
int m3 = 12;
int n3 = -5;
System.out.println(m3 % n3);//2
int m4 = -12;
int n4 = -5;
System.out.println(m4 % n4);//-2
//(前)++ :先自增1;后运算。(后)++ :先运算;后自增1
int a1 = 10;
int b1 = ++a1;
System.out.println("a1 = "+ a1 + ",b1 = "+b1);//11,11
int a2 = 10;
int b2 = a2++;
System.out.println("a2 = "+ a2 + ",b2 = "+b2);//11,10
int a3 = 10;
++a3;//a3++;
int b3 = a3;
//注意点:
short s1 = 10;
//s1 = s1 + 1;//编译失败
//s1 = (short) (s1 + 1);//正确的
s1++;//自增1不会改变本身的数据类型
System.out.println(s1);//11
byte bb1 = 127;
bb1++;
System.out.println(bb1);//-128
//(前)-- :先自减1;后运算。(后)-- :先运算;后自减1
int a4 = 10;
int b4 = a4--;
System.out.println("a4 = "+ a4 + ",b4 = "+b4);//9,10
int a5 = 10;
int b5 = --a5;
System.out.println("a5 = "+ a5 + ",b5 = "+b5);//9,9
赋值运算符
= += -= *= /= %=
典型代码
//=
int i1 = 10;
int j1 = 10;
int i2 , j2;
//连续赋值
i2 = j2 = 10;
int i3 = 10 , j3 = 20;
int num = 10;
num += 2;//num = num + 2;
num %= 5;//num = num % 5;
short s1 = 10;
//s1 = s1 + 2;编译失败
s1 += 2;//不会改变变量本身的数据类型
//开发中,如果希望变量实现+2的操作,一般推荐num += 2;
//开发中,如果希望变量实现+1的操作,一般推荐num++;
int m = 3;
int n = 6;
//n *= m++;
n *= ++m;
System.out.println(n);
System.out.println(m);
比较运算符
或关系运算符:== != > < >= <= instanceof
典型代码
int i = 10;
int j = 20;
System.out.println(i == j);//false
System.out.println(i = j);//20
boolean b1 = true, b2 = false;
System.out.println(b2 == b1);//false
System.out.println(b2 = b1);//true
//**说明**
1. 比较运算符的结果是boolean类型。
2. > < >= <= :只能使用在数值类型的数据之间。
3. ==和!= :不仅可以使用在数值类型数据之间,还可以使用在其他引用类型变量之间。
逻辑运算符
& && | || ! ^
典型代码
//区分& 与 &&
//相同点:1.& 与 && 的运算结果相同。 2.当符号左边是true时,二者都会执行符号右边的运算
//不同点:当符号左边是false时,&继续执行符号右边的运算,&&不再执行符号右边的运算。
//开发中,推荐使用&&
boolean b1 = true;
b1 = false;
int num1 = 10;
if (b1 & (num1++ > 0)){
System.out.println(1);
}else {
System.out.println(2);
}
System.out.println(num1);//11
boolean b2 = true;
b2 = false;
int num2 = 10;
if (b2 && (num2++ > 0)){
System.out.println(1);
}else {
System.out.println(2);
}
System.out.println(num2);//10
//区分| 与 ||
//相同点:1.| 与 || 的运算结果相同。 2.当符号左边是false时,二者都会执行符号右边的运算
//不同点:当符号左边是true时,|继续执行符号右边的运算,||不再执行符号右边的运算。
//开发中,推荐使用||
boolean b3 = false;
b3 = true;
int num3 = 10;
if (b3 | (num3++ > 0)){
System.out.println(1);
}else {
System.out.println(2);
}
System.out.println(num3);//11
boolean b4 = false;
b4 = true;
int num4 = 10;
if (b4 || (num4++ > 0)){
System.out.println(1);
}else {
System.out.println(2);
}
System.out.println(num4);//10
位运算符
<< >> >>> & | ^ ~
典型代码
/*
0000 0000 最高位为0,是正数,最高位为1,是负数
A = 0011 1100
b = 0000 1101
A&B = 0000 1100 有一个为0,则结果为0,同时为1时结果才是1
A|B = 0011 1101 有一个为1,则结果为1,同时为0时结果才是0
A^B = 0011 0001 相同时结果为0,不相同结果为1
~B = 1111 0010 与B完全相反
>> 右移
<< 左移
*/
System.out.println(2<<3);
/*
2的二进制为 0000 0010
左移相当于把数字往做移动3位
得到 0001 0000 相当于16
*/
/*
面试题:最高效2 * 8 的实现方式?
2 << 3 或 8 << 1
1.位运算符操作的都是整型的数据
2.<<:在一定范围内,每向左移1位,相当于 *2
>>:在一定范围内,每向右移1位,相当于 /2
*/
三元运算符
(条件表达式) ? 表达式1 : 表达式2
典型代码
//1.如果条件表达式为true,运算后的结果是表达式1;
//2.如果条件表达式为false,运算后的结果是表达式2;
int a = 99;
int b = 10;
int result = a > b ? a++ : b--; //表达式1 先赋值后自增
System.out.println(result);//输出99
System.out.println("a = " + a);//输出 100
System.out.println("b = " + b);//输出10
//表达式1和表达式2要为可以赋给接受变量的类型(或可以自动转换)
int a = 3;
int b = 8;
int c = a > b? 2.2 : 3.3;//改为 int c = a > b?(int) 2.2 : (int)3.3;
System.out.println(c);
double d = a > b ? a : b + 3;//满足 int --> double
//可以嵌套使用(实现三个数的最大值)
int a = 56;
int b = 122;
int c = 100;
int max1 = a > b ? a : b;
int max2 = max1 > c ? max1 : c;//推荐使用第一种
// int max = (a > b? a : b) > c ?(a > b? a : b):c;
System.out.println(max2);
//凡是可以用三元运算符的地方,都可以改if-else,反之不成立
//开发中,即可用三元运算符又可以用if-else的地方,优先用三元运算符。原因:简介、执行效率高。
流程控制
- 顺序结构:程序从上到下执行
- 分支结构:if-else switch-case
- 循环结构:for while do-while
分支结构
if-else
==结构一:==
if(条件表达式){
执行表达式
}
==结构二:==
if(条件表达式){
执行表达式1
}else{
执行表达式2
}
==结构三:==
if(条件表达式){
执行表达式1
}else if(条件表达式){
执行表达式2
}else if(条件表达式){
执行表达式3
}
...
else{
执行表达式n
}
说明:
- else结构是可选的。
- 针对条件表达式:
- 如果多个条件表达式之间“互斥”关系(或没有交集的关系),哪个判断和执行语句说明在上面或下面无所谓。
- 如果多个条件表达式之间有交集的关系,需要根据实际情况,考虑清楚应该将哪个结构声明在上面。
- 如果多个条件表达式之间有包含的关系,通常情况下,需要把范围小的声明在范围大的上面。否则,范围小的就没机会执行了。
- if-else结构是可以相互嵌套的。
- 如果if-else结构中的执行语句只有一行时,对应的{}可以省略的。但是,不建议。
switch-case
结构
switch(表达式){
case 常量1:
执行语句1;
//break;
case 常量2:
执行语句2;
//break;
...
default:
执行语句n;
//break;
}
说明:
- 根据switch表达式中的值,依次匹配case中的常量,一旦匹配成功,则进入相应的case结构中,调用执行语句。当执行完以后,则仍然继续向下执行case结构,直到遇到break关键字或结构末尾结束为止。
- break,可以在switch-case结构中使用,表示一旦执行到break,则跳出结构。
- switch结构中的表达式,只能是6种类型之一:byte、short、char、int、枚举(5.0)、String类型(7.0) 。
- case后声明的只能是常量,不能声明范围。
- break关键字是可选的。
- default:相当于if-else结构中的else;default结构是可选的,而且位置是灵活的。
注意:
//当case执行语句一样是可以考虑合并的,如下:
switch(表达式){
case 0:
case 1:
case 2:
执行语句;
break;
case 3:
case 4:
case 5:
执行语句;
break;
}
循环结构
循环结构的四要素:
- 初始化条件
- 循环条件 —》是boolean类型
- 循环体
- 迭代条件
说明:通常情况下,循环结束都是因为循环条件中返回false了。
for循环结构
for(1;2;4){
3
}
执行过程:1-2-3-4-2-3-4-...-2
while循环结构
1
while(2){
3;
4;
}
执行过程:1-2-3-4-2-3-4-...-2
说明:
1. 写while循环千万不要丢了迭代条件。一旦丢失,就可能导致死循环!
2. 我们写程序要避免程序出现死循环。
3. for循环和while循环时可以相互转换的!
区别:for循环和while循环的初始化条件部分的作用范围不同。
do-while循环结构
1
do{
3;
4;
}while(2);
执行过程:1-3-4-2-3-4-...-2
说明:do-while循环至少会执行一次循环体!
无限循环结构:while(true)或for(; ; )
如何结束一个循环结构:
1. 当循环条件是false时
2. 在循环体中,执行break
嵌套循环
- 嵌套循环:将一个循环结构A声明在另一个循环结构B的循环体中,就构成了嵌套循环。
- 内层循环:循环结构A
- 外层循环:循环结构B
- 说明:
- 内层循环结构遍历一遍,只相当于外层循环循环体执行了一次。
- 假设外层循环需要执行m次,内存循环需要执行n次。此时内层循环的循环体一共执行了m*n次。
- 外层循环控制行数,内层循环控制列数。
关键字:break和continue
使用范围 | 循环中使用的作用(不同点) | 相同点 | |
---|---|---|---|
break: | switch-case | ||
循环结构中 | 结束当前循环 | 关键字后面不能声明执行语句 | |
continue: | 循环结构中 | 结束当次循环 | 关键字后面不能声明执行语句 |
补充:带标签的break和continue的使用
补充:Scanner类的使用
具体实现步骤:
- 导包:import java.util.Scanner;
- 实例化:Scanner scan = new Scanner(System.in);
- 调用Scanner类的相关方法(next() / nextXxx()),来获取指定类型的变量。
- 注意:需要根据相应的方法,输入指定类型的值。如果输入数据类型与要求的类型不匹配,会报异常:.InputMismatchException ,导致程序终止。
数组
数组的概述
定义:数组是相同类型数据的有序集合,每一个数据称作一个数组元素,每个数组元素可以通过一个下标来访问它们。
特点:
- 数组是有序排列的;
- 数组属于引用数据类型变量。数组的元素,既可以是基本数据类型,也可以是引用数据类型;
- 创建数组对象会在内层中开辟一整块连续的空间;
- 数组的长度一旦确定,就不能更改。
数组的分类: - 照维数:一维数组、二维数组、。。。
- 照数组元素的类型:基本数据类型元素的数组、引用数据类型元素的数组
数据结构:
- 数据与数据之间的逻辑关系:集合、一对一、一对多、多对多
- 数据的存储结构:
- 线性表:顺序表(比如:数组)、链表、栈、队列
- 树形结构:二叉树
一维数组
声明与初始化
//声明:
dataType[] arrayRefVar; //首选的方法
dataType arrayRefVar[];
//创建
dataType[] arrayRefVar=new dataType[arraySize];
//静态初始化
int[] array=new int[]{1,2,3};//int[] array={1,2,3};//类型推断
Man[] mans={new Man(1,1),new Man(2,2)}; //Man是类
//动态初始化
int[] array=new int[2];
array[0]=1;
array[1]=2;
//注意错误的方式:
int[] arr1 = new int[];
int[5] arr2 = new int[5];
int[] arr3 = new int[3]{1,2,3};
一维数组元素的引用
通过角标的方式调用:下标合法区间—[0,length-1]
属性:length
数组一旦初始化,其长度就是确定的。arr.length
一维数组的遍历
for (int i = 0; i < arr.length; i++){
System.out.println(arr[i]);
}
一维数组元素的默认初始化
- 数组元素是整型:0
- 数组元素是浮点型:0.0
- 数组元素是char型:0或’\u0000’,而非’0’
- 数组元素是boolean型:false
- 数组元素是引用数据类型:null
一维数组的内存解析
二维数组
概述
- 二维数组其实就是一个特殊的一维数组,一维数组中每个元素就是一个一维数组.
- 三维数组又是一个特殊的二维数组.
声明与初始化
int[][] a = new int[10][10];
String[][] b = new String[10][10];
//静态初始化
int[][] a = {
{1,2,3},{4,5},{6,7,8}};
//动态初始化
//1.
String[][] b = new String[3][2];
//2.
String[][] b1 = new String[3][];
//也是正确的写法
int[] arr[] = {
{1,2,3,4},{4,5,6,7},{8,9,10,11}};
如何调用二维数组元素
System.out.println(a[0][1]);//2
System.out.println(b[1][1]);//null
b1[1] = new String[4];
System.out.println(b1[1][0]);
二维数组的属性
System.out.println(arr.length);//3
System.out.println(arr[0].length);//4
二维数组的遍历
public class Text0 {
public static void main(String[] args) {
//静态初始化
int[][] a={
{1,2,3,4},{4,5,6,7},{8,9,10,11}};
//遍历
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a[i].length; j++) {
System.out.print(a[i][j]+" ");
}
System.out.println();
}
}
}
二维数组元素的默认初始化
- 规定:二维数组分为外层数组的元素,内层数组的元素
- int[][] arr = new int[4][3];
- 外层元素:arr[0],arr[1]等
- 内层元素:arr[0][0],arr[1][2]等
- 数组元素的默认初始值
- 针对于初始化方式一:比如:int[][] arr = new int[4][3];
- 外层元素的初始化值为:地址值
- 内层元素的初始化值为:与一维数组初始化情况相同
- 针对于初始化方式二:比如:int[][] arr = new int[4][];
- 外层元素的初始化值为:null
- 内层元素的初始化值为:不能调用,否则报错。
- 针对于初始化方式一:比如:int[][] arr = new int[4][3];
二维数组的内存解析
数组的常见算法
一、数组元素的赋值(杨辉三角)//面试中考察较多
Scanner number=new Scanner(System.in);
System.out.println("输入杨辉三角形的行数");
int numbers= number.nextInt();
int[][] arr1=new int [numbers][numbers];
for(int i=0;i<numbers;i++){
for(int j=0;j<=i;j++){
if(i==j||j==0){
arr1[i][j]=1;
}else if(i>=2){
arr1[i][j]=arr1[i-1][j]+arr1[i-1][j-1];
}
System.out.print(arr1[i][j]);
}
System.out.print("\n");
}
二、求数值型数组元素中的最大值、最小值、平均数、总和等等
算法的考查:求数值型数组中元素的最大值、最小值、平均值、总和等
题目:
定义一个int型的一维数组,包含10个元素,分别赋一些随机数,然后求出所有元素的最大值、最小值、和值 、平均值并输出。
要求:所有的随机数都是两位数。
提示:获取[a,b]范围内的随机数 Math.random()*(b-a+1)+10 ; //radom 获取的值为double类型可以根据需求进行强制转换。
int [] arr =new int [10];
for(int i=0;i<arr.length;i++){
arr[i]=(int)(Math.random()*(99-10+1)+10);
}
for(int i=0;i<arr.length;i++){
System.out.print(arr[i]+" ");
}
System.out.print("\n");
//求数组元素的最大值
int maxValue=arr[0];
for(int i=0;i<arr.length;i++){
if(maxValue<arr[i]){
maxValue=arr[i];
}
}
System.out.println("最大值为:"+maxValue);
//求数组元素的最小值
int minValue=arr[0];
for(int i=0;i<arr.length;i++){
if(minValue>arr[i]){
minValue=arr[i];
}
}
System.out.println("最小值为:"+minValue);
//求数组元素的总和
int sum=0;
for(int i=0;i<arr.length;i++){
sum+=arr[i];
}
System.out.println("总和"+sum);
//求数组元素的平均值
int value=sum/arr.length;
System.out.println("平均值"+value);
三、数组的复制、反转、查找(线性查找、二分法查找)
1. 数组的复制(区别于数组的赋值)
//声名arr1和arr2两个int型的数组。
int [] arr1,arr2;
//使用静态初始化将arr1中的8个元素初始化为:2,3,5,7,11,13,17,19.
arr1=new int []{2,3,5,7,11,13,19};
//显示arr1中的内容。
for(int i=0;i<arr1.length;i++){
System.out.print(arr1[i]+" ");
}
//赋值arr1变量等于arr2,修改arr2中的偶索引元素使其等于索引值。打印出arr1。
arr2=arr1;
for(int i=0;i<arr2.length;i++){
if(i%2==0){
arr2[i]=i;
}
}
System.out.println();
for(int i=0;i<arr1.length;i++){
System.out.print(arr1[i]+" ");
}
//思考问题:arr1和arr2有什么关系
//我们可以发现该程序的输出结果和变化后的arr2中的值相同,所以arr2=arr1并不是一个数组间的复制操作,而是通过arr1对arr2进行了一步赋值操作。
//但是经过arr2=arr1这一操作后,使arr1和arr2的地址值相同,都指向了堆空间内的唯一的一个数组实体。
//那么下面我们修改代码实现arr2对arr1数组的复制
int [] arr1,arr2;
arr1=new int []{2,3,5,7,11,13,19};
for(int i=0;i<arr1.length;i++){
System.out.print(arr1[i]+" ");
}
//修改处:
//如果想要arr有独立的数值空间 就先用new给arr2开辟一个堆空间
arr2=new int[arr1.length];
for(int i=0;i<arr1.length;i++){
arr2[i]=arr1[i];
}
//
for(int i=0;i<arr2.length;i++){
if(i%2==0){
arr2[i]=i;
}
}
System.out.println();
for(int i=0;i<arr1.length;i++){
System.out.print(arr1[i]+" ");
}
2. 数组的反转
String [] arr=new String []{"AA","BB","CC","DD","GG","EE"};
String temp;
for(int i=0;i<arr.length/2;i++){
temp=arr[i];
arr[i]=arr[arr.length-1-i];
arr[arr.length-1-i]=temp;
}
for(int i=0;i<arr.length;i++){
System.out.print(arr[i]+" ");
}
3. 数组的查找
//查找
//线性查找:
String dest="BB";
boolean isflage=true;
String [] arr=new String []{"AA","BB","CC","DD","GG","EE"};
for(int i=0;i<arr.length;i++){
if(dest.equals(arr[i])){
System.out.println("找到了 ,指定元素的位置为:"+i);
isflage=false;
break;
}
}
if(isflage){
System.out.println("未找到指定元素的位置");
}
//二分法查找
//前提:所要查找的数组必须有序
int [] arr2=new int []{-98,-32,2,34,54,66,79,105,210,333};
int dest1=-32;
int head=0;//初始的首索引
int end=arr2.length-1;
boolean isFalse=true;
while(head<=end){
int middle=(head+end)/2;
if(dest1==arr2[middle]){
System.out.println("找到了指定元素位置为:"+middle);
isFalse=false;
break;
}else if(arr2[middle]>dest1){
end=middle-1;
}else {
head=middle+1;
}
}
if(isFalse){
System.out.println("未找到指定元素");
}
四、数组元素的排序算法//面试中考察较多
- 通常来说,排序的目的是快速查找
- 衡量排序算的优劣:1.时间复杂度 2.空间复杂度3.稳定性
比如冒泡排序的排序思想:
- 比较相邻的元素。如果第一个比第二个大(升序),交换他们两个。
- 对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这个步骤做完后,最后的元素会是最大的数。
- 针对所有的元素重复以上的步骤,除了最后一个。
- 持续每次对越来越少的元素重复上面的步骤,直到没有任何邮递数字需要比较为止。
//冒泡排序的实现
int temp;
int [] arr=new int[]{43,32,76,-98,0,64,33,-21,32,99};
for(int i=0;i<arr.length-1;i++){
for(int j=0;j<arr.length-i-1;j++){
if(arr[j]>arr[j+1]){
temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
for(int i=0;i<arr.length;i++){
System.out.print(arr[i]+" ");
}
Arrays工具类的使用
- 理解:
- 定义在java.util包下。
- Arrays:提供了很多操作数组的方法。
- 使用:
//boolean equals( int[] a, int[]b):判断两个数组是否相等
int[] arr1 = new int[]{1,2,3,4};
int[] arr2 = {2,1,3,4};
boolean isEquals = Arrays.equals(arr1, arr2);
System.out.println(isEquals);
//输出数组信息
System.out.println(Arrays.toString(arr1));
//将指定值填充到数组之中
Arrays.fill(arr1,10);
System.out.println(Arrays.toString(arr1));
//对数组进行排序
Arrays.sort(arr2);
System.out.println(Arrays.toString(arr2));
//int binarySearch(int[] a, int key),查找
int[] arr3 = {-98,-34,2,34,54,66,76,87,99,145};
int index = Arrays.binarySearch(arr3,87);
if (index >= 0){
System.out.println(index);
}else {
System.out.println("-1");
}
数组的常见异常
.ArrayIndexOutOfBoundsException数组角标越界异常
int[] a = {1,2,3,4};
System.out.println(a[4]);
.NullPointerException空指针异常
/* String[][] str = new String[4][];
System.out.println(str[0][0]);*/
/*int[] a = {1,2,3,4};
a = null;
System.out.println(a[0]);*/
String[] b = {"AA","BB"};
b[0] = null;
System.out.println(b[0].toString());
面向对象-上
类与对象
-
面向对象学习的三条主线:
- Java类及类的成员:属性、方法、构造器:代码块、内部类
- 面向对象的大特征:封装性、继承性、多态性、(抽象性)
- 其他关键字:this、super、static、final、abstract、interface、package、import等
-
面向对象和面向过程的理解:
- 面向过程:强调的是功能行为,以函数为最小单位,考虑怎么做。
- 面向对象:强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。
-
完成一个项目(或功能)的思路:
- 根据问题需要,选择问题所针对的现实世界中的实体。
- 从实际中寻找解决问题相关的属性和功能,这些属性和功能就形成了概念世界中的类。
- 把抽象的实体用计算机语言进行描述,形成计算机世界中类的定义。即借助某种程序语言,把类构成计算机能够识别和处理的数据结构。
- 将类实例化成计算机世界中的对象。对象是计算机世界中解决问题的最终工具。
-
面向对象中两个重要的概念:
- 类:对一类事物的描述,是抽象的、概念上的定义
- 对象:是实际存在的该类事物的每个个体,因而也称为实例(instance)
- 面向对象程序设计的重点是类的设计
- 设计类,就是设计类的成员
- 二者的关系:对象,是由类new出来的,派生出来的。
-
类和对象的使用(面向对象思想落地实现的规则一)
- 创建类,设计类的成员
- 创建类的对象
- 通过“对象.属性”或“对象.方法”调用对象的结构
补充:设计类,就是设计类的成员(几个概念的使用说明:)
- 属性 = 成员变量 = field = 域、字段
- 方法 = 成员方法 = 函数 = method
- 创建类的对象 = 类的实例化 = 实例化类
- 对象的创建于对象的内存解析
典型代码:
Person p1 = new Person();
Person p2 = new Person();
Person p3 = p1;//没有新创建一个对象,共用一个堆空间中的对象实体
说明:
如果创建了一个类的多个对象,则每个对象都独立的拥有一套类的属性。(非static的)
意味着:如果我们修改一个对象的属性a,则不影响另外一个对象属性a的值。
内存解析:
- 匿名对象:我们创建的对象,没显示的赋给一个变量名。即为匿名对象
特点:匿名对象只能调用一次。
举例:
new Phone().sendEmail();
new Phone().price = 1999;
应用场景:
PhoneMall mall = new PhoneMall();
//匿名对象的使用
mall.show(new Phone());
其中,
class PhoneMall{
public void show(Phone phone){
phone.sendEmail();
phone.playGame();
}
}
- 理解“万事万物皆对象”
- 在Java语言范畴中,我们都将功能、结构等封装到类中,通过类的实例化,来调用具体的功能结构。
- Scanner,String等
- 文件:File
- 网络资源:URL
- 涉及到Java语言与前端Html、后端的数据库交互时,前后端的结构在Java层面交互时,都体现为类、对象。
- 在Java语言范畴中,我们都将功能、结构等封装到类中,通过类的实例化,来调用具体的功能结构。
JVM的内存结构
- 编译完源程序以后,生成一个或多个字节码文件。
- 我们使用JVM中的类的加载器和解析器对生成的字节码文件进行解析运行。意味着,需要将字节码文件对应的类加载到内存中,涉及到内存解析。
内存解析
类的结构之一:属性
- 对比:属性 VS 局部变量
- 相同点:
- 定义变量的格式:数据类型 变量名 = 变量值
- 先声明,后使用
- 变量都其对应的作用域
- 不同点:
- 在类中声明的位置不同
- 属性:直接定义在类的一对{}内
- 局部变量:声明在方法内、方法形参、代码块内、构造器形参、构造器内部的变量
- 关于权限修饰符的不同
- 属性:可以在声明属性时,指明其权限,使用权限修饰符。常用的权限修饰符:private、public、缺省、protected --》封装性
- 局部变量:不可以使用权限修饰符。
- 默认初始化值的情况:
- 属性:类的属性,根据其类型,都默认初始化值。
- 整型(byte、short、int、long:0
- 浮点型(float、double:0.0
- 字符型(char:0(或 ‘\u0000’
- 布尔型(boolean:false
- 引用数据类型(类、数组、接口:null
- 局部变量:没默认初始化值。意味着,我们在调用局部变量之前,一定要先赋值。特别的:形参在调用时,我们赋值即可。
- 属性:类的属性,根据其类型,都默认初始化值。
- 在内存中加载的位置:
- 属性:加载到堆空间中(非static
- 局部变量:加载到栈空间
- 在类中声明的位置不同
- 相同点:
类的结构之二:方法
方法:描述类应该具备的功能。
比如:Math类:sqrt()\random() \ … Scanner类:nextXxx()…
举例:
public void eat(){}
public void eat(int hour){}
public String getName(){}
方法的声明:权限修饰符 返回值类型 方法名(形参列表){
方法体
}
注意:static、final、abstract来修饰方法的
说明:
- 关于权限修饰符:默认方法的权限修饰符先都使用public
- Java规定的4种权限修饰符:private、public、缺省、protected
- 返回值类型:有返回值 VS 没有返回值
- 如果方法有返回值,则必须在方法声明时,指定返回值的类型。同时,方法中,需要使用return关键字来返回指定类型的变量或常量:“return 数据”。
- 如果方法没有返回值,则方法声明时,使用void来表示。通常,没有返回值的方法中,就不需要使用return,都是,如果使用的话,只能“return;”表示结束此方法的意思。
- 我们定义方法时该不该返回值?
- 题目要求
- 凭经验:具体情况具体分析
- 方法名:属于标识符,遵循标识符的规则和规范,“见名知意”
- 形参列表:方法可以声明0个,1个或多个形参。
- 格式:数据类型 形参1 ,数据类型 形参2,…
- 我们定义方法时该不该定义形参?
- 题目要求
- 凭经验:具体情况具体分析
- 方法体:方法功能的体现
- 方法的使用中,可以调用当前类的属性或方法
- 特殊的:方法A中调用了方法A:递归方法。
- 方法中:不可以定义方法。
关键字:return
return关键字:
- 使用范围:使用在方法体中
- 作用:
- 结束方法
- 针对于返回值类型的方法,使用“return 数据”方法返回所有的数据。
- 注意点:return关键字后面不可以声明执行语句。
方法的重载
- 方法的重载概念
- 定义:在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。
- 总结:“两同一不同”:同一个类、相同方法名;参数列表不同,参数类型不同。
- 举例
public void getSum(int i,int j){
System.out.println(1);
}
public void getSum(double d1,double d2){
System.out.println(2);
}
public void getSum(String s,int i){
System.out.println(3);
}
- 如何判断是否构成方法的重载?
- 严格按照定义判断:两同一不同。
- 跟方法的权限修饰符、返回值类型、形参变量名、方法体都没关系!
- 如何确定类中某一个方法的调用:
- 方法名 ----》参数列表
- 面试题:方法的重载与重写的区别?
可变个数形参的方法
- 使用说明
- jak5.0新增的内容
- 具体使用:
- 可变个数形参的格式:数据类型 … 变量名。
- 当调用可变个数形参的方法时,传入的参数个数可以是:0个,1个,2个,。。。
- 可变个数形参的方法与本类中方法名相同,形参不同的方法之间构成重载。
- 可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不构成重载。换句话说,二者不能共存。
- 可变个数形参在方法的形参中,必须声明末尾。
- 可变个数形参在方法的形参中,最多只能声明一个可变形参。
- 举例
public void show(int i){}
public void show(String s){
System.out.println("show(String)");
}
public void show(String ... strs){
System.out.println("show(String ... strs)");
for (int i = 0;i < strs.length;i++){
System.out.print(strs[i]);
}
}
//不能与上一个同时存在
// public void show(String[] strs){}
调用时
ObjectOrientedTest test = new ObjectOrientedTest();
test.show("hello","ad");
test.show();
test.show(new String[]{"AA","aa","dd"});
Java的值传递机制
- 针对于方法内变量的赋值举例:
//基本数据类型
int m = 10;
int n = m;
System.out.println("m=" + m + ",n=" + n);
n = 20;
System.out.println("m=" + m + ",n=" + n);
//引用数据类型
ValTest v1 = new ValTest();
v1.valId = 1001;
ValTest v2 = v1;//赋值以后,v1和v2的地址值相同,都指向堆空间中同一个对象实体
System.out.println(v1.valId+","+v2.valId);
v2.valId = 1002;
System.out.println(v1.valId+","+v2.valId);
规则:
- 如果变量是基本数据类型,此时赋值的是变量所保存的数据值。
- 如果变量是引用数据类型,此时赋值的是变量所保存的数据的地址值。
- 针对于方法的参数概念
- 形参:方法定义时,声明的小括号内的参数
- 实参:方法调用时,实际传递给形参的数据
- Java中参数传递机制:值传递
- 规则:
- 如果参数是基本数据类型,此时实参赋给形参的是实参真实存储的数据值。
- 如果参数是引用数据类型,此时实参赋给形参的是实参存储数据的地址值。
- 规则:
- 典型例题与内存解析
递归方法
- 定义:一个方法体内调用它自身。
- 如何理解递归方法?
- 方法递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无需循环控制。
- 递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死循环。
- 举例:
public int getSum(int n){//计算1-n之间所有自然数的和
if (n == 1){
return 1;
}else {
return n + getSum(n - 1);
}
}
面向对象的特征一:封装性
封装与隐藏
- 为什么要引入封装性?
- 我们程序设计追求 “高内聚,低耦合”。
- 高内聚:类的内部数据操作细节自己完成,不允许外部干涉;
- 低耦合:仅对外暴露少量的方法用于使用。
- 隐藏对象内部的复杂性,只对外公开简单的接口。便于外界调用,从而提高系统的可扩展性、可维护性。通俗的说,把改隐藏的隐藏起来,该暴露的暴露出来。这就是封装性的设计思想。
- 我们程序设计追求 “高内聚,低耦合”。
- 问题引入:
- 当我们创建一个类的对象以后,我们可以通过“对象.属性”的方式,对对象的属性进行赋值。这里,赋值操作要受到属性的数据类型和存储范围的制约。除此之外,没其他制约条件。但是,在实际问题中,我们往往需要给属性赋值加入额外的限制条件。这个条件就不能在属性声明时体现,我们只能通过方法进行限制条件的添加。(比如:setLegs()同时,我们需要避免用户再使用“对象.属性”的方式对属性进行赋值。则需要将属性声明为私有的(private))。—》此时,针对于属性就体现了封装性。
- 封装性思想具体的代码体现:
- 将类的属性xxx私有化(private),同时,提供公共的(public)方法来获取(getXxx)和设置(setXxx)此属性的值。
private double r; public void setR(double r){ this.r = r; } public double getR(){ return r; }
- 不对外暴露的私有的方法。
- 单例模式。(将构造器私有化)
- 如果不希望类在包外被调用,可以将类设置为缺省的。
- Java规定的四种权限修饰符
-
权限从小到大顺序为:private 《 缺省 《 protected 《 public
-
具体的修饰范围:
-
权限修饰符可用来修饰的结构说明:4种权限都可以用来修饰类的内部结构:属性、方法、构造器、内部类;修饰类的话,只能使用:缺省、public。
-
类的结构:构造器Corstructor
- 构造器(或构造方法):Constructor
- 构造器的作用:1.创造对象 ;2.初始化对象信息。
- 使用说明:
- 如果没显示的定义类的构造器的话,则系统默认提供一个空参的构造器;
- 定义构造器的格式:权限修饰符 类名(形参列表){};
- 一个类中定义的多个构造器,彼此构成重载;
- 一旦我们显示的定义了类的构造器之后,系统就不再提供默认的空参构造器;
- 一个类中,至少会有一个构造器。
- 举例:
public PackageTest(){ System.out.println(1); } public PackageTest(double n){ r = n; } public PackageTest(double n,int a){ r = n; i = a; }
属性赋值的顺序
总结:属性赋值的先后顺序:1.默认初始化;2.显示初始化;3.构造器中初始化;4.通过 “对象.方法” 或 "对象.属性"的方式,赋值。
以上操作的先后顺序:1–2–3–4 。
JavaBean的概念
- JavaBean是一种Java语言写成的可重用组件。
- 所谓JavaBean,是指符合如下标准的Java类:
- 类是公共的
- 有一个无参的公共构造器
- 有属性,且有对应的get、set方法