杨明翰的Java教学系列之基础语法篇V1.1

Java教学系列 专栏收录该内容
11 篇文章 2 订阅


传送门

  1. 杨明翰的Java教学系列之认识Java篇

  2. 杨明翰的Java教学系列之基础语法篇

  3. 杨明翰的Java教学系列之初级面向对象篇

  4. 杨明翰的Java教学系列之数组篇

  5. 杨明翰的Java教学系列之进阶面向对象篇

  6. 杨明翰的Java教学系列之异常篇

  7. 杨明翰的Java教学系列之集合框架篇


前言

Java中包含了许多的基础语法知识点,
正是由于这些基础的知识点才有可能允许让我们编写出“绚烂”的程序。


变量与数据类型

编程时,其实大部分时间都是在跟数据的存储打交道,
那需要使用什么东西做临时存储呢?

答案是变量,变量前面需要定义数据类型,
来限定变量里具体存储的数据是什么类型。

变量

变量是指在程序运行过程中随时可以发生内容变化的数据,
Java使用变量临时存储各种数据,
变量是存储数据的基本单元,
创建变量的时候,系统自动在内存中申请空间。

例如:用户在界面中输入了一个数字,
我们要用变量存储这个数字,以便以后使用。

变量必须要先[定义/声明],
再初始化(也可以不手动初始化,有自动的默认值),
之后才能使用。

变量分为三种:
[类变量/静态变量]、实例变量、局部变量,
这些知识点会在后面的初级面向对象篇文章中展开,
暂不赘述。

那每个变量都是存储的什么样的数据呢?
这就衍生出来一个概念,数据类型。

数据类型

Java强制要求必须定义变量的数据类型,
所以说Java是强类型语言。

像Javascript则没有这种要求,
所以说Javascript是弱类型语言。
一般说来,在创建大型程序时,强类型有助于减少程序错误。

数据类型用于约束变量中存储的数据的类型,
需要为每个变量指明一个具体的数据类型。

数据类型可以五花八门,可以是字符、数字、数组、对象等等。
内存管理系统根据变量的类型为变量分配存储空间,
分配的空间只能用来储存该类型数据。

例如:
数据类型是字符串的变量,
那么这个变量只能存储字符串,不能存储数字。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Kb0TEcXi-1603360806825)(evernotecid://85A94EB2-9BD2-45DE-A16D-D9C9CD7ECF0B/appyinxiangcom/12192613/ENResource/p508)]

变量与数据类型语法

//语法: [修饰符] 数据类型 变量名 [= 初始值];
public String name = "frank";
private String address;
static int age = 20;
double b = 0.111;
Person p ;
String a = "张三",b = "李四";//变量还可以这样定义,但不推荐。
class Hello{
  public static void main(String args[]) {
    double salary;  //声明局部变量
    salary = 1500.00;  //局部变量赋初值,也可以简化成一句double salary = 1500.00;
    System.out.println(salary);   //访问局部变量
  }
}
  • 修饰符
    变量被final、private、protected、public、static等关键字修饰,具体关键字的定义会在后续的文章中展开,暂不赘述。

  • 数据类型
    基本数据类型与引用数据类型,
    例如:int是整型,String是字符串等等;

  • 变量名
    首字母必须小写,可以随意定义,但原则上是有意义的英文单词;

  • 初始值
    可以没有,如果没有则系统会给一个默认值,
    具体默认值要根据具体的数据类型而定;

  • “=”
    等号表示赋值,将等号左边右边的值赋给了等号左边的变量;

  • “;”
    分号表示一句话的结束;

数据类型种类

Java的数据类型分为:基本数据类型和引用数据类型。
在Java中有8种数据类型来存储数值(整数,小数)、字符和布尔值。
除了8种基本数据类型以外,其他所有的数据类型都被统称为引用数据类型。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JItuUebl-1603360806829)(evernotecid://85A94EB2-9BD2-45DE-A16D-D9C9CD7ECF0B/appyinxiangcom/12192613/ENResource/p507)]

当变量没有被赋值的时候,会有默认值,
根据不同的数据类型来区分不同的默认值。

数据类型默认值
byte0
short0
int0
long0L
float0.0f
double0.0d
char‘\u0000’
String&Objectnull
booleanfalse

注意:String字符串不是基本数据类型,而是引用数据类型。

基本数据类型


小贴士
字节:此处为存储空间大小,变量存储在内存中的大小;
表数范围:变量可以赋多大的数值;

整型

整型(整数类型)用来存储整数数值,
即没有小数部分的数值。
可以是正数,也可以是负数,默认是int类型。

byte

1个byte类型整数在内存里占8位(1个字节),
表数范围-128(-2的7次方)~127(2的7次方-1),
byte类型用在大型数组中节约空间,一般用于文件流等,主要代替整数,
因为byte变量占用的空间只有int类型的四分之一;

byte a = 50;
byte b = -100;

表数范围的例子:

byte a = 127;//正确
byte b = 128;//错误

(注意:内存是一种有限的资源,不要无休止的滥砍滥伐。)

short

1个short类型整数在内存里占16位(2个字节),
表数范围-32768(-2的15次方)~32767(2的15次方-1),
short数据类型也可以像byte那样节省空间。一个short变量是int型变量所占空间的二分之一;

short a = 1000;
short b = -2000;
int

1个int类型整数在内存里占32位(4个字节),
表数范围是:-2147483648~2147483647,
(-2的31次方)~(2的31次方-1),
一般地整型变量默认为int类型。

int a = 100000;
int b = -200000;
整数的4种表示方式
十进制

每位可以写0~9,注意第一位不能是0。

int a = 10;//输出10
int b = 50;//输出50
二进制

必须以0b或0B开头,可以写0~1。(在JDK1.7之后才有)

int a = 0b11101001;//输出233
int b = 0B00000001;//输出1
int c = 0B00000010;//输出2
八进制

必须以0开头,可以写0~7。

int a = 07;//输出7
int b = 017;//输出15
int c = 0123;//输出83
十六进制

必须以0x或0X开头,可以写09,AF,a~f,
不要认为看到定义的整型变量被赋值上字母是,
一件很奇怪的事情。

int a = 0X8A;//输出138
int b = 0x1f;//输出31
long

1个long类型整数在内存里占64位(8个字节),
表数范围-9223372036854775808(-2的63次方)~9223372036854775807(2的63次方-1),
long类型的整数是以L或者l在结尾表示,
不要写小写的L,因为会与数字1混淆。
这种类型主要使用在需要比较大整数的系统上;

long a = 100000L;
long b = -200000L;

浮点型

带小数点的数值均可使用浮点类型表示,
float为单精度浮点类型,double为双精度浮点类型。

在Java里面小数默认为double类型,
后面加f或F表示float类型 。

需要注意的是,float与double均不能进行精准小数运算, 因为底层二进制无法精准表述带小数点的十进制数,
通常的解决方案是使用BigDecimal。

浮点数无法进行精准运算,
因为底层二进制无法精准表述带小数点的十进制。

double a = 2.0 - 1.8;
//输出0.19999999999999996
System.out.println(a);

float b = 2.0f - 1.8f;
System.out.println(b);

//解决方案
BigDecimal b1 = new BigDecimal("2.0");
BigDecimal b2 = new BigDecimal("1.8");
System.out.println(b1.subtract(b2).doubleValue());

float:1个float类型浮点数在内存里占32位(4个字节),表数范围-3.403E38~3.403E38。
后缀为F与f均可使用,float在储存大型浮点数组的时候可节省内存空间;

float a = 234.5f;
float b = 234.0F;
float c = 33f;//输出33.0

double:1个double类型浮点数在内存里占64位(8个字节),表数范围-1.798E308~1.798E308。
后缀为D与d均可使用,默认不加后缀 ;

double a = 123.4;
double b = 12345.0;
double c = 110D;//输出110.0
double d = 120d;//输出120.0
浮点数的3种表示方式
十进制

包含一个小数点,例:5.12,512.0,0.512,3.1415926F等。

float a = 3.141566666666666666F;//输出3.1415668
double b = 3.141566666666666666;//3.141566666666667
科学计数法

5.12e2(即5.12*10的2次方),只有浮点类型才能用科学技术法,E与e均可使用。

double a = 5.12e-2;//输出0.0512
double b = 5.12e2;//输出512.0
表示溢出或出错

正无穷大:正数(不是正整数,而是正的小数)除以0,
用Double.POSITIVE_INFINITY或Float.POSITIVE_INFINITY表示。
负无穷大:负数(不是负整数,而是负的小数) 除以0,
用Double.NEGATIVE_INFINITY或Float.NEGATIVE_INFINITY表示。
非数:0.0除以0.0或对负数开方(例如:根号-2),用Double.NaN或Float.NaN表示。

所有正无穷数值相等+∞=+∞;
所有负无穷数值相等-∞=-∞;
非数不会与任何相等,包括非数,NaN≠NaN;

//正无穷大
double a = 6.0 / 0;//输出Infinity
double b = 255.0 / 0;//输出Infinity
double c = Double.POSITIVE_INFINITY;//输出Infinity
System.out.println(a==b);//输出true
System.out.println(a==c);//输出true

//负无穷大
double d = -15.0 / 0;//输出-Infinity
double e = -244.0 / 0;//输出-Infinity
double f = Double.NEGATIVE_INFINITY;//输出-Infinity
System.out.println(d==e);//输出true
System.out.println(d==f);//输出true

//非数
double g = 0.0/0.0;//输出NaN
double h = Double.NaN;
System.out.println(g==g);//输出false
System.out.println(g==h);//输出false

字符型

单个字符用char类型表示,必须使用单引号括起来。
char:1个char类型整数在内存里占16位(2个字节),
表数范围0~65535(2的16次方),无符号位,char数据类型可以储存任何字符;

字符的4种表示方式
作为整数值

16位无符号整数(不能是负数),0~65535,但这里并不是表示真正地数字而是ASCII码。
支持四种整型表示方式,分别为:二进制、八进制、十进制、十六进制。
不要认为看到定义的字符变量被赋值上整数是一件很奇怪的事情。

char x = 96;//表示'字符
//下面4个char变量都输出'a'
char a = 97;//十进制的97
char b = 0x61;//十六进制的97
char c = 0141;//八进制的97
char d = 0b1100001;//二进制的97
char e = 'e';
char f = 'f';
System.out.println(e+f);//输出为203,是ASCII码的数值相加


小贴士:
ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)
是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其他西欧语言。
它是现今最通用的单字节编码系统,并等同于国际标准ISO/IEC 646。

在计算机中,所有的数据在存储和运算时都要使用二进制数表示
(因为计算机用高电平和低电平分别表示1和0),
例如,像a、b、c、d这样的字母(包括大写)、以及0、1等数字还有一些常用的符号
(例如*、#、@等)

在计算机中存储时也要使用二进制数来表示,而具体用哪些二进制数字表示哪个符号,
当然每个人都可以约定自己的一套(这就叫编码),而大家如果要想互相通信而不造成混乱,
那么大家就必须使用相同的编码规则,于是美国有关的标准化组织就出台了ASCII编码,
统一规定了上述常用符号用哪些二进制数来表示。

ASCII 码使用指定的7 位或8 位二进制数组合来表示128 或256 种可能的字符。

单个字符(英文字母与汉字与符号)
char a = 'a';
char b = 'C';
char c = '我';
char d = '~';
转义符
转义字符含义
\r表示接受键盘输入,相当于按下了回车键
\n表示换行
\t表示制表符Table键
\b表示退格键,相当于Back Space
\'相当于单引号'
"相当于双引号"
\\表示一个斜杠\
\d八进制
\xd十六进制
\udUnicode字符
char a = '\n';
String b = "bbb";
String c = "ccc";
System.out.println(b+a+c); //输出bbb回车ccc
System.out.println(b+c);//bbbccc
Unicode值

格式为’\uxxxx’,Java使用UTF-16,使用4位16进制数字表示,
支持所有书面语言的字符,包括中文。
最小值为’\u0000’,最大值为’\uffff’

char a = '\u8888';//输出'袈'


小贴士:
Unicode又称为:统一码、万国码、单一码,是计算机科学领域里的一项业界标准,
包括字符集、编码方案等。
全球所有的文字,都可以用Unicode码表示,超过65,000个字符,而ASCII只有128~256个字符。

Unicode为每种语言中的每个字符设定了统一并且唯一的二进制编码,
以满足跨语言、跨平台进行文本转换、处理的要求。
1990年开始研发,1994年正式公布。

比较有趣的是,下面4个变量都表示’a’。

char a = '\u0061';//unicode值
char b = 97;//十进制的ASCII码所对应的字母
char c = 0141;//八进制的ASCII码对应的字母
char d = 'a';//单个英文字符

注意:

  1. char在正常开发中出镜率不是特别高,一般使用String字符串类型, String类型可不是基本数据类型哟,而是一个类。
  2. String除了不能表示整数ASCII码外,其余char的表示方式String都支持。
  3. char使用单引号'',String使用双引号""。

布尔型

boolean类型适于逻辑运算,一般用于程序流程控制。
boolean 数据类型有两个值:true和 false(不带引号),默认值是false。

boolean a;
a = true;

boolean b = false;
boolean flag = true;
if(flag){
  System.out.println("yes~");
}
if(flag==false){
  System.out.println("no~");
}

引用数据类型

除了8种基本数据类型以外的所有数据类型,都是引用数据类型。

(在Java中,引用类型的变量非常类似于C/C++的指针。)

类(Java官方以及第三方的类库+我们自己定义的类)、数组、接口都是引用数据类型。
所有引用类型的默认值都是null,主要是用类、数组、接口等作为数据类型来声明一个变量。
关于引用数据类型方面的知识会在面向对象初级篇中还有介绍。

Person p1 = new Person();
//Person类型的变量p1引用了Person类的实例(变量p1指向了Person类的实例的引用)
//新手玩家可以pass,因为涉及到Java堆栈内存:new Person()会生成一个Person对象的引用,
这个引用指向了p1变量。

//分解动作
Person p1;
//用Person类作为数据类型来声明一个变量p1
p1 = new Person();
//使用new关键字调用Person类的构造方法来实例化对象,
//将对象的引用指向给p1变量(将对象赋值给了p1变量),
//那p1就变成了Person对象的引用,或者说变量p1引用了Person类的对象。

//注意:p1不是对象,而是对象的引用。

Null

null代表声明了一个空对象,或者不确定的对象,即还没有分配内存空间,
对空对象做任何操作都不行,
除了使用"=“与”=="。
一般用在是一个对象引用指向空(基本数据类型无法设为null),释放内存,
让一个非null的引用类型变量指向null。
这样这个对象就不再被任何对象应用了。等待JVM垃圾回收机制去回收。

Person p1 = new Person();//变量p1指向Person对象
p1 = null;//变量p1指向空。

基本数据类型转换

在Java中经常会出现多种数据类型进行混合运算,
不同的数据类型必须先转换成同一类,才能进行运算,同一类数据类型也是有大小关系的。
Java中有两种数据类型转换方式:自动类型转换、强制类型转换。

先来记住一个口诀:
从小到大自动转;
从大到小强制转;
强制类型转换会有溢出风险,就像有两杯水:
1.一大满杯与一小空杯,大杯的水倒满小杯后会溢出来。
2.一大空杯与一小满杯,小杯的水倒满大杯后并不会溢出。

自动类型转换(隐式类型转换)

目标类型的取值范围要大于源类型
(例如:int大于byte,那么byte就可以自动转成int)。
byte->short->int->long->float->double(从小到大)
char->int->long->float->double(从小到大)

byte a = 4;
int b = a;//byte可以自动转换成int,因为int比byte大。

char x = 4;
int y = x;

long i = 4;
float j = i;

表达式类型的自动提升:
当一个算术表达式中包含多个基本数据类型的值在进行混合运算时,
整个表达式的数据类型将发生自动提升,
自动将所有数据类型转换成容量最大的数据类型,然后进行计算。

规则:
1.所有的byte,short,char之间不会相互转换,首先会自动升为int。
2.整个表达式的类型自动提升到与表达式中最高等级操作数同样的类型
(操作数的等级排列,从大到小:double->float ->long->int )

double a = 1;
int b = 2;
System.out.println(a+b);//输出3.0

byte d = 1;
byte e = 1;
int g = d+e;//2个byte相加,结果是int。
byte f = (byte)(d+e);//2个byte相加,结果是int,int需要强转成byte。

强制类型转换(显式类型转换)

容量大的数据类型转换为容量小的数据类型时,需要强制类型转换,需要显式的定义。
(例如:byte小于int,那么byte必须要强制转成int)。
语法:变量 = (目标类型)值;
double->float ->long->int->short->byte(从大到小)

进行强制类型转换时一定要谨慎,因为整数类型进行强制转换时会发生溢出,
浮点数进行强制转换时会发生精度失准的情况,就像碗小,水放的多了会溢出一样。

int a = 123456789;
byte b = (byte)a; //进行强制类型转换,b=21,因为发生溢出。

int c = 1;
byte d = (byte)c;//进行强制类型转换,d=1,没有发生溢出。

注意:
boolean无法转换成其他数据类型;
char的字符被转成int,变成对应的ASCII值;
浮点数到整数的转换是通过舍弃小数得到,而不是四舍五入;

基本数据类型封装类

基本数据类型封装类也叫包装类型
8种基本数据类型还对应着8种包装类,
包装类里有一些常见属性,
例如上面提到的表数范围、占多少位等,
以及提供一些工具方法可以做数据类型转换等操作,
基本数据类型与包装类型的初始值不同,
例如int的初始值为0,而包装类则为null,
包装类经常被用在数据表映射成实体Bean的属性中。

他们的对应关系如下:
byte->Byte
short->Short
int->Integer
long->Long
float->Float
double-Double
char->Character
boolean->Boolean

String a = "5";
int b = (int)a;//无法直接将字符串转成整型
int b = Integer.valueOf(a);//因此需要使用包装类的方法来实现

// byte
System.out.println("基本类型:byte 二进制位数:" + Byte.SIZE); 
System.out.println("包装类:java.lang.Byte"); 
System.out.println("最小值:Byte.MIN_VALUE=" + Byte.MIN_VALUE); 
System.out.println("最大值:Byte.MAX_VALUE=" + Byte.MAX_VALUE); 
System.out.println(); 

// short
System.out.println("基本类型:short 二进制位数:" + Short.SIZE); 
System.out.println("包装类:java.lang.Short"); 
System.out.println("最小值:Short.MIN_VALUE=" + Short.MIN_VALUE); 
System.out.println("最大值:Short.MAX_VALUE=" + Short.MAX_VALUE); 
System.out.println(); 

// int 
System.out.println("基本类型:int 二进制位数:" + Integer.SIZE); 
System.out.println("包装类:java.lang.Integer"); 
System.out.println("最小值:Integer.MIN_VALUE=" + Integer.MIN_VALUE); 
System.out.println("最大值:Integer.MAX_VALUE=" + Integer.MAX_VALUE); 
System.out.println(); 

// long 
System.out.println("基本类型:long 二进制位数:" + Long.SIZE); 
System.out.println("包装类:java.lang.Long"); 
System.out.println("最小值:Long.MIN_VALUE=" + Long.MIN_VALUE); 
System.out.println("最大值:Long.MAX_VALUE=" + Long.MAX_VALUE); 
System.out.println(); 

// float 
System.out.println("基本类型:float 二进制位数:" + Float.SIZE); 
System.out.println("包装类:java.lang.Float"); 
System.out.println("最小值:Float.MIN_VALUE=" + Float.MIN_VALUE); 
System.out.println("最大值:Float.MAX_VALUE=" + Float.MAX_VALUE); 
System.out.println(); 

// double 
System.out.println("基本类型:double 二进制位数:" + Double.SIZE); 
System.out.println("包装类:java.lang.Double"); 
System.out.println("最小值:Double.MIN_VALUE=" + Double.MIN_VALUE); 
System.out.println("最大值:Double.MAX_VALUE=" + Double.MAX_VALUE); 
System.out.println(); 

// char 
System.out.println("基本类型:char 二进制位数:" + Character.SIZE); 
System.out.println("包装类:java.lang.Character"); 
// 以数值形式而不是字符形式将Character.MIN_VALUE输出到控制台 
System.out.println("最小值:Character.MIN_VALUE="+ (int) Character.MIN_VALUE); 
// 以数值形式而不是字符形式将Character.MAX_VALUE输出到控制台 
System.out.println("最大值:Character.MAX_VALUE="+ (int) Character.MAX_VALUE);

自动装箱&拆箱

自动装箱:
把一个基本数据类型变量直接赋给对应的包装类变量,
或赋给Object(所有类的父类)变量。

自动拆箱:
允许直接把包装类对象直接赋给一个对应的基本数据类型变量。

int a = 1;
Integer b = a;//装箱,相当于自动调用了a = Integer.valueOf(a);
Object c = true;//装箱
int d = b;//拆箱,相当于自动调用了b = b.intValue();

Integer

Integer是int的包装类型,使用率很高,也会出现一些错误的使用方式而导致一些bug。
例如我们想对2个Integer类型的变量数值进行比相等,就必须要使用intValue()方法来取值。

在JDK1.5中添加了一项新特性,将-128~127这个范围内的数字缓存了起来,
在这个范围内的数字都会从缓存中取值,每次都返回相同内存地址的数字。

Integer a = 1314159265;
Integer b = 1314159265;

System.out.println(a==b);//输出false
System.out.println(a.intValue()==b.intValue());//输出true

Integer c = 127;
Integer d = 127;

System.out.println(c==d);//输出true
System.out.println(c.intValue()==d.intValue());//输出true


运算符

运算符是一种特殊的符号,
用以表示数据的运算、赋值和比较。
用于操作一个或多个参数以得出结果。

运算符的种类

算术运算符

符号含义备注
+加法a+b
-减法a-b
*乘法a*b
/除法a/b,两个整数相除,只保留整数部分。有小数参与,则保留小数。0除以任何数都等于0,任何数除以0会造成不同的错误(整数会报异常,浮点数会出正无穷和负无穷)。
%取余a%b,取余数,例如6%4=2
++自增操作数的值增加1,++放在变量前或后是有区别的,++变量名:变量在参与其他操作前先将自己加1,变量名++:先用原来的值参与其他操作后,再将自己加1。
--自减操作数的值减少1,其余同上
+字符串连接当操作数中只要有一个是String类型,系统会自动将另一个操作数转换成字符串类型,然后进行连接。注意:如果String是在后面做的连接,则前面先进行整数计算。2+3 + "你好"->5你好,"你好"+2+3->你好23
int x,y,z;
x = 18;
y = x++;//++运算符放在变量后面表示后加1,先把18赋值给y,然后x再加1,此时x=19,y=18
z = ++x;//++运算符放在变量前面表示先加1,x加1后为20,然后x再赋值给z,此时x=20,y=18,z=20

int d = 5%3; //输出2
int e = -5%3;//输出-2
int f = 5/2;//输出2
double g = 5.0/2;//输出2.5

比较运算符&关系运算符

符号含义备注
==相等于检查如果两个操作数的值是否相等,如果相等则条件为真。会返回一个true或false,注意不要写成"="。对于基本数据类型比较的是值;对于引用数据类型比较的是内存地址;
!=不等于检查如果两个操作数的值是否相等,如果值不相等则条件为真。
<小于检查左操作数的值是否小于右操作数的值,如果是那么条件为真。
>大于检查左操作数的值是否大于右操作数的值,如果是那么条件为真。
<=小于等于检查左操作数的值是否小于或等于右操作数的值,如果是那么条件为真。
>=大于等于检查左操作数的值是否大于或等于右操作数的值,如果是那么条件为真。
boolean a = true;
boolean b = false;
System.out.println(a==b);//输出false
System.out.println(a!=b);//输出true

int c = 10;
int d = 8;
System.out.println(c>d);//输出true

int a = 10;
int b = 10;
System.out.println(a==b);//输出true

String a = new String("123");
String b = new String("123");
System.out.println(a==b);//输出false

逻辑运算符

逻辑运算符两端的操作数必须是布尔类型的值。

符号含义备注
&&逻辑与当且仅当两个操作数都为真,条件才为真。相当于“且”,如果用&&连接表达式时,如果左面的表达式为false,则将不会计算其右边的表达式,又称"短路逻辑与"。
||逻辑或如果任何两个操作数任何一个为真,条件为真。相当于“或”,如果左面的表达式为true,则将不会计算其右边的表达式,又称"短路逻辑或"。
!逻辑非用来反转操作数的逻辑状态。如果条件为true,则逻辑非运算符将得到false。
boolean a = true;
boolean b = false;
System.out.println(a&&b); //输出false
System.out.println(a||b); //输出true
System.out.println(!(a&&b)); //输出true

int c = 2;
int d = 1;
boolean e = (c!=2 && d==d++);//猜猜e,d输出什么?
boolean f = (c==2 && d==d++);//猜猜f,d输出什么?

int x = 5;
boolean y = (x<4)&&(x++<10);
System.out.println(y); //输出false,因为短路了
System.out.println(x);//输出5

赋值运算符

符号含义备注
=x=y;将右操作数的值赋给左侧操作数,把变量y的值赋给x
+=x+=y;加和赋值操作符,它把左操作数和右操作数相加赋值给左操作数
-=x-=y;减和赋值操作符,它把左操作数和右操作数相减赋值给左操作数
*=x*=y;乘和赋值操作符,它把左操作数和右操作数相乘赋值给左操作数
/=x/=y;除和赋值操作符,它把左操作数和右操作数相除赋值给左操作数
%=x%=y;取模和赋值操作符,它把左操作数和右操作数取模后赋值给左操作数
<<=x<<=y左移位赋值运算符
>>=x>>=y右移位赋值运算符
&=x&=y按位与赋值运算符
^=x^=y按位异或赋值操作符
|=x|=y按位或赋值操作符
int a = 10;
int b = 20;
int c = 0;
c = a + b;
System.out.println(c); //输出30
c += a ;
System.out.println(c); //输出40
c -= a ;
System.out.println(c); //输出30
c *= a ;
System.out.println(c); //输出300
a = 10;
c = 15;
c /= a ;
System.out.println(c); //输出1
a = 10;
c = 15;
c %= a ;
System.out.println(c); //输出5
c <<= 2 ;
System.out.println(c); //输出20
c >>= 2 ;
c >>= 2 ;
System.out.println(c); //输出1
c &= a ;
System.out.println(c); //输出0
c ^= a ;
System.out.println(c); //输出10
c |= a ;
System.out.println(c);//输出10

String x = "alex";
String y = "jack";
x = y;
System.out.println(x); //猜猜看输出什么?
System.out.println(y);//猜猜看输出什么?

条件运算符

条件运算符很独特,因为它是用三个操作数组成表达式的三元运算符(也叫三目运算符)。
所谓三元运算符,是对三个表达式进行的集中比较,表达式1的结果为true时,就为第二个表达式,
如果为false时,就为第三个表达式。它可以替代某种类型的 if-else语句。
语法是: 表达式1?表达式2:表达式3

boolean a = (4 < 3) ? true : false;//a=false

instance of运算符(新手PASS)

该运算符用于操作对象实例,检查该对象是否是一个特定类型(类类型或接口类型)。

格式:

( Object reference variable ) instanceof (class/interface type)

如果运算符左侧变量所指的对象,
是操作符右侧类或接口(class/interface)的一个对象,
那么结果为真。

String name = "James";
boolean result = name instanceof String; 
// 由于 name 是 String 类型,所以返回真

位运算符

位运算符只对byte、short、char、int、long有效,
涉及到二进制编程&位运算,新手PASS。

符号含义备注
&按位“与”相当于“且”,如果用&连接表达式时,无论左面的表达式为true还是false,都会计算其右边的表达式,即左右两边都需要进行计算。位运算:如果相对应位都是1,则结果为1,否则为0
|按位“或”相当于“或”,如果用&连接表达式时,无论左面的表达式为true还是false,都会计算其右边的表达式,即左右两边都需要进行计算。位运算: 如果相对应位都是0,则结果为0,否则为1
^异或所组合的两个布尔表达式有相反的值时,才会产生true。如果两边都是true或都是false,则返回false。位运算:如果相对应位值相同,则结果为0,否则为1
~翻转位运算:按位补运算符翻转操作数的每一位,即0变成1,1变成0。
<<左移a<<b,将a的二进制数据左移b位,右边移空的部分补0。左移运算相当于实现整数乘以2的n次方。位移后不会改变操作数本身的结果。
>>右移a>>b,将a的二进制数据右移b位,如果最高位是0,则左边移空的部分补0,如果最高位是1,则左边移空的部分补1。右移运算相当于实现整数除以2的n次方。
>>>无符号右移不管最高位是0或1,左边移空部分都补0。

(新手可以暂时忽略左移、右移、无符号右移等位运算部分,因为涉及到二进制编程。)

A = 0011 1100
B = 0000 1101

A&b   = 0000 1100
A | B   = 0011 1101
A ^ B  = 0011 0001
~A      = 1100 0011

boolean c = true;
boolean d = false;
System.out.println(c^d);

int a = 60; /* 60 = 0011 1100 */
int b = 13; /* 13 = 0000 1101 */
int c = 0;
c = a & b;       /* 12 = 0000 1100 */
System.out.println("a & b = " + c ); //输出12

c = a | b;       /* 61 = 0011 1101 */
System.out.println("a | b = " + c ); //输出61

c = a ^ b;       /* 49 = 0011 0001 */
System.out.println("a ^ b = " + c ); //输出49

c = ~a;          /*-61 = 1100 0011 */
System.out.println("~a = " + c ); //输出-61

c = a << 2;     /* 240 = 1111 0000 */
System.out.println("a << 2 = " + c ); //输出240

c = a >> 2;     /* 15 = 1111 */
System.out.println("a >> 2  = " + c ); //输出15

c = a >>> 2;     /* 15 = 0000 1111 */
System.out.println("a >>> 2 = " + c ); //输出15

Java位运算

进位数制,简称“进制”,是按进位的原则进行计算的数制。

TIP:每位十六进制数相当于4位二进制数。

二进制数转换成十六进制数:
从个位数开始向左按每四位二进制数一组划分,
不足四位的前面以0补足,
然后将每组四位二进制数代之以一个十六进制数字即可。

十六进制数转换成二进制数,
将每一位十六进制数字代之与其等值的四位二进制数即可。

BC
10111100

B C
1011 1100

西文字符的编码:
计算机中的信息都是用二进制编码
表示的,用以表示字符的二进制编码称为
字符编码。例如ASCII码

ASCII码有7位码和8位码两种。
7位码使用7位二进制位表示一个字符的编码,
共有128个不同的编码值(2的7次方)
8位码则有256个不同的编码(2的8次方)

基数:一组固定不变的不重复数字的个数。
例如二进制的基数是2,十进制的基数是10.

位权:某个位置上的数代表的数量大小。
表示此数在整个数中所占的份量(权重)。
数位是指数码在一个数中所处的位置。
十进制的位权是10的i次方
二进制的位权是2的i次方
八进制的位权是8的i次方
十六进制的位权是16的i次方
其中i=(0,1,2,3,4,5…,n)为数位的编号,
表示数的某一数位

例如:
二进制的4位位权值为2的4次方=16
十六进制2位位权值为16的2次方=256

左移操作: x << n

x可以是byte, short, char, int, long基本类型, n(位移量)只能是int型

编译器的执行步骤:

  1. 如果x是byte, short, char类型, 则将x提升为int;

  2. 如果x是byte, short, char, int类型, 则n被重新赋值(过程是:取n的补码的低5位再转成十进制的int值,相当对n取32模: n=n%32);

如果x是long型, 则n被重新赋值(过程是:取n的补码的低6位再转成十进制的int值,相当对n取64模: n=n%64);

(因为int类型为4个字节,即32位,移动32位将没有任何意义.对于long则是模64)

  1. 对x左移n个位数, 整个表达式产生一个新值(x的值不变);

<<是左移符号,列x<<1,就是x的内容左移一位(x的内容并不改变)

>>是带符号位的右移符号,x>>1就是x的内容右移一位,如果开头是1则补1,是0责补0,(x的内容并不改变).

>>>是不带符号位的右移,x>>>1就是x的内容右移一位,
开头补0(x的内容并不改变)

补充说明

// 左移: 向左移动,右边补0

  for (int i = 0;i < 8 ;i++)

  System.out.print( (1 << i) + " ");

  output

  1 2 4 8 16 32 64 128

  // 右移: 向右移动,如果符号位(int型为32位)为0,左边补0,符号位为1,左边补1

  // 符号位为1的右移

  for (int i = 0;i < 8 ;i++)

  System.out.print( Integer.toHexString(0x40000000 >> i) + " ");

  output

  40000000 20000000 10000000 8000000 4000000 2000000 1000000 800000

  // 符号位为1的右移

  // 最高4位为1000, 右移1位,变成1100也就是c,

  for (int i = 0;i < 8 ;i++)

  System.out.print( Integer.toHexString(0x80000000 >> i) + " ");

  output

  80000000 c0000000 e0000000 f0000000 f8000000 fc000000 fe000000 ff000000

上面的通用法则没有错,但是有一个限制,对int型,移位的位数不超过32,对long型,移位的位数不超过64。现在进行如下测试:

System.out.println(Integer.toHexString(0x80000000 >> 31));

  // output: ffffffff

  System.out.println(Integer.toHexString(0x80000000 >> 32));

  // output: 80000000
  

0x80000000在右移31位后,每个位都成了1(也就是-1),按照这个想法,右移32位理所当然的还是-1,可是右移32位后,得到的结果却又这个数本身。

通过对int,long类型数据左右移进行测试,发现

java对移位运算"a <<||>> b"的处理,首先做 b mod 32||64运算, 如果a是int型,取mod 32,如果a是double型,取mod 64,然后再使用上面提到的通用移位运算规则进行移位。

到这里,就可以理解为什么在BitSet类中是

1L << bitIndex

这条语句,因为熟悉jdk的Programer知道,再写 1L << (bitIndex % 64) 对jdk来说是多余的。

运算符的优先级

在下面的表达式中,经常会出现一堆运算符同时出现的情况,那么哪个先执行哪个后执行呢?

顺序运算符
1括号
2一元运算符,如 -、++、- -和 !
3算术运算符,如 *、/、%、+ 和 -
4关系运算符,如 >、>=、<、<=、== 和 !=
5逻辑运算符,如 &、^、|、&&、||
6条件运算符和赋值运算符,如 ? :、=、*=、/=、+= 和 -=

表达式

表达式是符合一定语法规则的运算符和运算数的序列。

表达式名称表达式形式
算术表达式(x+y-12)*100
关系表达式x>y x>=y x!=y x==y
逻辑表达式x&&y x||y||z (!x)&&(!y)
赋值表达式x=y x+=y

Java语句分为两种:
1.声明语句:int i;
2.表达式语句:只有下面这几种表达式能够在末尾加上分号变成语句:
~含有=或者某个赋值表达式
~自加或自减表达式
~方法调用
~使用new来创建对象,即对象创建表达式


标识符

Java所有的组成部分都需要名字。
类名、对象名、变量名、接口名、数组名以及方法名等等都被称为标识符。

注意:
~只能由英文字母(A-Z或a-z)、数字(0-9)、下划线符号(_)组成;

~必须以英文字母、“_”或“$”开头,即不能以数字开头;

~除“_”和“$”以外,不能包含其它任何特殊字符,比如(@,#);

~不能与关键字(保留字)冲突;

~不能带有空格和数学符号;

~严格区分大小写;

合法标识符举例:age、$salary、_value、__1_value
非法标识符举例:123abc、-salary


关键字

所谓的关键字就是指在java中有特殊含义的词,
所有的关键字均为小写,
你起名的时候不可以用这些词,
goto与const作为保留关键字,在Java中并没有使用。
本列表按a-z的排列方式展现,红字必须背会。

关键字含义
abstract抽象类或方法
assert用来查找内部程序错误
boolean基本数据类型:8位布尔类型(因为java中没有1位这个单位)
break跳出一个switch或循环
byte基本数据类型:8位整数类型
char基本数据类型:16位字符类型
caseswitch的一个分支
catch捕获异常的try块子句
class定义一个类类型
continue在循环末尾继续
defaultswitch的缺省语句
dodo/while循环最前面的语句
double基本数据类型:64位双精度浮点数类型
elseif语句的else子句
enum枚举类型
extends继承一个父类
final一个常量,或不能覆盖的一个类或方法
finallytry块中总会执行的部分
float基本数据类型:32位单精度浮点数类型
for一个循环类型
false逻辑假
if一个条件语句
implements定义一个类实现的接口
import导入一个包
instanceof测试一个对象是否是某个类的实例
int基本数据类型:32位整型数
interface接口,一种抽象类型,仅有方法和常量的定义
long基本数据类型:64位长整数型
native由宿主系统实现的一个方法
new分配新的类实例,用于创建对象
null一个空引用
package包含类的一个包
private表示私有字段,或者方法等,只能从类内部访问
protected表示保护类型字段
public表示共有属性或者方法
return从一个方法中返回
short基本数据类型:16位整数类型
strictfp对浮点数计算使用严格的规则
switch选择语句
static修饰静态变量,静态代码块
super超类对象或构造函数
synchronized多线程同步机制,添加synchronized锁,修饰方法和块
throw抛出一个异常
this当前类的一个方法或构造函数的隐含参数
transient被transient修饰的属性无法被序列化
throws一个方法可能抛出的异常
try捕获异常的代码块
true逻辑真
void标记方法不返回任何值
volatile标记字段可能会被多个线程同时访问,而不做同步
while一种循环

流程控制

程序是按上下顺序执行的,
控制流语句允许改变程序执行的顺序,以及循环执行。

比如我需要你输出1万个"你好",
你会真的复制粘贴1万个System.out.println(“你好”);吗?
当然不,我们需要使用循环语句。

循环

顺序结构的程序语句只能被执行一次。
如果您想要同样的操作执行多次,就需要使用循环结构。

Java只有三种循环语句,
他们分别是:for循环,while循环,do while循环。

for循环

for循环为Java中最常见的循环,
比较灵活也比其他的循环略复杂一些,
for循环执行的次数是在执行前就确定的。

它的语法是:

for(初始化表达式;循环条件表达式;循环后的操作表达式) {
  //执行语句块
}

注意事项:

  1. 初始化表达式和循环后操作表达式可以只声明一个变量也可以用逗号分隔的声明多种变量或表达式,也可以是空语句;
  2. for语句中的循环后的操作表达式总会被执行,除非在循环体中出现了continue;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QAYGXeHL-1603360806832)(evernotecid://85A94EB2-9BD2-45DE-A16D-D9C9CD7ECF0B/appyinxiangcom/12192613/ENResource/p499)]

for(int x=1;x<3;x++){
  System.out.println("x="+x);
  //猜猜输出了什么?
}

在JDK1.5之后又出现了增强型的for循环,
也叫for each循环,主要用于数组&集合使用。
(数组&集合的概念会在之后讲解,新手可略过),
他的语法是:

for(声明语句 : 表达式){
   //代码句子
}

声明语句:声明新的局部变量,
该变量的类型必须和数组元素的类型匹配。

其作用域限定在循环语句块,其值与此时数组元素的值相等。
表达式:表达式是要访问的数组名,
或者是返回值为数组的方法。

int [] numbers = {10, 20, 30, 40, 50};

for(int x : numbers){
  System.out.print(x);
}

while循环

while是Java中最基本的循环,它的语法是:

while(条件表达式) {
  //执行语句块
}

只要条件表达式为 true,循环体会一直执行下去。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JqODlBHT-1603360806836)(evernotecid://85A94EB2-9BD2-45DE-A16D-D9C9CD7ECF0B/appyinxiangcom/12192613/ENResource/p502)]

int x = 1;
while(x < 3){
  System.out.println(x);
  x++;
}
//猜猜看输出了什么?

do while循环

对于while语句而言,如果不满足条件,
则不能进入循环。

但有时候我们需要即使不满足条件,也至少执行一次。
它的语法是:

do{
//执行语句块
} while(条件表达式);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AlGNu4kr-1603360806838)(evernotecid://85A94EB2-9BD2-45DE-A16D-D9C9CD7ECF0B/appyinxiangcom/12192613/ENResource/p503)]

int x = 3;
do{
  System.out.println(x);
  x++;
} while(x < 3);//猜猜看输出了什么?

中断

在使用循环语句时,只有循环条件表达式的值为false时,
才能结束循环。

有时,我们想提前中断循环,要实现这一点,
只需要在循环语句块中添加[break/continue/return]语句。
三者的作用范围:return>break>continue

continue

continue语句用在循环语句体中,用于终止某次循环过程,
让程序立刻跳转到下一次循环的迭代。

它的语法是:

continue;

只能出现在循环语句while、do…while、for中。

在for循环中,
continue语句使程序立即跳转到循环后的操作表达式。

在while或者do…while循环中,
程序立即跳转到布尔表达式的判断语句。

for(int i=1;i<50;i++) {
  if((i%2)==0){
    continue;
  }
  System.out.print(i+" ");
}

break

break语句用于终止某个语句块的执行。

用在循环语句体中,
可以强行退出本次循环(即本次循环后面的循环都不执行了),
它的语法是:

break;

可以出现在while、do while、for、switch语句体中。

for(int i=0;i<100;i++){
  if(i==10){
    break;
  }
  System.out.println("i="+i);
}
break的高级用法

break标签:可以出现在任何语句体中。

对Java来说,唯一用到标签的地方是在循环语句之前。
进一步说,它实际需要紧靠在循环语句的前方,
在标签和循环之间置入任何语句都是不明智的。

而在循环之前设置标签的唯一理由是:
我们希望在其中嵌套另一个循环或者一个开关。

  1. 简单的一个continue会退回最内层循环的开头(顶部),并继续执行;
  2. 带有标签的continue会到达标签的位置,并重新进入紧接在那个标签后面的循环;
  3. break会中断当前循环,并移离当前标签的末尾;
  4. 带标签的break会中断当前循环,并移离由那个标签指示的循环的末尾;
public class Test {
  public static void main(String[] args) {
    outer: for (int i = 0; i < 10; i++) {
      System.out.println("Outer loop");
        inner: while (true) {
          Scanner sc = new Scanner(System.in);
          String s = sc.next();
          System.out.println("inner Loop:" + s);
          if (s.equals("hello")) {
            break inner;
          }
          if (s.equals("kitty")) {
            break outer;
          }
        }
      }
    }
}

return

直接跳出当前方法,而不仅仅是跳出循环。
如果当前方法返回值为void,则直接写成:

return;

如果返回值不为void,则写成:

return 返回值;
public static void main(String[] args) throws Exception {
    for(int i = 0 ; i < 10 ; i ++){
        System.out.println(i);
        if(i==5){
            return; //可以分别把这里换成continue,return,break来感受一下
        }
    }
    System.out.println("我在外面");
}

嵌套循环

Java中允许循环套循环,例如:

for(int x = 0; x<2;x++){
  for(int y = 0;y<2;y++){
    System.out.println(x+" "+y);
  }
}

//输出
//0 0
//0 1
//1 0
//1 1

死循环

顾名思义,就是往死里循环,循环到死。。。

for(int x=1;;x++){
  System.out.println("x="+x);
}

while(true){
  System.out.println("死循环");
}

for(;;){
  System.out.println("死循环");
}

条件控制

顺序结构只能顺序执行,不能进行判断和选择,
因此需要分支结构。

Java只有两种分支结构:
if判断与switch判断

if

一个 if 语句包含一个布尔表达式和一条或多条语句。
语法1:

if(表达式){
  //执行语句块
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IgD2pKCu-1603360806839)(evernotecid://85A94EB2-9BD2-45DE-A16D-D9C9CD7ECF0B/appyinxiangcom/12192613/ENResource/p504)]

条件表达式可以是任何一种逻辑表达式如果表达式值为true,
则执行花括号的内容后,
再执行后面的语句如果表达的值为false,
则直接执行后面的语句


int a = 1;
if(a > 0){
  System.out.println("你好");
}

System.out.println("北京");

语法2:

if (表达式) {
  //执行语句块1
} else {
  //执行语句块
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eUrpveFR-1603360806840)(evernotecid://85A94EB2-9BD2-45DE-A16D-D9C9CD7ECF0B/appyinxiangcom/12192613/ENResource/p505)]
如果布尔表达式的值为true,
则执行语句1如果布尔表达式的值为false,
则执行语句2。

int x = 0;
if(x == 1){
  System.out.println(“x的值为1");
}else{
  System.out.println("x的值为“+x);
}

语法3:

if (表达式1) {
  //执行语句块1
} else if(表达式2) {
  //执行语句块2
} else if(表达式3) {
  //执行语句块3
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p3o0Bod8-1603360806840)(evernotecid://85A94EB2-9BD2-45DE-A16D-D9C9CD7ECF0B/appyinxiangcom/12192613/ENResource/p506)]

int x = -5;
if(x < 60){
  System.out.println("成绩不合格");
} else if(x >= 85){
  System.out.println("成绩优秀");
} else if(x == -5){
  System.out.println("系统出错");
} else{
  System.out.println("成级良好");
}

//猜猜看输出什么?有陷阱

for循环与if判断结合使用

for(int i = 1 ;i <= 1000 ; i ++){
  if(i == 3){
    System.out.println("Jack 我爱你");
  }else{
    System.out.println("Jack"+i);
  }
}

switch

switch语句判断一个变量与一系列值中某个值是否相等,
每个值称为一个分支。

语法:

switch (表达式){
  case 取值1:
    //语句块1
  break;//可选
  case 取值n:
    //语句块n
  break;//可选
  default: //语句块n+1
}

注意事项:

  1. 表达式的值只可以接受String(JDK1.7之后支持)、int、byte、char、short类型,枚举类型,不接受其他类型的值;
  2. 不允许有重复的case取值;
  3. switch一旦碰到第一次case匹配,程序就会跳转到这个标签位置,开始顺序执行以后所有的程序代码,而不管后面的case条件是否匹配,直到碰到break语句为止。因为这种写法会造成歧义,所以建议每个case必须写break;
  4. default,可选,default 在没有case语句的值和变量值相等的时候执行。dafault也可以写在case的上面,但不建议这么写;
int n = 2;
int result;
switch(n++){
  case 1:
    System.out.println("Block A");
    result = n;
  break;
  case 2:
      System.out.println("Block B");
      result = n*n;
  break;
  case 3:
      System.out.println("Block C");
      result = n*n*n;
  break;
  default: result = 0;
}
System.out.println("result="+result);
//猜猜输出的是什么?

int n = 1;//n=1与n=2的输出结果一样
switch(n++){
  case 1:
  case 2://此外case也可以叠在一起
      System.out.println("Block A or B");
  break;
  case 3:
      System.out.println("Block C");
  break;
}


总结

今天我们学习了Java里的大量基本语法,
为后面的编程打基础。


练习

  1. 在main()中定义8个变量,分别对应8种基本数据类型,并输出他们的初始值,之后再给他们赋值并输出。

  2. 不用程序运行,靠自己猜运行结果输出什么?

int a = 1;
int b = 2;
int c = 3;
System.out.println(b+=c--/++a);
//输出什么?复习上面的运算符优先级

int x = 2;
System.out.println(x++/3);
//输出什么?++在后面先操作再加1,相当于2/3,取整型

int y = 3;
System.out.println(x>=y);
//输出什么?x为什么是3而不是2呢?

y = 10;
System.out.println(x>=y);
//输出什么?
  1. 编写一个方法,需要传1个整型变量作为参数,方法中先把参数输出,再判断参数为偶数就返回true,非偶数返回false。
    在main方法中调用该方法3次,分别传入参数为3、4、5,并将方法的返回值输出。

  2. 编写一个方法,需要传入2个整型变量作为参数,方法中返回数值较大的参数,在main方法中调用该方法几次,参数自定义,并将方法的返回值输出。

  3. 编写一个方法,需要传入1个整型变量作为参数,方法中使用switch做判断,如果参数值为1则输出"星期一", 如果参数值为2则输出"星期二",
    依此类推,如果参数值不在1-7的范围内则输出"参数错误",在main方法中调用该方法几次,参数自定义。

  4. 编写一个方法,打印出一个菱形(这道题比较难,不允许搜百度上的答案)。

   *
  ***
 *****
*******
 *****
  ***
   *

友情提示:
System.out.println();输出是带换行的;
System.out.print();输出是不带换行的;
需要使用嵌套for循环;
一个循环输出空格,一个循环输出星号;一个循环输出换行;

  • 7
    点赞
  • 0
    评论
  • 4
    收藏
  • 一键三连
    一键三连
  • 扫一扫,分享海报

相关推荐
©️2020 CSDN 皮肤主题: 精致技术 设计师:CSDN官方博客 返回首页
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值