一、语言基础语法
1)注释
单行注释
使用//单行注释
//单行注释
多行注释
使用/**/多行注释
/*
这里是多行注释
这里是多行注释
这里是多行注释
*/
文档注释
使用/****/文档注释
/***
* 这里时文档注释
* author:作者
*
*/
使用这个命令 javaDoc -encoding UTF-8 -charset UTF-8 HelloWorld.java 去生成Java的api文档
2)数据类型
基本数据类型
类型 | 默认值 | 长度 | 数值范围 |
---|---|---|---|
byte | 0 | 8 | -128~127 |
short | 0 | 16 | -32768~32767 |
int | 0 | 32 | -2147483648 ~ 2147483647 |
long | 0L | 64 | -9223372036854775808 ~ 9223372036854775807 |
float | 0.0F | 32 | 3.4E-38~3.4E+38 |
double | 0.0D | 64 | 1.7E-308~1.7E+308 |
boolean | false | 1 | true和false |
char | ‘\u0000’ | 16 | ‘\u0000’ ~ ‘\uffff’ |
数据类型的扩展
- 整型
int decVal = 26;//十进制形式
int hexVal = 0x1a;//十六进制形式
int binVal = 0b11010;//二进制形式
int octVal = 010;//八进制形式
-
浮点型
不能用==来比较大小,因为他们是不精确的,所以不能用于银行数据
double d1 = 123.4;
double d2 = 1.234e2;
float f1 = 123.4f;
- 字符型
char c1 = "A";//输出字符A
char c2 = 65;//输出字符A
char c = '\u0065';//输出字符e
- 数字中可以使用下划线
作用是分隔数字文字中的数字组,这可以提高代码的可读性
例如:
long creditCardNumber = 1234_5678_9012_3456L;
long socialSecurityNumber = 999_99_9999L;
float pi = 3.14_15F;
long hexBytes = 0xFF_EC_DE_5E;
long hexWords = 0xCAFE_BABE;
long maxLong = 0x7fff_ffff_ffff_ffffL;
byte nybbles = 0b0010_0101;
long bytes = 0b11010010_01101001_10010100_10010010;
以下是非法例子
float pi1 = 3_.1415F; //无效:不能在小数点附近放置下划线
float pi2 = 3._1415F; //无效:不能在小数点附近放置下划线
socialSecurityNumber1 = 999_99_9999_L; //无效:不能在 L 后缀之前加上下划线 long
int x2 = 52_; //无效:不能放下划线在文字的末尾
int x4 = 0_x52; //无效:不能下划线在 0x 基数前缀
int x5 = 0x_52; //无效:不能在数字开头放置下划线
int x7 = 0x52_;//无效:不能在数字末尾添加下划线
变量的类型转换
不同类型之间的数据可以互相转换,但是要满足一定的规则
byte,short char->int->long->float->double
转换规则按照长度大小,从小到大自动转,从大到小强制转
虽然short和char都是16位的,长度是一样的但是彼此之间,依然需要进行强制转换(避免内存溢出)
操作大数时注意内存溢出问题
int money = 1_000_000_000;//十亿
int year = 20;
int total = money*year;
System.out.println(total);//输出-1474836480,不期望的结果
double total2 = money*year;
System.out.println(total2);//输出-1474836480,不期望的结果
double total3 = (long)money*year;
System.out.println(total3);//输出2.0E10,正确的结果
3)变量与常量
变量分类及作用域
分类
基本数据类型:数值(整数,浮点,字符),布尔
引用数据类型:类,接口,数组
- 实例变量(非静态字段):
对象将它们各自的状态存储在“非静态字段”中,即没有static关键字声明的字段。非静态字段也称为实例变量,因为它们的值对于类的每个实例(换句话说,对于每个对象)都是唯一的;作用域整个类 - 类变量(静态字段):
使用static修饰符声明的任何字段;这告诉编译器存在这个变量的一个副本,不管这个类被实例化了多少次,都有共同的一个字段。此外,可以添加关键字final来表示变量值永远不会改变。作用域整个类 - 局部变量:
方法通常会将其临时状态存储在局部变量中。声明局部变量的语法类似于声明字段(例如,int count = 0;)。局部变量不需修饰符;局部变量仅对声明它们的方法可见;其他类无法访问它们。作用域整个块 - 参数:
回想一下,该main方法public static void main(String[] args). 这里,args变量是这个方法的参数。要记住的重要一点是,参数总是被归类为“变量”而不是“字段”。作用域方法内
局部变量没有初始值,如果声明时没有初始化,必须在使用前赋值
变量和字段区别
如果我们谈论“一般的字段”(不包括局部变量和参数),我们可能会简单地说“字段”。如果讨论适用于“以上所有”,我们可以简单地说“变量”。如果上下文需要区分,我们将酌情使用特定术语(静态字段、局部变量等)
变量的命名
- 变量名区分大小写
- 以字母、美元符号“
$
”或下划线字符“_
”开头,然而惯例始终以字母开头,而不是“$
”或“_
” - 不允许使用空格
- 建议请使用完整的单词而不是隐晦的缩写
- 您选择的名称不能是 关键字或保留字
- 如果它包含多个单词,则将每个后续单词的第一个字母大写
- 如果您的变量存储一个常量值,则约定会略有变化,将每个字母大写并用下划线分隔后续单词
- 中文可以用来命名,但是别这么干
常量表示
当一个变量被final修饰的时候,该变量只有一次赋值的机会
final static double PI = 3.14;
4)运算符
算数运算符
+,-,*,/,%,++,–
重点关注:
b = a++,++在后是后++,意思是赋值完成后再++,b=a
b = ++a,++在前是前++,意思是赋值完成前就已经++完成,b=a+1
做除法时可能会产生小数,必须将其中一个强制类型转换为浮点,不然得不到想要的结果
赋值运算符
=,+=,-=,*=,/=
a+=3,等价于a=a+3,其他类似
关系运算符
<,>,>=,<=,==,!=,instenceof(对象使用)
逻辑运算符
&&,||,!
值得注意的是“与’'的时候有一个短路情况
(条件表达式1 && 条件表达式2),在条件表达式1为false时,就不会再判断条件表达式2,结果直接输出false
还有一种非短路的与或,使用单个&,|
位运算符
&,|,^,~,>>,<<,>>>(了解)
在很多算法里面会用到位运算得到精巧的计算,因为位运算和底层打交道效率非常的高
例如计算2^3的时候,用位运算非常快,只需左移两次就可以
左移时,原数据乘以2;右移时,原数据除以2
条件运算符
条件?语句1:语句2
条件为真时执行语句1,为假时执行语句2
5)数字与字符串
装箱拆箱
封装类:所有的基本类型,都有对应的类类型,比如int对应的类是Integer,这种类就叫做封装类
Number类:数字封装类有Byte,Short,Integer,Long,Float,Double,这些类都是抽象类Number的子类
基本类型转封装类,Integer it = new Integer(5);
封装类转基本类型,int i = it.intValue();
自动装箱,不需要调用构造方法,通过=符号自动把基本类型转换为类类型就叫装箱,Integer it = 5;
自动拆箱,不需要调用Integer的intValue方法,通过=就自动转换成int类型,就叫拆箱,int i = it;
字符串转换
数字转字符串:
方法1: 使用String类的静态方法valueOf,String str = String.valueOf(5)
valueOf的参数可以是很多基本类型,也可以是字符数组
方法2: 先把基本类型装箱为对象,然后调用对象的toString,String str = it.toString()
字符串转数字:
调用Integer的静态方法parseInt,int i= Integer.parseInt(str)
数学方法
四舍五入:Math.round(0.45)
随机浮点数(0-1,取不到1):Math.random()
随机整数(0-10,取不到10):(int)( Math.random()*10)
开方:Math.sqrt(9)
次方(2的4次方):Math.pow(2,4)
常数π :Math.PI
自然常数:Math.E
字符
char对应的封装类
char c1 = 'a';
Character c = c1; //自动装箱
c1 = c;//自动拆箱
Character常见方法
System.out.println(Character.isLetter('a'));//判断是否为字母
System.out.println(Character.isDigit('a')); //判断是否为数字
System.out.println(Character.isWhitespace(' ')); //是否是空白
System.out.println(Character.isUpperCase('a')); //是否是大写
System.out.println(Character.isLowerCase('a')); //是否是小写
System.out.println(Character.toUpperCase('a')); //转换为大写
System.out.println(Character.toLowerCase('A')); //转换为小写
String a = 'a'; //不能够直接把一个字符转换成字符串
String a2 = Character.toString('a'); //转换为字符串
常见转义字符
\t是制表符,代表让其后面的字符对齐到下一个制表位,不仅仅代表光标后移8个字符(idea控制台移动4个字符,可以设置为8个)
System.out.println("换行:\n");
System.out.println("制表符:\t");
System.out.println("退格:\b");
System.out.println("回车:\r");
System.out.println("反斜杠:\\");
System.out.println("单引号:\'");
System.out.println("双引号:\"");
字符串
创建字符串
字符串即字符的组合,在Java中,字符串是一个类,所以我们见到的字符串都是对象
常见创建字符串手段:
char[] c1 = new char[]{'我','是','中','国','人'};
String str = "你好"; //每当有一个字面值出现的时候,虚拟机就会创建一个字符串
String str1 = new String("我是new出来的"); //调用String的构造方法创建一个字符串对象
String str2 = new String(c1); //调用String的构造方法创建一个字符串对象
String str3 = str + str1; //通过+加号进行字符串拼接也会创建新的字符串对象
System.out.format("%s,%s,%s,%s",str,str1,str2,str3);
String 被修饰为final,所以是不能被继承的
一旦创建好一个字符串,里面的内容永远不能改变,String 的表现就像是一个常量
length方法返回当前字符串的长度,可以有长度为0的字符串,即空字符串
操做字符串
获取指定位置字符:charAt(int index),返回一个字符
获取对应的字符数组:toCharArray(),返回一个字符数组
截取子字符串:substring(3,5),截取3-4位置的字符,返回一个字符串
根据分隔符进行分隔:split(“,”),返回一个字符串数组
去掉首尾空格:trim(),返回一个字符串
全部变成小写:toLowerCase ,返回一个字符串
全部变成大写:toUpperCase ,返回一个字符串
判断字符或者子字符串第一次出现的位置; indexOf (),返回一个整型
判断字符或者子字符串最后一次出现的位置; lastIndexOf (),返回一个整型
判断字符或者子字符串在指定位置(5)之后第一次出现的位置; indexOf (“,”,5),返回一个整型
判断是否包含指定字符串,contains(),返回布尔类型
替换所有指定字符串,replaceAll(),返回一个字符串
替换第一个指定字符串,replaceFirst(),返回一个字符串
比较字符串
是否是同一个对象
String str1 = "hello";
String str2 = new String(str1);
//==用于判断是否为同一个字符串对象
System.out.println( str1 == str2);//结果为false
/***
* 一般说来,编译器每碰到一个字符串的字面值,就会创建一个新的对象
* 所以str1创建了一个新的字符串"hello"
* 但是创建str3时,编译器发现已经存在现成的"hello",那么就直接拿来使用,而没有进行重复创建
*/
String str3 = "hello";
System.out.println( str1 == str3);//结果为ture
内容是否相同
使用equals进行字符串内容的比较,必须大小写一致,equalsIgnoreCase,忽略大小写判断内容是否一致
是否以子字符串开始或者结束
str1.startsWith(str2) //是否以str2开始,str1.endsWith(str2) //是否以str2结束
Stringbuffer
StringBuffer是可变长的字符串
常用方法:append()追加,delete ()删除,insert() 插入,reverse() 反转
StringBuffer维护了一个长度16的字符数组。这个字符数组,留有冗余长度比如说new StringBuffer(“hello”),其内部的字符数组的长度是21,而不是5,这样调用插入和追加,在现成的数组的基础上就可以完成了。如果追加的长度超过了21,就会分配一个新的数组,长度比原来多一些,把原来的数据复制到新的数组中,看上去 数组长度就变长了length: “hello”的长度 5,capacity: 分配的总空间 21,21这个数量,不同的JDK数量是不一样的
练习题
1)自然对数e的计算
借助Math的方法,把自然对数计算出来,看看经过自己计算的自然对数和Math.E的区别有多大
/***
*自然对数的计算方式
*/
public class Exercise {
public static void main(String[] args){
double myE = 1;
int n = Integer.MAX_VALUE;
System.out.println("系 统:\t"+Math.E);
for (int i = 1; i < n; i++) {
myE = myE * (1+(double)1/n);
}
System.out.println("计算的:\t"+myE);
}
}
2)质数计算
统计找出一千万以内,一共有多少质数,质数概念: 只能被1和自己整除的数
/***
*质数计算
* 使用这个Math.sqrt(i),提高效率(不太好理解)
*/
public class Exercise {
public static void main(String[] args){
long start = System.currentTimeMillis();
int count = 0;
boolean isPrimeNumber = true;
for (int i = 2; i <= 10000000; i++) {
// if(i%2==0 && i!=2){continue;}
for (int j = 2; j <= Math.sqrt(i); j++) {
if(i%j == 0){
isPrimeNumber = false;
break;
}
}
if(isPrimeNumber){
count++;
}else{
isPrimeNumber = true;
}
}
System.out.printf("千万以内的质数数量:%d%n",count);
long end = System.currentTimeMillis();
System.out.printf("花费时间: %sms" , (end - start));
}
}
3)练习-Character
通过Scanner从控制台读取字符串,然后把字符串转换为字符数组
参考的转换方式:char[] cs = str.toCharArray();
转换为字符数组后,筛选出控制台读取到的字符串中的大写字母和数字,并打印出来
import java.util.Scanner;
/***
*
* 使练习-Character
*/
public class Exercise {
public static void main(String[] args){
Scanner scanner = new Scanner(System.in);
System.out.println("请输入字符串:");
String str = scanner.nextLine();
char[] ch = str.toCharArray();
for (char c : ch) {
if (Character.isUpperCase(c) || Character.isDigit(c)) {
System.out.print(c + "\t");
}
}
}
}
4)练习-随机字符串
创建一个长度是5的随机字符串,随机字符有可能是数字,大写字母或者小写字母
提示:创建随机数字,然后ASCII码转成字符
/***
*48-57数组 65-90大写 97-122小写
* 使练习-Character
*/
public class Exercise {
public static void main(String[] args) {
char[] c = new char[16];
for (int i = 0; i < c.length; i++) {
while (true) {
char rd = (char) (Math.random() * 74 + 48);
//此处也可以用isDigit判断数字,用isLetter判断是不是字母
if ((rd >= 48 && rd <= 57) || (rd >= 65 && rd <= 90) || (rd >= 97 && rd <= 122)) {
c[i] = rd;
break;
}
}
}
System.out.print(String.valueOf(c));
}
}
5)练习-字符串数组排序
创建一个长度是8的字符串数组,使用8个长度是5的随机字符串初始化这个数组,对这个数组进行排序,按 照每个字符串的首字母排序(无视大小写)
注1: 不能使用Arrays.sort() 要自己写
注2: 无视大小写
import java.util.Arrays;
/**
*48-57数字 65-90大写 97-122小写
* 练习-字符串数组排序
*/
public class Exercise {
public static void main(String[] args) {
String[] str = new String[20];
for (int i = 0; i < str.length; i++) {
str[i] = getString();
}
System.out.println(Arrays.toString(str));
sort(str);
System.out.println(Arrays.toString(str));
}
public static String getString() {
char[] c = new char[5];
for (int i = 0; i < c.length; i++) {
while (true) {
char rd = (char) (Math.random() * 74 + 48);
//此处也可以用isDigit判断数字,用isLetter判断是不是字母
if (Character.isDigit(rd) || Character.isLetter(rd)) {
c[i] = rd;
break;
}
}
}
return String.valueOf(c);
}
public static void sort(String[] str) {
String temp ;
for (int i = 0; i < str.length-1; i++) {
for (int j = 0; j < str.length-1-i; j++) {
//忽略大小写就是都转换成小写或大写比较,数值转换大小写不变
if(Character.toLowerCase(str[j].charAt(0)) > Character.toLowerCase(str[j+1].charAt(0))){
temp = str[j];
str[j] = str[j+1];
str[j+1] = temp;
}
}
}
}
}
6)练习-穷举法破解密码
生成一个长度是3的随机字符串,把这个字符串作为当做密码,使用穷举法生成长度是3的字符串,匹配 上述生成的密码
要求: 分别使用多层for循环 和 递归解决上述问题
import java.util.Arrays;
/**
* 三位数密码破解
* 穷举法
*/
public class Exercise {
public static void main(String[] args) {
String str = getString(3);
char[] c = new char[3];//存放待比较的密码
System.out.println(str);
String code = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
// System.out.println(code.substring(1,2));
for (int i = 0; i < 62; i++) {
for (int j = 0; j < 62; j++) {
for (int k = 0; k < 62; k++) {
c[0] = code.charAt(i);
c[1] = code.charAt(j);
c[2] = code.charAt(k);
String str1 = String.valueOf(c);
if (str.equals(str1)) {
System.out.printf("密码为:%s", str1);
i = 62; //猜到密码就终止
j = 62; //猜到密码就终止
break; //猜到密码就终止
}
}
}
}
}
public static String getString(int len) {
char[] c = new char[len];
for (int i = 0; i < c.length; i++) {
while (true) {
char rd = (char) (Math.random() * 74 + 48);
//此处也可以用isDigit判断数字,用isLetter判断是不是字母
if (Character.isDigit(rd) || Character.isLetter(rd)) {
c[i] = rd;
break;
}
}
}
return String.valueOf(c);
}
}
6-1)练习-递归法破解密码
import java.util.Arrays;
/**
* 三位数密码破解
* 递归法
*/
public class Exercise {
public static void main(String[] args) {
String str = getString(3);
String found = new String("");
char[] c = new char[3];//存放待比较的密码
System.out.printf("生成密码为:%s%n",str);
found = getPass(str,found);
System.out.printf("破解密码为:%s%n",found);
}
public static String getString(int len) {
char[] c = new char[len];
for (int i = 0; i < c.length; i++) {
while (true) {
char rd = (char) (Math.random() * 74 + 48);
//此处也可以用isDigit判断数字,用isLetter判断是不是字母
if (Character.isDigit(rd) || Character.isLetter(rd)) {
c[i] = rd;
break;
}
}
}
return String.valueOf(c);
}
/**
* 这个递归是单趟的
* 执行逻辑:
* 1、调用getpass传递随机密码和破解密码
* 2、比较两个密码是否相等
* 不相等的话,遍历62次循环去找出第一个字符
* 如果找到字符,把字符拼接在found里,并且递归进行下一个字符的查找
* 三次递归完成后pass.equals(found)就为true
* 如果找不到字符,return"该密码中包含了特殊字符"
* 相等的话,return一个破解的密码
*
* @param pass 传递进去系统生成的随机密码
* @param found 传递进去破解的密码,首次传递空字符串,
* 第二次递归进去传递的是找到的第一个字符,
* 依次类推,三次递归,就会把found填充到三个字符,也就是密码
* @return 返回破解后的密码
*/
public static String getPass(String pass,String found){
String code = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
if(!pass.equals(found)) {
char[] passChar = pass.toCharArray();
for (int i = 0; i < 62; i++) {
//因为found每次递归完都会给增加一个字符,所以他的length是递增的
//刚好用来指示比较的是哪一个索引
if (passChar[found.length()] == code.charAt(i)) {
found = found + code.charAt(i);
return getPass(pass, found);
}
}
return "该密码中包含了特殊字符";
}
else{
return found;
}
}
}
7)练习-每个单词的首字母都转换为大写
给出一句英文句子: “let there be light”,得到一个新的字符串,每个单词的首字母都转换为大写
import java.util.Arrays;
/**
* 每个单词的首字母都转换为大写
* 65-90大写 97-122小写
*/
public class Exercise {
public static void main(String[] args) {
String str = "you don't have to worry anymore about the window being resized";
System.out.println(str);
String[] strArray = str.split(" ");//以空格分割成字符串数组
for (int i = 0; i < strArray.length; i++) {
if (Character.isLowerCase(strArray[i].charAt(0))) {
char c = Character.toUpperCase(strArray[i].charAt(0));
//第一个字符转换为大写后,必须再转换成字符串,才能使用在replaceFirst中
String firstCharToString = Character.toString(c);
//正则表示式,意思只要第一个字符是a-z全部换成大写
strArray[i] = strArray[i].replaceFirst("[a-z]", firstCharToString);
}
}
String str3 ="";
for (int i = 0; i < strArray.length; i++) {
//最终此处应该使用StringBuffer
str3 = str3 + strArray[i]+" ";
}
System.out.println(str3);
}
}
8)练习-统计以p开头的单词数
peter piper picked a peck of pickled peppers,统计这段绕口令有多少个以p开头的单词
import java.util.Arrays;
/**
* 统计以p开头的单词数
* 65-90大写 97-122小写
*/
public class Exercise {
public static void main(String[] args) {
String str = "peter piper picked a peck of pickled peppers";
System.out.println(str);
int count = 0;
String[] strArray = str.split(" ");//以空格分割成字符串数组
for (int i = 0; i < strArray.length; i++) {
if (strArray[i].charAt(0) == 'p') {
count++;
}
}
System.out.printf("一共有%s个以p开头的单词%n",count);
}
}
9)练习-间隔大写小写模式
把 lengendary 改成间隔大写小写模式,即 LeNgEnDaRy
/**
* 间隔大写小写模式
* 65-90大写 97-122小写
*/
public class Exercise {
public static void main(String[] args) {
String str = "lengendary";
String str1 = "";
System.out.println(str);
for (int i = 0; i < str.length(); i++) {
if (i % 2 == 0) {
str1 = str1 + str.substring(i, i + 1).toUpperCase();
} else {
str1 = str1 + str.substring(i, i + 1);
}
}
System.out.printf("转换后%s%n",str1);
}
}
10)练习-最后一个字母变大写
把 lengendary 最后一个字母变大写
/**
* 最后一个字母变大写
* 65-90大写 97-122小写
*/
public class Exercise {
public static void main(String[] args) {
String str = "lengendary";
String str1 = "";
System.out.println(str);
str1 = str.substring(0,str.length()-1) +Character.toUpperCase(str.charAt(str.length()-1));
System.out.printf("转换后%s%n",str1);
}
}
11)练习-把最后一个目标单词首字母大写
Nature has given us that two ears, two eyes, and but one tongue, to the end that we should hear and see more than we speak,把最后一个two单词首字母大写
/**
* 把最后一个targetString单词首字母大写
* 65-90大写 97-122小写
*/
public class Exercise {
public static void main(String[] args) {
String targetString = "and";
String str = "Nature has given us that two ears, two eyes, and but one tongue" +
", to the end that we should hear and see more than we speak";
String str1 = "";
int index = 0;
System.out.printf("转换后%s%n",str);
index = str.lastIndexOf(targetString);
//目标字符前面字符串+目标字符转大写+目标字符后面的字符串
str1 = str.substring(0,index) + Character.toUpperCase(str.charAt(index))+str.substring(index+1);
System.out.printf("转换后%s%n",str1);
}
}
12)练习-比较字符串
创建一个长度是100的字符串数组,使用长度是2的随机字符填充该字符串数组,统计这个字符串数组里 重复的字符串有多少种
import java.util.Random;
/**
* 比较字符串
* 65-90大写 97-122小写
*/
public class Exercise {
public static void main(String[] args) {
String base = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
String[] strArray = new String[100];
for (int i = 0; i < strArray.length; i++) {
Random rand = new Random();
strArray[i] = "" + base.charAt(rand.nextInt(62)) +
base.charAt(rand.nextInt(62));
System.out.print(strArray[i] + " ");
if ((i + 1) % 20 == 0) {
System.out.println();
}
}
// String[] strArray = {"jh","jh","fg","jh","ds","jh","jh","jh","fg","bv","jh"};
for (int i = 0; i < strArray.length; i++) {
int count = 1;
for (int j = i + 1; j < strArray.length; j++) {
if (strArray[i].equals("")) {//如果是空串不比较,跳过进行下一个元素比较
break;
} else {
if (strArray[i].equals(strArray[j])) {
strArray[j] = "";//把重复字符串置空,让再循环到该空串时,跳过,避免重复比较
count++;
}
}
}
if (count != 1) {
System.out.printf("%s的重复数为%d%n", strArray[i], count);
}
}
}
}
13)练习-StringBuffer性能
生成10位长度的随机字符串,分别使用String的+和StringBuffer,连接10000个随机字符串,计算消耗的 时间
/**
* StringBuffer性能
* 65-90大写 97-122小写
*/
public class Exercise {
public static void main(String[] args) {
String base = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
String str = "";
StringBuffer sb = new StringBuffer();
long stime = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
str += getString(10);
}
long etime = System.currentTimeMillis();
System.out.printf("用+号总花费时间:%dms%n", etime - stime);
long stime1 = System.currentTimeMillis();
for (int i = 0; i < 10000; i++) {
sb.append(getString(10));
}
long etime1 = System.currentTimeMillis();
System.out.printf("用StringBuffer总花费时间:%dms%n", etime1 - stime1);
}
public static String getString(int len) {
char[] c = new char[len];
for (int i = 0; i < c.length; i++) {
while (true) {
char rd = (char) (Math.random() * 74 + 48);
//此处也可以用isDigit判断数字,用isLetter判断是不是字母
if (Character.isDigit(rd) || Character.isLetter(rd)) {
c[i] = rd;
break;
}
}
}
return String.valueOf(c);
}
}
14)练习-MyStringBuffer
Exercise.java
/**
* MyStringBuffer性能
* 65-90大写 97-122小写
*/
public class Exercise{
public static void main(String[] args) {
MyStringBuffer sb = new MyStringBuffer("abc");
System.out.println(sb.length());
System.out.println(sb.capacity());
System.out.println(sb.toString());
sb.append("123");
System.out.println(sb.length());
System.out.println(sb.capacity());
System.out.println(sb.toString());
sb.append("987654321");
System.out.println(sb.length());
System.out.println(sb.capacity());
System.out.println(sb.toString());
sb.append('w');
System.out.println(sb.length());
System.out.println(sb.capacity());
System.out.println(sb.toString());
sb.insert(4,'o');
System.out.println(sb.length());
System.out.println(sb.capacity());
System.out.println(sb.toString());
sb.insert(5,"WCO");
System.out.println(sb.length());
System.out.println(sb.capacity());
System.out.println(sb.toString());
sb.delete(5,8);
System.out.println(sb.length());
System.out.println(sb.capacity());
System.out.println(sb.toString());
sb.reverse();
System.out.println(sb.length());
System.out.println(sb.capacity());
System.out.println(sb.toString());
}
}
MyStringBuffer.java
public class MyStringBuffer implements InterfaceStringBuffer {
private char[] ch; //内部管理的个字符数组
private int len; // 全局都要使用的数组内有效元素的个数
public MyStringBuffer() {
ch = new char[16];//创建对象要默认创建一个大小16的空数组
}
public MyStringBuffer(String str) {
ch = new char[16];
append(str);//当创建对象时传递了一个字符串,则调用内部的append去添加
}
@Override
public void append(String str) {
insert(len,str);
}
@Override
public void append(char c) {
insert(len,c);
}
@Override
public void insert(int pos, char b) {
insert(pos,String.valueOf(b));
}
@Override
public void insert(int pos, String b) {
if(pos < 0 || pos>len){
return;
}
char[] c = b.toCharArray();
char[] temp = new char[capacity()];
while (len+c.length > temp.length){//一步一步扩容
temp = new char[temp.length*2 + 2];//原数组要进行扩容
}
System.arraycopy(ch, 0, temp, 0, pos);
System.arraycopy(c, 0, temp, pos, c.length);
System.arraycopy(ch, pos, temp, pos + c.length, len - pos);
ch = temp;
len = len + b.length();
}
@Override
public void delete(int start) {
delete(start,len);
}
@Override
public void delete(int start, int end) {
/*
* 总体思想就是清零ch数组
* 再把删除后的数组元素一个一个append进去
* 这样可以避免过分关注ch数组大小和有效元素的问题
* 全部由append去处理,最终还是由insert处理
* 所以insert一定要写全面一点
*/
if (end - start <= 0) {
return;
}
if (start < 0) {
return;
}
if (end > len) {
return;
}
char[] temp = ch; //把ch数组缓存
ch = new char[16];//ch数组清零
int lentemp = len;//长度缓存,到时循环时需要用到
len = 0;//ch都清零了,配套的len也得清零
for (int i = 0; i < start; i++) {
append(temp[i]);
}
for (int i = end; i < lentemp; i++) {
append(temp[i]);
}
}
@Override
public void reverse() {
char[] temp = new char[capacity()];
for (int i = 0; i < len; i++) {
System.arraycopy(ch, i, temp, len - 1 - i, 1);
}
ch = temp;
}
@Override
public int length() {
return len;
}
public int capacity() {
return ch.length;
}
public String toString() {
char[] temp = new char[len];
System.arraycopy(ch, 0, temp, 0, len);//避免打印后字符串后面有很多空字符
return String.valueOf(temp);
}
}
InterfaceStringBuffer.java
public interface InterfaceStringBuffer {
public void append(String str); //追加字符串
public void append(char c); //追加字符
public void insert(int pos,char b); //指定位置插入字符
public void insert(int pos,String b); //指定位置插入字符串
public void delete(int start); //从开始位置删除剩下的
public void delete(int start,int end); //从开始位置删除结束位置-1
public void reverse(); //反转
public int length(); //返回长度
}
6)输入输出
输入Scanner的使用
例:
//创建一个scanner对象
Scanner scanner = new Scanner(System.in);
System.out.println("请输入:");
String s = scanner.next();
System.out.println("您输入的是:" + s);
//关闭输入流,不关闭会一直占用资源
scanner.close();
next()和nextLine()的区别
next() 一定要输入有效字符才能结束,空格为结束标志
nextLine() 以回车作为结束标志
判断是否为指定数据类型
scanner.hasNextXXX 来检查输入的类型
读取了整数后,接着读取字符串
需要注意的是,如果在通过nextInt()读取了整数后,再接着读取字符串,读出来的是回车换行:“\r\n”,因为nextInt仅仅读取数字信息,而不会读取回车换行"\r\n".所以,如果在业务上需要读取了整数后,接着读取字符串,那么就应该连续执行两次nextLine(),第一次是取走回车换行,第二次才是读取真正的字符串
格式化输出
格式化
如果不使用格式化输出,就需要进行字符串连接,如果变量比较多,拼接就会显得繁琐
转 换 符 | 说 明 | 示 例 |
---|---|---|
%s | 字符串类型 | “string” |
%c | 字符类型 | ‘m’ |
%b | 布尔类型 | true |
%d | 整数类型(十进制) | 99 |
%x | 整数类型(十六进制) | FF |
%o | 整数类型(八进制) | 77 |
%f | 浮点类型 | 99.99 |
%a | 十六进制浮点类型 | FF.35AE |
%e | 指数类型 | 9.38e+5 |
%g | 通用浮点类型(f和e类型中较短的) | |
%h | 散列码 | |
%% | 百分比类型 | % |
%n | 换行符 | |
%tx | 日期与时间类型(x代表不同的日期与时间转换符) |
public class Exercise {
public static void main(String[] args) {
String name = "老张";
String gender = "男";
int age = 39;
int height = 170;
String info = "本人%s,%s,%d岁,身高%d";
System.out.printf(info, name, gender, age, height);
System.out.format(info, name, gender, age, height);
}
}
printf和format能够达到一模一样的效果,在printf中直接调用了format
//不同国家的千位分隔符
System.out.format(Locale.FRANCE,"%,.2f%n",Math.PI*10000);
System.out.format(Locale.US,"%,.2f%n",Math.PI*10000);
System.out.format(Locale.UK,"%,.2f%n",Math.PI*10000);
搭配转换符的标志,如图所示
标志 | 说 明 | 示 例 | 结 果 |
---|---|---|---|
+ | 为正数或者负数添加符号 | (“%+d”,15) | +15 |
− | 左对齐(5个空位,然后左对齐) | (“%-5d”,15) | |15 | |
0 | 数字前面补0 | (“%04d”, 99) | 0099 |
空格 | 在整数之前添加指定数量的空格 | (“% 4d”, 99) | | 99| |
, | 以“,”对数字分组 | (“%,f”, 9999.99) | 9,999.990000 |
( | 使用括号包含负数(正数没用) | (“%(f”, -99.99) | (99.990000) |
# | 如果是浮点数则包含小数点,如果是16进制或8进制则添加0x或0 | (“%#x”, 99)(“%#o”, 99) | 0x630143 |
< | 格式化前一个转换符所描述的参数 | (“%f和%❤️.2f”, 99.45) | 99.450000和99.45 |
$ | 被格式化的参数索引 | (“%1 d , d,%2 d,s”, 99,“abc”) | 99,abc |
常见日期和时间组合的格式,如图所示。
转 换 符 | 说 明 | 示 例 |
---|---|---|
c | 包括全部日期和时间信息 | 星期六 十月 27 14:21:20 CST 2007 |
F | “年-月-日”格式 | 2007-10-27 |
D | “月/日/年”格式 | 10/27/07 |
r | “HH:MM:SS PM”格式(12时制) | 02:25:51 下午 |
T | “HH:MM:SS”格式(24时制) | 14:28:16 |
R | “HH:MM”格式(24时制) | 14:28 |
日期格式转换符
转 换 符 | 说 明 | 示 例 |
---|---|---|
b | 月份简称 | Sep |
B | 月份全称 | September |
a | 星期简称 | Mon |
A | 星期全称 | Monday |
C | 年的前两位数字(不足两位前面补0) | 20 |
y | 年的后两位数字(不足两位前面补0) | 22 |
j | 一年中的天数(即年的第几天) | 076 |
m | 两位数字的月份(不足两位前面补0) | 03 |
d | 两位数字的日(不足两位前面补0) | 17 |
e | 月份的日(前面不补0) | 17 |
时间格式的转换符
转 换 符 | 说 明 | 示 例 |
---|---|---|
H | 2位数字24时制的小时(不足2位前面补0) | 15 |
I | 2位数字12时制的小时(不足2位前面补0) | 03 |
k | 2位数字24时制的小时(前面不补0) | 15 |
l | 2位数字12时制的小时(前面不补0) | 3 |
M | 2位数字的分钟(不足2位前面补0) | 03 |
S | 2位数字的秒(不足2位前面补0) | 09 |
L | 3位数字的毫秒(不足3位前面补0) | 015 |
N | 9位数字的毫秒数(不足9位前面补0) | 562000000 |
p | 小写字母的上午或下午标记 | 中:下午英:pm |
z | 相对于GMT的RFC822时区的偏移量 | +0800 |
Z | 时区缩写字符串 | CST |
s | 1970-1-1 00:00:00 到现在所经过的秒数 | 1193468128 |
Q | 1970-1-1 00:00:00 到现在所经过的毫秒数 | 1193468128984 |
换行符
换行符就是另起一行 — ‘\n’ 换行(newline),回车符就是回到一行的开头 — ‘\r’ 回车(return)
在idea里敲一个回车,实际上是回车换行符
然而在不同的操作系统,换行符是不一样的
(1)在DOS和Windows中,每行结尾是 “\r\n”;
(2)Linux系统里,每行结尾只有 “\n”;
(3)Mac系统里,每行结尾是只有 “\r”。
为了使得同一个java程序的换行符在所有的操作系统中都有一样的表现,使用%n,就可以做到平台无关的换行 System.out.printf("%n");
,注意一定要是printf而不是print
7)控制流程
表达式
表达式是由变量、运算符和方法调用组成的构造,这些构造根据语言的语法构造,计算结果为单个值
编写复合表达式时,要明确并用括号指出应首先计算哪些运算符。这种做法使代码更易于阅读和维护
语句
语句大致相当于自然语言中的句子。一条语句构成一个完整的执行单元。通过以分号 ( ;)结束表达式
还有另外两种语句:声明语句和控制流语句。声明语句声明一个变量,控制流语句控制语句执行的顺序
块
是一组位于一对大括号之间的零个或多个语句,可以在任何允许使用单个语句的地方使用。
顺序结构
程序从上往下一条一条执行
if选择结构
语法格式
if(布尔表达式){
//如果布尔表达式为true,则执行语句
}
if(布尔表达式){
//如果布尔表达式为true,则执行语句
}else{
//如果布尔表达式为false,则执行语句
}
if(布尔表达式1){
//如果布尔表达式1为true,则执行语句
}else if(布尔表达式2){
//如果布尔表达式2为true,则执行语句
}else if(布尔表达式3){
//如果布尔表达式3为true,则执行语句
}else{
//如果以上表达式都不为true,则执行语句
}
switch选择结构
switch可以使用byte,short,int,char,String,enum
String在Java1.7之前是不支持的, Java从1.7开始支持switch用String的,编译后是把String转化为hash值,其实还是整数
语法格式
switch(expression){
case value:
//语句
break;
case value:
//语句
break;
default:
//语句
}
while循环结构
语法结构
while(expression){
//只要表达式为真,一直执行语句,直到为false
}
do{
//至少执行一次的语句
}while(expression);
while先判断后执行语句,dowhile是先执行后判断
for循环结构
语句结构
for(初始化;布尔表达式;更新){
//代码
}
增强的for循环
语句结构
for(声明语句:表达式){
//代码块
}
声明语句:声明新的局部变量,该变量类型和数组元素类型一致,其值和此时数组元素值相等
表达式:要访问的数组名,或者是返回值为数组的方法
break、continue
break 结束整个循环
continue 结束本次循环
带标签的break和continue
标签是指后面跟一个冒号的标识符(不建议使用)
练习题
(1)计算0-100奇数和偶数的和
/***
* 计算0-100之间的奇数和偶数的和
*/
public class Exercise {
public static void main(String[] args) {
int oddSum = 0;
int evenSum = 0;
for (int i = 0; i <= 100; i++) {
if (i % 2 == 0) {
evenSum += i;
} else {
oddSum += i;
}
}
System.out.println("偶数和为:" + evenSum);
System.out.println("奇数和为:" + oddSum);
}
}
控制台输出
偶数和为:2450
奇数和为:2500
(2)计算BMI(肥胖指数)
根据键盘输入的身高体重,判断肥胖指数(BMI),BMI的计算公式是 体重(kg) / (身高*身高)
import java.util.Scanner;
/***
* 根据键盘输入的身高体重,判断肥胖指数(BMI)
*/
public class Exercise {
public static void main(String[] args) {
float bmi = 0f;
float weight = 0f;
float height = 0f;
Scanner scanner = new Scanner(System.in);
System.out.println("请输入体重(kg):");
weight = scanner.nextFloat();
System.out.println("请输入身高(m)");
height = scanner.nextFloat();
bmi = weight/(height * height);
if(bmi < 18.5){
System.out.println("当前BMI是:" + bmi);
System.out.println("身体状态是:体重过轻");
}else if(18.5 <= bmi && bmi < 24){
System.out.println("当前BMI是:" + bmi);
System.out.println("身体状态是:正常体重");
}else if(24 <= bmi && bmi < 27){
System.out.println("当前BMI是:" + bmi);
System.out.println("身体状态是:体重过重");
}else if(27 <= bmi && bmi < 30){
System.out.println("当前BMI是:" + bmi);
System.out.println("身体状态是:轻度肥胖");
}else if(30 <= bmi && bmi < 35){
System.out.println("当前BMI是:" + bmi);
System.out.println("身体状态是:中度肥胖");
}else {
System.out.println("当前BMI是:" + bmi);
System.out.println("身体状态是:重度肥胖");
}
}
}
控制台输出
请输入体重(kg):
85
请输入身高(m)
1.78
height = 1.78
weight = 85.0
当前BMI是:26.827423
身体状态是:体重过重
(3)判断某一年是否为闰年
通过Scanner输入一个年份,然后判断该年是否是闰年
闰年判断标准(满足任何一个)
1、如果能够被4整除,但是不能被100整除
2、能够被400整除
import java.util.Scanner;
/***
* 判断某一年是不是为闰年
*/
public class Exercise {
public static void main(String[] args) {
int year = 0;
Scanner scanner = new Scanner(System.in);
System.out.println("请输入年份:");
while (scanner.hasNextInt()) {
year = scanner.nextInt();
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
System.out.println(year + "是闰年");
} else {
System.out.println(year + "是平年");
}
System.out.println("请输入年份:");
}
}
}
控制台输出
请输入年份:
1990
1990是平年
(4)月份判断季节
通过Scanner输入月份,然后使用switch 判断季节
import java.util.Scanner;
/***
* 判断月份属于的季节
*/
public class Exercise {
public static void main(String[] args) throws Exception {
int month = 0;
Scanner scanner = new Scanner(System.in);
System.out.println("请输入月份:");
while (scanner.hasNextInt()) {
month = scanner.nextInt();
if (month>0 && month<=3) {
System.out.println(month + "月是春天");
} else if(month>3 && month<=6) {
System.out.println(month + "月是夏天");
}
else if(month>6 && month<=9) {
System.out.println(month + "月是秋天");
}
else if(month>9 && month<=12) {
System.out.println(month + "月是冬天");
}else {
System.out.println("!!!!!!!输入正确的月份!!!!!!!!");
}
System.out.println("请输入月份:");
}
System.out.println("输入了非法字符,程序退出");
}
}
(5)计算阶乘
通过Scanner获取一个整数,然后使用while计算这个整数的阶乘,N的阶乘等于 N* (N-1) * (N-2) * … * 1
import java.util.Scanner;
/***
* 计算阶乘
*/
public class Exercise {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输要计算的整数:");
while (scanner.hasNextInt()) {
long result = 1;
int i = scanner.nextInt();
while (i > 0) {
result *= i;
i -= 1;
}
System.out.println("结果为:" + result);
(6)细胞分裂
第一天1个,第二天2个,第三天4个,第四天8个,以此类推。求第十天有多少细胞?
/***
* 细胞分裂
*/
public class Exercise {
public static void main(String[] args) {
int day = 10;
long count = 1;
for (int i = 1; i <= day; i++) {
count = count * 2;
}
System.out.println(day + "天结束细胞总量为:" + count);
}
}
10天结束细胞总量为:1024
(7)被5整除的数
用while或for循环输出1-1000之间能被5整除的数,并且每行输出3个
/***
* 输出1-1000之间能被5整除的数,并且每行输出3个
*/
public class Exercise {
public static void main(String[] args) {
int num = 1000;
for (int i = 1; i < 1000; i++) {
if (i % 5 == 0){
System.out.print(i);
if(i % 3 == 0){
System.out.print("\n");//第三个数字结尾换行
}else {
System.out.print("\t");//另外两个数字结尾tab
}
}
}
}
}
(8)打印九九乘法表
/***
* 打印乘法表
*/
public class Exercise {
public static void main(String[] args) {
for (int i = 1; i <= 9; i++) {
for (int j = 1; j <= i; j++) {
System.out.print(j +"×" + i +"=" + i * j);
System.out.print("\t");
}
System.out.println();
}
}
}
(9)打印三角形
/***
* 打印三角形
*/
public class Exercise {
public static void main(String[] args) {
int line = 20;
for (int i = 0; i < line; i++) {
for (int j = line; j > i; j--) {
System.out.print(" ");
}
for (int j = 0; j < (2 * i + 1); j++) {
System.out.print("*");
}
System.out.println();
}
}
}
(10)利息计算
每年投资12000,投资回报率为20%,持续投资多少年,总收入达到100万。
复利公式:F = p* ( (1+r)^n ); (F 最终收入, p 本金 ,r 年利率 ,**n **存了多少年)
/***
* 每年投资12000,投资回报率为20%,持续投资多少年,总收入达到100万
*/
public class Exercise {
public static void main(String[] args) {
int assets = 0;
int principal = 0;
int investment = 12000;
float APR = 0.2f;
int year = 0;
while (assets<1000000){
principal = assets+investment;//年初向总资产中投入12000
assets=(int)(principal*(1+APR));//年末所得总资产
year++;
System.out.println("第"+year+"年总资产"+assets);
}
System.out.println("需要"+year+"年资产达到"+assets);
}
}
(11)寻找指定规则的数
寻找某两个数相除,其结果 离黄金分割点 0.618最近
分母和分子不能同时为偶数
分母和分子 取值范围在[1-20]
/***
* 寻找某两个数相除,其结果 离黄金分割点 0.618最近
*/
public class Exercise {
public static void main(String[] args) {
float f = 0f;
float resalt = 0f;
float preResalt = 1f;
int currentI = 0;
int currentJ = 0;
//只遍历了分母大于分子的数
for (int i = 1; i < 20; i++) {
for (int j = 20; j > i; j--) {
f = (float) i / j;
resalt = f - 0.618f;//每次相除后进行比较
resalt = (resalt > 0) ? resalt : -(resalt);//比较结果取绝对值(没用math)
if(resalt < preResalt){
preResalt = resalt; //如果比较值比上一次小,将结果替换
currentI = i;//记录当时最小时的i
currentJ = j;//记录当时最小时的j
}
}
}
System.out.println("离黄金分割两个数相除最近的是:"+currentI + "/" + currentJ + "=" + (float) currentI / currentJ);
}
}
(12)寻找所有的水仙花数
水仙花数定义:一定是3位数,每一位的立方,加起来恰好是这个数本身,比如153=1*1*1+5*5*5+3*3*3
/***
* 寻找所有的水仙花数
*/
public class HelloWorld {
public static void main(String[] args) {
int ge = 0;
int shi = 0;
int bai = 0;
for (int i = 100; i < 1000; i++) {
ge = i/1%10;
shi = i/10%10;
bai = i/100%10;
if(i == (ge*ge*ge)+(shi*shi*shi)+(bai*bai*bai)) {
System.out.println(i+"为水仙花数");
}
}
}
}
(13)小学算术题
求方框的数字
□ + □ = 8
+ +
□ - □ = 6
‖ ‖
14 10
/***
* 小学算术题
*/
public class HelloWorld {
public static void main(String[] args) {
int a = 0;//最大值8
int b = 0;//最大值8
int c = 0;//最大值14
int d = 0;//最大值10
for (a = 0; a <= 8; a++) {
for (b = 0; b <= 8; b++) {
for (c = 0; c <= 14; c++) {
for (d = 0; d <= 10; d++) {
if((a+b)==8&&(b+d)==10&&(c-d)==6&&(a+c)==14){
System.out.print(a+"\t");
System.out.print(b+"\t");
System.out.print(c+"\t");
System.out.print(d+"\t");
System.out.println();
}
}
}
}
}
}
}
结果3 5 11 5
8)数组
数组的声明与创建
数组是一个固定长度的,包含了相同类型数据的 容器
int[] a; 声明了一个数组变量,仅声明没创建
创建数组的时候,要指明数组的长度。new int[5];
数组下标从0开始,下标0,代表数组里的第一个数
.length属性用于访问一个数组的长度,数组访问下标范围是0到(长度-1),一旦超过这个范围,就会产生数组下标越界异常
初始化数组
//先创建,后赋值
int[] a = new int[5];
a[0] = 1;
//创建的同时赋值,两种写法
int[] a1 = new int[]{1,2,3,4};
int[] a2 = {1,2,3,4,5};
数组的使用
for each循环遍历数组
int[] a2 = {1,2,3,4,5};
for (int i:a2) {
System.out.println(i);
}
数组作为方法的参数
public static void meth(int[] i){
System.out.println(Arrays.toString(i));
}
数组做为返回值
public static int[] meth(int[] a){
int[] a1 = new int[a.length];
for (int i = 0; i < a.length ; i++) {
a1[i] = a[i]+10;
}
return a1;
}
二维数组
二维数组里面的每一个元素,都是一个一维数组,所以二维数组又叫数组的数组
int[][] a = new int[2][3];
a[1][2] = 5;
Arrays类
Arrays是针对数组的工具类,可以进行 排序,查找,复制填充等功能。 大大提高了开发人员的工作效率。
类里面为static的方法可以直接类名调用,
int[] a = new int[5];
Arrays.toString(a);//转换字符串
Arrays.copyOfRange(a, "0", "3")//复制数组
Arrays.toString(a)//数组排序
Arrays.binarySearch(a, 62)//搜索62在a数组中的位置,使用前必须给数组排序
Arrays.equals(a, b)//比较两个数组的内容是否一样
Arrays.fill(a, 5)//使用5填充数组
数组排序
选择排序,把第一位和其他所有的进行比较,只要比第一位小的,就换到第一个位置来比较完后,第一位就是最小的然后再从第二位和剩余的其他所有进行比较,只要比第二位小,就换到第二个位置来比较完后,第二位就是第二小的,依次类推
import java.util.Arrays;
/***
* 选择排序
*/
public class Exercise {
public static void main(String[] args) {
int[] array = new int[5] ;
for (int i = 0; i < array.length-1; i++) {
int rdom = (int) (Math.random() * 100);
array[i] = rdom;
}
System.out.println("原数组"+Arrays.toString(array));
int[] array2 = sort(array);
System.out.println("排序后"+Arrays.toString(array2));
}
public static int[] sort(int[] a){
int temp;
for (int i = 0; i < a.length-1 ; i++) {
//后一次进入大循环比较的循环往后推移一个元素,所以j = i+1
for (int j = i+1; j < a.length ; j++) {
if(a[i] > a[j]){
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
}
return a;
}
}
冒泡排序,第一步:从第一位开始,把相邻两位进行比较如果发现前面的比后面的大,就把大的数据交换在后面,循环比较完毕后,最后一位就是最大的第二步: 再来一次,只不过不用比较最后一位
import java.util.Arrays;
/***
* 冒泡排序
*/
public class Exercise {
public static void main(String[] args) {
int[] array = new int[5] ;
for (int i = 0; i < array.length-1; i++) {
int rdom = (int) (Math.random() * 100);
array[i] = rdom;
}
System.out.println("原数组"+Arrays.toString(array));
int[] array2 = sort(array);
System.out.println("排序后"+Arrays.toString(array2));
}
public static int[] sort(int[] a){
int temp;
for (int i = 0; i < a.length-1 ; i++) {
for (int j = 0; j < a.length-1-i ; j++) {
if(a[j] > a[j+1]){
temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
System.out.println("显示每一步"+Arrays.toString(a));
}
}
}
return a;
}
}
稀疏数组
保存一个二维数组时,如果里面很多默认值为零或同一个值,因此记录了很多没有意义的数,使用稀疏数组可以解决这个问题
稀疏数组的处理方式
-
记录数组一共有几行几列,有多少个不同值
-
把具有不同值的元素和行列及值记录在一个小规模的数组中,从而缩小程序的规模
import java.util.Arrays;
/***
* 稀疏数组
*
*
* | 原数组行数 | 原数组列数 | 原数组有效数值个数
* |------------|-------------|-------------
* |有效值1所在行 | 有效值1所在列 | 有效值1的值
* |有效值2所在行 | 有效值2所在列 | 有效值2的值
* |有效值3所在行 | 有效值3所在列 | 有效值3的值
* |有效值4所在行 | 有效值4所在列 | 有效值4的值
* |有效值5所在行 | 有效值5所在列 | 有效值5的值
*
*/
public class Exercise {
public static void main(String[] args) {
int[][] array = new int[10][11];
array[8][8] = -6;
array[2][9] = 5;
array[6][2] = 18;
array[7][3] = 8;
array[9][2] = 3;
array[4][1] = 6;
System.out.println("原数组");
printArray(array);
int[][] array1 = compressArray(array);
System.out.println("压缩后的数组");
printArray(array1);
int[][] array2 = uncompressArray(array1);
System.out.println("解压后的数组");
printArray(array2);
}
public static int[][] compressArray(int[][] a) {
//获取原数组有效数值的个数
int sum = 0;
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a[0].length; j++) {
if (a[i][j] != 0) {
sum++;
}
}
}
int[][] array = new int[sum + 1][3];
array[0][0] = a.length;
array[0][1] = a[0].length;
array[0][2] = sum;
int k = 1;
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a[0].length; j++) {
if (a[i][j] != 0) {
array[k][0] = i;
array[k][1] = j;
array[k][2] = a[i][j];
k++;
}
}
}
return array;
}
public static int[][] uncompressArray(int[][] a) {
int[][] array = new int[a[0][0]][a[0][1]];
int k = 1 ;
for (int i = 1; i <a.length ; i++) {
array[a[i][0]][a[i][1]] = a[i][2];
}
return array;
}
public static void printArray(int[][] a) {
for (int i = 0; i < a.length; i++) {
for (int j = 0; j < a[0].length; j++) {
System.out.print(a[i][j] + "\t");
}
System.out.println();
}
}
}
练习题
1)找出数组最小值
首先创建一个长度是5的数组,并填充随机数,通过for循环,遍历数组,找出最小的一个值出来。
import java.util.Arrays;
/***
*求最小值
*/
public class Exercise {
public static void main(String[] args) {
int[] array = new int[5];
int min = 0;
array[0] = (int) (Math.random() * 100);
array[1] = (int) (Math.random() * 100);
array[2] = (int) (Math.random() * 100);
array[3] = (int) (Math.random() * 100);
array[4] = (int) (Math.random() * 100);
min = array[0];
for (int i = 0; i < array.length; i++) {
if(min > array[i]){
min = array[i];
}
System.out.print(array[i]+"\t");
}
System.out.println();
System.out.println("最小值为:"+min);
}
}
2)反转数组
首先创建一个长度是5的数组,并填充随机数,使用for循环或者while循环,对这个数组实现反转效果
import java.util.Arrays;
/***
*反转数组
*/
public class Exercise {
public static void main(String[] args) {
int[] array = new int[5];
int temp;
array[0] = (int) (Math.random() * 100);
array[1] = (int) (Math.random() * 100);
array[2] = (int) (Math.random() * 100);
array[3] = (int) (Math.random() * 100);
array[4] = (int) (Math.random() * 100);
System.out.println("原数组:"+ Arrays.toString(array));
for (int i = 0; i < array.length/2; i++) {
temp = array[i];
array[i] = array[array.length - 1 - i];
array[array.length - 1 - i] = temp;
}
System.out.println("反转数组:"+ Arrays.toString(array));
}
}
3)数组排序
首先创建一个长度是5的数组,并填充随机数,首先用选择法正排序,然后再对其使用冒泡法倒排序
如上!
4)找出数组最大值
首先创建一个长度是5的数组,并填充随机数,用增强型for循环找出最大的那个数
和最小值的一样,大于号变小于号
5)合并数组
首先准备两个数组,他俩的长度是5-10之间的随机数,并使用随机数初始化这两个数组,然后准备第三个数组,第三个数组的长度是前两个的和,通过System.arraycopy 把前两个数组合并到第三个数组中
import java.util.Arrays;
/***
* 合并数组
*使用System.arraycopy复制两个数组到新的数组
*/
public class Exercise {
public static void main(String[] args) {
int[] array = new int[5];
int[] array1 = new int[10];
for (int i = 0; i < array.length; i++) {
array[i] = (int) (Math.random() * 100);
}
for (int i = 0; i < array1.length; i++) {
array1[i] = (int) (Math.random() * 100);
}
int[] array2 = new int[array.length+array1.length];
System.out.println("array >>>>"+Arrays.toString(array));
System.out.println("array1 >>>>"+Arrays.toString(array1));
System.arraycopy(array,0,array2,0,array.length);
System.arraycopy(array1,0,array2,array.length,array1.length);
System.out.print("array2 >>>>"+Arrays.toString(array2));
}
}
6)二维数组最大值
定义一个5X5的二维数组。 然后使用随机数填充该二维数组。找出这个二维数组里,最大的那个值,并打印出其二维坐标
import java.util.Arrays;
/***
* 二维数组最大值
*/
public class Exercise {
public static void main(String[] args) {
int[][] array = new int[5][5];
int[] max = new int[3]; //存储最大值和坐标
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[0].length; j++) {
array[i][j] = (int) (Math.random() * 100);
System.out.print(array[i][j]+"\t");
}
System.out.println();
}
max[2] = array[0][0];
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[0].length; j++) {
if(array[i][j] > max[2]){
max[0] = i;
max[1] = j;
max[2] = array[i][j];
}
}
}
System.out.println("最大值为:"+max[2]+"坐标为:"+max[0]+","+max[1]);
}
}
7)二维数组排序
首先定义一个5X8的二维数组,然后使用随机数填充满。借助Arrays的方法对二维数组进行排序。
import java.util.Arrays;
/***
* 二维数组排序
*/
public class Exercise {
public static void main(String[] args) {
int[][] array = new int[10][5];
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[0].length; j++) {
array[i][j] = (int) (Math.random() * 100);
System.out.print(array[i][j]+"\t");
}
System.out.println();
}
//将生成的二维数组变成一维数组
int[] a = new int[array.length*array[0].length];
for (int i = 0; i < array.length; i++) {
System.arraycopy(array[i],0,a,array[i].length*i,array[i].length);
}
Arrays.sort(a);
System.out.println(Arrays.toString(a));
//将排好序的一维数组写入二维数组中
int k = 0;
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[0].length; j++) {
array[i][j] = a[k];
k++;
System.out.print(array[i][j]+"\t");
}
System.out.println();
}
}
}