JAVASE
计算机执行机制
编译执行:
将源文件编译成机器码,一次编译,多次执行。
执行效率高,不可跨平台。
解释执行:
将源文件一行一行解释,一行一行执行,不同的操作系统具备不同的解释器。
执行效率低,可以跨平台。
java的运行机制
先编译,在解释
将源文件编译成字节码文件,再将字节码文件进行解释执行。
Write Once Run Anywhere(一次编译,到处执行)
Java跨平台原理
JVM JRE JDK
JVM (Java Virtual Machine)虚拟机:
使用软件在不同操作系统,模拟相同的环境
JRE (Java Runtime Environment)运行环境:
包含JVM和解释器 ,完整的Java运行环境
JDK (Java Development Kit)开发环境:
包含JRE+类库+开发工具包(编译器+调试工具)
第一个Hello World
/*修饰符 类 类名*/
public class Hello{
/*修饰符 静态关键字 返回值 main (字符串数组参数)*/
public static void main(String[] args){
System.out.println("Hello World!");
}
}
类的阐述
同一个源文件中可以定义很多类
编译后的.java文件,会生成独立的.class文件
一个类中只能有一个主函数,每个类都可以有自己的主函数
public修饰的类为公开的类,要求类名和文件名必须保持一致包括大小写
一个源文件中只能有一个公开的类
包
包用来管理class文件,也可以区分同名不同包的文件
命名规则:必须位于源文件的第一行
package 包名
包名采用域名倒置com.xxx.xxx
包全部小写,不能以.开头和结尾,可以包含.,每个.都是一个子文件夹
带包编译:javac -d . 源文件
带包运行:ava 包名.类名 (全限定名)
注释
单行注释: //
多行注释:/* 多行注释 */
javadoc文档注释:/** doc文档注释 生成一个帮助文档 */
javadoc生成帮助文档: javadoc -d .源文件名
查看index.html即可
注:注释不参与编译
标识符
标识符:主要用来给方法 类 对象 变量 定义名字
规则:首字母可以是字母 _ $ 但是不能以数字开头,其他部分可以是数字 字母 下划线 $
命名采用驼峰命名尽量注意语义化 见名知意
// 合法
int aa
int $a
int _a
// 不合法
int 1a
// java严格区分大小写
int a
int A 这两个不是同一个变量
保留字
保留字 给系统特定使用的关键字:比如 int for if void static break … 等等
转义字符
转义字符 | 描述 |
---|---|
\n | 换行符 |
\t | 制表符缩进一个tab间距 |
\ \ | 反斜线 |
\ ’ | 单引号 |
\ ‘’ | 双引号 |
变量
变量:可变的量称为变量 变量声明就是在内存中开辟一块空间
java是一个强类型语言 声明变量都要先声明其类型
变量是java程序中最基本的存储单元,其要素包括变量名,变量类型,作用域
存储位置
基本数据类型 存储在栈(stack)中
引用数据类型 栈中存放的是指向当前对象的引用 真正的值存储在堆(heap)中
生命周期 随着方法的入栈(压栈)而生效,随着方法的出栈(弹栈)而死亡
// 变量声明
// 数据类型 变量名
// 声明一个int 类型的变量 变量名为a
int a ; // 为变量a开辟内存空间
// 赋值
// 变量名 = 值
a = 10; // 将10 赋值给变量
// 声明变量的三种方式
// 1.先声明 再赋值 (常用)
int i ;
i = 10;
// 2.生命并赋值(常用)
int b = 10 ;
// 3.多个同类型变量声明与赋值(了解)
int c = 1, d = 2, e = 3;
变量命名规范:
遵循驼峰命名,见名知意,第一个单词首字母小写,其他单词首字母都大写
注意:
每个变量都有类型,类型可以是基本类型,也可以是引用类型
变量名必须是合法的标识符
变量声明是一条完整的语句,因此每一个变量声明都需要;分号结束
数据类型
基本数据类型
整数
类型 | 字节 | 取值范围(二进制) | 取值范围(十进制) |
---|---|---|---|
byte | 1字节 | -27~27-1 | -128 ~ 127 |
short | 2字节 | -215~215-1 | -32768 ~ 32767 |
int | 4字节 | -231~231-1 | -2147483648 ~ 2147483647 |
long | 8字节 | -263~263-1 | -9223372036854775808 ~ 9223372036854775807 |
注意:int类型为整数的默认类型
如果使用long类型给long赋值需要在值的末尾加上L 大小写都可以 推荐大写
byte b = 127;
short s = -32768;
int i = 2147483647;
long l = 9223372036854775807L;
// 进制: 二进制0b 八进制 0 十进制 十六进制0x
int a = 10; // 十六进制
int b = 010; // 八进制
int c = 0x10; // 十六进制
System.out.println(a); // 输出10
System.out.println(b); // 输出 8
System.out.println(c); // 输出 10
小数
类型 | 字节 | 负数取值范围 | 正整数取值范围 |
---|---|---|---|
float | 4字节 | -3.4E+38 ~ -1.4E-45 | 1.4E-45 ~ 3.4E+38 |
double | 8字节 | -1.7E+308 ~ -4.9E-324 | 4.9E-324 ~ 1.7E+308 |
double类型是小数|浮点数的默认类型,如需给float类型赋值,需要在值后面加F
float f = 3.14F;
double d = 3.1415926;
// 浮点数 float 大约 不精确 舍入误差 接近但不等于
float f = 0.1f;
double d = 0.1;
System.out.println(f == d); // 输出为false
布尔
类型 | 字节 | 取值范围 | 描述 |
---|---|---|---|
boolean | 1字节 | true | false | 描述’真’或’假’ |
可以直接赋值为true | false 也可以 赋值 一个结果为true | false的表达式
注:boolean在java中不能参加算数运算
boolean bl = true;
// 赋值一个表达式 10 >20 错误 所以结果为false
boolean bl1 = 10 >20;
字符
类型 | 字节 | 取值范围(无符号数) | 字符编码 |
---|---|---|---|
char | 2字节 | 0~65535 | Unicode字符集(万国码) |
Unicode字符集支持ASCII编码(美国标准信息交换码)
Unicode中每个字符都对应一个十进制整数,从而可以是多种方式赋值
// 直接赋值字符
char c1 = 'A';
// 整数赋值 通过十进制数65在字符集中找到对应的字符
char c2 = 65 ;
// 进制赋值 通过十六进制数41在字符集中为所对应的字符赋值
char c3 = '\u0041';
// char 字符 强转之后输出的数字就是unicode所对应的字符码
char ch1 = 'A';
System.out.println(ch1); // 输出A
System.out.println((int)ch1); //强转之后输出字符所对应的数值
引用数据类型
String
类型 | 取值范围 | 字符编码 |
---|---|---|
String | 任何 “” 之间的字面值 | Unicode字符序列 |
引用数据类型 : 数组 字符串 对象 。。。等等
类型转换
由于java是强类型的语言,所以做一些运算的时候会用到类型转换
低 -------------------------------------------------------------------------> 高
byte —> short—> char —> int—> long—> float—> double
运算中,不同类型运算先转换成同一类型运算
强制转换
转换的类型由高到低转换称为 强制转换
转换规则:
两种类型兼容,目标类型小于源类型
// 强制转换 (类型) 变量名
int i = 128;
// byte 最大取值范围 127
byte b = (byte) i; // 输出-128 存在内存溢出问题
// 强转的精度问题
System.out.println((int)3.14); // 输出3
System.out.println((int) -3.14f); // 输出-3
char c1 = 'a'; // 对应的数值97
int d = c1 +1; // 自动转换 97 + 1 = 98
System.out.println(d);
System.out.println((char)d); // 98对应的字符是b
// 操作较大的数值,要注意内存溢出问题
// JDK7新特性 ,数字之间可以用下划线分割
int a = 10_0000_0000;
int b = 20;
// 超出了int 的最大取值范围 内存溢出 输出 -1474836480
int c = a * b;
System.out.println(c);
// 默认是int类型 为转换前就存在问题 所以 输出 还是-1474836480
long l1 = a * b;
// 先把一个数转换成long 计算的时候都会用long的取值 输出20000000000
long l2 = a * (long)b;
注意 :
1.不能对布尔值进行转换
2.把高容量强制转换成低容量时,强制转换的结果可能会存在内存溢出,或精度问题
自动转换
转换的类型由低到高转换称为 自动转换
转换规则:
两种类型兼容,目标类型大于源类型
// 自动转换
byte b = 127;
int i = b;
自动转换规则:
进行算数运算时:
两个操作数有一个为double,计算结果提升为double。
如果操作数中没有double,有一个为float,计算结果提升为float。
如果操作数中没有float,有一个为long,计算结果提升为long。
如果操作数中没有long,有一个为int,计算结果提升为int。
如果操作数中没有int,均为short或byte,计算结果仍旧提升为int。
特殊:任何类型与String相加(+)时,实为拼接,其结果自动提升为String。
运算符
算术运算符
操作符 | 描述 |
---|---|
+ | 相加 求和 |
- | 相减 求差 |
* | 乘 求积 |
/ | 除 求商 |
% | 模 求余 |
int a = 10;
int b = 6;
String s = "1";
a + b // 16
a + s = 101 // 注意 + 两头有一端是字符串那么就会拼接
a - b // 4
a * b // 60
a / b // 1
a % b // 4
自增自减
操作符 | 描述 |
---|---|
++ | 递增,自身+1 |
– | 递减,自身-1 |
int a = 3;
a++ // 输出3 先做运算 在自身 + 1
++a // 输出5 先自身 +1 得到 4 在做运算
运算符
操作符 | 描述 |
---|---|
= | 直接赋值 |
+= | 求和后赋值 |
-= | 求差后赋值 |
*= | 求积后赋值 |
/= | 求商后赋值 |
%= | 求余后赋值 |
int a = 10; // 直接把3赋值给a
int b = 3;
a += b // 13
a -= b // 10
a *= b // 30
a /= b // 3
a %= b // 1
关系运算符
操作符 | 描述 |
---|---|
> | 大于 |
< | 小于 |
>= | 大于等于 |
<= | 小于等于 |
== | 等于 |
!= | 不等于 |
int a = 10;
int b = 3;
a > b // true
a < b // false
a >= b // false
a <= b // false
a == b // false
a != b // true
逻辑运算符
操作符 | 语义 | 描述 |
---|---|---|
&& | 与(并且) | 两个操作数,同时为真,结果为真 |
|| | 或(或者) | 两个操作数,一个为真,结果为真 |
! | 非(取反) | 意为:“不是”,真即是假,假即是真 |
int a = 10;
int b = 3;
int c = 2;
// && 两边同时为true 结果为true
(a > b && a <c) // false a > b 成立 a < c不成立
(a > b && a >c) // true a > b 成立 a > c成立
// || 两边有一个为true 结果为true
(a < b || a <c) // false a < b 不成立 a < c不成立
(a > b || a >c) // true a > b 成立 a > c成立
(a > b || a <c) // true a > b 成立 a < c不成立
// ! 取反
!(a>c); // false
// 短路运算
int a = 10;
boolean b = (a > 20) && (a ++ <20);
// (a > 20) 不成立 就不再 往后执行 a还是10
// (a < 20) 成立 往后执行 a是11
三元运算符
操作符 | 语义 | 描述 |
---|---|---|
? : | 布尔表达式?结果1 : 结果2 | 当表达式为真,获得结果1,反之,结果2 |
// 三元运算符
int a = 10;
int b = 2;
// a > b 表达式 成立 把结果为true 不成立 为false
a > b ? true : false
位运算
操作符 | 描述 | 运算规则 |
---|---|---|
& | 与 | 两个位都为1,结果才为1 |
| | 或 | 两个位都为0,结果才为0 |
^ | 异或 | 两个位相同为0,相异为1 |
~ | 取反 | 0变1,1变0 |
<< | 左移 | 各二进制全部左移若干位,高位丢弃,低位补0 |
> > | 右移 | 各二进制全部右移若干位,如果该数为正,则高位补0,若为负数,则高位补1 |
A = 0011 1100
B = 0000 1101
A & B = 0000 1100 // &与 两个二进制数比较 两个位都为1时,结果才为1
A | B = 0011 1101 // 两个二进制数比较 两个位上都为0 结果才为0
A ^ B = 0011 0001 // 两个二进制数比较 两个位相同为0,相异为1
~B = 1111 0010
/*
<< 左移
2 << 3 向左移动三位
2在二进制中表示
0000 0010
左移三位后
0001 0000 // 得到 16
0001 0000右移动 16 >> 3
0000 0010 // 16 1向右移动三位 得到2
*/
Scanner类
Scanner类可以用来获取用户输入。
Scanner类在util工具包中,导入 这个类 import java.util.Scanner
public static void main(String[] args) {
// 创建一个Scanner扫描对象 用于接受键盘输入
Scanner scanner = new Scanner(System.in);
System.out.println("请输入");
// 判断是否还有输入
if(scanner.hasNext()){
// next() 接收
// String next = scanner.next();
// nextLine()接收
String s = scanner.nextLine();
System.out.println("输入的结果为" + s);
}
}
next()和nextLine()区别:
next():
- 1.一定要读取到有效字符输入后才可以结束输入;
- 2.对输入的有效字符之前遇到的空白,next()方法会自动将其去掉
- 3.只有输入有效字符后才将其后面输入的空白作为分隔或结束符
- next()不能得到带有空格的字符串
nextLine():
- 1.以Enter为结束符,也就是说 nextLine()方法返回的是输入回车之前的所有字符
- 2.可以获得空白
// 接收 int 类型
int i = scanner.nextInt();
// 接收 double 类型
double d = scanner.nextDouble();
// 接收 float 类型
float f = scanner.nextFloat();
条件分支
if
if:条件分支用于判断某个连续区间
// 执行流程 对表达式进行判断结果为true执行代码块,在执行后续,
// 结果为false跳出代码块再执行后续代码。
if(布尔表达式){
//代码块
}
====================================================
// 对布尔表达式进行判断。
// 结果为true,则先执行代码块1,再退出整个结构,执行后续代码。
// 结果为false,则先执行代码块2,再退出整个结构,执行后续代码。
if(布尔表达式){
//代码块1
}else{
//代码块2
}
====================================================
/* 表达式1为true,则执行代码块1,再退出整个结构。
表达式2为true,则执行代码块2,再退出整个结构。
表达式3为true,则执行代码块3,再退出整个结构。
以上均为false,则执行代码块4,再退出整个结构。
注意:相互排斥,有一个为true,其他均不再执行,
适用于区间判断。*/
if(布尔表达式1){
//代码块1
}else if(布尔表达式2){
//代码块2
}else if(布尔表达式3){
//代码块3
}else{
//代码块4
}
====================================================
// 嵌套if
if(外层表达式){
if(内层表达式){
//内层代码块1
}else{
//内层代码块2
}
}else{
//外层代码块
}
// 当外层条件满足时,再判断内层条件。
// 注意:一个选择结构中,可嵌套另一个选择结构。嵌套格式正确的情况下,支持任意组合。
switch
switch:用于处理等值的情况
支持的数据类型有:byte,short,int,char,String,(JDK7+)枚举
/*
如果变量中的值等于值1,则执行逻辑代码1。
如果变量中的值等于值2,则执行逻辑代码2。
如果变量中的值等于值n,则执行逻辑代码n。
如果变量中的值没有匹配的case值时,执行default中的逻辑代码。*/
switch(变量|表达式){
case 值1:
逻辑代码1;
case 值2:
逻辑代码2;
case 值n:
逻辑代码n;
default:
未满足时的逻辑代码;
}
// break 终止不再执行 所有case取值都不同
循环结构
while
// 起始条件
/*
必要条件:
1.起始条件
2.判断条件
3.循环体
4.计数器自增自减
while循环可以处理循环次数固定的情况,但是更擅长处理循环次数不确定的情况
*/
while ( 循环条件 ) {
// 循环操作
}
do-while
// 起始条件
do {
// 循环操作
// 计数器自增自减
} while ( 循环条件 );
// do-while特点:先执行,后判断,最少执行一次
for
/*
for循环的必要条件和while do...while相同
执行顺序
1.计数器初始化,最先执行,并且只执行一次
2.判断条件
3.循环体
4.计数器自增或自减
*/
for(起始条件,判断条件,计数器自增自减){
// 循环体
}
/*
for常见的问题:
for(;i<10;i++){} 缺少起始条件 变量i没有初始化
for(int i=0;;i++){} 缺少循环条件 死循环
for(int i=0;i<10;){} 缺少计数器 死循环
for(;;){} 缺少必要的循环控制 死循环
*/
while和do-while和for的区别:
while循环:先判断,如果条件不成立一次都不执行 用于循环次数不固定的情况
do-while循环:先执行,再判断,不管条件是否成立,至少执行一次
for循环:先判断,如果条件不成立一次都不执行 ,通常用于次数固定的情况
break和continue
break关键字:可以用于switch中 表示跳出当前switch语句 执行switch之后的代码
也可以用于循环中,表示终止循环,不再继续向后执行
continue关键字: 一般用于循环中,表示跳出本次循环,继续执行下一次循环
break终止整个循环,没有执行完的次数不再执行
continue跳出本次循环,继续执行下一次循环
方法
方法:方法就是完成特定功能的代码块,可重复使用。类似于其他语言的函数
方法定义
// 普通方法
访问修饰符 返回值类型 方法名 (参数列表){
方法体
return 返回值;
}
// 静态方法
// 访问修饰符 static(静态) 返回值类型int 方法列表(int int)
public static int sum(int a,int b){
// 返回值类型是int 我们返回的值也一定是int
return a + b;
}
public static void main(String[] args) {
// 调用sum方法 1 传递给了int a 这个形参,2 传递给了int b这个形参
sum(1,2); // 输出3
}
返回值类型
返回值类型:方法可能会有返回值 而返回值需要遵守返回值的类型
/*返回值时 int类型 所以返回值必须也是int类型的
返回值可以书写的类型
byte short int long boolean double float char String 对象 数组 ...*/
public int returns(){
return 0;
}
return关键字
使用return 关键字来返回值
return 之后的value类型必须和返回值类型匹配
在分支结构情况下,必须保证每一个分支下都有返回值
在返回值类型为void的方法中,可以使用return,表示结束方法,但是return后不能在写任何内容
public static int returns(int a){
// 当表达式为true return就会直接返回并且终止
if(a > 10){
return a;
}
// 表达式不成立 才会执行最后一个return
return a;
}
// 返回值类型为void可以写 return 但是return关键字之后 不能写任何内容
public static void returns(int a){
System.out.println("hello");
return ;
}
形参实参
形参:形式参数,表示在定义方法时就定义的参数,相当于局部变量的声明,形参没有个数上限,形参规定了参数的个数,类型,顺序,这些规定实参必须遵守,也就是实参需要复合形参的约束。
实参:实际参数,必须遵循形参的约定,可以书写对应类型的变量,也可以写对应类型的值
public static void main(String[] args) {
sum(1); // 1代表实际参数
}
// a 代表形参
public static int sum(int a){
return a;
}
方法调用
public class MyClass{
public static void main(String[] args) {
MyClass MyClass = new MyClass();
MyClass.eat();
}
// 普通方法的调用 需要类名.方法名调用 要先new类的实例才能调用
public void eat(){
System.out.println("eat");
}
}
public class MyClass{
public static void main(String[] args) {
eat();
}
// static 会和类一起加载 所以方法名就可以调用
public static void eat(){
System.out.println("eat");
}
}
方法多级调用
public class test {
public static void main(String[] args) {
m1(); // 当我们调用m1方法 执行顺序为 1 3 4 2
}
public static void m1() {
System.out.println("m1方法开始执行"); // 1
m2();
System.out.println("m1方法执行完毕"); // 2
}
public static void m2() {
System.out.println("m2方法开始执行"); // 3
System.out.println("m2方法执行完毕"); // 4
}
}
方法重载
重载:在同一个类中 方法名相同 ,形参 参数列表不同(参数的个数 类型 顺序有一个不同就满足重载的条件,)只有满足这三个不同之一,才能确保每一个方法的唯一性
重载和返回值无关 和访问修饰符无关
public static void main(String[] args) {
sum(1,2);
sum("hello","world");
sum(1,2,3);
}
public static int sum(int a,int b){
return a + b; // 两个int 类型的参数 调用这个方法