1.1 java概述
- Java 是由 Sun Microsystems 公司于 1995 年 5 月推出的高级程序设计语言。
- Java是一门面向对象的编程语言,具有功能强大和简单易用两个特征。
1.1.1、java语言的特性
- 简单性:Java语言底层采用C++语言实现,相对于C++来说,Java是简单的,在Java语言中程序员不需要再操作复杂的指针(指针的操作是很复杂的),继承方面也是只支持单继承(C++语言是一种半面向对象的编程语言,支持多继承,多继承会导致关系很复杂),在很多方面进行了简化。
- 健壮性:自动垃圾回收机制(GC机制)、异常处理机制、多种开源api支持等成为java高可用的有利保障。
- 面向对象:Java中提供了封装、继承、多态等面向对象的机制。
- 多线程:Java语言支持多个线程同时并发执行,同时也提供了多线程环境下的安全机制。
- 可移植性/跨平台:可移植性/跨平台表示Java语言只需要编写/编译一次,即可处处运行。既可以支持windows环境,又可以支持linux、ios环境。
1.1.2、Java的三种技术架构
JAVASE:Java Platform Standard Edition,完成桌面应用程序的开发,是其它两者的基础;
JAVAEE:Java Platform Enterprise Edition,开发企业环境下的应用程序,主要针对web程序开发;
JAVAME:Java Platform Micro Edition,开发电子消费产品和嵌入式设备,如手机中的程序;
1.1.3、java应用程序的运行机制
先编译(.class),在解释运行。
1.1.4、java程序开发的三个步骤
- 编写源程序,java源代码文件。
- 编译源程序,编译器编译编译成java字节码文件。
- 运行,java虚拟机(JVM)。
1.1.5、开发java应用的要点
- 一个源文件中只能有一个public修饰的类,其他类个数不限。
- 一个源文件有n个类时,编译结果的class文件就有n个。
- 源文件的名字必须和public修饰的类名相同
- java语言中单词拼写大小写严格区分。
- main方法入口
- 每一句以分号(;)结束
1.2、Java 开发环境配置
1.2.1、JDK、JRE和JVM
JDK:(Java Development Kit)java的开发和运行环境,包含java的开发工具和jre。注意:如果只是在这台机器上运行Java程序,则不需要安装JDK,只需要安装JRE即可。
JRE:(Java Runtime Environment)java程序的运行环境,包含java运行的所需的类库(Java核心类库)+JVM(java虚拟机)。
JVM:(Java Virtual Machine)Java虚拟机。
1.2.2、JDK安装
1)安装JDK---选择jdk、jre安装目录,建议两个都安装在同一个java文件夹中的不同文件夹中
2)安装完JDK后配置环境变量 计算机→属性→高级系统设置→高级→环境变量
3)系统变量→新建 JAVA_HOME 变量 。
变量值填写jdk的安装目录(本人是 C:\Program Files\Java\jdk1.8.0_102)
4)系统变量→寻找 Path 变量→编辑
在变量值最后输入 %JAVA_HOME%\bin;%JAVA_HOME%\jre\bin;
或者绝对路径
C:\Program Files\Java\jdk1.8.0_102\bin;C:\Program Files\Java\jdk1.8.0_102\jre\bin;
5)系统变量→新建 CLASSPATH 变量
变量值填写 .;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar(注意最前面有一点)
.;%JAVA_HOME%\lib;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;
6)检验是否配置成功 运行cmd 输入 java -version
7)编写一个小程序测试一下
class HelloWorld{
public static void main(String[] args){
System.out.println("hello world!");
}
}
1.2.3、JDK安装jdk历史版本下载
搜索 java archive
或者
或者
1.3 基本语法
1.3.1、标识符
1)概念
自定义的代表一定含义的单词,标识类、方法、变量、参数等。由字母、下划线、数字和美元符号组成,不能以数字开头。
2)命名规范
- 由字母、下划线、数字和美元符号组成,不能以数字开头,区分大小写,不能是关键字和保留字(goto、const),长度一般不超过15个字符。
- 见名知意。(看到这个单词就知道它表示什么)
- 遵循驼峰命名方式。(单词界线更明确)
3)驼峰式命名
类名、接口:单个单词,首字母大写,多个单词,首字母都大写。
方法名、参数名、变量名:单个单词,首字母小写,多个单词,第一单词首字母小写,其他单词首字母大写。
常量名全部大写,单词和单词之间使用“_”衔接。
包名:全部小写
4)注意事项
- 关键字不能用作标识符
- 标识符区分大小写
1.3.2、关键字
1)概念
赋予了特殊含义的标识符。
关键字不能用作变量名、方法名、类名、包名和参数等。
2)Java中的关键字
访问控制:private、protected、public、default
类、方法和变量修饰符:abstract、class、extends、final、implements、interface、native、new、static、strictfp、synchronized、transient、volatile
程序控制语句:break、case、continue、default、do、else、for、if、instanceof、return、switch、while
错误处理:assert、catch、finally、throw、throws、try
包相关:import、package
基本类型:boolean、byte、char、double、float、int、long、short
变量引用:super、this、void
保留关键字:goto、const、null
1.3.3、变量
1)字面量
字面量就是数据/数值,例如:1234,true,”abc”,’中’,3.14等。
2)变量
变量是内存当中存储数据最基本的单元,将字面量(数据/数值)放到内存当中,给这块内存空间起一个名字,这就是变量。所以变量就是内存当中的一块空间,这块空间有名字、有类型、有值,这也是变量必须具备的三要素。
3)变量声明
语法格式为:数据类型 变量名; //例如:int i;
4)变量分类
数据类型划分:
- 基本类型变量:数据的值
- 引用类型变量:数据的地址
声明的位置划分:局部变量、全局变量
局部变量和全局变量的区别:
1. 默认值
- 局部没有默认值,使用前必须初始化。
- 全局有默认值,默认为0,不必须初始化。
2. 声明位置
- 局部在方法内。
- 全局在方法外类中。
3.作用位置
- 局部只能在自己声明的方法里。
- 全局在整个类中
- 变量根据声明的位置不同可以分为:局部变量和成员变量。
- 在方法体当中声明的变量以及方法的每一个参数变量都是局部变量。
- 在方法体外,类体内声明的变量称为成员变量,成员变量声明时如果使用static关键字修饰的称为静态成员变量(简称静态变量),如果没有static关键字修饰则称为实例成员变量(简称实例变量),如以下代码:
public class VarTest {
//实例变量(成员变量)
int x = 20;
//静态变量(成员变量)
static int y = 200;
//方法:int a,int b都是局部变量
public static void sum(int a, int b){
//局部变量
int firstNum = 100;
}
}
- 局部变量只在方法体当中有效,方法开始执行的时候局部变量的内存才会被分配,当方法执行结束之后,局部变量的内存就释放了。所以局部变量的生命周期非常短暂。
Java语言支持的变量类型有:
- 类变量:方法外,类中,用 static 修饰。
- 实例变量:方法外,类中,不过没有 static 修饰。
- 局部变量:类的方法(方法体内变量或方法参数)或代码块中的变量。
5)局部变量
- 局部变量声明在方法、构造方法或者语句块中;
- 局部变量在方法、构造方法、或者语句块被执行的时候创建,当它们执行完成后,变量将会被销毁;
- 访问修饰符不能用于局部变量;
- 局部变量只在声明它的方法、构造方法或者语句块中可见;
- 局部变量是在栈上分配的。
- 局部变量没有默认值,所以局部变量被声明后,必须经过初始化,才可以使用。
6)实例变量
- 实例变量声明在一个类中,但在方法、构造方法和语句块之外;
- 当一个对象被实例化之后,每个实例变量的值就跟着确定;
- 实例变量在对象创建的时候创建,在对象被销毁的时候销毁;
- 实例变量的值应该至少被一个方法、构造方法或者语句块引用,使得外部能够通过这些方式获取实例变量信息;
- 实例变量可以声明在使用前或者使用后;
- 访问修饰符可以修饰实例变量;
- 实例变量对于类中的方法、构造方法或者语句块是可见的。一般情况下应该把实例变量设为私有。通过使用访问修饰符可以使实例变量对子类可见;
- 实例变量具有默认值。数值型变量的默认值是0,布尔型变量的默认值是false,引用类型变量的默认值是null。变量的值可以在声明时指定,也可以在构造方法中指定;
- 实例变量可以直接通过变量名访问。但在静态方法以及其他类中,就应该使用完全限定名:ObejectReference.VariableName。
7)类变量(静态变量)
- 类变量也称为静态变量,在类中以 static 关键字声明,但必须在方法之外。
- 无论一个类创建了多少个对象,类只拥有类变量的一份拷贝。
- 静态变量除了被声明为常量外很少使用,静态变量是指声明为 public/private,final 和 static 类型的变量。静态变量初始化后不可改变。
- 静态变量储存在静态存储区。经常被声明为常量,很少单独使用 static 声明变量。
- 静态变量在第一次被访问时创建,在程序结束时销毁。
- 与实例变量具有相似的可见性。但为了对类的使用者可见,大多数静态变量声明为 public 类型。
- 默认值和实例变量相似。数值型变量默认值是 0,布尔型默认值是 false,引用类型默认值是 null。变量的值可以在声明的时候指定,也可以在构造方法中指定。此外,静态变量还可以在静态语句块中初始化。
- 静态变量可以通过:ClassName.VariableName的方式访问。
- 类变量被声明为 public static final 类型时,类变量名称一般建议使用大写字母。如果静态变量不是 public 和 final 类型,其命名方式与实例变量以及局部变量的命名方式一致。
1.3.4、Java数据类型
1)基本数据类型
数值型:
byte 1字节 8位 -128~127
short 2字节 16位 -32768~32767
int 4字节 32位 -2^31~2^31-1
long 8字节 64位 2^63~2^63-1
浮点类型:
float 4字节 32位
double 8字节 64位
字符型:
char 2字节 16位 0~65535
布尔型:
boolean true false
基本数据类型之间的转换:
自动类型转换:
范围小→范围大 byte→short→int→long→float→double;
char→int→long→float→double
强制类型转换:范围大→范围小,需要加强制转换符
byte:
- byte 数据类型是8位、有符号的,以二进制补码表示的整数;
- 最小值是 -128(-2^7);
- 最大值是 127(2^7-1);
- 默认值是 0;
short:
- short 数据类型是 16 位、有符号的以二进制补码表示的整数
- 最小值是 -32768(-2^15);
- 最大值是 32767(2^15 - 1);
- 默认值是 0;
int:
- int 数据类型是32位、有符号的以二进制补码表示的整数;
- 最小值是 -2,147,483,648(-2^31);
- 最大值是 2,147,483,647(2^31 - 1);
- 一般的整型变量默认为 int 类型;
- 默认值是 0 ;
long:
- long 数据类型是 64 位、有符号的以二进制补码表示的整数;
- 最小值是 -9,223,372,036,854,775,808(-2^63);
- 最大值是 9,223,372,036,854,775,807(2^63 -1);
- 默认值是 0L;
float:
- float 数据类型是单精度、32位;
- float 在储存大型浮点数组的时候可节省内存空间;
- 默认值是 0.0f;
double
- double 数据类型是双精度、64 位
- 浮点数的默认类型为 double 类型;
- 默认值是 0.0d;
boolean
- 只有两个取值:true 和 false
- 默认值是 false
char:
- char 类型是一个单一的 16 位 Unicode 字符;
- 最小值是 \u0000(十进制等效值为 0);
- 最大值是 \uffff(即为 65535);
2)引用类型
字符串 String、 类 class 、枚举 enum、接口interface
1.3.5、Java 常量
Java 中使用 final 关键字来修饰常量,声明方式和变量类似。
final double PI = 3.1415927;
1.3.6、运算符
算术运算符:+ - * / % ++ --
赋值运算符:= += -= *= /= %= >= &= ^= |=
关系运算符:> < >=
逻辑运算符:! & | ^ && ||
位运算符:
&:按位与。
|:按位或。
~:按位非。
^:按位异或。
>>:右位移运算符。
三目运算符(条件运算符):x ? y : z
1)对两个变量的数据进行互换
a = a + b;
b = a - b;
a = a - b;
a = a ^ b;
b = a ^ b;
a = a ^ b;
2)注意
& 和 &&区别
&:无论左边结果是什么,右边都参与运算。
&&:短路与,如果左边为false,那么右边不参数与运算。
| 和|| 区别
|:两边都运算。
||:短路或,如果左边为true,那么右边不参与运算。
前缀自增自减法(++a,--a):先进行自增或者自减运算,再进行表达式运算。
后缀自增自减法(a++,a--):先进行表达式运算,再进行自增或者自减运算。
int a = 5;//定义一个变量;
int b = 5;
int x = 2*++a;
int y = 2*b++;
System.out.println("自增运算符前缀运算后a="+a+",x="+x);
System.out.println("自增运算符后缀运算后b="+b+",y="+y);
3)Java运算符优先级
优先级 | 运算符 | 结合性 |
1 | ( ) [ ] . | 从左到右 |
2 | ! ~ ++ -- | 从右到左 |
3 | * / % | 从左到右 |
4 | + - | 从左到右 |
5 | > >>> | 从左到右 |
6 | < >= instanceof | 从左到右 |
7 | == != | 从左到右 |
8 | & | 从左到右 |
9 | ^ | 从左到右 |
10 | | | 从左到右 |
11 | && | 从左到右 |
12 | || | 从左到右 |
13 | ? : | 从左到右 |
14 | = += -= *= /= %= &= |= ^= ~= >= >>>= | 从右到左 |
1.3.7、二进制
计算机中的数据都以二进制数据保存。
计算机信息的存储单位:
位(bit):是计算机存储处理信息的最基本的单位
字节(byte):一个字节有8个位组成。
1.3.8、转义字符
\n 换行 \r 回车 \t 水平制表 ' 单引号 " 双引号 \斜杠
1.4、Java流程控制语句
程序三种执行顺序:顺序结构、选择(分支)结构、循环结构。
1.4.1、选择结构
1)if语句
//if语句
if(){
}
//if...else...
if(){
}else{
}
//if...else if...else
if(){
}else if(){
}else{
}
//if嵌套
if(){
if(){
}else{
}
}
2)switch语句
switch(表达式expr){
case const1:
statement1;
break;
...
case constN:
statementN;
break;
[default:
statement_dafault;
break;]
}
注意:
- 表达式必须是int、byte、char、short、enmu、String类型
- constN必须是常量或者final变量,不能是范围
- 所有的case语句的值不能相同,否则编译会报错
- default可要可不要
- break用来执行完一个分支后使程序跳出switch语句块,否则会执行下面的语句。
1.4.2、循环结构
Java中有三种主要的循环结构:
- while 循环
- do…while 循环
- for 循环
1)while语句
while(判断条件){
循环体;
}
2)do...while语句
do{
循环体;
}while(判断条件);
3)for语句
for(初始化; 布尔表达式; 迭代更新){
循环体;
}
4)增强for
for(声明语句 : 表达式){
循环体;
}
声明语句:声明新的局部变量,该变量的类型必须和数组元素的类型匹配。其作用域限定在循环语句块,其值与此时数组元素的值相等。
表达式:表达式是要访问的数组名,或者是返回值为数组的方法。
5)break 关键字
break 主要用在循环语句或者 switch 语句中,用来跳出整个语句块。
break 跳出最里层的循环,并且继续执行该循环下面的语句。
public class BreakTest {
public static void main(String[] args) {
int [] numbers = {10, 20, 30, 40, 50};
for(int x : numbers ) {
// x 等于 30 时跳出循环
if( x == 30 ) {
break;
}
System.out.print( x );
System.out.print("\n");
}
}
}
//运行结果如下:
10
20
6)continue 关键字
continue 适用于任何循环控制结构中。作用是让程序立刻跳转到下一次循环的迭代。
在 for 循环中,continue 语句使程序立即跳转到迭代更新语句。
在 while 或者 do…while 循环中,程序立即跳转到布尔表达式的判断语句。
public class ContinueTest {
public static void main(String[] args) {
int [] numbers = {10, 20, 30, 40, 50};
for(int x : numbers ) {
// x 等于 30 时跳出循环
if( x == 30 ) {
continue;
}
System.out.print( x );
System.out.print("\n");
}
}
}
continue:只作用于循环结构,继续循环用的
1.5、Java方法
1.5.1、什么是方法
- Java方法是语句的集合,它们在一起执行一个功能。
- 方法是解决一类问题的步骤的有序组合
- 方法包含于类或对象中
- 方法在程序中被创建,在其他地方被引用
1.5.2、方法的优点
- 使程序变得更简短而清晰。
- 有利于程序维护。
- 可以提高程序开发的效率。
- 提高了代码的重用性。
1.5.3、方法的定义
[修饰符] 返回值类型 方法名([形式参数列表]){
方法体;
[return 返回值;]
}
1.5.4、方法的重载
方法重载(overload)是指在一个类中定义多个方法名相同,参数列表不同的方法。
参数列表不同:参数个数、参数顺序或者参数类型其中一项或多项不同。
在一个类中,方法名字相同,参数类型不同。
参数类型不同:个数、数据类型、顺序。
注意:
- 重载和返回值类型,修饰符没有任何关系。
- 参数变量名修改也不能够称为重载
1.5.5、递归方法
1)什么叫递归
递归函数就是直接或间接调用自身的函数,也就是自身调用自己。
2)一般什么时候使用递归?
递归是常用的编程技术,其基本思想就是“自己调用自己”,一个使用递归技术的方法即是直接或间接的调用自身的方法。递归方法实际上体现了“以此类推”、“用同样的步骤重复”这样的思想。
还有些数据结构如二叉树,结构本身固有递归特性;此外,有一类问题,其本身没有明显的递归结构,但用递归程序求解比其他方法更容易编写程序。
注意事项:
- 有能够跳出循环的控制语句,否则会发生栈内存溢出。
- 递归次数不能太多,否则也会发生栈内存溢出。
- 构造方法,禁止递归
汉罗塔问题,求阶乘,求1-100累加和。八皇后问题,迷宫问题...
3)经典递归算法
1、用代码实现递归阶乘的结果:n! = n * (n-1) * (n-2) * ...* 1(n>0)
/**
* @author cz
*/
public class DiGui {
/**方法一*/
static int result=1;
public static int getFactorial(int a){
if(a>0){
result=result*a;
getFactorial(--a);
}
return result;
}
public static void main(String[] args) {
int result = getFactorialTest(4);
System.out.println(result);
}
/**方法二*/
public static int getFactorialTest(int b){
if(b>0){
int number = b*getFactorialTest(--b);
return number;
}else if(b==0){
return 1;
}else{
return -1;
}
}
/**方法三*/
public static Integer recursionMulity(Integer n){
if(n==1){
return 1;
}
return n*recursionMulity(n-1);
}
}
2、判定一系列字符串中是否有相同的内容
public class Crf{
public static void main(String[] args) {
String[] a = {"a1","a2","a3","b3","c","b","33","33"};
fun(0, a);
}
public static void fun(int n,String[] a){
if(n==a.length){
return;
}
for(int i = n; i < a.length-1; i++){
System.out.println(n+" "+(i+1));
if(a[n].equals(a[i+1])){
System.out.println("存在相同字符");
System.out.println(a[n]);
}
}
n++;
fun(n,a);
}
}
3、兔子数列(斐波那契数列)
假设一对刚出生的小兔子一个月后就能长成大兔子,再过一个月就能生下一对小兔子,并且此后每个月都生一对小兔子,如果兔子不死的话,请问每个月兔子的总数是多少。
第一个月 1小 1
第二个月 1中 1
第三个月 1大1小 1+1=2
第四个月 1大1中1小 1+1+1=3
第五个月 2大1中2小 2+1+2=5
第六个月 3大2中3小 3+2+3=8
第七个月 5大3中5小 5+3+5=13
第八个月 8大5中8小 8+5+8=21
第九个月 13大8中13小 13+8+13=34
public static void main(String[] args) {
int i = 1;
for(i=1;i<=12;i++){
System.out.println("兔子第"+i+"个月的总数为:"+f(i));
}
}
public static int f(int x) {
if (x == 1 || x == 2) {
return 1;
} else {
//当前月的兔子的个数等于前两个月兔子的相加
return f(x - 1) + f(x - 2);
}
}
4、猴子吃桃子问题:
猴子第一天摘下若干个桃子,当即吃了快一半,还不过瘾,又多吃了一个。第二天又将仅剩下的桃子吃掉了一半,又多吃了一个。以后每天都吃了前一天剩下的一半多一个。到第十天,只剩下一个桃子。试求第一天共摘了多少桃子?
public static int getPeach(int days) {
//第十天剩1个桃子
if (days == 10) {
return 1;
}
//前一天的桃子=当天桃子(getPeach方法)+1*2
return (getPeach(days+1) + 1) * 2;
}
4)递归的小结
- 一个递归的方法每次用不同的参数值反复调用自身,
- 某个参数值时递归的方法返回,而不再调用自身,这种称为基值情况,
- 一个递归的方法必须存在一个或多个基值,
- 任何可以用递归完成的操作都可以用一个栈来实现,
- 递归的方法可能效率低,如果是这样的话,有时可以用一个简单循环或者是一个基于栈的方法来代替。
1.5.6、可变参数
JDK 1.5 开始,Java支持在方法参数列表中传递同类型的可变参数。
可变参数语法: paramType... paramName
//可变参数
修饰符 返回值类型 方法名(参数类型... 参数名){}
注意事项:
一个方法中只能指定一个可变参数,它必须是方法的最后一个参数。任何普通的参数必须在它之前声明。
1.5.7、return关键字
- 将数据返回给调用者,除了void外,return后必须跟着返回值,只能返回一个。
- 终止方法的执行,返回数据类型必须是void,return后不能添加数据。
- 当return结束方法的时候,要让其后面的代码有可能被执行到。
- 一个方法里可以有多个return,在void里不能有返回值,其他的必须有返回值。
1.5.8、回调函数
class A{
private B b;
public void aMethod(){
b.bMethod();
}
public void callback(){
//回调逻辑
}
}
class B{
private A a;
public void bMethod(){
//b方法执行逻辑
a.callback{}
}
}
1.6、Java数组
1.6.1、数组的定义
数组:用于存储同一类型数据的一个容器。
1.6.2、数组初始化
元素类型[] 变量名 = new 元素类型[元素的个数];
元素类型[] 变量名 = {元素1,元素2...};
元素类型[] 变量名 = new 元素类型[]{元素1,元素2...};
1.6.3、数组的遍历
//for-each循环
for(type element: array){
System.out.println(element);
}
//for循环
for(int i=0;i<array.size;i++>){
System.out.println(array[i]);
}
1.6.4、数组的应用
1.6.4.1、数组的遍历
/*数组的遍历,循环,根据每个数组下标依次取出每个元素*/
int[] arr={10,8,21,13,66,22,91,68};
for(int i=0;i<arr.length;i++){
System.out.println(arr[i]);
}
1.6.4.2、求数组最大值
/*思路一:先取出一个元素作为最大值,然后遍历数组,和数组的每一个元素比较,比最大值大就交换*/
int[] arr={10,8,21,13,66,22,91,68};
int max=arr[0];
for(int i=0;i<arr.length;i++){
if(arr[i]>max){
/*
交换逻辑:
第一种方法: int a,b a=a+b; b=a-b; a=a-b;
a=a^b; b=a^b; a=a^b;
第二种方法: int a,b,temp temp=a; a=b; b=temp;
*/
arr[i]=arr[i]+max;
max=arr[i]-max;
arr[i]=arr[i]-max;
}
System.out.println("数组最大值:"+max);
}
/*思路二:先取出第一个元素的下标作为最大值下标,然后遍历数组,和数组的每一个元素比较,比最大值大就交换下标*/
int[] arr={10,8,21,13,66,22,91,68};
int max=0;
for(int i=0;i<arr.length;i++){
if(arr[i]>arr[max]){
i=i+max;
max=i-max;
i=i-max;
}
System.out.println("数组最大值:"+arr[max]);
}
1.6.4.3、找出数组中的某一个元素
//遍历数组,如果相等打印输出并记录下标。
int[] arr={10,8,21,13,66,22,91,68};
int temp=91,index=-1;
for(int i=0;i<arr.length;i++){
if(arr[i]==temp){
System.out.println("元素:"+temp+"在数组下标第:"+i+"位置");
index=i;
}
}
if(index==-1){
System.out.println("元素:"+temp+"不在数组中!");
}
1.6.4.4、打印乘法口诀表
/*
1*1=1
2*1=2 2*2=4
3*1=3 3*2=6 3*3=9
...
1*1口诀表:第一行(i=1),有1列(j=1) 1*1=1
2*2口诀表:第一行(i=1),有2列(j=1) 1*1=1
第二行(i=2),有2列(j=1) 2*1=2 (j=2)2*2=4
n*n口诀表:第一行(i=1),有1列(j=1) 1*1=1
第二行(i=2),有2列(j=1) 2*1=2...
第三行(i=3),有3列(j=1) 3*1=3...
第i行(i=n), 有j列(j=1) i*1=i...
...
n*n口诀表:第i行,第j列 i*j;最大行数 i=n,每一行列数 j<=i
*/
public void printMulTab(int n){
for(int i=1;i<=n;i++){
for(int j=1;j<=i;j++){
System.out.print(i+"*"+j+"="+i*j+"\t");
}
System.out.print("\n");
}
}
1.6.4.5、数组动态扩容问题
//数组动态扩容
//指定初始大小
int[] arr=new int[0];
int[] newArr=new int[newLen];
//第一种方法:遍历数组,把每一项元素放入新生成的数组中
for(int i=0;i<arr.length;i++){
newArr[i]=arr[i];
}
//第二种方法:调用System.arraycopy方法
//将array数组从0位置至array.length位置,复制到newArray数组0位置到array.length位置。
System.arraycopy(arr,0,newArr,0,arr.length);
1.6.4.6、数组排序
1)冒泡排序
//冒泡排序 相邻两个数比较,大的数往后移,一轮比较下来,最后一个数(arr.length-1位置)就是最大的数,
//然后前(arr.length-1)个数再次比较出最大的数,放到(arr.length-2)的位置。
//依次比较下来,每轮比出剩下的数中最大的数,移动到剩余数组最后面。
//n轮之后,剩下的数arr.length-n==1的时候,排序完成。
int[] arr={10,8,21,13,66,22,91,68};
//循环几轮
for(int i=0;i<arr.length-1;i++){
//每一轮循环
for(int j=0;j<arr.length-1-i;j++){
//前一个数比后一个数大,交换位置
if(arr[j]>arr[j+1]){
arr[j]=arr[j+1]+arr[j];
arr[j+1]=arr[j]-arr[j+1];
arr[j]=arr[j]-arr[j+1];
}
}
}
2)选择排序
//选择排序
//从数组n个元素中,选出一条最大或者最小值,记录他的下标,并把他和数组最前面或者最后面元素交换;
//每轮比较下来,剩下的元素减1,确定一条最大或者最小值元素。
//n轮比较完,当剩下的元素只有一个的时候,排序完成
int[] arr={10,8,21,13,66,22,91,68};
//循环几轮
for(int i=0;i<arr.length-1;i++){
//记录最大值下标
int max=0;
//每一轮最后一个元素的下标
int last=arr.length-i-1;
//每一轮循环,记录最大值下标
for(int j=0;j<arr.length-i;j++){
if(arr[j]>arr[max]){
max=j;
}
}
//一轮比较完,把最大值和最后元素交换位置
if(last!=max){
arr[max]=arr[last]+arr[max];
arr[last]=arr[max]-arr[last];
arr[max]=arr[max]-arr[last];
}
}
int[] arr={10,8,21,13,66,22,91,68};
//循环几轮
for(int i=0;i<arr.length-1;i++){
//剩余元素的第一个数下标
int temp=i;
//每一轮循环,记录最小值下标
for(int j=i;j<arr.length;j++){
if(arr[j]<arr[temp]){
temp=j;
}
}
//一轮比较完,把最小值和最前面的元素交换位置
if(temp!=i){
arr[temp]=arr[i]+arr[temp];
arr[i]=arr[temp]-arr[i];
arr[temp]=arr[temp]-arr[i];
}
}
3)插入排序
//插入排序
//数组从左到右依次取出元素,和他左边的元素比较,如果元素比他大就右移一位,直到找到比他小的那个数;
//此时,比他小的那个数下标+1就是这个元素要插入的位置。
//依次论推,每次都能找到一个元素在这个数组的正确排序,并放入。n-1次后就能排好n个元素的数组。
int[] arr={10,8,21,13,66,22,91,68};
//从下标0开始,依次取出数组中的一个元素作为要插入的数
for(int i=1;i<arr.length;i++){
//要插入的数
int target=arr[i];
//数组左边是已插入的元素(有排序),和左边的元素依次比较,j左边元素的下标
int j=i-1;
//如果数组小下标方向还有元素,且当前小下标元素大于目标元素(要插入的元素),当前小下标元素右移一位
while(j>=0 && arr[j]>target){
arr[j+1]=arr[j];
j--;
}
//找到比目标元素小的元素,将目标元素放到这个元素后一位
arr[j+1]=target;
}
for(int i=1;i<arr.length;i++){
//要插入的数
int target=arr[i];
//数组左边是已插入的元素(有排序),和左边的元素依次比较,j左边元素的下标
//如果数组小下标方向还有元素,且当前小下标元素大于目标元素(要插入的元素),当前小下标元素右移一位
for(int j=i-1;j>=0 && arr[j]>target;j--){
arr[j+1]=arr[j];
}
//找到比目标元素小的元素,将目标元素放到这个元素后一位
arr[j+1]=target;
}
1.6.4.7、打印杨辉三角
/*
打印杨辉三角
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
第一行 空格 5-1 数据 1
第二行 空格 5-2 数据 1 1
第三行 空格 5-3 数据 1 1+1=2 1
第四行 空格 5-4 数据 1 1+2=3 2+1=3 1
第五行 空格 5-4 数据 1 1+3=4 3+3=6 3+1=4 1
第一行 1
第二行 1 1
第n行 第一个数1,最后一个数1,空格最大行数n-当前行数i,中间数(第i行第j列)上一行i-1,第j-1列数+第j列数
递归方法
*/
1.6.4.8、找出数组中的某一个元素
二分查找法。前提:数组中的元素要有序。