注释
在 Java 中根据注释的功能不同,主要分为单行注释、多行注释和文档注释。
? 单行注释
单行注释使用“//”开头。
? 多行注释
多行注释以“/*”开头以“*/”结尾。注意,多行注释不能嵌套使用。
? 文档注释
文档注释以“/**”开头以“*/”结尾,注释中包含一些说明性的文字及一些JavaDoc 标签(后期写项目时,可以生成项目的 API)
标识符和关键字
标识符是用来给变量、类、方法以及包进行命名的。
4 大规则:
1. 必须以字母、下划线_、美元符号$开头。
2. 其它部分可以是字母、下划线“_”、美元符“$”和数字的任意组合。
3. 大小写敏感,且长度无限制。
4. 不可以是 Java 的关键字。
标识符的使用规范
? 表示类名的标识符:每个单词的首字母大写,如 Man, GoodMan
? 表示方法和变量的标识符:第一个单词小写,从第二个单词开始首字母大写,我们称之为“驼峰原则”,如 eat(), eatFood()
变量
变量的本质
1. 变量本质上就是代表一个”可操作的存储空间”,空间位置是确定的,但是里面放置什么值不确定。
2. 可通过变量名来访问“对应的存储空间”,从而操纵这个“存储空间”存储的值。
3. Java 是一种强类型语言,每个变量都必须声明其数据类型。变量的数据类型决定了变量占据存储空间的大小。 比如,int a=3; 表示 a 变量的空间大小为 4 个字节。
变量的分类和作用域
变量有三种类型:局部变量、成员变量(也称为实例变量)和静态变量。
常量
在 Java 语言中,用关键字 final 来定义一个常量。常量一旦被初始化后不能再更改。
变量和常量命名规范
? 所有变量、方法、类名:见名知义
? 类成员变量:首字母小写和驼峰原则: monthSalary
? 局部变量:首字母小写和驼峰原则
? 常量:大写字母和下划线:MAX_VALUE
? 类名:首字母大写和驼峰原则: Man, GoodMan
? 方法名:首字母小写和驼峰原则: run(), runRun()
基本数据类型
Java 数据类型分为两大类:基本数据类型(primitive data type)和引用数据类型(reference data type)。
转义字符
运算符
二元运算符的运算规则:
整数运算:
? 如果两个操作数有一个为 long, 则结果也为 long。
? 没有 long 时,结果为 int。即使操作数全为 short,byte,结果也是 int。
浮点运算:
? 如果两个操作数有一个为 double,则结果为 double。
? 只有两个操作数都是 float,则结果才为 float。
取模运算:
? 其操作数可以为浮点数,一般使用整数,结果是“余数”,“余数”符号和左边操作数相同,如:7%3=1,-7%3=-1,7%-3=1。
数据类型的转换
基本类型转化时常见错误和问题
1. 操作比较大的数时,要留意是否溢出,尤其是整数操作时。
2. L 和 l 的问题:
(1) 不要命名名字为 l 的变量,字母 l 容易和数字 1 混淆。
(2) long 类型使用大写 L,不要用小写 l。
控制语句:把语句组合成能完成一定功能的小逻辑模块。它分为三类:顺序、选择和循环。学会控制语句,是真正跨入编程界的“门槛”,是成为“程序猿”的“门票”。
1. “顺序结构”代表“先执行 a,再执行 b”的逻辑。比如,先找个女朋友,再给女朋友打电话;先订婚,再结婚;
2. “条件判断结构”代表“如果…,则…”的逻辑。比如,如果女朋友来电,则迅速接电话;如果看到红灯,则停车;
3. “循环结构”代表“如果…,则重复执行…”的逻辑。比如,如果没打通女朋友电话,则再继续打一次; 如果没找到喜欢的人,则再继续找。
条件判断结构(选择结构)
条件判断结构有:if 结构和 switch 结构。而 if 结构又可以分为 if 单分支结构、if-else 双分支结构、if-else if-else 多分支结构。
新手雷区
1. 如果 if 语句不写{},则只能作用于后面的第一条语句。
2. 强烈建议,任何时候都写上{},即使里面只有一句话!
if 单分支结构
if-else 双分支结构
if-else if-else 多分支结构
switch 语句
switch 多分支结构(多值情况)
语法结构:
switch (表达式) {
case 值 1:
语句块 1;
[break];
case 值 2:
语句块 2;
[break];
… … … … …
[default:
默认语句块;]
}
1. switch 会根据表达式的值从相匹配的 case 标签处开始执行,一直执行到 break 处或者是 switch 的末尾。如果表达式的值与任一 case 值不匹配,则进入 default 语句。
2. switch 中表达式的值,是 int(byte、short、char 也可,long 不行)、枚举,字符串。
switch 接收字符串(JDK7 新特性)
String str = "audi";
switch (str){
case "audi":
System.out.println("我买了个奥迪车");
break;
case "benz":
System.out.println("我买了个奔驰车");
break;
default:
System.out.println("比亚迪,挺好!");
}
循环结构
循环结构分两大类,一类是当型,一类是直到型。
? 当型:
当布尔表达式条件为 true 时,反复执行某语句,当布尔表达式的值为 false 时才停止循环,比如:while 与 for 循环。
? 直到型:
先执行某语句, 再判断布尔表达式,如果为 true,再执行某语句,如此反复,直到布尔表达式条件为 false 时才停止循环,比如 do-while 循环。
while 循环
do-while 循环
循环结构(for)
逗号运算符
public class Test11 {
public static void main(String[ ] args) {
for(int i = 1, j = i + 10; i < 5; i++, j = i * 2) {
System.out.println("i= " + i + " j= " + j);
}
}
}
无限循环
public class Test12 {
public static void main(String[ ] args) {
for ( ; ; ) { // 无限循环: 相当于 while(true)
System.out.println("北京尚学堂");
}
}
}
嵌套循环
public class Test15 {
public static void main(String args[ ]) {
for (int i = 1; i < 10; i++) { // i 是一个乘数
for (int j = 1; j <= i; j++) { // j 是另一个乘数
System.out.print(j + "*" + i + "=" + (i * j < 10 ? (" " + i * j) : i * j) + "
");
}
System.out.println();
}
}
}
break 语句和 continue 语句
1. break 用于强行退出整个循环
2. continue 用于结束本次循环,继续下一次
带标签的 continue 语句
“标签”是指后面跟一个冒号的标识符,例如:“label:”。对 Java 来说唯一用到标签的地方是在循环语句之前。
“goto 有害”论中,最有问题的就是标签,而非 goto,随着标签在一个程序里数量的增多,产生错误的机会也越来越多。但 Java 标签不会造成这方面的问题,因为它们的活动场所已被限死,不可通过特别的方式到处传递程序的控制权。
//控制嵌套循环跳转(打印 101-150 之间所有的质数)
public class Test18 {
public static void main(String args[ ]) {
outer: for (int i = 101; i < 150; i++) {
for (int j = 2; j < i / 2; j++) {
if (i % j == 0){
continue outer; //符合某条件,跳到外部循环继续
}
}
System.out.print(i + " ");
}
}
}
语句块
语句块(也叫复合语句)。语句块中定义的变量只能用于自己,外部不能使用。
语句块可以使用外部的变量,而外部不能使用语句块的变量;
public class Test19 {
public static void main(String[ ] args) {
int n;
int a;
{
int k;
int n; //编译错误:不能重复定义变量 n
} //变量 k 的作用域到此为止
}
}
方法
1. 方法(method):一段用来完成特定功能的代码片段,类似于其它语言的函数(function)。
2. 方法用于定义该类或该类的实例的行为特征和功能实现。
3. 面向过程中,函数是最基本单位,整个程序由一个个函数调用组成。
4. 面向对象中,整个程序的基本单位是类,方法是从属于类和对象的。
方法的详细说明
? 形式参数:在方法声明时用于接收外界传入的数据。(方法定义时)
? 实参:调用方法时实际传给方法的数据。 (方法调用时)
? 返回值:执行完毕后,返还给调用它的环境的数据。? 返回值类型:事先约定的返回值的数据类型,如无返回值,则为 void。
注意事项
? 实参必须和形参列表匹配。
? return:终止方法运行,并返回的数据。
? Java 中传递参数,遵循值传递的原则(传递的都是数据的副本):
? 基本类型传递的是该数据值的 copy 值。
? 引用类型传递的是该对象引用的 copy 值,但指向的是同一个对象。
递归结构
递归结构包括两个部分:
? 定义递归头。 解决:什么时候不调用自身方法。如果没有头,将陷入死循环,也就是递归的结束条件。
? 递归体。 解决:什么时候需要调用自身方法。
public class Test22 {
public static void main(String[ ] args) {
long d1 = System.currentTimeMillis();
factorial(10);
long d2 = System.currentTimeMillis();
System.out.printf("递归费时:"+(d2-d1)); //耗时:32ms
}
/** 求阶乘的方法*/
static long factorial(int n){
if(n==1){//递归头
return 1;
}else{//递归体
return n*factorial(n-1);//n! = n * (n-1)!
}
}
}
递归的缺陷
算法简单是递归的优点之一。但是递归调用会占用大量的系统堆栈,内存耗用多,在递归调
用层次多时速度要比循环慢的多,所以在使用递归时要慎重。
数组的定义
数组是相同类型数据的有序集合。其中,每一个数据称作一个元素,每个元素可以通过一个索引(下标)来访问它们。数组的四个基本特点:
1. 长度是确定的。数组一旦被创建,它的大小就是不可以改变的。
2. 其元素的类型必须是相同类型,不允许出现混合类型。
3. 数组类型可以是任何数据类型,包括基本类型和引用类型。
4. 数组变量属于引用类型,数组也是对象,数组中的元素相当于对象的属性!
创建数组和初始化
数组的声明方式(以一维数组为例)
type[ ] arr_name; //方式一
type arr_name[ ]; //方式二
注意事项
? 声明的时候并没有实例化任何对象,只有在实例化数组对象时,JVM 才分配空间,这时才与长度有关。
? 声明一个数组的时候并没有数组真正被创建。
? 构造一个数组,必须指定长度。
初始化
数组的初始化方式总共有三种:静态初始化、动态初始化、默认初始化。
1. 静态初始化
除了用 new 关键字来产生数组以外,还可以直接在定义数组的同时就为数组元素分配空间并赋值
int [ ] a = { 1, 2, 3 };// 静态初始化基本类型数组;
Man[ ] mans = { new Man(1, 1), new Man(2, 2) };// 静态初始化引用类型数组;
2.动态初始化
数组定义与为数组元素分配空间并赋值的操作分开进行。
int[ ] a1 = new int[2];//动态初始化数组,先分配空间;
a1[0]=1;//给数组元素赋值;
a1[1]=2;//给数组元素赋值;
3.数组的默认初始化
数组是对象,它的元素相当于对象的属性;每个元素也按照属性的方式被默认初始化
int a2[ ] = new int[2]; // 默认值:0,0
boolean[ ] b = new boolean[2]; // 默认值:false,false
String[ ] s = new String[2]; // 默认值:null, null
数组常见操作
1. 遍历指的就是“通过循环遍历数组的所有元素”。
2. 拷贝指的是将某个数组的内容拷贝到另一个数组中
注:实质上,容器的扩容就是“数组的拷贝”。
public class Test {
public static void main(String[ ] args) {
int[ ] a = new int[4];
//初始化数组元素的值
for(int i=0;i<a.length;i++){
a[i] = 100*i;
}
//读取元素的值
for(int i=0;i<a.length;i++){
System.out.println(a[i]);
}
}
}
for-each 循环
for-each 专门用于读取数组或容器中所有的元素。
public class Test {
public static void main(String[ ] args) {
String[ ] ss = { "aa", "bbb", "ccc", "ddd" };
for (String temp : ss) {
System.out.println(temp);
}
}
}
注意事项
? for-each 增强 for 循环在遍历数组过程中不能修改数组中某元素的值。
? for-each 仅适用于遍历,不涉及有关索引(下标)的操作。
数组的拷贝
System.arraycopy(object src,int srcpos,object dest, int destpos,int length)
该方法可以将 src 数组里的元素值赋给 dest 数组的元素,其中 srcpos 指定从 src 数组的第几个
元素 开始赋值,length 参数指定将 src 数组的多少个元素赋给 dest 数组的元素。
public class Test {
public static void main(String args[ ]) {
String[ ] s = {"阿里","尚学堂","京东","搜狐","网易"};
String[ ] sBak = new String[6];
System.arraycopy(s,0,sBak,0,s.length);
for (int i = 0; i < sBak.length; i++) {
System.out.print(sBak[i]+ "\t");
}
}
}
java.util.Arrays 类
Arrays 类包含了:排序、查找、填充、打印内容等常见的数组操作。
import java.util.Arrays;
public class Test {
public static void main(String args[ ]) {
int[ ] a = { 1, 2 };
System.out.println(a); // 打印数组引用的值;
System.out.println(Arrays.toString(a)); // 打印数组元素的值;
}
}
菜鸟雷区
此处的 Arrays.toString()方法是 Arrays 类的静态方法,不是前面讲的 Object 的 toString()
方法。
import java.util.Arrays;
public class Test {
public static void main(String args[ ]) {
int[ ] a = {1,2,323,23,543,12,59};
System.out.println(Arrays.toString(a));
Arrays.sort(a);
System.out.println(Arrays.toString(a));
}
}
import java.util.Arrays;
public class Test {
public static void main(String[ ] args) {
int[ ] a = {1,2,323,23,543,12,59};
System.out.println(Arrays.toString(a));
Arrays.sort(a); //使用二分法查找,必须先对数组进行排序;
System.out.println(Arrays.toString(a));
//返回排序后新的索引位置,若未找到返回负数。
System.out.println("该元素的索引:"+Arrays.binarySearch(a, 12));
}
}
import java.util.Arrays;
public class Test {
public static void main(String[ ] args) {
int[ ] a= {1,2,323,23,543,12,59};
System.out.println(Arrays.toString(a));
Arrays.fill(a, 2, 4, 100); //将2到4索引的元素替换为100;
System.out.println(Arrays.toString(a));
}
}
多维数组
多维数组可以看成以数组为元素的数组。可以有二维、三维、甚至更多维数组,但是实际开发中用
的非常少。最多到二维数组(学习容器后,我们一般使用容器,二维数组用的都很少)。
public class Test {
public static void main(String[ ] args) {
// Java中多维数组的声明和初始化应按从低维到高维的顺序进行
int[ ][ ] a = new int[3][ ];
a[0] = new int[2];
a[1] = new int[4];
a[2] = new int[3];
// int a1[ ][ ]=new int[ ][4];//非法
}
}
public class Test {
public static void main(String[ ] args) {
int[ ][ ] a = { { 1, 2, 3 }, { 3, 4 }, { 3, 5, 6, 7 } };
System.out.println(a[2][3]);
}
}
import java.util.Arrays;
public class Test {
public static void main(String[ ] args) {
int[ ][ ] a = new int[3][ ];
// a[0] = {1,2,5}; //错误,没有声明类型就初始化
a[0] = new int[ ] { 1, 2 };
a[1] = new int[ ] { 2, 2 };
a[2] = new int[ ] { 2, 2, 3, 4 };
System.out.println(a[2][3]);
System.out.println(Arrays.toString(a[0]));
System.out.println(Arrays.toString(a[1]));
System.out.println(Arrays.toString(a[2]));
}
}
数组存储表格数据
我们观察表格,发现每一行可以使用一个一维数组存储:
Object[ ] a1 = {1001,"高淇",18,"讲师","2-14"};
Object[ ] a2 = {1002,"高小七",19,"助教","10-10"};
Object[ ] a3 = {1003,"高小琴",20,"班主任","5-5"};
注意事项
? 此处基本数据类型”1001”,本质不是 Object 对象。JAVA 编译器会自动把基本数据类型“自动装箱”成包装类对象。大家在下一章学了包装类后就懂了。
这样我们只需要再定义一个二维数组,将上面 3 个数组放入即可:
Object[ ][ ] emps = new Object[3][ ];
emps[0] = a1;
emps[1] = a2;
emps[2] = a3;
import java.util.Arrays;
public class Test {
public static void main(String[ ] args) {
Object[ ] a1 = {1001,"高淇",18,"讲师","2-14"};
Object[ ] a2 = {1002,"高小七",19,"助教","10-10"};
Object[ ] a3 = {1003,"高小琴",20,"班主任","5-5"};
Object[ ][ ] emps = new Object[3][ ];
emps[0] = a1;
emps[1] = a2;
emps[2] = a3;
System.out.println(Arrays.toString(emps[0]));
System.out.println(Arrays.toString(emps[1]));
System.out.println(Arrays.toString(emps[2]));
}
}
使用 javabean 和一维数组保存表格信息
import java.util.Arrays;
public class Test {
public static void main(String[ ] args) {
Emp[] emps = {
new Emp(1001,"高淇",18,"讲师","2-14"),
new Emp(1002,"高小七",19,"助教","10-10"),
new Emp(1003,"高小八",20,"班主任","5-5")
};
for (Emp e:emps){
System.out.println(e);
}
}
}
class Emp {
private int id;
private String name;
private int age;
private String job;
private String hiredate;
public Emp(int id, String name, int age, String job, String hiredate) {
this.id = id;
this.name = name;
this.age = age;
this.job = job;
this.hiredate = hiredate;
}
@Override
public String toString() {
return "["+id+","+name+","+age+","+job+","+hiredate+"]";
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String 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 String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public String getHiredate() {
return hiredate;
}
public void setHiredate(String hiredate) {
this.hiredate = hiredate;
}
}
Comparable 接口(定义比较策略)
多个对象做比较,就要有“比较规则”,然后实现排序。
事实上,java 中排序算法的底层也依赖 Comparable 接口。
Comparable 接口中只有一个方法:
public int compareTo(Object obj) obj 为要比较的对象
方法中,将当前对象和 obj 这个对象进行比较,如果大于返回 1,等于返回 0,小于返回-1. (此处的 1 也可以是正整数,-1 也可以是负整数)。 compareTo 方法的代码也比较固定:
/**
* 测试Comparable接口
*/
public class TestComparable {
public static void main(String[] args) {
Man[ ] msMans = { new Man(3, "a"), new Man(60, "b"), new Man(2, "c") };
Arrays.sort(msMans);
System.out.println(Arrays.toString(msMans));
}
}
class Man implements Comparable{
int age;
int id;
String name;
public Man(int age,String name) {
super();
this.age = age;
this.id = id;
this.name = name;
}
@Override
public String toString() {
return this.name;
}
@Override
public int compareTo(Object o) {
Man man = (Man) o;
if (this.age < man.age) {
return -1;
}
if (this.age > man.age) {
return 1;
}
return 0;
}
}