Java的基本语法
- Java代码的基本格式
修饰符 class 类名 {
程序代码
}
- 一个Java源文件只定义一个类,不同的类使用不同的源文件定义;将每个源文件中单独定义的类都定义成public的;保持Java源文件的主文件名与源文件中的类名一致。
- Java中的程序代码可分为结构定义语句和功能执行语句,其中,结构定义语句用于声明一个类或方法,功能执行语句用于实现具体的功能。
- 代码都定义在类中,类由class来定义,代码严格区分大小写,Java程序中一句连续的字符串不能分开在两行中书写。
- main方法的作用:
程序的入口
保证程序的独立运行
被JVM调用
- Java中的注释
注释是对程序的某个功能或者某行代码的解释说明
多行注释和文档注释都不能嵌套使用。
行注释//
块注释/*...*/
文档注释/** ... */
- Java中的标识符
为了增强阅读性自定义的名称
如,包名、类名、方法名、参数名、变量名等,这些符号被称为标识符。
- 作用:给类和方法 变量取名
- 规则
1、包名所有字母一律小写。例如:com.li.test。
2、类名和接口名每个单词的首字母都要大写。如:ArrayList、Iterator。
3、常量名所有字母都大写,单词之间用下划线连接。例如:DAY_OF_MONTH。
4、变量名和方法名的第一个单词首字母小写,从第二个单词开始每个单词首字母大写。例如:lineNumber、getLineNumber。
5、在程序中,应该尽量使用有意义的英文单词来定义标识符,使得程序便于阅读。例如使用userName表示用户名,password表示密码。
- 驼峰标识
类名每个单词首字母大写
变量和方法名从第二个单词开始每个单词首字母大写
命名常量全大写,多个单词用下划线隔开
- Java中的关键字
所有的关键字都是小写的。
程序中的标识符不能以关键字命名。
有特殊含义的单词(50)
能用的(48)
public - 公开的(访问修饰符)
private - 私有的(访问修饰符)
protected - 受保护的(访问修饰符)
new - 创建对象的运算符
void - 空的(方法没有返回值返回类型就是void)
return - 返回(方法中用于返回一个值)
if / else - 分支结构
switch / case / default - 等值判断的多分支结构
abstract - 抽象的(定义抽象类和抽象方法)
throw - 抛出异常对象
throws - 声明异常
try / catch - 尝试执行捕获异常
finally - 定义总是执行代码块(释放外部资源)
do - 循环结构
while - 循环结构
for - 循环结构
break - 终止循环
continue - 让循环进入下一轮
this - 代表当前对象(当前对象的引用)
super - 代表父类对象(父类类对象的引用)
static - 静态的(静态属性、静态方法、静态代码块、静态内部类)
enum - 声明枚举(有限个常量)
class - 声明类
interface - 声明接口
extends - 继承(Java中只允许单继承)
implements - 实现接口
final - 最终的(常量、终结类、终结方法)
byte / short / int / long - 整型
float / double - 实型
char - 字符型
boolean - 布尔型
instanceof - 运行时类型识别的运算符
native - 定义本地方法(用C写的方法)
import - 导入包/类
package - 建包(解决命名冲突)
synchronized - 同步(方法、同步代码块)
transient - 临时的/短暂的(放在属性前表示不需要序列化)
assert - 断言
strictfp - 声明严格浮点运算
volatile - 易挥发的/不稳定的(防止编译器错误的优化假设)
不能用的(2)
goto
const
- Java中的常量
常量就是在程序中固定不变的值,是不能改变的数据。
包括整型、浮点、字符、布尔、字符串、null常量
- 特殊字符--反斜杠\
被称为转义字符,它的作用是用来转义后面一个字符
\r 表示回车,\n 表示换行,\t 表示制表符,\b 表示退格符号
\' 表示单引号字符,\" 表示双引号字符,\\ 表示反斜杠字符
- 整型常量进制间的转换
十进制转换成二进制就是一个除以2取余数的过程。
二进制转十进制要从右到左用二进制位上的每个数去乘以2的相应次方
二进制转八进制时,首先需要将二进制数自右向左每三位分成一段,然后将二进制的每段的三位数转为八进制的一位。
二进制转十六进制时,与转八进制类似,不同的是要将二进制数每四位分成一段,查表转换即可。
Java中的变量
- 变量的定义
在程序运行期间,随时可能产生一些临时数据,应用程序会将这些数据保存在一些内存单元中,每个内存单元都用一个标识符来标识。这些内存单元我们称之为变量,定义的标识符就是变量名,内存单元中存储的数据就是变量的值。
- 为什么要定义变量:用来不断的存放同一类型的常量,并可以重复使用;
- 定义变量的格式:数据类型 变量名 = 初始化值;
- 分类
- 局部变量
定义在方法内或者语句块内 从属于方法或者语句块使用之前,必须手动初始化,没有默认初始化值
- 成员(全局)变量
定义在类里面、方法外面。从属于对象。作用于整个类中如果没有手动初始化成员变量,系统会自动初始化。初始化的规则如下:数字:0,0.0 布尔 false char \u0000 引用类型 :null
- 静态变量
定义在类里面 、方法外面、使用static修饰,从属于类,可以使用类名.变量名直接调用
如果没有手动初始化静态变量,系统会自动初始化,初始化规则同成员变量一样。
-
变量的数据类型
- 基本数据类型---<4 种整数型区别主要在每个数据在内存中占用的空间大小和代表的数值的范围。>
整数类型(byte short int long)
浮点数(float double)
字符型char
布尔型boolean
- 引用数据类型(4个字节)
类class,接口interface,数组,对象,枚举enum,注解annotation
- 变量的类型转换
将一个类型的数据转变为另一种类型的数据
- 向上转型(隐式类型转换或自动类型转换)
容量小的类型可自动转换为容量大的数据类型;
byte,short,char → int → long → float → double
byte,short,char之间不会相互转换,他们在计算时首先会转换为int类型。
boolean 类型是不可以转换为其他基本数据类型。
要实现自动类型转换,必须同时满足两个条件,
第一是两种数据类型彼此兼容,
第二是目标类型的取值范围大于源类型的取值范围。
Eg:
int i = 123;
long l = i; //自动转换,不需强转
float f = 3.14F;
double d = f;
- 向下转型(显式类型转换或强制类型转换)
当两种类型彼此不兼容,或者目标类型取值范围小于源类型时,自动类型转换无法进行,这时就需要进行强制类型转换。
格式:目标类型 变量 = (目标类型) 值
Eg:
long l = 123L;
int i = (int) l;//必须强转
double d = 3.14;
float f = (float) d;
- 变量的作用域
定义开始到定义它的代码块结束
- 实例变量和类变量的区别
1.存放位置:类变量随着类的加载而存在于方法区中。
实例变量随着对象的建立而寻在于堆内存中
2.生命周期:类变量生命周期最长,随着类的消失而消失
实例变量生命周期随着对象的消失而消失
Java中的运行符
- 算术运行符
+ - * / % ++ --
- 赋值运行符
= += -= *= /= %=
- 比较运行符
== != < > <= >=
-
逻辑运行符
- &与 |或 !非 &&短路与 ||短路或
(1)逻辑运算符可以针对结果为布尔值的表达式进行运算。如:x > 3 && y != 0。
(2)运算符“&”和“&&”都表示与操作,当且仅当运算符两边的操作数都为true时,其结果才为true,否则结果为false。当运算符“&”和“&&”的右边为表达式时,两者在使用上还有一定的区别。在使用“&”进行运算时,不论左边为true或者false,右边的表达式都会进行运算。如果使用“&&”进行运算,当左边为false时,右边的表达式不会进行运算,因此“&&”被称作短路与
(3)运算符“|”和“||”都表示或操作,当运算符两边的操作数任何一边的值为true时,其结果为true,当两边的值都为false时,其结果才为false。同与操作类似,“||”表示短路或,当运算符“||”的左边为true时,右边的表达式不会进行运算。
(4)运算符“^”表示异或操作,当运算符两边的布尔值相同时(都为true或都为false),其结果为false。当两边布尔值不相同时,其结果为true。
-
位运行符
- &按位与 |按位或 ~取反 <<左移 >>右移 >>>无符号右移
(1)与运算符“&”是将参与运算的两个二进制数进行与运算,如果两个二进制位都为1,则该位的运算结果为1,否则为0。
(2)位运算符“|”是将参与运算的两个二进制数进行“或”运算,如果二进制位上有一个值为1,则该位的运行结果为1,否则为0。
(3)位运算符“~”只针对一个操作数进行操作,如果二进制位是0,则取反值为1;如果是1,则取反值为0。
(4)位运算符“^”是将参与运算的两个二进制数进行“异或”运算,如果二进制位相同,则值为0,否则为1。
(5)位运算符“<<”就是将操作数所有二进制位向左移动一位。运算时,右边的空位补0。左边移走的部分舍去。
(6)位运算符“>>“就是将操作数所有二进制位向右移动一位。运算时,左边的空位根据原数的符号位补0或者1(原来是负数就补1,是正数就补0)。
(7)位运算符“>>>”就是将操作数所有二进制位向右移动一位。运算时,左边的空位补0(不考虑原数正负)。
- 条件运算符(三目运算符)
判断条件 ? 表达式1 : 表达式2
其他
new创建对象instanceof运行时类型识别()强制类型转换、改变运算优先级[]下标运算符.取成员运算符
运算符的优先级
搞不清楚优先级直接加()
选择结构语句
- if条件语句
if、if...else、if...elseif...else
public class If3 {
public static void main(String args[]) {
int i = 3;
if (i > 5) {
System.out.println("变量i大于5");
}
else if (i > 4) {
System.out.println("变量i小于4");
}
else {
System.out.println("其他");
}
}
}
- switch条件语句
遇到break,switch语句执行结束。
switch语句只能使用byte、char、short、int四种基本类型以及它们的包装类和枚举,java 7以后可以接受字符串。
class switch2 {
public static void main(String[] args) {
int a = 7,b = 5;
switch(a-b) {
case 3://表达式可能的值;{
System.out.println("33!");
}
break;
case 4: {
System.out.println("44!");
}
break;
default: //都没有执行则 执行该语句!
System.out.println("其它的");
}
}
}
循环结构语句
用于处理需要重复执行的操作;
根据判断条件的成立与否,决定程序段落的执行次数,而这个程序段落我们称为循环体;
- while循环语句
先判断后执行,事先不需要知道循环执行多少次
while(条件表达式值为true) {
执行语句;
}
- do...while循环语句
先执行后判断,同上,只是至少要执行一次
do {
执行语句;
}
while(条件表达式值为true);
- for循环语句
需要知道循环次数
for(初始化表达式(1);循环条件表达式(2);循环后的操作表达式(3)) {
执行语句;(4)
}
执行顺序:(1) → (2) → (4) → (3) → (2) → (4) → (3)
用三种循环控制求出100以内前5个3的倍数的数字
class while {
public static void main(String[] args) {
int i = 1,k = 0;
while(i<=100) {
if(i%3==0) {
if(k<5)
System.out.println(i);
k++;
}
i++;
}
}
} class dowhile {
public static void main(String[] args) {
int i = 1,k = 0;
do {
if(i%3==0) {
if(k<5)
System.out.println(i);
k++;
}
i++;
}
while(i<=100);
}
} class for {
public static void main(String[] args) {
int i = 1,k = 0;
for(i=1;i<100;i++) {
if(i%3==0&&k<5) {
System.out.println(i);
k++;
}
}
}
}
循环嵌套
Eg:利用for循环语句的嵌套打印出乘法口诀表
class break1 {
public static void main(String[] args) {
for(int i=1;i<=10;i++) { //定义i与j的值必须在for循环里面,否则每次跳出循环重新执行就无法取值
for(int j=1;j<=10;j++) {
if(j<=i)
System.out.print(j+"*"+i+"="+i*j+" ");//注意:print()括号里面必须传递参数,println()无限制!
}
System.out.println();
}
}
}
- 跳转语句(break、continue)
break:强制终止整个循环
continue:结束本次循环,继续下次循环
Eg:
package reviewDemo; public class Demo2 {
public static void main(String[] args) {
int i = 1;
for (; i < 10; i++) {
System.out.println(i);
if(i == 8) {
break; //流程控制,不会完全执行!
}
}
}
}
注:
①:若这两个语句离开应用范围,存在是没有意义的。
②:这个两个语句后面都不能有语句,因为执行不到。
③:continue语句是跳过本次循环,继续下次循环。
④:标签的出现,可以让这两个语句作用于指定的循环。
方法
- 什么是方法
完成特定功能的代码块
[访问修饰符][修饰符] 返回值类型 方法名([参数列表]) [异常声明]) { 执行语句 返回值}
访问修饰符
public
protected
默认default
private
修饰符
static
abstract
final
修饰变量,变量变成常量
修饰类,类不能被继承
修饰方法,方法不能被重写
synchronized
native
- 方法调用
静态方法:类名.方法名(实参列表)
非静态方法:对象.方法名(实参列表)
- 方法的重载
是指一个类中可以定义有相同的名字,但是参数列表不同,调用时,会根据不同的参数列表选择对应的方法。
void show(int a ,char b,double c) {}
1. void show(int x, char y, double z){}//没有重载 与原函数一样
2.int show(int a, double c,char b){}//重载了 参数列表不同
3.void show (int a, double c,char b){}//重载了 参数列表不同 同上
4.boolean show (int c, char b)//重载了 参数列表不同
5.void show(double c)//重载了 参数个数不同
6.double show(intx, char y,double z)//没有重载 参数一致
规则:两同三不同
--同一个类,同一个方法名
--不同:参数列表不同(类型、个数、顺序不同)
--只有返回值不同不能构成方法的重载
--只有形参的名称不同,不能构成方法的重载
什么时候用重载?
当定义的功能相同,但参与运算的未知内容不同,那么,这时就定义一个函数名称表示该功能,方便阅读,而通过参数列表的不同来区分多个同名函数。
- 方法的重写
方法名保持一致
子类权限修饰符可以大于等于父类的
子类的返回值类型小于等于父类的类型,子类声明异常类型不能超过父类的类型
- 方法的递归
方法的递归是指在一个方法的内部调用自身的过程,递归必须要有结束条件,不然就会陷入无限递归的状态,永远无法结束调用。
递归算法:
递归头:什么时候不调用自己
递归体:什么时候调用自己
- 字符串
- String
- 创建字符串对象
- String
- 创建字符串对象
String s = "Hello";
s引用静态区的字符串字面量
String s = new String("Hello");
s引用堆上的字符串对象
String str = new String( char[] a); //使用字符数组中的所有元素创建字符串
String str = new String( char[] a,offset,count); //使用字符数组中的一部分元素创建字符串,其中offset表示起始截取位置,count表示截取个数
- 字符串的方法
- 字符串的方法
长度:length()
取字符:charAt(int)
变大/小写:toUpperCase()/toLowerCase()
连接:concat(String)
比较:equals(String) / compareTo(String)/equalsIgnoreCase()忽略大小写
判断开头/结尾:startsWith(String) / endsWith(String)
模式匹配:indexOf(String, [int]) / lastIndexOf(String, [int])
取子串:substring(int, [int])
修剪左右两边空白:trim()
替换:replace(String, String) / replaceAll(String, String)
拆分:split(String)
- String代表的是不变字符串
- 可以被修改的字符串
- StringBuilder
- String代表的是不变字符串
- 可以被修改的字符串
- StringBuilder
适用于单线程环境
- StringBuffer
- StringBuffer
适用于多个线程操作同一个字符串的场景
StringBuffer():该构造方法为对象提供可容纳16个字符的空间。利用new关键字创建的一个不带参数的构造方法:
StringBuffer str=new StringBuffer();
StringBuffer(int length):该构造方法为对象提供length个字符位。利用new关键字创建的一个以整型数为参数的构造方法,参数值为1024:
StringBuffer str=new StringBuffer(1024);
StringBuffer(String str):该构造方法用str为对象进行初始化。利用new关键字创建的一个以String对象作为参数的构造方法,字符串值为“Hello”:
StringBuffer str=new StringBuffer(“Hello”);
StringBuffer类是动态的字符串类,它可以动态的执行添加、删除、插入等字符串的编辑操作。
- StringBuffer类的方法
- StringBuffer类的方法
追加:append(String)这个方法有多种实现方式,它们可以接受任何类型的数据。
删除指定位置的字符:delete(int, int)/deleteCharAt()
在指定位置插入字符串:insert(int, String)可以在任意特定的位置进行任意数据类型的值的插入。
倒转:reverse()
setCharAt()方法:作用是修改对象中索引值为特定位置的字符为新的字符。
数组
- 数组的定义
数组就是同一种类型数据的集合,是一个容器,是引用类型,存储在堆中。
格式
1. int[] arr=new int[5]; 创建一个长度为5 的,变量名为arr,类型为整型的数组。
2. int[] arr=new []{5,6,8,3,4}; 静态初始化
int[] arr={5,6,8,3,4};
数组中的每个元素被称为元素,在数组中可以存放任意类型的元素,但同一个数组中存放的元素类型必须一致。
- 数组中常见问题
1、数组角标越界 //ArrayIndexOutofBoundsException
2、空指针异常 //NUllPointerException 当引用没有任何指向,值为空的情况,该引用还在用于操作实体。
- 数据的常见操作
1.获取数组中的数据,通常会用到遍历(for循环),arr.length代表数组的长度
int[] arr=new int[5];
for(int x=0;x<arr.length;x++) {
arr[x];
}
2.打印数组中的元素,元素间用逗号隔开。
int[] arr=new int[5];
for(int x=0;x<arr.length;x++) {
if(x!=arr.length-1)
System.out.print( arr[x]+",");
else
System.out.print( arr[x]);
}
3.获取最值
//定义一个方法,返回最大值角标
public static int getmax(int[] arr) {
int max=0; //定义一个变量初始化数组的0角标值
for(int x=0; x<arr.length;x++) { //循环遍历数组
if(arr[max]<arr[x]) { //如果临时元素小于遍历到的元素
max=x; //将遍历到的值的角标付给临时变量角标
}
}
return max; //返回最大值角标
}
4.数组排序-选择排序:内循环结束一次,最值出现在头角标位置上,第一个依次和后面的几个相比较
public static void xuanze(int[] arr) {
for(int x=0; x<arr.length-1;x++) {//控制比较的圈数
for(int y=x+1;y<arr.length;y++) { //控制每圈比较的次数
if(arr[x]>arr[y]) {
int temp=arr[y];
arr[y]=arr[x];
arr[x]=temp;
}
}
}
}
5.数组排序-冒泡排序:相邻的两个元素进行比较,第一圈,最值出现在最后。
public static void maopao(int[] arr) {
for(int x=0; x<arr.length-1;x++) {//控制比较的圈数
for(int y=0;y<arr.length-x-1;y++) { //控制每圈比较的次数 -1是避免角标越界,-x是让每一次比较的元素减少
if(arr[y]>arr[y+1]) {
int temp=arr[y+1];
arr[y+1]=arr[y];
arr[y]=temp;
}
}
}
}
6.数组置换
public static void maopao(int[] arr,int x, int y) {
int temp=arr[x];
arr[x]=arr[y];
arr[y]=temp;
}
7.数组的一般查找:获取key第一次出现在数组中的位置,如果返回-1,则不存在
public static int select(int[] arr,int key) {
for(int x=0; x<arr.length;x++) {
if(arr[x]==key) {
return x;
}
}
return -1;
}
8.数组的折半查找:可以提高查找效率,但是必须是有序数组
1:
先找到头角标 和尾角标
min =0 //头角标
max=arr.length-1;//尾角标
mid =(min+max)/2;//中间角标
在要找得的值和中间角标不相等的情况下,循环查找。
如果要找的值比中间角标值大的话,头角标就是中间角标+1;
如果要找的值比中间角标小的话,尾角标就是中间角标-1;
中间角标重新赋值 mid =(min+max)/2;//中间角标
查找之后,如果头角标大于了尾角标的话 ,数组中就没有这个值,
2:
如果头角标和尾角标之间有距离,也就是说头角标和尾角标小于等于尾角标的时候,就进行折半。否则不存在 返回 -1
mid =(min+max)/2;//中间角标
之后呢 如果要找的值比中间角标值大的话,头角标就是中间角标+1;
如果要找的值比中间角标小的话,尾角标就是中间角标-1;
如果相等的话 就返回中间角标值。找到了
直接遍历的方法——Arrays.asList()方法。使用这种方法我们就可以直接输出数组中的全部内容。
- 数组的进制转换
十进制转二进制
public static void tobin(int num) {
StringBuffer sb=new StringBuffer(); //创建一个StringBuffer容器用于接收对2取模的数
while (num>0) {
sb.append(num%2);
num=num/2;
}
System.out.print(sb.reverse());
}
十进制转十六进制
public static void toHex(int num) {
StringBuffer sb=new StringBuffer();
for(int x=0;x<8;x++) {
int temp=num & 15;
if(temp>9)
sb.append((char)(temp-10+'A'));
else
sb.append(temp);
num= num>>>4;
}
System.out.println(sb.reverse());
}
- 多维数组
二维数组:数组中的数组
格式
int[][] arr=new int [3][4];//定义了一个名称为arr的二维数组,这个二维数组中有3个一位数组,每一个一位数组中有四个元素
//3代表的是二维数组的长度,4代表的是二维数组中每一个一位数组的长度。
int[][] arr =new int[3][];
int[][] arr={{5,8,6,5},{4,5,2},{8,8,9}}
表现方式
int[][] x; int x[][]; int[] x[];
arr.length:二维数组的长度
arr[0].length:二维数组中第一个一维数组的长度
二维数组的遍历
for(int x=0;x<arr.length;x++){
for(int y=0;y<arr[x].length;y++) {
sum=sum+arr[x][y];
}
}
练习
int[] x,y[]; x是一维数组,y是二维数组。相当于 int x[] int y[][];
a)x[0]=y //错误
b)y[0]=x //正确 两边都是一维数组
c)y[0][0]=x; //错误
d)x[0][0]=y;//错误