JAVA核心技术I---JAVA基本程序设计结构
一:讨论一个简单的Java程序
package hello; public class Hello { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub System.out.println("We will not use 'Hello World'!"); } }
注意:
(0)命名统一
源代码的文件名必须与公共类的名字相同
(1)关键字class
关键字class表明Java程序全部内容都包含在类中,这里,只需要将类作为一个加载程序逻辑的容器,程序逻辑定义了程序的行为
(2)命名方法
采用驼峰命名法"ClassName"
(3)main方法
Java语言规范:main方法必须声明public,不过当main不是public时,某些Java解释器依旧可以执行,这是一个不予理会的bug
(4)编译执行
编译:javac 文件名.java ---->类名.class 执行:java 类名(无后缀) ----->注意:可能我们需要到父级目录进行调用 java hello.Hello
(5)println方法
将一个文本行输入到控制台,输出后换行
其实在System.out中也有print方法,不过不会自动换行
(6)注释(同C)
// 行注释 /**/ 段注释
二:基本数据类型
Java是一种强类型语言,不同于Python脚本语言,和C/C++一样必须对每一个变量声明一种类型。其一共有8中基本类型:
4种整型
2种浮点类型
1种表示Unicode编码字符单元的字符类型char
1种表示真值的布尔类型
补充:
Java有一个可以表示任意精度的算术包,通常称为“大数值”,但是不是一种java类型,而是一个java对象
(一)整型
与C/C++不同,java中类型大小五目标平台无关
而且java中没有任何无符号形式的int,long,short,byte类型
(二)浮点型
溢出和出错情况下的三个特殊浮点数值:
正无穷
负无穷
NaN
(三)字符型
Java中,char类型用UTF-16编码描述一个代码单元
(四)布尔类型
true和false
三:变量
(一)变量声明定义
逐一声明每个变量可以很好提高程序可读性 int i,j;不出错,但是不提倡
在java中变量的声明可以放在任何地方,尽量放在靠近变量第一次使用的地方
不同于C/C++,在java中不区分变量的声明和定义 C/C++中 int i = 10; 是定义 extern int i; 是声明
(二)常量final
关键字final表示该变量只能被赋值一次,之后不允许修改,一般常量全用大写 final double CM_PER_INCH = 2.54 public static final double CM_PER_INCH = 2.54 声明类常量
在C/C++中使用const作为常量定义。const是java的保留字
四:类型转换
小转大,无丢失,大转小可能出现丢失数据,同大小,类型不同转换有可能有丢失
强制转换
(cast)强制转换 double x = 9.997 int nx = (int)x nx-->9将小数部分截断 注意:强制转换可能会将数值严重丢失精度
五:枚举类型(是一个类)
enum Size { SMALL, MEDIUM, LARGE, EXTRA_LARGE }; public class Hello { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Size s = Size.SMALL; System.out.println(s); } }
六:字符串
Java没有内置字符串类型,但是在标准类库中提供了一个预定义类String。每个用双引号括起来的字符串都是一个String实例 String e = "dafaw";
拼接:
1.使用+号 2.使用join进行路径拼接 String.join("/","C:","pro")--->C:/pro
java不能对字符串直接操作修改
同python一样对于字符串使用常量方式存储,虽然每次都需要创建一个新的字符串才行,但是原来的字符串,可以被编译器实现字符串共享,可以提高效率。
将各种字符串存放在公共存储池中。字符串变量指向存储池中的相应位置。如果复制一个字符串变量,原始字符串与复制字符串共享相同的字符
而且,java设计者认为共享带来的高效率远远高于提取,拼接字符串。一般程序中,很少需要修改字符串,而是往往需要对字符串进行比较
会自动进行内存回收
注意:只有字符串常量是共享的,对于使用+拼接的字符串或者substring等操作产生的结果并不是共享的。只有对于共享的字符串常量,才可以使用==运算符进行检测是否相等
String h = "Hello"; if(h == "Hello") { System.out.println("equal h"); #可以输出 } if((h+"b")=="Hellob") { System.out.println("equal hb"); #不可以输出 } if(h.substring(0,3)=="Hel") { System.out.println("equal hs"); #不可以输出 }
空串和Null串
空串有自己的长度0和内容"" if(str.length() == 0) if(str.equals("")) null表示该变量没有和任何对象关联 if(str==null)
码点和代码单元
代码点(Code Point)和代码单元(Code Unit)
char 码点和代码单元
代码点(Code Point):Unicode是属于编码字符集(CCS)的范围。
Unicode所做的事情就是将我们需要表示的字符表中的每个字符映射成一个数字,这个数字被称为相应字符的码点(code point)。
例如“严”字在Unicode中对应的码点是U+0x4E25。
“𝕆”在Unicode中对应的码点就是\uD835\uDD46两个代码单元
String h = "Hello"; int n = h.length(); //5 int m = h.codePointCount(0, h.length()); //获取码点数量 int index = h.offsetByCodePoints(0, 3); //码点偏移 System.out.println(h.charAt(index)); //获取码点处的代码单元 l
深入了解代码点和代码单元
码点:就是某个任意字符在Unicode编码表中对应的代码值(详细可以看看上面提到的)
代码单元:是在计算机中用来表示码点的,大部分码点只需要一个代码单元表示,但是有一些是需要两个代码单元表示的。
String h = "\uD835\uDD46Hello"; // 𝕆Hello System.out.println(h); int n = h.length(); //7 int m = h.codePointCount(0, h.length()); //获取码点数量 6 //int index = h.offsetByCodePoints(0, 3); //码点偏移 System.out.println(m); //获取码点处的代码单元 l System.out.println(h.charAt(6)); //o
𝕆Hello码点数量为6,但是代码单元为7,因为“𝕆”这一个代码点占有两个代码单元
System.out.println(h.charAt(0)); //?无法正常输出那个两个代码单元的符号
对于使用两个代码单元表示的字符:
int cp = h.codePointAt(0); //120134 获取代码点值 一般大于0x10000就是在增补字符范围内,需要两个代码单元
if(Character.isSupplementaryCodePoint(cp)) #我们可以通过判断代码点值是否在增补字符范围内来判断输出方法
七:输入输出
(一)读取输入
要想通过控制台进行输入,首先需要构造一个Scanner对象,并与“标准输入流”System.in相互关联
Scanner in = new Scanner(System.in);
import java.util.Scanner;
public class Hello { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Scanner in = new Scanner(System.in); System.out.println("Who are you?"); String name = in.nextLine(); //读取一行next()读取下一个单词,hasnext()是否还有下一个单词,hasNextInt,hasNextDouble() System.out.println("How old are you?"); int age = in.nextInt(); //读取一个整数,nextDouble是读取下一个浮点数 System.out.println("Hello,"+name+". Next year,you wiil be "+(age+1)); } }
Scanner类的输入是可见的,因此不适用于从控制台读取密码。不过可以使用Console类,注意:Console类的使用与底层平台有关,在IDE上cons可能为null
import java.io.Console; public static void main(String[] args) { // TODO Auto-generated method stub Console cons=System.console(); if(cons!=null) { String username = cons.readLine("Username:"); char[] passwd = cons.readPassword("Password:"); System.out.println("username:"+username+" Password:"+passwd); }else{ System.out.println("console==null"); } }
java Console 控制台为null问题 Console con = System.console()
(二)printf格式化输出
索引:类似于正则%开始$结束
import java.util.Date;
System.out.printf("%1$s %2$tB %2$te,%2$tY","Due date:",new Date()); #注意:索引是从1开始 %1$s---->将第一个参数"Due date:"用s格式输出
%2$tB--->将第二个参数new Date() t代表转换字符,B代表转换字符中月份的完整拼写
te --->转换两位数的日期
tY --->转换四位数年份
Due date: 七月 15,2018
补充:<标志:说明前面格式的参数将再次被使用
System.out.printf("%s %tB %<te,%<tY","Due date:",new Date());
%<te前面格式的参数是new Date()再次被使用
(三)文件的输入与输出
读取文件
import java.io.IOException; import java.nio.file.Paths; import java.util.Date; import java.util.Scanner; public class Hello { /** * @param args */ public static void main(String[] args) throws IOException #必须捕获异常 { // TODO Auto-generated method stub Scanner in = new Scanner(Paths.get("C:\\cfg.ini"), "UTF-8"); System.out.println(in.nextLine()); } }
写入文件
public class Hello { /** * @param args */ public static void main(String[] args) throws IOException { // TODO Auto-generated method stub PrintWriter out = new PrintWriter("cfg.ini", "UTF-8"); //写在当前项目目录根目录下 out.write("dddddd"); } }
八:控制流程
(一)while计算多长时间才能够存储一定数量的退休金
public class Hello { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Scanner in = new Scanner(System.in); System.out.println("目标金额:"); double goal = in.nextDouble(); System.out.println("每年存入金额:"); double payment = in.nextDouble(); System.out.println("每年利率:"); double interestRate = in.nextDouble(); double balance = 0; int year = 0; while(balance < goal) { balance += payment; double interest = balance*interestRate/100; balance += interest; year ++; } System.out.println("需要"+year+"年"); } }
(二)do....while
do { balance += payment; double interest = balance*interestRate/100; balance += interest; year ++; System.out.printf("After year %d,your balance is %,.2f%n",year,balance); System.out.println("Ready to retired?(Y/N)"); input = in.next(); }while(input.equals("N"));
(三)for是while的一种简化
public class Hello { /** * @param args */ public static void main(String[] args) throws IOException { // TODO Auto-generated method stub Scanner in = new Scanner(System.in); System.out.println("目标金额:"); double goal = in.nextDouble(); System.out.println("每年存入金额:"); double payment = in.nextDouble(); System.out.println("每年利率:"); double interestRate = in.nextDouble(); double balance = 0; int year = 0; for(year=1;balance < goal;year++) { balance += payment; double interest = balance*interestRate/100; balance += interest; System.out.printf("After year %d,your balance is %,.2f%n",year,balance); } System.out.println("需要"+(year-1)+"年"); } }
注意:
在循环中,检测两个浮点数是否相等需要格外小心。 for(double x=0;x!=10;x += 0.1)... 可能永远不会结束,由于输入的误差,最终可能得不到精确值。因为0.1无法精确用二进制表示,所以,x将从9.999 999 999 999 98跳到10.099 999 999 9999 98
(四)switch多重选择
(五)break中断
九:大数值
如果基本的整数和浮点数精度不能够满足需求,那就可以使用java.math包中的两个很有用的的类:BigInteger和BigDecimal
这两个类可以处理包含任意长度数字序列的数值
使用静态方法valueof可以将普通的数值转换为大数值
BigInteger a = BigInteger.valueOf(100);
不能用算术运算符处理大数值。而是需要使用大数值类中的add和multiply等方法
处理在字符串连接重载了+,其他地方Java中没有重载运算符
(一)使用案例490个数中抽取60个,抽中的概率
import java.math.BigInteger;
public class Hello { /** * @param args */ public static void main(String[] args) throws IOException { Scanner in = new Scanner(System.in); System.out.println("How many numbers do you need to draw?"); int k = in.nextInt(); System.out.println("what is the highest number you can draw?"); int n = in.nextInt(); BigInteger lotteryOdds = BigInteger.valueOf(1); for(int i=1;i <= k;i++) { lotteryOdds = lotteryOdds.multiply(BigInteger.valueOf(n-i+1)).divide(BigInteger.valueOf(i)); } System.out.println("Yours odds asr 1/"+lotteryOdds+" ,Good luck!"); } }
How many numbers do you need to draw? 60 what is the highest number you can draw? 490 Yours odds asr 1/716395843461995557415116222540092933411717612789263493493351013459481104668848 ,Good luck!
十:数组
(一)数组创建
int[] a; 声明数组 int[] a = new int[100]; 创建数组
创建数字数组时,所有元素被初始化为0.Boolean会被初始化为false,对象数组全部为null(还未存放对象) 对象数组:String[] names = new String[10]; 会创建一个包含10个字符串的数组,所有的字符串都为null。若是希望都为空串,使用for循环进行赋值为"" 注意:一旦创建数组,不能在修改大小。若是想要进行扩展,可以参考另一种数据结构----数组列表
(二)for each循环
for (variable : collection) statement
注意:当我们想要打印全部的数组信息时,可以使用toString()方法
Arrays.toString(a) 会打印处所有的元素--->"[n1,n2,.....nn]"以字符串形式返回
(三)数组初始化
一:像上面使用new初始 int[] a = new int[100]; 二:创建数组时,直接初始化 int[] a = {2,3,5,7};
(四)匿名数组
new int[] {12,3,44,5} 这种语法形式可以在不创建新变量的情况下重新初始化一个数组。
int[] a = {2,3,5,7};
a = new int[] {17,12,15,13};
(五)数组拷贝
浅拷贝
int[] a = {2,3,5,7}; int[] smallPrimes = a; //浅拷贝 smallPrimes[2] = 15; System.out.println(Arrays.toString(a)); //[2, 3, 15, 7]
深拷贝
int[] a = {2,3,5,7}; int[] smallPrimes = Arrays.copyOf(a, 2*a.length); smallPrimes[2] = 15; System.out.println(Arrays.toString(a)); //[2, 3, 5, 7] System.out.println(Arrays.toString(smallPrimes)); //[2, 3, 15, 7, 0, 0, 0, 0]多余的元素将被赋值为0,布尔型则全部为false
(六)与C/C++比较
java数组与C/C++中的数组指针相似
int[] a = new int[100] ---> int* a = new int[100] java中的[]被用于检测数组边界,而且没有指针运算,不能使用a + 1 将指针下移得到下一个元素
(七)命令行参数
public static void main(String[] args)
在java中程序名没有存储在args数组中
java 程序名 参数一 参数二
会将后面两个参数存放在args中,在C/C++中会将程序名一块传入
(八)数组排序
Arrays.sort(a)使用了优化的快排序算法
(九)实例随机获取数组中几个值
public static void main(String[] args) throws IOException { Scanner in = new Scanner(System.in); System.out.println("what is the higest number to draw?"); int n = in.nextInt(); System.out.println("How many number to draw?"); int k = in.nextInt(); int[] numbers = new int[n]; //1-n for(int i=0;i<numbers.length;i++) { numbers[i] = i + 1; } int[] result = new int[k]; for(int i=0;i<result.length;i++) { int r = (int)(Math.random()*n); result[i] = numbers[r]; numbers[r] = numbers[n-1]; n--; } Arrays.sort(result); System.out.println(Arrays.toString(result)); }
what is the higest number to draw? 450 How many number to draw? 12 [20, 51, 72, 136, 179, 231, 256, 316, 363, 377, 420, 431]
(十)二维数组
double[][] balances; 声明 balances = new double[4][4]; 初始化 int[][] magicSquare = 初始化 { {16,3,2,1}, {45,12,1,3}, {46,24,0,13}, {3,4,9,67}, }
Arrays.deepToString(balance) 快速打印
(十一)二维数组案例:不同利率下的投资增长情况
public static void main(String[] args) throws IOException { final double STARTRATE = 10; final int NRATES = 6; final int NYEARS = 10; double[] interestRate = new double[NRATES]; //利率数组 for(int i=0;i<interestRate.length;i++) { interestRate[i] = (STARTRATE+i)/100; } double[][] balances = new double[NYEARS][NRATES]; //设置第一年的存储资金 for(int j=0;j<balances[0].length;j++) { balances[0][j] = 10000; } //开始循环增长 for(int i=1;i<balances.length;i++) { for(int j=0;j<balances[i].length;j++) { double oldBalance = balances[i-1][j]; double interest = oldBalance * interestRate[j]; balances[i][j] = oldBalance + interest; } } //打印出来增长率先 for(int i=0;i<interestRate.length;i++) { System.out.printf("%9.0f%%", 100*interestRate[i]); } System.out.println(); //换行 //打印出来增长数据 for(double[] row:balances) { for(double bal:row) { System.out.printf("%10.2f",bal); } System.out.println(); } }
10% 11% 12% 13% 14% 15% 10000.00 10000.00 10000.00 10000.00 10000.00 10000.00 11000.00 11100.00 11200.00 11300.00 11400.00 11500.00 12100.00 12321.00 12544.00 12769.00 12996.00 13225.00 13310.00 13676.31 14049.28 14428.97 14815.44 15208.75 14641.00 15180.70 15735.19 16304.74 16889.60 17490.06 16105.10 16850.58 17623.42 18424.35 19254.15 20113.57 17715.61 18704.15 19738.23 20819.52 21949.73 23130.61 19487.17 20761.60 22106.81 23526.05 25022.69 26600.20 21435.89 23045.38 24759.63 26584.44 28525.86 30590.23 23579.48 25580.37 27730.79 30040.42 32519.49 35178.76
(十二)不规则数组(打印杨辉三角)
public static void main(String[] args) throws IOException { final int NMAX = 10; //分配内存 int[][] odds = new int[NMAX][]; for(int i=0;i<NMAX;i++) { odds[i] = new int[i+1]; } //设置值 for(int i=0;i<odds.length;i++) { for(int j=0;j<odds[i].length;j++) { int val = 1; if(j>=1 && j<odds[i].length-1) { val = odds[i-1][j-1] + odds[i-1][j]; } odds[i][j] = val; } } //打印值 for(int i=0;i<odds.length;i++) { for(int j=0;j<odds[i].length;j++) { System.out.printf("%4d",odds[i][j]); } System.out.println(); } }
1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 1 5 10 10 5 1 1 6 15 20 15 6 1 1 7 21 35 35 21 7 1 1 8 28 56 70 56 28 8 1 1 9 36 84 126 126 84 36 9 1
JAVA中:
double[][] balances = new double[10][6];
不同于
double balances[10][6]; 数组
不同于
double (*balances)[6] = new double[10][6];
而是分配了一个包含10个指针的数组
double ** balances = new double*[10]
然后指针数组的每一个元素都被填充一个包含6个数字的数组
for(i=0;i<10;i++){
balances[i] = new double[6];
}
注意:
我们在使用某些方法时候需要import相关包文件,使用eclipse提示Alt + /补全代码会自动在文件前面为我们加上包名