镇楼图
![](https://img2022.cnblogs.com/blog/2146310/202204/2146310-20220429232913276-304673296.jpg)
Pivix:₩ANKE
一、Hello World
JAVA技术体系
Java SE标准版(J2SE),提供了完整的Java核心API
Java EE企业版(J2EE),主要针对Web应用程序开发
Java ME小型版(J2ME),支持移动端,且API有所精简
运行环境
JDK:官网下载地址
JDK(Java Development Kit)是Java开发工具包,里面主要包含JRE和其他开发工具(javac、java、javadoc....)
JRE(Java Runtime Environment)是Java运行环境,包含了JVM(Java Virtual Machine,Java虚拟机)和其他核心类库等
JVM:将字节码(.class文件)翻译成可运行程序
java:运行.class字节码文件的程序
javac:(Java Complier),将java源码翻译成字节码
jar:打包工具
jdb:查错工具
javadoc:文档生成工具
javah:实现C/C++和Java程序的相互调用
javap:分解class文件
appletviewer:小程序Java浏览器
Hello World
JAVA程序会先从.java文件经过javac.exe程序编译成.class字节码文件,然后由java.exe运行
/* Hello.java */
public class Hello {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
需要注意的是程序名和class后的名字必须一致否则会在编译阶段报错,此外使用java.exe程序时无需加上后缀名.class
一、基本语法
■大小写敏感
■语句以 ; 结束
■一个源文件最多有一个public类且文件名与该类名一致
■非public类数量上无限制
■main可以在public类内或是其他类内
转义字符(略)
注释
//注释
/*注释*/
/**文档注释
*1
*2
*...
*特殊语法可以生成javadoc文档
*/
数据类型
Java是强类型语言,数据类型分为基本数据类型和引用数据类型
基本数据类型:
■整数:byte(1)short(2)int(4)long(8)
■浮点数:float(4)double(8)
■布尔boolean(1)【true、false】
■字符char(2)【单个字符'x'】
引用数据类型:
■类class
■接口interface
■数组[]
命名变量规则
■由英文字母、数字、_
、$
组成
■首个字符不能为数字
■不能为保留字
■大小写敏感
默认类型
整数默认为int类型,若要表示long类型需要加l
或L
300//这是int类型
300L//这是long类型
int x = 300l;//类型不一致会报错
long y = 300L;//类型一致
long z = 300;//由于会转换类型也都是long
//后续会说明类型转换
浮点数默认为double,若要表示float类型需要加f
或F
若要表示double类型需要加d
或D
double z = 0.1f;//正确
double u = .123f;//整数部分为0可忽略
double v = 1.35e-7;
double w = 1.35e10;
//科学计数法
double r = 0.1;
Math.abs(z-u) < r
/*
判断浮点数相等时应当小心
浮点数是不精确的,完完全全相等几乎不可能
应当使用两数绝对值之差判断
Math.abs是绝对值的函数
r表示你所想表达的精度
当|z-u|<r满足时便表示相等
*/
布尔类型只允许true和false,不定义的null也是不被允许的
自动类型转换
像绝大多数语言一样,java会自动地将精度低的数据类型转换为精度高的数据类型。反之如果使用精度高的数据给精度低的数据类型会报错
char→int→long→float→double
byte→short→int→long→float→double
long x = 'c';//正确
double y = 100;//正确
int z = .123;//错误
float u = x+1.1;//错误
char v = 100;//正确
byte n = 10;//正确
char w = n;//错误
byte a = 1;
short b = 1;
short c = a+b;
//错误,byte、short、char使用基本运算符时会转成int
byte d = 1;
byte e = a+d;
//错误,一样是int
强制类型转换
强制转换后可能会降低精度
int i = (int).123;//结果为0
int a = 100;
byte b = (byte)a;
short s = 12;
s -= 9;
//报错
byte b = 10;
b += 11;
//报错
char a = 'a';
int i = 16;
float d = .314f;
double r = a+i+d;
//正确
byte b = 16;
short s = 14;
short t = s+b;
//报错
String类型转换
char x1 = 'c';
short x2 = 100;
float x3 = 15.0f;
String s1 = x1+"";
String s2 = x2+"";
String s3 = x3+"";
//通过拼接运算即可将其他类型转成String
Integer.parseInt("100");
Double.parseDouble("10.0");
Float.parseFloat("10.0");
Short.parseShort("100");
Long.parseLong("100");
Boolean.parseBoolean("false");
Byte.parseByte("10");
//可以使用parse可以将String转换为其他类型
String s = "123456789";
s.charAt(i);
//可以使用charAt获取第i个字符
char c1 = 'a';//97
char c2 = 'b';//98
System.out.println(c1+c2);
//结果为195
//对于char类型而言相加不会是拼接而是加法得到整数
API(Application Programming Interface)
API是自带的应用程序接口,使用好API可以为开发带来不少便利,而且难度也不高
参考:MaTools
一个库包含了接口、类、异常
一个类包含了字段、构造器(构造方法)、成员方法(方法)
二、运算符
算术运算符
算术运算符 | 说明 |
---|---|
+ | 单目,正号 |
- | 单目,负号 |
+ | 双目,加法或拼接 |
- | 双目,减法 |
* | 双目,乘法 |
/ | 双目,除法(根据数据类型判断是整除或是实除) |
% | 双目,求余(可以实数求余) |
a++ b-- | 单目,自增/自减。先运算后自增 |
++a --b | 单目,自增/自减。先自增后运算 |
关系运算符
关系运算符 | 说明 |
---|---|
== | 相等 |
!= | 不相等 |
< | 小于 |
> | 大于 |
<= | 小于等于 |
>= | 大于等于 |
instanceof | 检查是否为类的对象("string" instanceof String) |
逻辑运算符
逻辑运算符 | 说明 |
---|---|
a & b | 逻辑与 |
a | b | 逻辑或 |
!a | 非 |
a && b | 短路与 |
a || b | 短路或 |
a ^ b | 异或 |
注:与C语言不同的是,除了短路与还引入了正常的逻辑运算。但效率上附有短路的更快
赋值运算符
赋值运算符 | 说明 |
---|---|
= | 等于 |
+= | 加等 |
-= | 减等 |
*= | 乘等 |
/= | 除等 |
%= | 求余等 |
注:复合赋值运算会自动进行类型转换
byte b = 2;
b += 3;//b = (byte)(b+3);
b++;//b = (byte)(b+1);
进制表示
在Java中各个进制分别如下表示
■二进制:0b或0B开头
■八进制:0开头
■十进制
■十六进制:0x或0X表示
int a = 0b1001000;
int b = 090;
int c = 0x48;
位运算符
位运算符 | 说明 |
---|---|
<< | 算术左移(符号位不变,低位补0) |
>> | 算术右移(符号位不变,符号位补溢出的高位) |
>>> | 无符号右移(没有左移)(0补溢出的高位) |
~ | 按位取反 |
& | 按位与 |
| | 按位或 |
^ | 按位异或 |
三元运算符
条件 ? 表达式1 : 表达式2 ;
//与C语言一致
//若满足条件1则为表达式1否则为表达式2
优先级
优先级 | 运算符 | 运算方向 |
---|---|---|
1 | ++ -- ~ ! | 从右到左 |
2 | * / % | 从左到右 |
3 | + - | 从左到右 |
4 | << >> >>> | 从左到右 |
5 | < > <= >= instanceof | 从左到右 |
6 | == != | 从左到右 |
7 | & | 从左到右 |
8 | ^ | 从左到右 |
9 | | | 从左到右 |
10 | && | 从左到右 |
11 | || | 从左到右 |
12 | ? : | 从左到右 |
13 | = *= /= %= += -= <<= >>= | 从右到左 |
总体而言,除括号,单目 > 算术运算符 > 位移运算符 > 比较运算符 > 逻辑运算符 > 比较运算符
三、控制结构
基本和C语言一致,就不过多介绍了
分支
if(/*条件*/) /*条件满足时执行的语句*/;
if(/*条件*/){
/*条件满足时执行的代码*/;
}
if (/*条件*/){
;//
} else {
;//
}
switch (/*表达式*/){
case constvalue1:
;//
break;
case constvalue2:
;//
break;
//...
default:
;//
break;
}
■switch表达式的类型和case后的常量必须是可比的。像int、String就没有可比性
■switch表达式的返回值只能是byte、short、int、char、enum、String类型
■具体有关break的细节在C都学过就不介绍了
循环
for(/*初始化*/;/*条件*/;/*步长*/){
;//
}
while(/*条件*/){
;//
}
do{
;//
}while(/*条件*/);
跳转
break;
continue;
label1:{
label2:{
label3:{
break label1;
continue label2;
//break、continue也可以使用标签表示要跳出哪一层
}
}
}
return;
//用于跳出所在方法中
//若在main方法中则等于退出程序
四、数组
int[] a = {1,2,3,4,5,6};
boolean b[] = {true,false,true,false};
//静态
double c[] = new double[3];//动态创建长度为3的数组
//动态
a[0] = 5;
//访问数组元素
b.length
//获取数组长度
动态初始化
int a[];
//声明数组(不占用空间)
//未初始化直接使用会报错
a = new int[5];
//动态分配(占用空间)
静态初始化
int b[] = {1,2,3};
注意事项
■数组可以是任何数据类型的数组
■数组只能存储相同类型的数据(自动提升类型的可以)
■数组创建后若没有定义值会有默认值2
类型 | 默认值 |
---|---|
char | \u0000 |
byte short int long | 0 |
float double | 0.0 |
boolean | false |
String | null(表示没有值) |
■数组下标不可越界否则报错
多维数组
int a[][] = {{1,2,3},{4,5,6}};
//2x3的二维数组
//a[0][1]为2
//a.length返回为2而不是总的元素数6
//a[0].length返回为3
//所以类似的
int b[][][] = new int[5][2][7];
int length = b.length*b[0].length*b[0][0].length;
//数组总长度为70
int []c[] = new int[2][];
c[0] = new int[5];
c[1] = new int[12];
//数组每一元素下的数组长度也可以不一样
int []d,e[],f[];
//d是一维数组,e,f是二维数组
//杨辉三角
import java.util.*;
public class Hello{
public static void main(String[] args){
int n = 15;
long a[][] = new long[n][];
for(int i = 0;i < a.length;i++){
a[i] = new long[i+1];
for(int j = 0;j < a[i].length;j++){
if(j == 0 || j == i){
a[i][j] = 1;
}else {
a[i][j] = a[i-1][j]+a[i-1][j-1];
}
System.out.printf("%-8d",a[i][j]);
}
System.out.println();
}
}
}
垃圾回收机制
int a[] = {1,2,3};
int b[] = new int[3];
a = b;
//与C语言不同是这并不会导致内存泄漏
//而是触发Java的垃圾回收机制处理b无法再引用的内存
五、类、对象
类是由对象组成的,是某一对象的类型
对象则是某一类的实例,具有属性和方法两个方面
class Object{
//属性
int a = 3;//可以定义默认值
String b;
//...
//方法
public void c(){
//...
}
//...
}
//...
//创建对象
Object one = new Object();
one.a = 3;//使用属性
//直接定义对象
Object two;
two = new Object();
//先声明再定义
two = one;
//进行赋值,"指针"一致因此是指向是同一内存
//注:类只会加载一次,再次创建同名的类不会有任何效果
属性(成员变量、字段)
除去方法可以将类看成一个结构体就好理解了
属性是指一个类的成员变量,当然类里面也可以嵌套类做链表之类的都是可以的
此外属性的默认值是和数组一样的
(成员)方法
简单来说就是结构体还封装了函数,达到一类数据类型专门地集成了函数,而不是在外面写
方法与函数大体类似,返回类型、函数名、参数列表都是类似的
class Object{
public void get(){
System.out.println("Hello World");
return;
}
}
//...
Object a = new Object();
a.get();//只有调用方法才能生效
注:一个方法只能有一个返回值,如果要有多个返回值可以返回数组或对象
调用
同类方法之中可以直接调用
但不同类方法需要创建其类才能再调用
class P{
void print1(){
System.out.println(p.hashcode());
//可以调用hashcode方法获取对象的哈希值
}
void print2(){
print1();
//同类可直接调用
}
}
class T{
void print3{
P p = new p();
p.print2();
//不同类方法调用必须先创建其类
}
}
递归
class Tool {
int f(int n){
return (n == 1)return 1? : n*f(n-1);
}
}
重载
重载简单来说就是允许方法同名的存在,但其参数列表是不同的(与返回类型、参数名无关)
一方面可以在实现同一功能但参数类型可能发生变化的情况而避免起不同名,另一方面减少了函数名的数量
System.out.println("123");
System.out.println(123);
System.out.println(123.00);
//比如println函数不可避免会遇到不同参数类型的情况
//但其函数名都是一致的
//可以避免功能上一致但因参数类型不同函数名不同的尴尬
void a(int n){
//...
}
int a(int a){
//...
}
//上述会直接报错
//虽然返回类型不同,但参数类型相同无法知晓调用哪一方法
//同名函数是否构成重载关键看函数名、参数列表
可变参数
即参数数量不定的情况,有时是会遇到这种需求的,这时候Java提供了机制方便实现
int sum(int... num){
//本质上是改成传入数组
//此外可变参数只能在最后为最后一个
int r = 0;
for(int i = 0;i < n.length;i++){
r += n[i];
}
return r;
}
//调用
sum();//可变参数不限定数量,传入0个也是可以的
sum(1,2,3);
sum(1,2);
int a[] = {4,5,6};
sum(a);
/*也可以传入数组
但只能传入一个数组
除此之外无法添加额外数组或是参数类型
*/
int b[] = {4,5,6};
sum(a,1,2,3); //错误
sum(a,b);//错误
int c[][] = {{1,2,3},{4,5,6}};
sum(c);//错误,只允许一维数组
作用域、生命周期(略)
作用域即变量所作用的范围
大体上分为全局变量、局部变量
全局变量即类的属性,可以直接在方法中调用进而减少函数的参数
局部变量是在代码块中的变量,比如A类的属性无法在B类中直接使用
全局变量(属性)有其默认值可以直接使用,但局部变量无默认值直接使用会直接报错
此外作用域不同的变量可以同名,调用时会优先选择作用域最局限的
生命周期是指其作用的时间,比如创建对象后其属性的生命周期,除非对象被销毁否则其生命周期会一直持续下去
构造器(构造方法)
一般情况是创建好对象后再对其属性进行赋值,虽然也有其默认值。但构造器提供了一种在创建对象时便可以通过参数根据需求来对属性进行初始化
构造器也是方法的一种
class Player{
String name;
int hp;
int atk;
int def;
Player(String cname,int chp,int catk,int cdef){
name = cname;
hp = chp;
atk = catk;
def = cdef;
//System.out.println("要是愿意也可以当一个初始化的void函数来使用");
}
//修饰符+方法名+形参
}
//方法名与类名必须一致
//构造器无返回值
//其余与方法定义大体相同,但不存在返回类型
//(默认返回本类类型)
Player p1 = new Player("玩家", 30, 5, 5);
//在创建时便根据构造器来创建
//但是必须要严格按构造器格式创建
//Player p1 = new Player()这种省略参数的都会报错的
Player(String cname,int... n){
//与可变参数结合,提高定义上的灵活性
name = cname;
if(n.length > 0){
hp = n[0];
if(n.length > 1){
atk = n[1];
if(n.length > 2){
def = n[2];
}
}
}
}
//用户创建时最少只需要输入一个String类型即可
//以下调用都是正确的
Player p1 = new Player("玩家");
Player p1 = new Player("玩家", 30);
Player p1 = new Player("玩家", 30, 5);
Player p1 = new Player("玩家", 30, 5, 5);
Player p1 = new Player("玩家", 30, 5, 5, 1,1,4,5,1,4);
构造器同样可以重载,除了可变参数提高一定的灵活性,重载可以进一步提高灵活性
class Player{
String name;
int hp;
int atk;
int def;
Player(String cname,int... n){
//与可变参数结合,提高定义上的灵活性
name = cname;
if(n.length > 0){
hp = n[0];
if(n.length > 1){
atk = n[1];
if(n.length > 2){
def = n[2];
}
}
}
}
Player(){}
//现在也可以不需要输入就能定义了
//重载+可变参数可以极大提高定义上的灵活性
}
class Player{
String name;
int hp;
int atk;
int def;
/*
当用户没定义构造器时
会默认定义一个构造
如此处默认定义的便是Player(){}
*/
}
创建对象流程:
属性优先进行默认值初始化,然后根据执行构造方法,然后在栈中创建空间("指针")指向堆(对象的具体内容在堆、方法区中)由此完成创建
this指针
this用于区分属性和局部变量,使得代码更清晰
class Player{
String name;
int hp;
int atk;
int def;
Player(String name,int hp, int atk,int def){
//this指针指向当前对象
//使得属性与局部变量同名依然可区分
this.name = name;
this.hp = hp;
this.atk = atk;
this.def = def;
}
Player(String name,int hp){
//this指针也可以用于构造器
//但this所调用的构造器必须在第一行
this(name,hp,5,5);
System.out.println("正确");
}
Player(String name){
System.out.println("错误");
this.Player(name,30,5,5);
}
Player(){}
void f1(){
System.out.println("1");
}
void f2(){
//this指针可以调用属性、方法、构造器
this.f1();
}
}