1、Java语言基础
2、内容
2.1、标识符
标识符可以标识类名,变量名,接口名,方法名
1. Java标识符的命名规则
a) 标识符是由:数字、字母、下划线和美元符号构成,其他符号不可以
b) 必须以字母、下划线或美元符号开头,不能以数字开头
2. 关键字不能作为标识符
3. 标识符区分大小写
4. 标识符理论上没有长度限制
参见表格
| 合法标识符 | 不合法标识符 | 
|---|---|
| _123Test | 123Test | 
| HelloWorld | Hello-World | 
| HelloWorld | HelloWorld# | 
| public1 | public | 
| HelloWord | Hello World | 
命名Java标识符,最好见名知意
Java规范要求:
类名,接口名首字母大写,后面每个单词首字母大写。
变量名、方法名首字母小写,后面每个单词首字母大写。
常量都是大写。
注意类的命名:首字母要大写,单词之间首字母大写,这种命名方式称为“驼峰标识”
访问控制修饰符
Java中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。Java 支持 4 种不同的访问权限。
- default (即默认,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。
 - private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
 - public : 对所有类可见。使用对象:类、接口、变量、方法
 - protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)。
 
我们可以通过以下表来说明访问权限:
| 修饰符 | 当前类 | 同一包内 | 子孙类(同一包) | 子孙类(不同包) | 其他包 | 
|---|---|---|---|---|---|
| public | Y | Y | Y | Y | Y | 
| protected | Y | Y | Y | Y/N | N | 
| default | Y | Y | Y | N | N | 
| private | Y | N | N | N | N | 
2.2、关键字
在Java中关键字都是小写的
| class | extends | implements | interface | import | 
|---|---|---|---|---|
| package | break | case | continue | default | 
| do | if | else | for | return | 
| switch | while | false | true | null | 
| boolean | byte | char | short | int | 
| long | float | double | try | catch | 
| throw | throws | finally | abstract | final | 
| native | private | protected | public | static | 
| synchronized | transient | volatile | instanceof | new | 
| super | void | assert | enum | goto | 
| const | 
2.3、数据类型
Java总共有两种数据类型,基本类型和引用类型,基本类型有8种,引用数据类型有3种
数据类型
- 基本数据类型
- 数值类型
- 整数型(byte,short,int,long)
 - 浮点型(float,double)
 
 - 字符类型(char)
 - 布尔类型(boolean,只能取值true和false)
 
 - 数值类型
 - 引用数据类型
- 数组
 - 类
 - 接口
 
 
基本数据类型有八种:boolean、char、byte、short、int、long、float、double
- Java语言中浮点类型默认为double
 - Java语言中整型默认为int
 
八种数据类型的取值范围(不需要记!)
在计算机内部,所有信息都采用二进制表示,每个二进制由0和1两种状态,一个字节有8位,也就是由8个0或1构成
short类型的6在计算机中是如何存储的?
short是两个字节,那么short 6的二进制为:00000000 00000110
int类型的6在计算机中存储为32位:00000000 00000000 00000000 00000110
2.3、进制换算(不需要记,了解即可)
二进制: 0 1八进制: 0 1 2 3 4 5 6 7十进制: 0 1 2 3 4 5 6 7 8 9十六进制:0 1 2 3 4 5 6 7 8 9 a b c d e f
简单了解十进制到二进制的换算
规则:除2取余,逆序输出
如10进制6二进制换算方式为:
6/2=3 余 0
3/2=1 余 1
1/2=0 余 1
将余数逆序输出就是6的二进制表示:110,位数不够补零
简单了解二进制到十进制的换算
规则:取出最后一位,从2的0次方开始乘,将得到的结果相加即可
如:二进制的110的十进制换算:
02的0次方=0
12的1次方=2
1*2的2次方=4
110的十进制为:0+2+4=6
2.4、字符编码
| ASCII字符编码 | 采用一个字节编码,主要针对英文编码 | 
|---|---|
| unicode | Unicode统一了全世界上的所有文字编码 unicode有几种实现:UTF-8,UTF-16,UTF-32 UTF-8 :动态4个字节 UTF-32:固定4字节,空间浪费  | 
UTF-8存储格式(UTF8主要就是为了节省空间):
Char的测试
public class CharTeset01 {public static void main(String[] args) {char c = 's';//中文是占两个字节,char是两个字节,所以char可以存储一个汉字char c1 = '中';}}
2.5、变量、常量(字面值)
1.变量
变量其实是java中的一个最基本的单元,也就是内存中的一块区域,Java中的变量有四个基本属性:变量名,数据类型,存储单元和变量值
- 变量名:合法的标识符
 - 变量的数据类型:可以是基本类型和引用类型(必须包含类型)
 - 存储单元:存储单元大小是由数据类型决定的,如:int为4个字节32位
 - 变量值:在存储单元中放的就是变量值(如果是基本类型放的就是具体值,如果是引用类型放的是内存地址,如果null,表示不指向任何对象)
 
变量的声明格式:
    类型 变量名;
【示例代码】
/** 变量的声明*/public class VarTest01 {public static void main(String[] args) {byte b = 1;int i = 0;long l;//声明l = 0;//赋值double d = 10.88;boolean flag = true;System.out.println(flag);//必须被初始化之后才能使用}
2.常量(字面值)
常量:固定不变的量(也可以叫字面值)
常量分类:
- 基本类型常量
 - 引用类型的null
int a = 10;//10就是常量,字面值System.out.println("Hello World");//Hello World 也是常量,字面值
2.6、数据类型详解
2.6.1、整数型
Java整型包括:byte/short/int/long
Java语言整数型常量有三种表示方法 
- 十进制
 - 八进制,八进制0开头,如:013
 - 十六进制,十六进制0x开头,如:0x23
 
Java语言整数型默认为int类型,如果要声明成long类型在变量值后加入L或者l,如:
long l = 999999999999L
二进制:0,1
八进制:0,1,2,3,4,5,6,7
十进制:0,1,2,3,4,5,6,7,8,9
十六进制:0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f
2.6.2、浮点类型
Java语言中浮点类型包括:float/double
Java语言中浮点类型默认为double
【代码示例】
public class DataTypeTest01 {public static void main(String[] args) {//正确,因为默认为double类型double d = 10.5;}}
【示例代码】
public class DataTypeTest02 {public static void main(String[] args) {//会出现错误//因为10.5默认为double类型,double为8个字节,//而float为4个字节,所以double向float赋值会出现精度丢失的问题float f = 10.5;}}
【示例代码】,改善以上示例
public class DataTypeTest03 {public static void main(String[] args) {//声明为float类型的变量,数值后面必须加入Ffloat f = 10.5F;}}
2.6.3、布尔类型
布尔类型的取值只能是true和false,不能取其他的
【代码示例】
public class DataTypeTest04 {public static void main(String[] args) {//boolean类型只能取值为true和falseboolean a = true;boolean b = false;}}
【代码示例】
public class DataTypeTest05 {public static void main(String[] args) {//boolean类型只能取值为true和falseboolean a = 1;boolean b = 0;}}
2.6.4、基本类型的转换
- 在java中基本类型可以相互转换,boolean类型比较特殊不可以转换成其他类型
 - 转换分为默认转换和强制转换:
- 默认转换:容量小的类型会默认转换为容量大的类型
- byte—>short—> int—>long—>float—>double
 - char—>
 - byte、short、char之间计算不会互相转换,首先先转换成int
 
 - 强制转换
- 将容量大的类型转换成容量小的类型,需要进行强制转换
 - 注意:只要不超出范围可以将整型值直接赋值给byte,short,char
 
 
 - 默认转换:容量小的类型会默认转换为容量大的类型
 
2.7、运算符
按功能划分主要运算符如下:
| 算术运算符 | +, -, *, /, ++, —, % | 
|---|---|
| 关系运算符 | <, <=, >, >=,==, != | 
| 布尔运算符 | &&, ||,! &&,|| 短路的情况下只执行左侧  | 
| 赋值类运算符 | =, +=, -=, *=, /=, %= | 
| 字符串连接运算符 | + | 
| 条件运算符 | ? : | 
| 其他运算符 | instanceof, new | 
| 位移运算符 | << ; >>; >>> | 
| 位运算符 | &,|,^,~ | 
Java运算符优先级列表
| 优先级 | 运算符 | 简介 | 结合性 | 
|---|---|---|---|
| 1 | ( ) | 方法调用,属性获取 | 从左向右 | 
| 2 | !、~、 ++、 — | 一元运算符 | 从右向左 | 
| 3 | * 、/ 、% | 乘、除、取模(余数) | 从左向右 | 
| 4 | + 、 - | 加减法 | 从左向右 | 
| 5 | <<、 >>、 >>> | 左位移、右位移、无符号右移 | 从左向右 | 
| 6 | < 、<= 、>、 >=、 instanceof | 小于、小于等于、大于、大于等于, 对象类型判断是否属于同类型  | 
从左向右 | 
| 7 | == 、!= | 2个值是否相等,2个值是否不等于。 下面有详细的解释  | 
从左向右 | 
| 8 | & | 按位与 | 从左向右 | 
| 9 | ^ | 按位异或 | 从左向右 | 
| 10 | | | 按位或 | 从左向右 | 
| 11 | && | 短路与 | 从左向右 | 
| 12 | || | 短路或 | 从左向右 | 
| 13 | ?: | 条件运算符 | 从右向左 | 
| 14 | =、 += 、-= 、*= 、/=、 %=、 &=、 |=、 ^=、 <、<= 、>、>= 、>>= | 混合赋值运算符 | 从右向左 | 
在多种类型混合运算过程中,首先先将所有数据转换成容量最大的那种,再运算
【示例代码】
public class DataTypeTest06 {public static void main(String[] args) {//出现错误,1000超出了byte的范围//byte a = 1000;//正确,因为20没有超出byte范围//所以赋值byte a = 20;//变量不能重名//short a = 1000;//正确,因为数值1000没有超出short类型的范围//所以赋值正确short b = 1000;//正确,因为默认就是int,并且没有超出int范围int c = 1000;//正确,可以自动转换long d = c;//错误,出现精度丢失问题,大类型-->>小类型会出现问题//int e = d;//将long强制转换成int类型//因为值1000,没有超出int范围,所以转换是正确的int e = (int)d;//因为java中的运算会会转成最大类型//而10和3默认为int,所以运算后的最大类型也是int//所以是正确的int f = 10/3;//声明10为long类型long g = 10;//出现错误,多个数值在运算过程中,会转换成容量最大的类型//以下示例最大的类型为double,而h为int,所以就会出现大类型(long)到小类型(int)//的转换,将会出现精度丢失问题//int h = g/3;//可以强制转换,因为运算结果没有超出int范围//int h = (int)g/3;//可以采用long类型来接收运算结果//long h = g/3;//出现精度损失问题,以下问题主要是优先级的问题//将g转换成int,然后又将int类型的g转换成byte,最后byte类型的g和3运算,那么//它的运算结果类型就是int,所以int赋值给byte就出现了精度损失问题//byte h = (byte)(int)g/3;//正确//byte h = (byte)(int)(g/3);//不能转换,还有因为优先级的问题//byte h = (byte)g/3;//可以转换,因为运算结果没有超出byte范围//byte h = (byte)(g/3);//可以转换,因为运算结果没有超出short范围short h = (short)(g/3);short i = 10;byte j = 5;//错误,short和byte运算,首先会转换成int再运算//所以运算结果为int,int赋值给short就会出现精度丢失问题//short k = i + j;//可以将运算结果强制转换成short//short k = (short)(i + j);//因为运算结果为int,所以可以采用int类型接收int k = i + j;char l = 'a';System.out.println(l);//输出结果为97,也就是a的ascii值System.out.println((byte)l);int m = l + 100;//输出结构为197,取得a的ascii码值,让后与100进行相加运算System.out.println(m);}}
2.6.1、算术运算符
【示例代码】
public class OperatorTest01 {public static void main(String[] args) {int a = 1;//a++相当于a=a+1;int b = a++;System.out.println("a=" + a);System.out.println("b=" + b);}}
以上会看到a=2,b=1,为什么会出现这种结果?
++在变量的后面,先把值赋值给b,然后a再加(也就是先赋值再自加)
所以就输出了a=2,b=1
【示例代码】,将++放到变量的前面
public class OperatorTest02 {public static void main(String[] args) {int a = 1;int b = ++a;System.out.println("a=" + a);System.out.println("b=" + b);}}
输出结果为a=2,b=2,如果++在变量的前面,是先自加在赋值
【示例代码】取余/取模
public class OperatorTest03 {public static void main(String[] args) {int a = 10/3;System.out.println(a);//取余int b = 10 % 3;System.out.println(b);}}
2.7.2、关系运算符和布尔运算符
- 与:两个操作数相与,如果都为true,则为true
 - 或:两个操作数相或,有一个为true,则为true
 
注意:操作数必须是boolean型
短路与:左侧如果是false,右侧不会继续执行
短路或:左侧如果是true,右侧不会继续执行
| op1 | op2 | op1&&op2 op1&op2  | 
op1||op2 op1|op2  | 
op1^op2 | !op1 | 
|---|---|---|---|---|---|
| true | true | true | true | false | false | 
| true | false | false | true | true | false | 
| false | true | false | true | true | true | 
| false | false | false | false | false | true | 
【代码示例】
public class OperatorTest04 {public static void main(String[] args) {boolean op1 = (10 > 5);//输出trueSystem.out.println("op1=" + op1);boolean op2 = (10 < 5);System.out.println("op2=" + op2);System.out.println("op1 && op1 =" + (op1 && op2));System.out.println("op1 & op1 =" + (op1 & op2));System.out.println("op1 || op1 =" + (op1 || op2));System.out.println("op1 | op1 =" + (op1 | op2));System.out.println("op1 ^ op1 =" + (op1 ^ op2));System.out.println("!op1 =" + !op1);}}
2.7.3、赋值类运算符
| += | a+=b | a=a+b | 
|---|---|---|
| -= | a-=b | a=a-b | 
| *= | a*=b | a=a*b | 
| /= | a/=b | a=a/b | 
| %= | a%=b | a=a%b | 
【代码示例】
public class OperatorTest05 {public static void main(String[] args) {int a = 1;int b = 2;//a=a + ba+=b;System.out.println(a);}}
2.7.4.、条件运算符
条件运算符是java语言中的三元运算,格式如下:
op1 ? op2 : op3
如果操作数op1为true则输出op2,否则输出op3
public class OperatorTest06 {public static void main(String[] args) {int a = 11;int b = a>0?1:-1;System.out.println(b);boolean c = a%2==0?true:false;System.out.println(c);}}
2.8、控制语句
java控制语句可以分为7种:
- 控制选择结构语句
- if、if else
 - switch
 
 - 控制循环结构语句
- for
 - while
 - do while
 
 - 改变控制语句顺序
 
面试题:
    需求:
        1.在系统中给定一个人的年龄,[1-100]
        2.根据年龄判断这个人处在生命的哪个阶段:
            [1-5] 幼儿
            [6-18] 少年
            [19-35] 青年
            [36-55] 中年
            [56-100] 老年
2.8.2、switch语句
switch也称为多重分支,具体格式如下
switch (表达式) {
    case 值1:
        语句1
break;
    case 值2:
        语句2
       break;
    default:
        语句
Break;
}
说明:
- 表达式的值只能为:char, byte, short, int, Character, Byte, Short, Integer, String, or an enum
 - break语句可以省略,但会出现switch穿透
 - default语句也可以省略,一般不建议省略,并且放置在最后
 
注意类的命名:首字母要大写,单词之间首字母大写,这种命名方式称为“驼峰标识”
【代码示例】
public class SwitchTest01 {public static void main(String[] args) {char c = 'd';switch(c) {case 'a':System.out.println("优秀");break;//注意breakcase 'b':System.out.println("良好");break;case 'c':System.out.println("一般");break;default:System.out.println("很差");}System.out.println("switch执行结束!");}}
【代码示例】
public class SwitchTest02 {public static void main(String[] args) {//byte c = 1;//short c = 1;//int c = 1;//不能为long,switch只能为byte、short、int、charlong c = 1;switch(c) {case 1:System.out.println("优秀");break;case 2:System.out.println("良好");break;case 3:System.out.println("一般");break;default:System.out.println("很差");}System.out.println("switch执行结束!");}}
2.8.3、for语句
for语句格式如下:
for(初始化部分表达式;条件表达式; 更新表达式) {
    一条或多条语句
}
【代码示例】
public class ForTest01 {public static void main(String[] args) {for (int i=1; i<=10; i++) {System.out.println(i);}}}
2.8.4、while语句
while语句格式
    while(布尔表达式) {
    一条或多条语句
}
【代码示例】
public class WhileTest01 {public static void main(String[] args) {int i = 1;//注意死循环问题while(i<=10) {System.out.println(i);i++;}}}
以上程序同样完成了1~10的输出,可以看出for更加简单,可以看做for是while语句的便利方式,采用for语句完全可以模仿while语句,如将for语句中的“初始化部分表达式”和“更新表达式”省略
for (; 条件表达式 ;) {
    语句
}
public class WhileTest02 {public static void main(String[] args) {int i = 1;for(;i<=10;) {System.out.println(i);i++;}}}
2.8.5、do while语句
do while格式
do {
    语句
}while(布尔表达式);
注意while括号后必须写分号
do while与while非常相似,不同点在于do while先执行循环体,也就是说不管条件符不符合,循环体至少执行一次
【代码示例】
public class DoWhileTest01 {public static void main(String[] args) {int i = 1;do{System.out.println(i);i++;}while(i<=10); //注意分号}}
2.8.6、break语句
break可以用在switch、循环语句和带标号的语句块中
在循环语句中主要是为了终止循环
public class BreakTest01 {public static void main(String[] args) {for (int i=1; i<=100; i++) {System.out.println(i);if (i == 50) {break; //会跳出当前循环}}//break跳到这里}}
在循环语句中主要是为了终止循环(多重循环)
public class BreakTest02 {public static void main(String[] args) {for (int i=1; i<=5; i++) {System.out.println("i===================" + i);for (int j=1; j<=10; j++) {System.out.println(j);if (j == 5) {break;}}//以上break会到此为止}//以上break不会跳到这里}}
2.8.7、continue语句
continue只能用在循环语句中,表示在循环中执行到continue时,自动结束本次循环,然后判断条件,决定是否进行下一次循环(多个循环的跳出使用—-标签:的方式)
public class ContinueTest01 {public static void main(String[] args) {for (int i=1; i<=100; i++) {//if (i % 2 != 0) {// System.out.println(i);//}if (i % 2 == 0) {continue; //继续下一次循环}System.out.println(i);}}}
2.9、方法初步
方法是可以重复调用的代码块,通常为了实现各种功能
方法的定义格式:
[方法修饰列表]  返回值类型 方法名(方法参数列表){
    方法体
[返回]
}
- 方法修饰列表
 
是可选项,方法的修饰符可以包括:public,protected,private,abstract,static, final,synchronized,其中public,protected,private不能同时存在
- 返回值类型
 
如果没有返回值使用void关键字,如果存在返回值可以是基本类型和引用类型,
如果存在返回值,使用return语句。Return语句后面不能再执行语句,因为不可能会执行到,编译器        会    发生错误。
- 方法名
 
任意合法的标识符
- 方法参数列表
 
参数列表可以多个,如:method1(int a, int b),多个采用逗号分割
2.9.1、普通方法示例
【代码示例】,存在返回值
public class MethodTest01 {public static void main(String[] args) {String s = method1(1);System.out.println(s);}public static String method1(int c) {String retValue= "";switch(c) {case 1://System.out.println("优秀");retValue = "优";break;case 2://System.out.println("良好");retValue = "良好";break;case 3://System.out.println("一般");retValue = "一般";break;default://System.out.println("很差");retValue = "很差";}return retValue;}}
【代码示例】,没有返回值
public class MethodTest02 {public static void main(String[] args) {method1(1);}public static void method1(int c) {switch(c) {case 1:System.out.println("优秀");break;case 2:System.out.println("良好");break;case 3:System.out.println("一般");break;default:System.out.println("很差");}}}
2.9.2、方法的重载(Overload)
重载的条件
- 方法名相同
 - 方法的参数类型,个数,顺序至少有一个不同
 - 方法的返回类型可以不同(不依靠返回类型来区分重载)
 - 方法的修饰符可以不同,因为方法重载和修饰符没有任何关系
 - 方法重载只出现在同一个类中
 
【代码示例】
public class OverloadTest01 {public static void main(String[] args) {int retInt = sumInt(10, 20);System.out.println(retInt);float retFloat = sumFloat(1.5f, 2.5f);System.out.println(retFloat);double retDouble = sumDouble(2.2, 3.2);System.out.println(retDouble);}//对int求和public static int sumInt(int v1, int v2) {return v1+v2;}//对float求和public static float sumFloat(float v1, float v2) {return v1+v2;}//对double求和public static double sumDouble(double v1, double v2) {return v1+v2;}}
【代码示例】,采用重载改善以上代码,重载会使我们的编程风格会更好
public class OverloadTest02 {public static void main(String[] args) {int retInt = sum(10, 20);System.out.println(retInt);float retFloat = sum(1.5f, 2.5f);System.out.println(retFloat);double retDouble = sum(2.2, 3.2);System.out.println(retDouble);}//对int求和public static int sum(int v1, int v2) {return v1+v2;}//对float求和public static float sum(float v1, float v2) {return v1+v2;}//对double求和public static double sum(double v1, double v2) {return v1+v2;}//正确public static double sum() {return 0L;}//错误,重载不依赖返回值//public static void sum() {// return 0L;//}//正确public static double sum(double v1, double v2, int v3) {return 0L;}//正确public static double sum(int v3, double v1, double v2) {return 0L;}//正确public static double sum(double v1, int v3, double v2) {return 0L;}//不正确//public static double sum(double v2, double v1) {// return 0L;//}}
3.0、递归问题
3.1、程序
先不使用递归计算1+2+3+4+5的和,要求程序设计灵活,如果传入一个5过求出1+2+。。。+5的和
public class RecursionTest01 {public static void main(String[] args) {int sum = 0;for(int i=0;i<10;i++){sum += i;}System.out.println(sum);}}
public class RecursionTest02 {public static void main(String[] args) {int retValue = method1(5);System.out.println(retValue);}//采用递归求和public static int method1(int n) {if (n == 1) {return 1;}else {//递归调用,调用自身return n + method1(n-1);}}}/*** num* 10 + 9 + 8 + 7 + ....1* @param num* @return*/public static int rec2(int num){System.out.println("num = " + num);if(num==1){return 1;}return num + rec2(num -1);}public static int rec3(int num) {if(num == 1){return 1;}return num * rec3(num - 1);}
3、Java虚拟机
3.1、java内存分配
| JAVA虚拟机 | |||||||
|---|---|---|---|---|---|---|---|
| 栈内存Stack | 堆内存Heap | 方法区 | |||||
- 栈Stack:存储方法的局部变量、参数、运算的结果、返回值等,变量的引用,基本类型,这些都是存储在栈内存中。每当启动一个新线程时,Java虚拟机都会为它分配一个Java栈。
 - 栈帧:当调用一个方法时,会分配一个栈帧,然后压入栈中。
 - 堆Heap:Java程序在运行时创建的所有类实例或者数组都放在同一个堆中。
 - 方法区:类的信息都是存储在方法区。比如:静态方法、常量、静态变量、class文件的属性。
 
