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类型的变量,数值后面必须加入F
float f = 10.5F;
}
}
2.6.3、布尔类型
布尔类型的取值只能是true和false,不能取其他的
【代码示例】
public class DataTypeTest04 {
public static void main(String[] args) {
//boolean类型只能取值为true和false
boolean a = true;
boolean b = false;
}
}
【代码示例】
public class DataTypeTest05 {
public static void main(String[] args) {
//boolean类型只能取值为true和false
boolean 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);
//输出true
System.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 + b
a+=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;//注意break
case '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、char
long 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文件的属性。