变量、数据类型、运算符

463 阅读11分钟

常用的dos命令

磁盘操作系统(Disk Operation System),是早期个人计算机上的一类操作系统, 常用命令:

cd 目录路径      进入一个目录
cd..            进入父目录
dir             查看本目录下的文件和子目录列表
cls             清除屏幕命令
上下键           查找敲过的命令
Tab键           自动补全命令

开发工具

入门学习是,进行简单的Java程序编写,我们可以使用文本编辑器,比如:记事本。但是,记事本功能不够强大,我们可以考虑使用“更强大的记事本”,常见的如下三种软件

  • Notepad++
  • Sublime
  • EditPlus

在真正学习开发中,包括以后在企业中从事软件开发时,一般使用集成开发环境(IDE)

IDEA 官方网址: www.jetbrains.com/idea/

二进制

万物总有规律;有规律,就可量化;可量化,就能数字化;数字化,就能使用计算机化

在线进制转换工具:tool.lu/hexconvert

十进制转二进制

十进制整数转换为二进制整数采用“除2取余,逆序排列”法

image.png

十进制29转成二进制就是:11101

二进制转十进制

二进制转十进制采用“权相加法”

image.png

注释

注释不会出现在字节码文件中,即Java编译器编译时会跳过注释语句

在Java中根据注释的功能不同,主要分为单行注释、多行注释和文档注释

1. 单行注释

单行注释用“ /**/ ” 开头

2. 多行注释

多行注释以“ \ * ” 开头,以 “ * / ” 结尾,多行注释不能嵌套使用

备注: 多行注释也可以用作行内注释,非整行注释

3. 文档注释

文档注释以“ / ** ”开头,以“* / ”结尾,注释内容采用缩进及“ * ”开头,注释中包含一些说明性的文字及一些JavaDoc标签

/**
  * 这是文档注释,主要用于开发环境:IDEA、VScode等
  * 第一个java程序
  * hello world
  * @version 1.0.0
  * @auther LG
*/

标识符和关键字

标识符

标识符是用来给变量、类、方法及包进行命名的。

4大规则:

  1. 必须以字母、下划线、美元符号$开头(不能以数字开头名命名)
  2. 其他部分可以是字母、下划线"_"、美元符"$" 和数字的任意组合
  3. 大小写敏感,且长度无限制
  4. 不可以是Java的关键字

标识符的使用规范

  • 表示类名的标识符:每个单词的首字母大写,如Man、HelloWorld、UserName
  • 表示方法和变量的标识符: 第一个单词小写,第二个单词开始到结束的单词,首字母大写,我们称为“驼峰原则”,如:eat()、eatFood()

Java不采用ASCll字符集,而是采用Unicode字符集。因此,这里字母的含义不仅仅是英文,还包括汉字等等。但是不建议使用汉字来定义标识符

eg: 合法的标识符

int a = 1;
int _123 = 2;
int $12abcd = 3;
int 变量1 = 4;      // 不建议使用中文命名的标识符

关键字 / 保留字

Java关键字是Java语言保留供内部使用的,如class用于定义类,我们不能使用关键字作为变量名或方法名

image.png

变量(variable)

image.png

变量的本质

  1. 变量本质上就是代表一个“可操作的存储空间”,空间位置是确定的,但是里面放置什么值不确定
  2. 可通过变量名来访问“对应的存储空间”,从而操作这个“存储空间”存储的值
  3. Java是一种强类型语言,每个变量都必须声明其数据类型。变量的数据类型决定了变量占据存储空间的大小。比如,int a = 6;表示a变量的空间大小为4个字节

变量的声明

double salary               (8个字节)
long earthPopulation        (8个字节)
int age                     (4个字节)

image.png

eg: 声明变量和初始化

int age = 18;
double e = 2.718281828
int i,j;              // 一行声明多个变量,数据类型都是int

备注

Java中使用某个变量之前,必须对其进行初始化,否则就报错

变量的分类和作用域

变量有三种分类:局部变量、成员变量(也称为实例变量)和静态变量

image.png

public class TestVariable {
        // 成员变量
        int a = 3;
	public static void main(String[] args){
       
        // 静态变量
        static b = 4;
        // 局部变量
        int age = 18;
        int x = 0,y=1,z=2;
        System.out.println(age);
        System.out.println(x);
	}
}

常量(constant)

在Java语言中,用关键字final来定义一个常量。常量一旦被初始化后不能再更改

public class TestConstant{
	public static void main(String[] args){
		final double PI = 3.14;
		PI = 3.1415926;    // 无法为常量再分配值
	}
}

运行结果

image.png

备注:常量的命名全用大写字母,单词之间下划线隔开

为了更好的区分和表述,一般将1、2、3、'a'、'b'、true、false、'hello world'等称为字符常量,而使用final修饰的PI等称为符号常量

变量和常量命名规范

  • 所有变量、方法、类名: 要做到见名知意
  • 类成员变量: 首字母小写和驼峰原则:monthSalary
  • 局部变量: 首字母小写和驼峰原则
  • 常量: 大写字母和下划线 MAX_VALUE
  • 类名 首字母大写和驼峰原则 Person , PersonName
  • 方法名 首字母小写和驼峰原则 run() , sayName()

eg: 计算圆的面积和周长

public class TestConstant{
	public static void main(String[] args){
		final double PI = 3.14;
		// PI = 3.1415926;               // 无法为常量再次赋值
		final int MAX_SPEED = 120;       // 常量的命名全用大写字母,单词之间下划线隔开
		int r = 4;
		double area = PI * r * r;
		double circle = 2 * PI * r;
		System.out.println("面积 = " + area);
		System.out.println("周长 = " + circle);
	}
} 

运行结果

image.png

基本数据类型(primitive data type)

image.png

8个基本数据类型,其中数值型6个,字符型和布尔型各1个

每种数据类型占内存空间的大小:

  1. byte 1个字节
  2. short 2个字节
  3. int 4个字节
  4. long 8个字节
  5. float 4个字节
  6. double 8个字节
  7. char 1个字节
  8. boolean 1个字节
  9. 引用数据类型占4个字节

备注:

1byte = 8bit

字节叫byte,它有8位,即8bit

一个位置叫一个比特(1bit)

一个位置有2个状态(一个是0、一个是1)

8位中第一位用来表正正号,即正、负,因此实际上是7个位置用来表示值

一个位置表示2种状态,那么一个字节可以表示 282^8 种状态,表示的数的范围 27-2^7 ~ 2712^7 - 1(+0 和-0 作为值只取1个)

image.png

整型常量

image.png

备注

  • 一个字节是8位,第一个位置只能放符号,即正负,因此1个字节实际上只保留了7个位置来表示值,1个字节可表示的范围就是 27-2^7 ~ 272^7。因此,1个字节可表示的范围就是 27-2^7 ~ 2712^7 - 1 = 256种数值(因为+0 和-0 作为值只取1个)

  • 同理,2个字节共16位,第一位放符号表示正负,实际上15个位置用来表示值,2个字节可表示的范围就是 215-2^15 ~ 21512^15 - 1 = 65536 种数值

  • int 可表示的数值大约是 -21亿 ~ 21亿

  • 整型常量默认是int类型,如 int a = 888

  • 如果声明变量的时候值超过其类型的最大范围就会报错

eg: int类型的值的范围大约 21亿 ~ -21亿

int yearSalary = 3000000000;

image.png

解决的办法就是在值后面加L,作用是把整型常量定义为long类型

long yearSalary = 3000000000L;

如果不加L就会报错

long yearSalary = 3000000000;

image.png

进制

Java语言整型常量的四种表示形式

  • 十进制整数,如12,-34,0
  • 八进制整数, 要求以0开头,如015
  • 十六进制数,要求0x 或 0X 开头,如:0x15
  • 二进制数, 要求0b 或 0B开头,如0b01110011

浮点型(Floating Point Number)

浮点型的重要特点是不精确

image.png

备注

3.14e0e^0 === 3.14 * 10010^0

3.14e1e^-1 === 3.14 * 10110^-1 = 3.14 * 0.1 = 0.314

float & double

  1. float类型又被称作单精度类型,位数可以精确到7位有效数字

  2. double 表示这种类型的数值精度约是float类型的2倍,又被称作双精度类型,绝大部分应用程序都采用double类型

  3. Java浮点类型常量有两种表示形式

  • 十进制数形式: eg: 3.14 314.0 0.314
  • 科学计数法形式: eg: 3.14e0 3.14E2 3.14E-1
  1. 浮点型不精确,不要用于比较

浮点数存在误入误差,数字不能精确表示。浮点数适合普通的科学和工程计算,精度足够;但不适合精度要求非常高的商业计算,这时候用要使用BigDecimal进行运算和比较

  1. 浮点常量默认类型是 double,要改成float可以后面加F或f,就像前面说的整型常量的默认类型是int,如果要转成long类型,就要在数值后面加L或l道理是一样的

敲代码

/*
 * 测试浮点数的基本用法
*/
public class TestFloatNumber{
	public static void main(String[] args){
        double d1 = 3.14;
        double d2 = 3.14E2;    // 科学技术法

        float f1 = 1.65F;      // 浮点常量的默认类型是double,改float后面需要加f

        // 浮点数是不精确的,尽量不要直接比较
        float f2 = 0.1F;
        double d3 = 1.0/10;
        System.out.println(f2 == d3);   // false

        float f3 = 123123123123L;
        float f4 = f3 + 1;
        System.out.println(f3 == f4);   // true
        System.out.println(d2);
	}
}

备注

如果将浮点数默认类型double改为float,数值后面又不加F或f,那么就会报错

尽量不要使用浮点型做比较,如果非要使用精确的比较,那么就使用BigDecimal

image.png

image.png

image.png

字符型

image.png

image.png

历史

  • ASCll用一个字节表示一个字符,一个字节是$2^8$= 256 位,也就是说它最多可以表示256个字符

  • 实际上没有用完256个,只用了128个

  • 如上图2所示,左侧表示的是控制符,右侧才是我们常见的字符

  • 但是英文只有26个字母,1个字节可以搞得定,中文有几万个汉字,搞不定

  • 发展到西欧字符集的时候,它也是用一个字节表示,只不过它用完了256个字符,也就是说对ASCll进行了扩展

  • 到了中国(需要将计算机本地化),由于汉字众多,GB2312就使用2个字节表示一个字符,2162^16 = 65536,后面又陆续的扩展为GBK、GB18030

  • 由于国家众多、文字众多,一人搞一套太麻烦了,于是国际组织弄了一个Unicode字符集(统一的字符集,uni是Unite的缩写),它也是2个字节表示一个字符,也就是说它也可以表示65536个字符

  • 在Unicode字符集出现之前,字符集和编码是一个概念,但是在Unicode字符集出现之后,这两个概念就独立成两个不同的概念。其中UTF-8编码主要用于中文,如果表示中文也用2个字节就太浪费了,于是就采用了可变长度的编码方式,英文采用1个字节表示,其他文字2个字节,中文使用3个字节表示

Unicode

字符型在内存中占2个字节,在Java中使用单引号来表示字符常量。例如:'A'是一个字符,它与“A”是不同的,“A”表示含有一个字符的字符串

char 类型用来表示Unicode编码中的字符。Unicode编码被设计用来处理各种语言的文字,它占2个字节,可允许有65536个字符

备注

Java中字符串不是基本数据类型,而是一个类

字符串:顾名思义一串字符,如果字符串中有4个字符,它就表示4个字符类型串在一起

转义字符

Java语言中允许使用转义字符“\”来将其后的字符转变为其他含义。常用的转义字符机器含义和Unicode值如下所示

image.png

备注

String类,其实是字符序列(char sequence),本质是char字符组成的数组

敲代码

/*
 * 测试char类型的使用
*/
public class TestChar{
    public static void main(String[] args){
        char c1 = 'a';
        char c2 = '中';
        char c3 = '\u0082';  // /u表示Unicode字符集
        System.out.println(c1);
        System.out.println(c2);
        System.out.println(c3);

        // Java中字符串不是基本数据类型,而是一个类
        String str = "平安喜乐";
        System.out.println(str);

        // 转义字符
        System.out.println("\"a\"\n\"b\"\nc\nd\ne\nf\ng");
        System.out.println("q\tw\te\tr");
    }
}

运行结果

image.png

布尔型(boolean)

基本介绍

  1. boolean 类型有两个常量值,true和false
  2. 在内存中占一个字节或4个字节(一般情况是1个字节,定义布尔数组是4个字节),不可以使用0或非0的整数替代true和false。这点和C语言不一样,使用0表示false,使用非0表示true

敲代码

/*
 * 测试boolean类型
*/
public class TestBoolean{
	public static void main(String[] args){
        boolean b1 = true;
        boolean b2 = false;
        if(b1){
                System.out.println("b1是true!");
        }else {
                System.out.println("b1是false!");
        }
	}
}

运行结果

image.png

运算符(operator)

image.png

备注

1. 算数运算符

基本内容

  1. +,-,*,/,% 属于二元运算符。%是取模运算符,就是我们常说的求余数操作
  2. 算数运算符中++(自增),--(自减)属于一元运算符

二元运算符的运算规则

整数运行

  • 如果两个操作数有一个为long,则结果也为long
  • 如果没有long时,结果为int。即使操作数全为short,byte,结果也是int。

浮点运行算

  • 如果两个操作数有一个为double,则结果为double
  • 仅有两个操作数都是float,则结果才为float

取模运算

  • 其操作数可以为浮点数,一般使用整数,结果是“余数”,“余数”符号和左边操作数相同,如: 7 % 3 = 1,-7 % 3 = -1, 7 % -3 = 1

敲代码

/*
  * 测试算数运算符用法
*/
public class TestOperator01{
	public static void main(String[] args){
        int a = 3;
        long b = 4;
        //int c = a + b;       // a+b 的结果是long,long赋值给c是int,报错
        long c = a + b;

        double d = 3 + 3.14;  // 3.14是double类型加整数结果还是double类型
        int d2 = 32 / 3 ;     // 2个整数相除,直接保留结果的整数部分,不四舍五入
        double d3 = 32.0 / 3; // 如果想让结果不是整数,就将其中一个变成浮点数


        System.out.println(d2); // 10
        System.out.println(d3); // 10.666666666666666

        // 取模运算
        int e = 10 % 3;        // 取余操作,结果符号和左边操作数相同
        System.out.println(e); // 1

        // 测试自增、自减
        int g = 30;
        g++;                  // 相当于: g = g + 1
        g--;                  // 相当于: g = g - 1

        g = 10;
        int h = g++;	     // ++在后,先赋值后自增,h=10,g=11
        g = 10;
        int i = ++g;         // ++在前,先自增后赋值,g=11,i=11

        System.out.println(h);  // 10
        System.out.println(i);  // 11
	}
}  

运行结果

image.png

2. 赋值及其拓展赋值运算符

image.png

敲代码

/*
  * 测试拓展运算符的用法
*/
public class TestOperator02{
    public static void main(String[] args){
        int a = 3;
        int b = 4;
        a += b;                 // 相当于 a = a+b
        System.out.println(a);  // 7

        a = 3;
        a *= b + 3;            // 相当于 a = a*(b+3)
        System.out.println(a); // 21
    }
}

3. 关系运算符

关系运算符用来进行比较运算。关系元素的结果是布尔值: true / false;

image.png

备注

  • “=” 号是赋值运算,而真正的判断两个操作数是否相等的运算符是 “==”
  • “==”、“!=” 是所有(基本和引用)数据类型都可以使用
  • “>”、“>=”、“<”、“<=” 仅针对数值类型(byte/short/int/long,float/double 以及char(比较的是Unicode值 0 ~ 65536))

敲代码

/*
  * 测试关系运算符的用法
*/
public class TestOperator03{
    public static void main(String[] args){
        int a = 3;
        int b = 4;
        boolean c = a > b;
        System.out.println(c);                    // false

        char d = 'h';
        System.out.println((int)d);               // char值位于0~65536之间,可以通过int强制转型成数字   14
        boolean e = d > 100;
        System.out.println(e);                    // true
    }
}

4. 逻辑运算符

逻辑运算的操作数和运算结果都是boolean值

image.png

短路与和短路或采用短路的方式。从左到右计算,如果只通过运算符左边的操作数就能够确定该逻辑表达式的值,则不会继续计算运算符右边的操作数,提高效率

敲代码

/*
  * 测试逻辑运算符的用法
*/
public class TestOperator04{
    public static void main(String[] args){
        boolean b1 = false;
        boolean b2 = true;
        System.out.println(b1&b2); //与:有一个false,结果为false
        System.out.println(b1|b2); // 或:有一个true,结果为true
        System.out.println(!b2);   // 非: 取反 ,结果为false
        System.out.println(b1^b2); // 异或:相同为false,不同为true

        // 短路与、短路或
        //int b3 = 3/0;              // 报不能除以0的异常
        boolean b3 = 1 > 2 && (4 < 3 / 0);
        System.out.println(b3);      // 短路与遇到false,得到结果,运算符右边不执行,所以不报错

        boolean b4 = 1 > 2 & (4 < 3 / 0);
        System.out.println(b4);      // 报错,因为不是短路与,运算符右边也执行
    }
}

5. 位运算符

位运算符值得是进行二进制位的运算

image.png

敲代码

/*
  * 测试位运算符的用法
*/
public class TestOperator05{
	public static void main(String[] args){
        int a = 7;
        int b = 8;
        System.out.println(a & b);         // 按位与:0 0 0 0                             结果: 0
        System.out.println(a | b);         //  按位或:1 1 1 1                             结果: 15
        System.out.println(a ^ b);         // 按位异或(相同false即0,不同true 1) 1 1 1 1  结果: 15
        System.out.println(~b);            // 取反:0 1 1 1 (补码,暂不用掌握)            结果:-9

        // 移位
        int c = 5 << 1;                    // 左移一位乘2,相当于5*2
        int d = 5 << 2;                    // 相当于5*2*2      
        System.out.println(c);             // 10
        System.out.println(d);             // 20
        System.out.println(40>>3);         // 右移一位除以2,相当于 40 / 8 = 5
	}
}

image.png

备注

eg: 按位与计算时,从右往左数,用7的二进制的第一位和8的二进制第一位进行位运算(等同于逻辑运算), 1 相当于true,0相当于false;

image.png

乘以2,除以2,使用移位运算最快

6. 字符串连接符

“+” 运算符两侧的操作数中只要有一个是字符串(String)类型,系统为自动将另外一个操作数转换为字符串后再进行连接

敲代码

/*
  * 测试字符串连接符的用法
*/
public class TestOperator06{
	
    public static void main(String[] args){
        String a = "3";
        int b = 4;
        System.out.println(a + b);         // 结果:字符串"34"

        // 条件是String,不是char。若是char,则仍然是加法
        char c1 = 'h';
        char c2 = 'i';
        System.out.println(c1 + c2);       // 结果: 209
        // 通过加空字符串,将c1左边的加号变成字符串连接符
        System.out.println("" + c1 + c2);  // 结果:"hi"
}
}

注意

Java中的双引号和单引号表示的意思也是不一样的,单引号表示的是字符,而双引号表示的是字符串,这点和JS不同

7. 条件运算符 / 三元运算符

就是JS中的三目运算符

image.png

运算符优先级

image.png

备注

  • 括号运算符 > 算数运算符( 乘除 > 加减 ) > 关系运算符 > 位运算符和逻辑运算符(其中非>与>或)
  • 不用刻意其记这些优先级,表达式里优先使用小括号来组织!
  • 逻辑与、逻辑或、逻辑非的优先级一定要熟悉(逻辑非>逻辑与>逻辑或)。如:a||b&&c的运算结果是:a||(b&&c) ,而不是(a||b)&&c
  • 建议使用小括号去组织表达式的逻辑顺序

敲代码

// 优先级问题的用法
boolean s1 = true,s2 = true,s3 = false; // 逻辑运算符: 非 > 与 > 或
System.out.println(s1||s2&&s3);         //true
// 建议使用小括号组织表达式
boolean s4 = (3>1 || 4>3) && (3<5);  
System.out.println(s4);                 // true

自动类型转换

八种数据类型中,除了boolea之外的其中类型是可以自动转化的

自动类型转换值得是容量小的数据类型可以自动转换为容量大的数据类型。如下图所示,黑色实线表示无数据丢失的自动类型转换,而虚线表示在转换时可能会有精度的损失

image.png

备注

  • 容量的大与小,并不是指表示的字节数,而是指这个类型能表示的范围
  • byte可表示1个字节,表示的范围是 -128 ~ 127;short可表示2个字节,表示的范围大约是正负3万;int可表示4个字节,表示的范围是正负21亿;long可表示八个字节;char可表示2个字节,可表示的范围是0~65536;float可表示4个字节;double可表示8个字节

敲代码

/*
 测试类型自动转化
*/
public  class  TestTypeAutoConvert{
	public static void main(String[] args){
        // 容量小的类型可以自动转化成容量大的类型
        int a = 1234;
        long b = a;
        //int c = b;              // long类型不能自动转化成int
        double d = b;             // long转double可转,只是可能会丢失精度
        float f = b;              // long可转float,只是可能会丢失精度


        // 特例:整型常量是int类型,但是可以自动转成:byte/short/char
        // 只要不超过对应类型的表述范围
        byte b1 = 123;
        //byte b2 = 1234           // int自动转byte类型失败,因为1234超过了byte可表示的范围

        char h3 = 97;
        System.out.println(h3);    // a
}
}

运行结果

image.png

image.png

备注

整型常量是int类型,但是可以自动转成:byte/short/char,只要不超过对应类型的表述范围。

如:上例中,整型123默认是int类型,byte = 123,没有超过byte可表示的范围(-128~127),因此就可以将int类型自动转成byte类型

强制类型转换

强制类型转换,又称为造型(cast),用于强制转换数值的类型,可能损失精度

强制转换的格式: (type) var

敲代码

/*
 * 测试类型强制转换
*/
public class TestTypeCast{
	public static void main(String[] args){
        double a = 3.141592654;
        int b = (int)a;        // 浮点数强转为整数,直接丢失小数部分                
        System.out.println(b); // 3

        int c = 97;
        char d = (char)c;
        System.out.println(d);  // 'a'

        // 强制转型,超过了表示的范围,则会转成一个完全不同的值
        byte b1 = (byte)300;
        System.out.println(b1); // 44
}
}

备注

强制类型转换,超过了表示的范围,则会转成一个完全不同的值(什么值呢?谁都不知道^^)

基本类型转化是常见错误和问题

内容

  1. 操作比较大的数时,要留意是否溢出,尤其是整数操作时
  2. L和l的问题:
    • 不要命名名字带有l的变量。字母l容易和数字1混淆。
    • long类型使用大写L,不要用小写l

敲代码

/*
 * 测试类型强制转换 
*/
public class TestTypeCast{
	public static void main(String[] args){
		double a = 3.141592654;
		int b = (int)a;        // 浮点数强转为整数,直接丢失小数部分                
		System.out.println(b); // 3
		
		int c = 97;
		char d = (char)c;
		System.out.println(d);  // 'a'
		
		// 强制转型,超过了表示的范围,则会转成一个完全不同的值
		byte b1 = (byte)300;
		System.out.println(b1); // 44
		
		// 测试常见错误之溢出
		int money = 1000000000; // 10亿
		int years = 20;
		// 返回total是负数,超出int的范围
		int total = money*years;
		System.out.println("total=" + total);
		// 返回total1是负数,乘积还是int类型且值为200亿,已经溢出了int的最大表示范围
		long total1 = money*years;
		System.out.println("total1=" + total1);
		//返回total2正确:先将一个因子变成long,整个表达式发生提升,全部用long来计算
		long total2 = money*((long)years);
           // 1变成long类型,结果还是long类型
	        long total2 = 1L*money*years
		System.out.println("total2=" + total2);
	}
}

运行结果

image.png

备注

int可以表示正负21亿的数

为什么total1使用long接收也会溢出呢?

image.png

因为 money 和 years 都是int类型,它们的乘积还是int类型且值为200亿,已经溢出了int的最大表示范围,结果就会出现不正常的值(money 和 years的乘积会赋值给total1,相当于把一个错误的值赋值给了total1)

Scanner处理键盘输入

Scanner让程序和用户通过键盘交互

敲代码

/*
 * 测试键盘输入:Scanner用法
*/
import java.util.Scanner;

public class TestScanner{
	public static void main(String[] args){
        Scanner  s = new Scanner(System.in);

        // 输入用户名、年龄、月薪
        System.out.println("请输入用户名:");
        String uname = s.nextLine();  		    // 从控制台读取一个字符串

        System.out.println("请输入你的年龄:");
        int age = s.nextInt();

        System.out.println("请输入你的月薪:");
        double monthSalary = s.nextDouble();

        System.out.println("\n\n\n\n\n\n");
        System.out.println("***************年薪计算器*****************");
        System.out.println("用户名:"+uname);
        System.out.println("年龄:" + age);
        System.out.println("年薪" + (monthSalary*12));
}
}

运行结果

image.png

使用IDEA实现一个基础桌球游戏

敲代码

/**
 * (温馨提示:仅作为提高学习兴趣,照着代码一样敲一遍就行,不懂没关系,很多知识还没学)
 * 第一步: 创建项目和窗口
 * 第二步:加载两个图片
 * 第三步: 实现动画,小球沿着水平方向移动并做边界检测
 * 第四步: 实现小球沿着任意角度飞行(会用到三角函数)
 */

import java.awt.*;
import javax.swing.*;
public class BallGame extends JFrame{
    //加载图片
    Image ball = Toolkit.getDefaultToolkit().getImage("images/ball.png");
    Image desk = Toolkit.getDefaultToolkit().getImage("images/desk.jpg");

    double x = 200;
    double y = 200;

    double degree = 3.14 / 3;  // 弧度  3.14 = 180º   60º

    //绘制窗口
    public void paint(Graphics g){
        System.out.println("窗口被画了一次");
        g.drawImage(desk,0,0,null);
        g.drawImage(ball,(int)x,(int)y,null);

        // 控制小球移动
        x = x + 10 * Math.cos(degree);
        y = y + 10 * Math.sin(degree);

        // 改变小球撞击后的方向
        //小球撞上下边界的时候,反射角等于负的入射角;小球撞左右边界的时候,反射角度等于180度 - 小球入射角
        // 碰到上下边界
        if(y > 501 - 40 - 30 || y < 40 + 30){  // 前面的:40是桌边的高度 30是小球的直径;后面的: 一个40是标题栏的高度、一个40是桌边的高度
            degree = -degree;
        }
        // 碰到左右边界
        if(x > 856 -40 - 30 || x < 40){        // 40是边的宽度 30是小球的直径
            degree = 3.14 - degree;
        }

    }

    //创建窗口
    void launchFrame(){
        setSize(856,501);
        // 弹窗相对于窗口左上角原点的坐标
        setLocation(100,100);
        setVisible(true);

        // 实现动画,每秒绘制窗口25次
        while (true){
            repaint();

            try {
                Thread.sleep(40); // 1s = 1000ms;大约1秒绘制1000/40 = 25次。
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

    }
    public static void main(String[] args){
        System.out.println("我的小游戏开始了!");

        BallGame game = new BallGame();
        game.launchFrame();
    }
}

运行结果

202.gif